ourphp 1.6.2~2.0.0 前台getshell 0day公开

2020-07-21 02:00:19 18 4530 5


6月初审计这套cms找了这个洞,同时还有另一个前台sqli这里不提,我看见ourphp官网前几天更新了版本
可能是迫于压力更新修复漏洞了?

此文在贵坛首发。仅做交流、交友,请先明白滥用漏洞会让你承担什么风险。

这里我以v2.0.0 源代码示例,网站在进行安装时通过文件 /function/install/index.php 执行安装,相关代码如下


安装过程会动态创建出 /config/ourphp_config.php 配置文件,生成代码如下


配置文件中有一个全局变量 safecode,从安装文件 install.php可以看到 safecode 的生成算法,
调用 getRandomString 生成随机32位字符串,再截取这个32位字符串第6位开始的6个字符拼接在后面。
另外还有一个全局变量 validation 默认是12345,目前线上运营的网站很少有人改动这个变量,所以绝大部分都是12345。


function getRandomString($len, $chars=null){
   if (is_null($chars)){ $chars = "bcdefghijklmnpqrtuvwxyzBCDEFGHIJKLMNPQRTUVWXYZ12345679"; }  
   mt_srand(10000000*(double)microtime());
   for ($i = 0, $str = '', $lc = strlen($chars)-1; $i < $len; $i++){
      $str .= $chars[mt_rand(0, $lc)];  
   }
   return $str;
}


这里贴出 getRandomString 函数代码仔细分析,首先设定要随机的字符集如下
$chars = "bcdefghijklmnpqrtuvwxyzBCDEFGHIJKLMNPQRTUVWXYZ12345679";

接着用 10000000*(double)microtime() 作为种子调用 mt_srand 设定随机数种子
mt_srand(10000000*(double)microtime());
循环调用mt_rand 随机从 $chars抽取一个字符叠加起来,叠加得到的字符串返回。

问题是,当mt_srand设定好种子后 mt_rand 生成的序列将是固定的,什么意思呢
比如 mt_srand(1); mt_rand 生成序列为 1,3,5...
再次用1作为种子 mt_srand(1); mt_rand生成的序列还是 1,3,5...

所以对于同一个种子,getRandomString 函数返回的字符串将是完全一样的,
因为种子设定好后,循环调用mt_rand抽取字符,序列将是固定的

最终结论,getRandomString 的随机性仅取决于种子 10000000*(double)microtime()
这个种子我先直接给出结果,后面再做分析。
在所有php版本里,10000000*(double)microtime() 的结果集如下
0、10、20、30、40、50 ...... 9999960、9999970、9999980、9999990
一共100万个,也就是函数 getRandomString 生成的结果集为100万个。

我们用这100万个种子根据getRandomString的算法生成100万个safecode。
代码及生成结果如下


如果网速快或者多台机器并发,使用burpsuite插件 Turbo Intruder 发起一百万个请求只需要一根烟的功夫,
很快就可以爆破出safecode。下面接着说通过哪个接口爆破safecode,以及拿到safecode如何getshell

这里贴出文件 /client/manage/ourphp_filebox.php 关键代码如下


接口 /client/manage/ourphp_filebox.php 通过 $_GET取出两个 get 参数
validation code,传入了函数 pw,下面是函数pw代码


可以看到get取出的参数用来和全局变量 $ourphp[‘validation’]  $ourphp[‘safecode’] 进行比较,
如果不一致的话会进入else逻辑最后 include ‘ourphp_checkadmin.php’;
ourphp_checkadmin.php 这个文件作用是管理员身份校验。
那么使用正确的validation safecode 就通过了校验,
这里我直接用/config/ourphp_config.php配置文件里正确的safecode试试看通过校验会发生什么,访问如下接口



可以看到这是一个可编辑网站代码的接口,直接向代码插入一句话 @eval($_POST[1]);就拿到webshell了。
但是如果是错误的safecode、validation参数,请求结果如下


所以正确和错误的safecode参数响应结果不一样,使用默认的12345作为validation,以及前面生成的100万个safecode,
通过此接口即可爆破出safecode,并且直接编辑网站代码插入一句话拿webshell。

关于此漏洞要注意的事项,mt_rand 生成的序列和php版本也相关,我通过测试多个php版本,
5.3.29~7.0.33(未测试所有版本) 会生成一组序列,7.1.32~7.4.1(未测试所有版本) 是另一组序列。
所以最好能先确定目标网站的php版本,如果不能确定,那么爆破200百万次也不是事儿。

最后,来分析看看为什么种子 10000000*(double)microtime() 仅有100万个结果集。
下面是函数 microtime 的php官方文档

它返回的结果是字符串,使用如下代码打印一组数据看看



左边是毫秒级的时间戳小数部分,中间是空格,右边是当前时间戳。
特别注意左边小数部分最后两位都是0,即有效小数位数只有6位!
经过double强制转换 (double)microtime() ,使用如下代码打印一组结果



可以看到microtime的结果经过double强制转换后变成了小数部分最多有6位有效数字的小数,最小值是0,最大值是0.999999
这个范围的小数再乘上10000000 得到的范围就是 0~9999990, 这个序列是10为步长,
因为小数部分是6位,乘上10000000导致左移7位

使用如下代码打印一组序列验证



末尾都是0,有效位只有6个。所以结果集是
0、10、20、30、40、50 ...... 9999960、9999970、9999980、9999990
100万个。

以上就是6月初提交给cnvd并通过审核的漏洞材料全部信息,感谢阅读。

本人第一次审代码,如有笔误请联系我更正,可能因为近4年的码龄对代码比较敏感,让我上来就看见这个漏洞。

文末想聊下生活,顶着初中的学历找工作一路坎坷,这两天在论坛的天融信做内推的朋友用两天时间跟我邮件交流,
给了我很多指导建议,最后帮我内推,说我要的工资低了,可以多要些,当时感动的心酸了。在此感谢这位兄弟。
不指望打工拿多少工资,只为出门交上一辈子的朋友。愿介绍工作或者朋友不嫌多一个的请call我!

TCV 3

关于作者

suifeng7篇文章65篇回复

评论18次

要评论?请先  登录  或  注册