出问题的是用于cookie加解密的encrypt和decrypt函数
首先看一下函数内容include/global.func.php 122行
粗看有随机数、有随机时间值、还做md5hash再异或好像很安全的样子
因为有两个未知key md5(microtime())和DT_KEY
等等 真的是两个么?搜一下microtime()的定义
定义和用法
microtime() 函数返回当前 Unix 时间戳和微秒数。
例子
输出
时间戳好说 http头中有个date值就是,微秒嘛后面两位固定为00前面有6位不可预知
6位也就是100W个可能,只要穷举100W次肯定有一次是正确的key(不要被100W吓到,本地跑起来是很快的)
再来看encrypt函数 简单表示一下
加密前的原文txt = a
microtime生成的key = b
md5(DT_KEY) = c
最后生成的密文 = d
整个流程简单来说就是
现在b是已知的 如果能找到一个原文和密文的对照 也就是a和d
那就可以通过abd来推算出c 也就是key
destoon很贴心的写了一段正好符合要求的代码
include/module.func.php 140行
这个函数的功能是“将电话、传真、Email等重要信息显示为图片格式,防止采集和复制”
调用示范
没有比这个更好的输出点了,没有任何干扰。
这里拿官方demo做演示,随便找家公司查看联系方式
http://**.**.**.**/contact/
Mon, 26 May 2014 07:12:43 GMT 转成unix时间戳并加8个小时为1401088363
运气不错 15W多次就出来了 总共脚本运行时间大概就2秒
到这里 我们已经拿到了MD5后的DT_KEY,那么怎么来用这个key呢
跑MD5来还原真实的KEY也是一种思路,不过15位大小写+数字的彩虹表还是蛮大的。
回去搜了一下encrypt和decrypt函数的调用,找到了cookie的加解密
module/member/member.class.php 行376
登录完成后setcookie的地方,可以看到 cookie是用 userid{制表符}username{制表符}groupid{制表符}password{制表符}admin拼起来然后用
md5(DT_KEY+useragent)作为密钥用encrypt函数做加密的
小伙伴们都知道 user-agent是客户端提交的,如果我提交个空的user-agent,cookie就会用md5(DT_KEY)作为密钥,是不是很眼熟呢,这个就是我们上一步跑出来的东西。
现在我们已经可以伪造出任意合法的cookie了,一般到这里漏洞就要结束了
可惜destoon没想那么简单(已经很麻烦了)把rank给我,我们来看看cookie的验证过程
/common.inc.php行135
不死心继续搜索decrypt的调用,终于又发现了一个问题
module/member/admin.inc.php
很明显的一个注入点,虽然Destoon默认不开启DEBUG,不显示错误信息,但我们一样可以用时间延迟来注入。
来看看注入的条件,首先进入查询的前提是$_groupid == 1
来看这个文件的调用,还是在/common.inc.php行135
这个地方纠结很久 差点都放弃了 不管cookie里userid和groupid改成什么只要流程进了第一个if就废了
userid跟password匹配的话,groupid就会被extract覆盖,userid跟password不匹配的话进入else userid会被置0
不进入这个if的方法 一是userid为false 二就是NT_NONUSER,搜了一下发现一个很合适的文件。
api/js.php
只要get moduleid>3就能带着我们的DT_NONUSER包含common.inc.php从而进入admin.inc.php的包含最终实现注入了
1、首先随便找个公司主页查看联系方式,需要记录3样东西:时间戳、原文、密文
2、将以上信息填入POC,运行POC获取cookie
3、用上一步生成的cookie去访问/api/js.php?moduleid=5,记得user-agent要设置为空
为了方便演示我这里把debug打开了 报错信息里能看到我们的注入语句
poc:(这个poc还有很多问题,比如它获取第一个符合正则的key就停止了 事实上有可能会碰上正好符合正则却不是真正key的情况,只要多获取几组数据看相同的就能找出真正的md5(DT_KEY))