RSS Feed
更好更安全的互联网
  • Exim Off-by-one(CVE-2018-6789)漏洞复现分析

    2018-04-02

    作者:Hcamael@知道创宇404实验室

    前段时间meh又挖了一个Exim的RCE漏洞[1],而且这次RCE的漏洞的约束更少了,就算开启了PIE仍然能被利用。虽然去年我研究过Exim,但是时间过去这么久了,所以这次复现还是花了大量时间在熟悉Exim源码上。

    本次漏洞复现的过程中,踩了好多坑,实际复现的过程中发现堆块的实际情况无法像meh所说的那样的构造,所以在这部分卡了很久(猜测是因为环境不同的原因),之后决定先理解meh利用的大致思路,然后自己根据实际情况对堆块进行构造,虽然过程艰难,但最终基本算是成功了。

    复现环境搭建

    本次使用的环境和上次大致相同, 首先去github上该漏洞的patch commit[2]

    然后把分支切换到上一个commit

    Makefile仍然使用上次那个:

    然后就是编译安装了:

    启动也是跟上次一样,但是这里有一个坑点,开启debug,输出所有debug信息,不开debug,这些都堆的布局都会有影响。不过虽然有影响,但是只是影响构造的细节,总体的构造思路还是按照meh写的paper中那样。

    本篇的复现,都是基于只输出部分debug信息的模式:

    漏洞复现

    因为我觉得meh的文章中,漏洞原理和相关函数的说明已经很详细,我也没啥要补充的,所以直接写我的复现过程

    STEP 1

    首先需要构造一个被释放的chunk,但是没必要像meh文章说的是一个0x6060大小的chunk,只需要满足几个条件:

    这个chunk要被分为三个部分,一个部分是通过store_get获取,用来存放base64解码的数据,用来造成off by one漏洞,覆盖下一个chunk的size,因为通过store_get获取的chunk最小值是0x2000,然后0x10的堆头和0x10的exim自己实现的堆头,所以是一个至少0x2020的堆块。

    第二部分用来放sender_host_name,因为该变量的内存是通过store_malloc获取的,所以没有大小限制

    第三部分因为需要构造一个fake chunk用来过free的检查,所以也是一个至少0x2020的堆块

    和meh的方法不同,我通过unrecognized command来获取一个0x4041的堆块,然后通过EHLO来释放:

    0x1d15180是通过unrecognized command获取的一个0x4040大小的chunk,在执行完EHLO命令后被释放, 然后0x1d191c0是inuse的sender_host_name,这两部分就构成一个0x6060的chunk

    STEP 2

    现在的情况是sender_host_name位于0x6060大小chunk的最底部,而我们需要把它移到中间

    这部分的思路和meh的一样,首先通过unrecognized command占用顶部0x2020的chunk

    之前的文章分析过,unrecognized command申请内存的大小是ss = store_get(length + nonprintcount * 3 + 1);

    通过计算,只需要让length + nonprintcount * 3 + 1 > yield_lengthstore_get函数就会从malloc中申请一个chunk

    这个时候我们就能使用EHLO释放之前的sender_host_name,然后重新设置,让sender_host_name位于0x6060大小chunk的中部

    STEP 3

    现在我们的堆布局是:

    • 第一块未被使用的0x2020大小的chunk
    • 第二块正在被使用0x2000大小的sender_host_name
    • 第三块未被使用,并且和之后堆块合并, 0x6060大小的chunk

    我们现在再回过头来想想各个chunk的size的设置的问题

    CHUNK 1

    第一个chunk是用来触发off by one漏洞,用来修改第二个CHUNK的size位,只能溢出1byte

    store_get最小分配一个0x2020的chunk,能储存0x2000的数据

    这就导致了,如果按照store_get的最小情况来,只能溢出覆盖掉第二个chunk的pre_size位

    然后因为(0x2008-1)%3==0,所以我们能通过b64decode函数的漏洞申请一个能储存0x2008的数据,size=0x2020的chunk,然后溢出一个字节到下一个chunk的size位

    CHUNK2

    第二块chunk,我们首先需要考虑,因为只能修改一个字节,所以最大只能从0x00扩展到0xf0

    其次,我们假设第二块chunk的原始size=0x2021,然后被修改成0x20f1,我们还需要考虑第二块chunk+0x20f1位置的堆块我们是否可控,因为需要伪造一个fake chunk,来bypass free函数的安全检查。

    经过多次调试,发现当第二块chunk的size=0x2001时,更方便后续的利用

    CHUNK3

    第三个chunk只要求大于一个store_get申请的最小size(0x2020)就行了

    STEP 4

    根据第三步叙述的,我们来触发off by one漏洞

    并且构造在第三块chunk中构造一个fake chunk

    STEP 5

    下一步跟meh一样,通过释放sender_host_name,把一个原本0x2000的chunk扩展成0x20f0, 但是却不触发smtp_reset

    STEP 6

    meh提供了一种不需要泄露地址就能RCE的思路

    exim有一个expand_string函数,当其处理的参数中有${run{xxxxx}}, xxxx则会被当成shell命令执行

    acl_check函数中会对各个命令的配置进行检查,然后把配置信息的字符串调用expand_string函数

    我复现环境的配置信息如下:

    所以我有rcpt, data, auth这三个命令可以利用

    比如0x0000000001cedae0地址当前的内容是:

    当我把该字符串修改为${run{/usr/bin/touch /tmp/pwned}}

    则当我向服务器发送AUTH命令时,exim将会执行/usr/bin/touch /tmp/pwned

    所以之后就是meh所说的利用链:

    修改storeblock的next指针为储存acl_check_xxxx字符串的堆块地址 -> 调用smtp_reset -> 储存acl_check_xxxx字符串的堆块被释放丢入unsortedbin -> 申请堆块,当堆块的地址为储存acl_check_xxxx字符串的堆块时,我们可以覆盖该字符串为命令执行的字符串 -> RCE

    STEP 7

    根据上一步所说,我们首先需要修改next指针,第二块chunk的原始大小是0x2000,被修改后新的大小是0x20f0,下一个storeblock的地址为第二块chunk+0x2000,next指针地址为第二块chunk+0x2010

    所以我们申请一个0x2020的chunk,就能够覆盖next指针:

    这里有一个问题

    第二个chunk在AUTH CRAM-MD5命令执行时就被分配了,所以b64decode的内存是从next_yield获取的

    这样就导致一个问题,我们能通过之前的构造来控制在执行b64decodeyield_length的大小,最开始我的一个思路就是,仍然利用off by one漏洞来修改next,这也是我理解的meh所说的partial write

    但是实际情况让我这个思路失败了

    当前的next指针的值为0x1d171b0,如果利用我的思路是可以修改1-2字节,然而储存acl_check_xxx字符的堆块地址为0x1ced980

    我们需要修改3字节,所以这个思路行不通

    所以又有了另一个思路,因为exim是通过fork起子进程来处理每个socket连接的,所以我们可以爆破堆的基地址,只需要爆破2byte

    STEP 8

    在解决地址的问题后,就是对堆进行填充,然后修改相关acl_check_xxx指向的字符串

    然后附上利用截图:

    总结

    坑踩的挺多,尤其是在纠结meh所说的partial write,之后在github上看到别人公布的exp[3],同样也是使用爆破的方法,所以可能我对partial write的理解有问题吧

    另外,通过与github上的exp进行对比,发现不同版本的exim,acl_check_xxx的堆偏移也有差别,所以如果需要RCE exim,需要满足下面的条件:

    1. 包含漏洞的版本(小于等于commit 38e3d2dff7982736f1e6833e06d4aab4652f337a的版本)
    2. 开启CRAM-MD5认证,或者其他有调用b64decode函数的认证
    3. 需要有该exim的binary来计算堆偏移
    4. 需要知道exim的启动参数

    参考

    1. https://devco.re/blog/2018/03/06/exim-off-by-one-RCE-exploiting-CVE-2018-6789-en/
    2. https://github.com/Exim/exim/commit/cf3cd306062a08969c41a1cdd32c6855f1abecf1
    3. https://github.com/skysider/VulnPOC/tree/master/CVE-2018-6789
    作者:知道创宇404实验室 | Categories:安全研究技术分享 | Tags:
  • 从补丁到漏洞分析 –记一次joomla漏洞应急

    2018-02-07

    作者:LoRexxar’@知道创宇404实验室

    2018年1月30日,joomla更新了3.8.4版本,这次更新修复了4个安全漏洞,以及上百个bug修复。

    https://www.joomla.org/announcements/release-news/5723-joomla-3-8-4-release.html

    为了漏洞应急这几个漏洞,我花费了大量的时间分析漏洞成因、寻找漏洞触发位置、回溯逻辑,下面的文章比起漏洞分析来说,更接近我思考的思路,希望能给大家带来不一样的东西。

    背景

    其中的4个安全漏洞包括

    根据更新,我们去到github上的joomla项目,从中寻找相应的修复补丁,可以发现,4个安全漏洞的是和3.8.4的release版同时更新的。

    https://github.com/joomla/joomla-cms/commit/0ec372fdc6ad5ad63082636a0942b3ea39acc7b7

    通过补丁配合漏洞详情中的简单描述我们可以确定漏洞的一部信息,紧接着通过这部分信息来回溯漏洞成因。

    SQLi vulnerability in Hathor postinstall message

    https://developer.joomla.org/security-centre/722-20180104-core-sqli-vulnerability.html

    补丁分析

    第一个漏洞说的比较明白,是说在Hathor的postinstall信息处,由于错误的类型转换导致了注入漏洞。

    我们来看看相应的补丁

    符合漏洞描述的点就是这里,原来的取第一位改为了对取出信息做强制类型转换,然后拼接入sql语句。

    这里假设我们可以控制$adminstyle,如果我们通过传入数组的方式设置该变量为数组格式,并且第1个字符串可控,那么这里就是一个可以成立的漏洞点。

    现在我们需要找到这个功能的位置,并且回溯变量判断是否可控。

    找到漏洞位置

    hathor是joomla自带的两个后台模板之一,由于hathor更新迭代没有isis快,部分功能会缺失,所以在安装完成之后,joomla的模板为isis,我们需要手动设置该部分。

    修改完成后回到首页,右边就是postinstallation message

    回溯漏洞

    回到代码中,我们需要找到$adminstyle这个变量进入的地方。

    这里user为JFactory::getUser(),跟入getParam方法

    这里$this->_params来自$this->_params = new Registry;

    跟入Registry的get方法

    根据这里的调用方式来看,这里会通过这里的的判断获取是否存在adminstyle,如果没有则会返回default(这里为空)

    接着回溯$this->data,data来自$this->data = new \stdClass;

    回溯到这里可以发现$admin_style的地方是从全局变量中中读取的。

    默认设置为空/administrator/components/com_users/models/forms/user.xml

    但我们是可以设置这个的

    后台users->users->super user设置,右边我们可以设置当前账户使用的后台模板,将右边修改为使用hathor型模板。

    通过抓包我们可以发现,这里显式的设置了当前账户的admin_type,这样如果我们通过传入数组,就可以设置admin_type为任意值

    然后进入代码中的数据库操作
    /administrator/templates/hathor/postinstall/hathormessage.php function hathormessage_postinstall_condition

    访问post_install页面触发

    XSS vulnerability in com_fields

    https://developer.joomla.org/security-centre/720-20180102-core-xss-vulnerability.html

    补丁分析

    漏洞详情写了很多,反而是补丁比较模糊,我们可以大胆猜测下,当插入的字段类型为list、radio、checkbox多出的部分变量没有经过转义

    首先我们需要先找到触发点

    后台content->fields->new,然后设置type为radio,在键名处加入相应的payload

    然后保存新建文章

    成功触发

    漏洞分析

    由于补丁修复的方式比较特殊,可以猜测是在某些部分调用时使用了textContent而不是nodeValue,在分析变量时以此为重点。

    漏洞的出发点/administrator/components/com_fields/libraries/fieldslistplugin.php line 31

    由于找不到该方法的调用点,所以我们从触发漏洞的点分析流程。

    编辑文章的上边栏是通过administrator/components/com_content/views/article/tmp/edit.php line 99载入的

    这里JLayoutHelper:render会进入/layouts/joomla/edit/params.php

    然后在129行进入JLayoutHelper::render('joomla.edit.fieldset', $displayData);

    跟入/layouts/joomla/edit/fieldset.php line 16,代码在这里通过执行formgetFieldset获取了提交的自定义字段信息。

    跟入/libraries/src/Form/Form.php line 329 function getFieldset

    跟如1683行 findFieldsByFieldset函数。

    这里调用xml来获取数据,从全局的xml变量中匹配。

    这里的全局变量中的xml中的option字段就来自于设置时的$option->textContent,而只有list, radio and checkbox.这三种是通过这里的函数做处理,其中list比较特殊,在后面的处理过程中,list类型的自定义字段会在/libraries/cms/html/select.php line 742 function options被二次处理,但radio不会,所以漏洞存在。

    整个xss漏洞从插入到触发限制都比较大,实战价值较低。

    XSS vulnerability in Uri class

    https://developer.joomla.org/security-centre/721-20180103-core-xss-vulnerability.html

    补丁分析

    比起其他几个来说,这里的漏洞就属于特别清晰的,就是在获取系统变量时,没做相应的过滤。

    前台触发方式特别简单,因为这里的script_name是获取基础url路径的,会拼接进所有页面的和链接有关系的地方,包括js或者css的引入。

    漏洞利用

    让我们来看看完整的代码

    很明显只有当$script_name = $_SERVER['PHP_SELF']的时候,漏洞才有可能成立

    只有当php是fastcgi运行,而且cgi.fix_pathinfo = 0时才能进入这个判断,然后利用漏洞还有一个条件,就是服务端对路径的解析存在问题才行。

    当该路径能被正常解析时,http://127.0.0.1/index.php/{evil_code}就会被错误的设置为基础URL拼接入页面中。

    一个无限制的xss就成立了

    XSS vulnerability in module chromes

    https://developer.joomla.org/security-centre/718-20180101-core-xss-vulnerability.html

    补丁分析

    漏洞存在的点比较清楚,修复中将$moduleTag进行了一次转义,同样的地方有三处,但都是同一个变量导致的。

    这个触发也比较简单,当我们把前台模板设置为protostar(默认)时,访问前台就会触发这里的modChrome_well函数。

    漏洞利用

    让我们看看完整的代码

    很明显后面module_tag没有经过更多处理,就输出了,假设我们可控module_tag,那么漏洞就成立。

    问题在于怎么控制,这里的函数找不到调用的地方,能触发的地方都返回了传入的第二个值,猜测和上面的get_param一样,如果没有设置该变量,则返回default值。

    经过一番研究,并没有找到可控的设置的点,这里只能暂时放弃。

    ref

    作者:知道创宇404实验室 | Categories:安全研究技术分享 | Tags:
  • DeDeCMS v5.7 密码修改漏洞分析

    2018-01-18

    作者:LoRexxar'@知道创宇404实验室

    #### 0x01 背景

    织梦内容管理系统(DedeCms)以简单、实用、开源而闻名,是国内最知名的PHP开源网站管理系统,也是使用用户最多的PHP类CMS系统,在经历多年的发展,目前的版本无论在功能,还是在易用性方面,都有了长足的发展和进步,DedeCms免费版的主要目标用户锁定在个人站长,功能更专注于个人网站或中小型门户的构建,当然也不乏有企业用户和学校等在使用该系统。

    2018年1月10日, 锦行信息安全公众号公开了一个关于DeDeCMS前台任意用户密码修改漏洞的细节\[2]。

    2018年1月10日,Seebug漏洞平台\[3]收录该漏洞,漏洞编号为SSV-97074,知道创宇404漏洞应急团队成功复现该漏洞。

    2018年1月17日,阿里先知平台公开了一个任意用户登陆漏洞\[4]\[5],和一个安全隐患\[6],通过组合漏洞,导致后台密码可以被修改。

    2018年1月18日,知道创宇404漏洞应急团队成功复现该漏洞。

    #### 0x02 漏洞简述

    整个漏洞利用链包括3个过程:

    1. 前台任意用户密码修改漏洞
    2. 前台任意用户登陆漏洞
    3. 前台管理员密码修改可影响后台的安全隐患

    通过3个问题连起来,我们可以重置后台admin密码,如果我们获得了后台地址,就可以进一步登陆后台进行下一步攻击。

    ##### 1、前台任意用户密码修改漏洞
    前台任意用户密码修改漏洞的核心问题是由于DeDeCMS对于部分判断使用错误的弱类型判断,再加上在设置初始值时使用了NULL作为默认填充,导致可以使用弱类型判断的漏洞来绕过判断。

    漏洞利用有几个限制:

    1. 漏洞只影响前台账户 admin账户在前台是敏感词无法登陆
    2. admin账户的前后台密码不一致,无法修改后台密码。
    3. 漏洞只影响未设置密保问题的账户

    ##### 2、前台任意用户登陆漏洞

    前台任意用户登陆漏洞主要是利用了DeDeCMS的机制问题,通过一个特殊的机制,我们可以获得任意通过后台加密过的cookie,通过这个cookie我们可以绕过登陆,实现任意用户登陆。

    漏洞利用有一个限制:

    如果后台开启了账户注册审核,那就必须等待审核通过才能进行下一步利用。

    ##### 3、前台管理员密码修改可影响后台的安全隐患

    在DeDeCMS的设计中,admin被设置为不可从前台登陆,但是当后台登陆admin账户的时候,前台同样会登陆管理员账户。

    而且在前台的修改密码接口,如果提供了旧密码,admin同样可以修改密码,并且这里修改密码会同步给后台账户。

    通过3个漏洞配合,我们可以避开整个漏洞利用下的大部分问题。

    前台任意用户密码修改漏洞->修改admin密码,前台任意用户登录漏洞->登陆admin账户,通过刚才修改的admin密码,来重置admin账户密码。

    #### 0x03 漏洞复现

    ##### 1、 登陆admin前台账户

    安装DeDeCMS
    ![](https://images.seebug.org/content/images/2018/01/5d867e22-6725-44a0-8921-eb1a470accb1.png-w331s)

    注册用户名为000001的账户

    ![](https://images.seebug.org/content/images/2018/01/2c982abb-8803-4ace-b900-b76fdebb1090.png-w331s)

    由于是本地复现漏洞,所以我们直接从数据库中修改为审核通过

    ![](https://images.seebug.org/content/images/2018/01/62afac8d-5130-4df8-9755-b14d505cadc2.png-w331s)

    访问

    http://your_website/member/index.php?uid=0000001

    ![](https://images.seebug.org/content/images/2018/01/f5289b12-2d0c-4d1c-9c7a-f4ad0d1053cd.png-w331s)

    获取cookie中last_vid_ckMd5值,设置DeDeUserID_ckMd5为刚才获取的值,并设置DedeUserID为0000001

    访问

    http://your_website/member/

    ![](https://images.seebug.org/content/images/2018/01/81bdc4e1-6df5-4cb8-be06-1aebe66d7e47.png-w331s)

    ##### 2、修改admin前台登陆密码

    使用DeDeCMS前台任意用户密码修改漏洞修改admin前台密码。

    构造漏洞利用请求


    http://yourwebsite/member/resetpassword.php

    dopost=safequestion&safequestion=0.0&safeanswer=&id=1

    ![](https://images.seebug.org/content/images/2018/01/65169b22-9cca-49a4-b049-6b781721bad5.png-w331s)

    从Burp获取下一步利用链接

    /member/resetpassword.php?dopost=getpasswd&id=1&key=nlszc9Kn

    ![](https://images.seebug.org/content/images/2018/01/01734ff4-d48d-42ca-b5d2-ec8837ee70e9.png-w331s)

    直接访问该链接,修改新密码

    ![](https://images.seebug.org/content/images/2018/01/c0f3ffe5-6eb1-4064-92e4-16c366d84ba8.png-w331s)

    成功修改登陆admin密码

    ##### 3、修改后台密码

    访问


    http://yourwebsite/member/edit_baseinfo.php

    使用刚才修改的密码再次修改密码

    ![](https://images.seebug.org/content/images/2018/01/e77740d5-d2f6-443b-b4db-3ba0dbb7a37b.png-w331s)

    成功登陆

    ![](https://images.seebug.org/content/images/2018/01/c68183da-b541-40e3-86d2-8b75aadb361a.png-w331s)

    #### 0x04 代码分析

    ##### 1、 前台任意用户登陆

    在分析漏洞之前,我们先来看看通过cookie获取登陆状态的代码。


    /include/memberlogin.class.php 161行

    ![](https://images.seebug.org/content/images/2018/01/ca006dbb-b378-48b4-a907-1fb7ea9b3c85.png-w331s)

    通过GetCookie函数从DedeUserID取到了明文的M_ID,通过intval转化之后,直接从数据库中读取该id对应的用户数据。

    让我们来看看GetCookie函数


    /include/helpers/cookie.helper.php 56行

    ![](https://images.seebug.org/content/images/2018/01/0a4a3a7c-3378-4d06-b4d4-e92f6f838185.png-w331s)

    这里的cfg_cookie_encode是未知的,DeDeCMS通过这种加盐的方式,来保证cookie只能是服务端设置的,所以我们没办法通过自己设置cookie来登陆其他账户。

    这里我们需要从别的地方获取这个加密后的值。


    /member/index.php 161行

    ![](https://images.seebug.org/content/images/2018/01/083c37a6-97ff-4655-8c96-0bf481c554e9.png-w331s)

    161行存在一段特殊的代码,这段代码是用来更新最新的访客记录的,当last_vid没有设置的时候,会把userid更新到这个变量中,更新到flag中。

    而这里的userid就是注册时的用户名(如果不是已存在的用户名的话,会因为用户不存在无法访问这个页面)。

    通过这种方式,我们就可以通过已知明文来获取我们想要的密文。

    这里我们通过注册userid为形似00001或者1aaa这样的用户,在获取登陆状态时,mid会经过intval的转化变为1,我们就成功的登陆到admin的账户下。

    ps:该漏洞影响所有用户

    ##### 2、前台任意用户密码修改

    漏洞主要逻辑在 /member/resetpassword.php 75行至95行

    ![](https://images.seebug.org/content/images/2018/01/80dc5c44-533f-4eb2-8dae-c75f255a936b.png-w331s)

    当找回密码的方式为安全问题时

    dedecms会从数据库中获取用户的安全问题、回答进行比对,当我们在注册时没设置安全问题时。

    从数据库中可以看到默认值为NULL(admin默认没有设置安全问题)

    ![](https://images.seebug.org/content/images/2018/01/33dd3447-bc19-4fc4-a869-f3961a67bd55.png-w331s)

    下面是设置了安全问题时数据库的样子,safequestion代表问题的id,safeanswer代表安全问题的回答。

    我们需要绕过第一个判断

    if(empty($safequestion)) $safequestion = '';

    这里我们只要传入0.0就可以绕过这里,然后0.0 == 0为True,第二个判断NULL==""为True,成功进入sn函数。

    跟入/member/inc/inc_pwd_functions.php 第150行

    ![](https://images.seebug.org/content/images/2018/01/005be5b8-87cc-433d-8b39-2f7dadeec734.png-w331s)

    有效时间10分钟,进入newmail函数

    跟入/member/inc/inc_pwd_functions.php 第73行

    ![](https://images.seebug.org/content/images/2018/01/23657efd-40df-4619-a322-89d3d68974c9.png-w331s)

    77行通过random生成了8位的临时密码。

    这里我们使用的是安全问题修改密码,所以直接进入94行,将key代入修改页。

    跳转进入形似

    /member/resetpassword.php?dopost=getpasswd&id=1&key=nlszc9Kn

    的链接,进入修改密码流程

    唯一存在问题的是,这里&错误的经过一次编码,所以这里我们只能手动从流量中抓到这个链接,访问修改密码。

    ##### 3、修改后台密码安全隐患

    在DeDeCMS的代码中,专门对前台修改管理员密码做了设置,如果是管理员,则一并更新后台密码,也就是这个安全隐患导致了这个问题。


    /member/edit_baseinfo.php 119行

    ![](https://images.seebug.org/content/images/2018/01/921e15f3-9e3e-4a34-a1f3-54475a6f25eb.png-w331s)

    #### 0x05 修复方案

    截至该文章完成时,DeDeCMS的官方仍然没有修复该漏洞,所以需要采用临时修复方案,等待官方正式修复更新。

    由于攻击漏洞涉及到3个漏洞,但官方仍然没有公开补丁,所以只能从一定程度上减小各个漏洞的影响。

    - 前台任意用户登陆漏洞:开启新用户注册审核,当发现userid为1xxxx或1时,不予以
    通过审核。

    在官方更新正式补丁之前,可以尝试暂时注释该部分代码,以避免更大的安全隐患

    /member/index.php 161-162行

    ![](https://images.seebug.org/content/images/2018/01/f88b5b3e-567b-4f72-a3cb-5efb4a7a18cb.png-w331s)

    - 前台修改后台管理员密码:设置较为复杂的后台地址,如果后台地址不可发现,则无法登陆后台。
    - 前台任意用户密码修改漏洞:

    修改文件/member/resetpassword.php 第84行
    ![](https://images.seebug.org/content/images/2018/01/7b8c7600-68dc-4eb9-bfc5-bfee00d158b7.png-w331s)

    将其中的==修改为===

    ![](https://images.seebug.org/content/images/2018/01/920c7470-c038-44a7-b43d-12c27a8f5a87.png-w331s)

    即可临时防护该该漏洞。

    #### 0x06 ref

    [1] DeDeCMS官网

    [2] 漏洞详情原文

    [3] Seebug漏洞平台

    [4] 阿里先知平台漏洞分析1

    [5] 阿里先知平台漏洞分析2

    [6] 漏洞最早分析原文

    作者:知道创宇404实验室 | Categories:安全研究技术分享 | Tags:
  • 如何通过TTL调试光猫

    2018-01-17

    作者:Sebao@知道创宇404实验室

    序言

    众所周知,光猫是现在每个家庭必备的一款设备,但是光猫背面写的账号密码,只是普通用户权限,会限制很多功能。这篇文章讲述,如何通过TTL调试的方法获取光猫超级管理员的权限。

    0x00 名词解释

    引脚介绍(COM口pin比较多,但是常用的也是这几个):

    VCC:供电pin,一般是3.3v,在我们的板子上没有过电保护,这个pin一般不接更安全

    GND:接地pin,有的时候rx接受数据有问题,就要接上这个pin,一般也可不接

    RX:接收数据pin

    TX:发送数据pin,我之前碰到串口只能收数据,不能发数据问题,经baidu,原来是设置了流控制,取消就可以了,适用于putty,SecureCRT

    在调试的时候, 多数情况下我们只引出rx,tx即可.

    0x01 所需工具:

    1,万用表

    2,TTL转USB版

    3,电烙铁

    4,杜邦线若干只

    5,SecureCRT

    0x02 华为光猫

    TTL调试的第一步骤就是拆机,拆机步骤这里就不详细描述。这里先看一下拆下来的光猫板子是什么样子的。

    TTL调试我们首先要找出 GND,RX,TX。从图中可以看到,已经标识出了 GND,RX,TX的接口,就需要通过USB转TTL小板串口读取固件。 查找GND,可以用万用表查找。

    用杜邦线连接到板子上,线序为GND接GND,RXD接TTL板的TXD,TXD 接TTL板的RXD。

    USB端连接上电脑,在控制面板,设备管理器查看串口(一般在COM1-COM12之间),Connection type设置为:Serial,Serial line设置为你电脑上显示的串口,Speed设置为115200,然后连接。接通电源后等待,在这一段时间内串口应该会打印很多启动信息,启动差不多后,敲回车:

    然后输入默认的账号root 密码 admin登录进去,输入shell命令,进入busybox.看一下此设备的cpu架构,用的是ARM7.

    准备查找超级管理员的密码。进入/mnt/jffs2目录,复制配置文件hw_ctree.xml到myconf.xml.gz中。这个文件是AES加密的,所以先解密,命令为aescrypt2 1 myconf.xml.gz tmp

    解密后的文件还是被压缩了的,所以要用gzip命令展开压缩文件myconf.xml.gz,得到myconf.xml。命令为:gzip -d myconf.xml.gz

    然后用 grep 命令 查找telecomadmin,也就是超级管理员的密码。命令为:grep telecomadmin myconf.xml

    0x03 烽火光猫

    和上述步骤一样,首先拆开光猫找到 GND,RX,TX。这个板子人性化的已经标明了GND,RX,TX。

    所以直接用杜邦线连接到板子上,线序为GND接GND,RXD接TTL板的TXD,TXD 接TTL板的RXD。

    USB端连接上电脑。

    接通电源后等待,在这一段时间内串口应该会打印很多启动信息,这里直接CTRL+C 跳过直接进入shell模式,这个也算是一个“后门”。输入命令 cat proc/cpuinfo查看cpu的架构。

    进入shell获取超级管理员的方法差不多,参考上文即可,这里不再详细描述。

    0x04 长虹光猫

    和上述步骤一样。

    因为这里没有针孔,所以需要焊接杜邦线到板子上,以便于固定杜邦线。

    USB端连接上电脑。

    0x05 总结

    感谢 知道创宇404实验室 dawu,fenix提供的思路以及技巧。

    作者:知道创宇404实验室 | Categories:安全研究技术分享 | Tags:
  • Huawei HG532 系列路由器远程命令执行漏洞分析

    2017-12-28

    作者:fenix@知道创宇404实验室
    English version: https://paper.seebug.org/508/

    背景

    华为 HG532 系列路由器是一款为家庭和小型办公用户打造的高速无线路由器产品。

    2017/11/27,Check Point 软件技术部门报告了一个华为 HG532 产品的远程命令执行漏洞(CVE-2017-17215)【1】

    该漏洞在被报告前,互联网上产生了大量未被关注的此类漏洞攻击利用包,遍及全球多个国家。Payload 已被证实是知名病毒 Mirai 的升级版变种 OKIRU/SATORI。该 Payload 功能非常简单,主要通过发送精心制作的 UDP/TCP 报文来对目标发起 DDoS 攻击。

    2017/11/23,知道创宇 404 实验室的 ZoomEye 网络探针系统也捕获到了该攻击的 Payload。

    漏洞分析

    固件下载

    网上有 HG532e 版本的公开固件,下载地址【2】

    下载该固件,利用 binwalk 直接解压。

    目标系统是 MIPS 32 位 大端架构。

    漏洞分析

    根据 Check Point 的报告【1】,该远程命令执行漏洞的漏洞点位于 UPnP 服务中。

    UPnP 是由“通用即插即用论坛”(UPnP™ Forum)推广的一套网络协议。该协议的目标是使家庭网络(数据共享、通信和娱乐)和公司网络中的各种设备能够相互无缝连接,并简化相关网络的实现。

    直接将固件中负责 UPnP 服务的 upnp 程序扔到 IDA。

    通过字符串 NewStatusURL 对漏洞点进行定位。

    跟踪数据交叉引用

    漏洞点如下

    ATP_XML_GetChildNodeByName 函数的定义如下。

    程序首先进行 SOAP XML 报文解析,得到元素 NewDownloadURL 和 NewStatusURL 的值。然后进行以下拼接,最终调用 system() 函数执行。

    upg 是路由器的一个升级程序,他的参数功能如下。

    现在我们有两个命令注入点,NewDownloadURLNewStatusURL

    漏洞验证

    目标系统提供了以下命令。

    利用 wget 命令进行漏洞测试。发送以下报文。

    可以看到,我们成功在监听的端口上收到了请求。

    值得一提的是,HG532e 路由器的 uPnP 服务和防火墙都是默认开启的,防火墙默认等级为低级。

    在默认设置下,从 WAN 口访问 37215 端口会被防火墙拦截,漏洞无法被利用。

    防护方案

    2017/11/30,华为官方发布了安全公告【4】,确认了该漏洞。
    公告中提到了以下漏洞缓解措施

    • 配置路由器内置的防火墙
    • 更改路由器默认密码
    • 在路由器外部署防火墙

    是的,没找到固件升级包,所以,没有补丁分析…

    总结

    1. 和爱尔兰宽带路由器 SetNTPServers 命令注入【3】类似,这个漏洞整体来看就是一个简单的命令拼接。
    2. 该漏洞也为我们漏洞挖掘提供了一个很好的方向。snprintf()、system() 等函数附近的程序逻辑都应该被重点关注。
    3. 还是那句话,一切进入函数的变量都是有害的。大部分远程命令执行漏洞要么是过滤不全,导致命令拼接。要么是没有进行变量长度控制,造成缓冲区溢出。关于这点设备供应商应该负责任,安全开发意识非常重要。

    参考链接

    【1】 Check Point 漏洞报告
    https://research.checkpoint.com/good-zero-day-skiddie/
    【2】 HG532e 固件下载
    https://ia601506.us.archive.org/22/items/RouterHG532e/router%20HG532e.rar
    【3】 爱尔兰宽带路由器 SetNTPServers 命令注入
    https://www.seebug.org/vuldb/ssvid-97024/https://www.seebug.org/vuldb/ssvid-97024
    【4】 华为安全公告
    http://www.huawei.com/en/psirt/security-notices/huawei-sn-20171130-01-hg532-en/http://www.huawei.com/en/psirt/security-notices/huawei-sn-20171130-01-hg532-en

    作者:知道创宇404实验室 | Categories:安全研究技术分享 | Tags:
  • Vivotek 摄像头远程栈溢出漏洞分析及利用

    2017-12-14

    作者:fenix@知道创宇404实验室

    前言

    近日,Vivotek 旗下多款摄像头被曝出远程未授权栈溢出漏洞,攻击者发送特定数据可导致摄像头进程崩溃。

    漏洞作者@bashis 放出了可造成摄像头 Crash 的 PoC :https://www.seebug.org/vuldb/ssvid-96866/https://www.seebug.org/vuldb/ssvid-96866

    该漏洞在 Vivotek 的摄像头中广泛存在,按照官方的安全公告,会影响以下版本

    Vivotek 官方提供了各种型号摄像头的固件下载:http://www.vivotek.com/firmware/ ,这也为我们的研究带来了很多便利。

    我们发现,漏洞被曝出之后,在官网固件下载页面中的大多数固件均早于漏洞曝出时间,我们下载了几款摄像头的最新固件进行验证,发现漏洞依然存在,这意味着截止漏洞被曝出,Vivotek 官方对该漏洞的修复并不彻底。众所周知,栈溢出是存在潜在的远程命令执行风险的,为了深入了解该漏洞的影响,我们决定研究下该漏洞的原理及利用。

    调试环境搭建

    固件下载

    由于手头上并没有 Vivotek 的摄像头,我们在官网下载其中一款摄像头固件,使用 qemu 模拟运行。(注:官方在陆续发布各个版本的固件更新,可根据固件发布时间判断官方是否已经修复漏洞)

    首先下载摄像头固件:http://download.vivotek.com/downloadfile/downloads/firmware/cc8160firmware.zip/http://download.vivotek.com/downloadfile/downloads/firmware/cc8160firmware.zip

    通过 binwalk 直接解压出其中的文件系统,和漏洞有关的主要文件如下

    根据 file 命令的结果可知目标架构为 ARM、小端、32位。且该 ELF 文件为动态链接。

    修复运行依赖

    尝试用 qemu 运行,结果如下

    服务没有运行起来,且没有明显的报错,猜想到可能是缺少某些依赖,程序直接退出了,扔到 IDA,从程序退出前的提示:gethostbyname:: Success,回溯程序异常退出原因。

    依次加载IDA 菜单栏 -> View -> Open subviews -> Strings,Command + F 搜索 gethostname

    查看交叉引用信息,定位相应代码段

    异常退出部分代码如下

    为了看的更直观,我们来贴一下 F5 的结果,如下

    这部分主要涉及两个函数。gethostname():返回本地主机的标准主机名,如果函数成功,则返回 0。如果发生错误则返回 -1。gethostbyname():用域名或主机名获取IP地址。

    Linux 操作系统的 hostname 是一个 kernel 变量,可以通过 hostname 命令来查看本机的 hostname。也可以直接 cat /proc/sys/kernel/hostname 查看。

    我们只需要将二者改成一致,httpd 服务即可成功运行。

    调试环境

    为了方便调试,还需要搭建 qemu 虚拟机环境。

    qemu 镜像文件下载:https://people.debian.org/~aurel32/qemu/armel/ (下载内核 3.2 的版本)

    远程调试 gdbserver:https://github.com/mzpqnxow/gdb-static-cross/tree/master/prebuilt-static/https://github.com/mzpqnxow/gdb-static-cross/tree/master/prebuilt-static

    qemu 虚拟机建议采用 桥接 方式和主机连接。

    启动虚拟机,进行简单配置等待远程调试。

    漏洞研究

    定位溢出点

    以下为漏洞作者 @bashis 提供的 PoC

    老套路, 根据 Content-Length 很容易定位到溢出点,如下

    惊讶到了,strncpy() 函数的长度参数竟然这么用,妥妥的溢出。

    调用栈布局

    dest 缓冲区起始地址距离栈底 0x38 字节,栈上依次为 LR、R11-R4。Content-Length 长度超过 0x38 - 4 字节就会覆盖函数的返回地址 LR。

    exp 研究

    strncpy() 函数引起的栈溢出,在利用时就会有很 egg hurt 的 0x00 坏字符问题,如果我们的输入数据中包含 0x00,将会被截断导致漏洞利用失败。根据溢出点附近的汇编代码来看,0x0a 也会被截断。且开启了 NX 保护,这意味着我们无法在栈上部署 shellcode

    尝试通过 return2libc 的方式 getshell。由于没有实际的摄像头,我们不知道目标系统是否开启了 ASLR ,如果 ASLR 是开启的且没有其它可用来暴露 libC 动态链接库内存地址的漏洞,那么利用该漏洞将会是一个很难受的过程。

    采用以下方式暂时关闭 ASLR

    libC 库的加载地址如下

    接下来就需要精心构造数据,劫持函数的执行流程了。有一点需要注意,X86 架构下的所有参数都是通过堆栈传递的,而在 MIPS 和 ARM 架构中,会优先通过寄存器传递参数,如果参数个数超过了寄存器的数量,则将剩下的参数压入调用参数空间(即堆栈)。

    从前面的分析来看,只要我们构造 0x38 - 4 字节以上的数据,栈底的函数返回地址就会被我们劫持。system() 函数地址 = libC 库在内存中的加载基址 + system() 函数在 libC 库中的偏移,通过劫持该地址为 libC 库中的 system() 函数地址,再设置 R0 寄存器指向命令字符串,就可以执行任意命令。

    经过验证,nc 命令可以正常使用。

    接下来我们开始构造 ROP 利用链,大致思路见以下汇编代码。

    Github 上有个很赞的项目:https://github.com/JonathanSalwan/ROPgadget/https://github.com/JonathanSalwan/ROPgadget

    它可以用来搜索 ELF 文件中的 gadgets,方便我们构造 ROP 链。

    我们需要将字符串参数 nc -lp2222 -e/bin/sh 部署到栈上,并且将地址存入 R0。该参数包含 20 个字节,且不含坏字符。

    libC 基址为 0xb6f2d000,由该地址可知 gadget 在内存中的有效地址。发生溢出时栈顶地址为 0xbeffeb50

    利用 ROPgadget 搜索可用的 gadgets,在选择 gadget 时要还考虑坏字符的问题。比如说如下的 gadget 就不得行。

    再搜索一条可用的 gadget,俗称曲线救国。

    选择以下两条 gadget,构造 ROP 如下。

    通过调试 ,我们可以获得崩溃时的栈顶地址,为了确保命令能执行,我们在真正要执行的命令前加了部分命令作为缓冲。

    可以看到,开启了 NX 保护的栈上虽然不可执行代码,但是依然可以在上面部署数据。我们只需要将要执行的命令部署到栈上,构造 ROP 让 R0 寄存器指向栈上的命令所在区域,然后 return2libC 调用系统函数,就可以执行任意命令了。

    已将 PoC 和 EXP 整理成 Pocsuite 脚本:https://www.seebug.org/vuldb/ssvid-96866/https://www.seebug.org/vuldb/ssvid-96866,验证效果如下。

    致谢

    第一次接触 ARM 汇编,有很多不足之处,欢迎各大佬指正。中途踩了不少坑,感谢 404 小伙伴 @Hcamael 和 @没有ID 的各种疑难解答。

    参考链接

    作者:知道创宇404实验室 | Categories:安全研究技术分享 | Tags:
  • CVE-2017-16943 Exim UAF漏洞分析–后续

    2017-12-13

    作者:Hcamael@知道创宇404实验室

    上一篇分析出来后,经过@orange的提点,得知了meh公布的PoC是需要特殊配置才能触发,所以我上一篇分析文章最后的结论应该改成,在默认配置情况下,meh提供的PoC无法成功触发uaf漏洞。之后我又对为啥修改了配置后能触发和默认情况下如何触发漏洞进行了研究

    重新复现漏洞

    比上一篇分析中复现的步骤,只需要多一步,注释了/usr/exim/configure文件中的control = dkim_disable_verify

    然后调整下poc的padding,就可以成功触发UAF漏洞,控制rip

    分析特殊配置下的触发流程

    在代码中有一个变量是dkim_disable_verify, 在设置后会变成true,所以注释掉的情况下,就为默认值false, 然后再看看receive.c中的代码:

    进入了dkim_exim_verify_init函数,之后的大致流程:

    在上一篇文章中说过了,无法成功触发uaf漏洞的原因是,被free的堆处于堆顶,释放后就和top chunk合并了。

    在注释了dkim的配置后,在dkim_exim_verify_init 函数的流程中,执行了一个store_get 函数,申请了一个0x4000大小的堆,然后在dkim_exim_verify_init 函数和dkim_exim_verify_feed 函数中,都有如下的代码:

    store_pool全局变量被修改为了1,之前说过了,exim自己实现了一套堆管理,当store_pool不同时,相当于对堆进行了隔离,不会影响receive_msg 函数中使用堆管理时的current_block这类的堆管理全局变量

    当dkim相关的代码执行结束后,还把store_pool恢复回去了

    因为申请了一个0x4000大小的堆,大于0x2000,所以申请之后yield_length全局变量的值变为了0,导致了之后store_get(0x64)再次申请了一块堆,所以有了两块堆放在了heap1的上面,释放heap1后,heap1被放入了unsortbin,成功触发了uaf漏洞,造成crash。(之前的文章中都有写到)

    默认配置情况下复现漏洞

    在特殊配置情况下复现了漏洞后,又进行了如果在默认配置情况下触发漏洞的研究。

    @explorer大佬的教导下,发现了一种在默认情况下触发漏洞的情况。

    其实触发的关键点,就是想办法在heap1上面再malloc一个堆,现在我们从头来开始分析

    首先,当有新连接进来的时候,fork一个子进程,然后进入上面代码中的那个分支,smtp_setup_msg函数是用来接收命令的函数,我们先发一堆无效的命令过去(padding),控制yield_length的值小于0x100,目的上一篇文章说过了,因为命令无效,流程再一次进入了smtp_setup_msg

    这时候我们发送一个命令BDAT 16356

    然后有几个比较重要的操作:

    首先是把输入的16356赋值给chunking_data_left

    然后把receive_getc换成bdat_getc函数

    再做完这些的操作后,进入了receive_msg函数,按照上篇文章的流程差不多,显示申请了一个0x100的heap1

    然后进入receive_getc=bdat_getc读取数据:

    lwr_receive_getc=smtp_getc通过该函数获取16356个字符串

    首先,我们发送16352个a作为padding,然后执行了下面这流程:

    • store_extend return 0 -> store_get -> store_release

    先申请了一个0x4010的heap2,然后释放了长度为0x2010的heap1

    然后发送:\r\n,进入下面的代码分支:

    跳到了EOL,最重要的是最后几行代码:

    把一些变量重新进行了初始化,因为之前因为padding执行了store_get(0x4000),所以这个时候yield_length=0 这个时候再次调用store_get将会申请一个0x2000大小堆,从unsortbin中发现heap1大小正好合适,所以这个时候得到的就是heap1,在heap1的顶上有一个之前next->text使用,大小0x4010,未释放的堆。

    之后流程的原理其实跟之前的差不多,PoC如下:

    exp

    根据该CVE作者发的文章,得知是利用文件IO的fflush来控制第一个参数,然后通过堆喷和内存枚举来来伪造vtable,最后跳转到expand_string函数来执行命令,正好我最近也在研究ctf中的_IO_FILE的相关利用(之后应该会写几篇这方面相关的blog),然后实现了RCE,结果图如下:


    参考链接

    1. https://devco.re/blog/2017/12/11/Exim-RCE-advisory-CVE-2017-16943-en/
    作者:知道创宇404实验室 | Categories:安全研究技术分享 | Tags:
  • CVE-2017-16943 Exim UAF漏洞分析

    2017-12-01

    作者:Hcamael@知道创宇404实验室

    感恩节那天,meh在Bugzilla上提交了一个exim的uaf漏洞:https://bugs.exim.org/show_bug.cgi?id=2199,这周我对该漏洞进行应急复现,却发现,貌似利用meh提供的PoC并不能成功利用UAF漏洞造成crash

    漏洞复现

    首先进行漏洞复现

    环境搭建

    复现环境:ubuntu 16.04 server

    然后再修改下配置文件/etc/exim/configure文件的第364行,把
    accept hosts = : 修改成 accept hosts = *

    PoC测试

    https://bugs.exim.org/attachment.cgi?id=1050获取到meh的debug信息,得知启动参数:

    PoC有两个:

    1. https://bugs.exim.org/attachment.cgi?id=1049
    2. https://bugs.exim.org/attachment.cgi?id=1052

    需要先安装下pwntools,直接用pip装就好了,两个PoC的区别其实就是padding的长度不同而已

    然后就使用PoC进行测试,发现几个问题:

    1. 我的debug信息在最后一部分和meh提供的不一样
    2. 虽然触发了crash,但是并不是UAF导致的crash

    debug信息不同点比较: