用到的知识:延迟绑定,strcpy特性,scanf特性,文件描述符
我这里用的libc2.35(用任意libc都行,这里不涉及堆)
关于ret2dl内容比较简单就不做说明了,这个程序坑点还是很多的,首先看看程序:
main:
main函数里面,有个strcpy,而strcpy除了会在末尾添加x00以外,还会被00截断,所以发送数据的时候记得不能用"x00"
sub_804930B:
这里读取了flag文件,返回的是文件描述符,如果文件不存在返回-1,这个坑放下面讲
sub_8049385:
是个比较函数
sub_8049269:
这里使用的scanf输入的,scanf遇到换行符终止,如果你用的send就会把下一次的输入,输入进这次的,需要注意。
sub_8049236:
栈溢出,溢出内容很大
程序全程没有输出,这时候最简单的打法就是想到re2dl了,先看3个exp
exp1:
exp2:
exp3:
首先有几个地方需要注意:
第一个:
也就是第二次发送的时候不能发送"x00"*0x20,因为会00截断,然后发送0x20大小是因为
dest和我们读取的flag文件描述符正好相差0x20,这时候可以通过strcpy特性把文件描述符变成0,也就成了标准输入。
第二个:
在一开始读取文件的时候,如果本地没有这个文件的话就会返回-1
本地无文件时候返回-1
本地有文件时候返回描述符3
如果没有文件这时候传给unk_804C080的值就是如下
这时候文件描述符就成了这个
如果ffffff00内存可以访问就不出错,不可访问的话直接退出,由于文件描述符不是0,也没办法达成后续修改src的目的
第三个:
exp2和3传入的内容不一样但是均可利用成功是因为满足了不同的条件:
满足其中一个即可,条件一&&就是判断两个表达式的真假性,只有两个表达式同时为真才为真,有一个为假则为假,具有短路性质,所以可以发送x00绕过,条件二就默认满足对比字符串就行
第四个:
scanf由于换行结束的原因,对比exp1和exp2,为什么后面多发送了一次,exp1使用的sendline,exp2使用的send,这样会卡住(或者把下一次输入当成这一次输入内容),而scanf参数用的整形的话不会把后面的ascii字母当作数字的
比如:
所以这里输入任意内容,只要不是数字就行,接收满了自然返回
然后这里主要说的ret2dl模块用法,能够快速的构建payload
Ret2dlresolvePayload的参数用法如下:
elf:相应的文件
symbol:libc里面的函数
args:函数的参数
data_addr:该payload所在的地址(默认会会放在bss比较高的地址上)
结合rop的话通用模板如下:
from pwn import*
elf =ELF("./xxx")
rop =ROP("./xxx")
dlresolve =Ret2dlresolvePayload(elf,symbol="system",args=["/bin/sh"])
rop.read(0,dlresolve.data_addr)
rop.ret2dlresolve(dlresolve)
raw =rop.chain()
io =process("./xxx")
io.sendafter('n',flat([{填充:raw}]))
io.send(dlresolve.payload)
io.interactive()
原文始发于微信公众号(由由学习吧):dlresolvePayload
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论