写点什么

别再说什么渗透学到好 牢饭少不了之类的话了。你,够格吗?(渗透 tp 技巧)

用户头像
Machine Gun
关注
发布于: 2021 年 05 月 29 日

概述

距离 tp5 rce 漏洞公开已经过去两年多,但是在实战中仍然可以遇到很多 thinkphp 的框架,关于 thinkphp 的白盒分析文章和 rce payload 网上已经一抓一大把,所以本文主要以黑白盒结合的形式谈谈如何在黑盒下对 tp 网站进行测试。

tp5 的渗透要点

(最最常规 payload 一把梭.哈的情况就不讨论了)

以下渗透思路以 5.0.*列举

开启 debug 下的数据库连接

tp5.0.*在 debug 模式下如果在数据交互点构造如 sql 注入、空参数等方式使数据库查询等出错,在一定情况下可能导致数据库账号密码直接显示出来。(报错信息太细了不仔细容易忽略掉)



在 debug 模式下找注入点也可以通过报错语句进行构造,并且由于 debug 模式可能导致本来没有回显的注入变成报错注入。当然目标数据库无法外连的时候,这个注入就挺有用的了



关于 log 文件的利用

log 文件是 runtime/log 目录下的,比较常见的路径类似 /runtime/log/2020001/01.log ,默认是启用的,关于该文件主要有以下三点利用方式。

1.关于 http 请求的部分

常见的 log 文件会记录 http 请求,如果对应的站点存在后台等登陆,可以通过记录请求中的 cookie 登陆后台。



2.关于构造 sql 注入

某些配置下日志还会记录 sql 语句的执行和报错,可以用于构造 sql 注入,但是一般这种利用比较少,需要先找到数据交互点然后和日志中记录的赋值以及报错一一对应

3.关于 cache 文件名

tp 下通过缓存文件获取 webshell 是一个老生常谈的问题,白盒下理论上都说得通,但是实际上在使用该漏洞的时候是存在部分难点的,如生成 cache 文件的方式,cache 文件名等。

在 log 文件中可能存在 cache 文件生成时的报错,这样可以确定目标 tp 的 cache 文件命名方式等,举个例子:

在某次渗透中目标 tp 的 log 文件



可以注意到这里由于生成缓存文件出错,导致直接将缓存文件的文件名输出。根据输出的缓存文件名去猜测生成规则,由于 tp5 的缓存文件命名默认是 md5(value),所以大部分时候可以把文件名等带进 value 进行比对。

这里通过猜测和比对确定是 view 的文件绝对路径生成的 cache 文件名。



一般来说使用 php 原生的 md5 函数去生成 md5 比较稳妥,笔者为了方便直接在线加密的。

这里基本上就排除了 cache getshell 的一大难题。之后正常去寻找能进库的交互点,比如发帖,留言这种,就能想办法获取 webshell 了

tp5 路由

thinkphp 系列的官方开发文档是期望网站运维人员将 public 设置为 web 根目录,即使用./public/index.php 作为入口文件。在实际的渗透过程中由于 thinkphp 是框架涉及很多二次开发,部分开发人员会选择自定义一个入口文件而不置于 public 目录下,如/var/www/html/index.php 的形式。这里会涉及到打 exp 的路由问题,由于部分开发人员自定的入口文件可能导致调用的路径出现差异。

一般来说打 exp 的时候尽量使用./public/index.php 来打,以下列 exp 为例

?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=phpinfo&vars[1][]=1
复制代码



点击并拖拽以移动

可能会出现例如

http://xxx/index.php?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=phpinfo&vars[1][]=1 http://xxx/public/index.php?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=phpinfo&vars[1][]=1 http://xxx/index.php?s=\think\app/invokefunction&function=call_user_func_array&vars[0]=phpinfo&vars[1][]=1
复制代码



点击并拖拽以移动

等情况。

所以很多时候不是打一个 exp 无效就代表没洞,在黑盒测试的时候可能只是没有找对路由。

下面是实战中的案例



可以看到如果以常规的 exp 进行测试是返回方法不存在的,因为原生路由被二次开发修改了,所以最终代码执行的 payload 如下



5.0.*和 5.1.*

相对来说 5.0 可利用的 exp 比较 5.1 要多一些,5.1 主要的利用方式还是上面举例用的 exp

App.php 出现问题的代码如下:



其实就是把反斜杠认定为类名,最终使得类实例化,具体的分析在这里就不拿出来水字数了。

而在渗透的过程中大的思路其实是差不多的,尝试多种 exp,尝试读 log 文件等,

可以通过简单比对两个版本的目录结构在没有其他信息的情况下判断版本

TP5



TP5.1



如果网站不是以/public/作为根目录的话,又没通过报错直接体现版本的,可以通过访问目录看目录是否存在来做判断比如访问./thinkphp/,这里不推荐通过/app/目录来做判断,因为笔者遇到过很多开发者会修改这个目录,比方说改成/apps/,/applications/,也就无法准确判断是 5.1 还是 5.0

tp3 的渗透思路

tp3 关于 log 文件相关的利用同上,目录一般为./Application/Runtime/logs/xxx/xx_xx_xx.log ,其中 xxx 为 app 名,文件名为年_月_日.log,如 Application\Runtime\Logs\Home\16_09_09.log

sql 注入

tp3 的 sql 注入指的是框架层面的注入问题,即二次开发的时候如果调用了 model 内的 find, delete, select 方法的话,就可能出现注入问题。

对于白盒测试而言,只要 model.class.php 没修复然后找到调用了方法的地方就可以挖掘到注入。

以 select 方法简单做个分析

Model.class.php



函数可以接受一个 options 参数,为了构成注入肯定是要进入到_parseoptions 方法,也就是要绕过两次判断,也就是只要传输的 options 为数组,同时主键不是数组,就能进到_parseOptions 方法



可以看到传入 options['table']或 options['alias']且设置 options['where']值为字符串,最终会 options 直接返回,整个过程是没有过滤的,

然后进到 ThinkPHP\Libray\Think\Db\Diver.class.php,进到 select 方法



可以看到 sql 语句是最后的 parseSql 生成的。



跟进到 parseWhere 方法,只要绕过 if,最终的 return 的 sql 语句是直接拼接的,也就是注入的产生原因,会直接带入 select 方法执行。



黑盒测试也比较类似,一般情况下找到数据库交互点后进行注入尝试即可。

cache 写 shell

cache 写 webshell 的难点在于 cache 文件名的确定,一般情况下是 md5(绝对路径)生成的 cache 文件,上文也提到某些情况下可以通过 log 文件确定 cache 文件名称

cache 文件写入的时候会被注释,所以需要通过 %0d%0a 提行绕过注释

所以最终的 payload 一般为

%0d%0aeval($_POST['cmd']);%0d%0a//
复制代码



点击并拖拽以移动

找到参数影响页面的点后通过传参写入 webshell,本地可以复现,实战中倒是没遇到过。

tp3 渗透主要思路

tp3 的渗透在实战中利用的点比较少,所以一般而言遇到 tp3 的目标,最主要的思路在于找 log,然后通过 log 去看有没有后台之类的,相对来说效一起会比怼框架的注入,cache 写 shell 等靠谱。

tp3 关于 log 文件相关的利用同 tp5,目录一般为./Application/Runtime/logs/xxx/xx_xx_xx.log ,其中 xxx 为 app 名,文件名为年_月_日.log,如 Application\Runtime\Logs\Home\16_09_09.log,文件名的格式可能会有变化,多尝试一下一般也能找到。

tp6 的新型问题

tp6 的利用链

关于 model.php 的__destruct()方法调用其他类__tostring()方法的文已经有人发过了,但是文中把 poc 打码了,这里简单跟一下。



将对象的 lazySave 属性设置为 True 进入 save 方法



然后进 updateData 方法



在 checkAllowFields 方法中调用 db 方法,图中方法中框起来的语句是可以拼接的,只需要将这两个属性中的一个设置为类对象,即可触发对象的__toString 方法。之后的利用方式和 tp5.*相同。




接着与 tp5.*后的 gadget 是一致的,最终目的是要这个效果实现代码执行



接下来是构造 poc,由于测试利用链,笔者手写了一个 unserialize



然后通过 Dido1960 大佬的 poc 代码生成 payload(poc 参见:https://github.com/Dido1960/thinkphp/blob/master/v6.0.x/poc/poc.php



该利用链需求一个反序列化的可控点,二次开发在使用 unserialize 后可能导致代码执行。同时也可能利用该问题构成一个 tp6 的后门,如已经通过其他方式获取服务器权限,则可在某些地方加入 unserialize 函数实现反序列化的一个后门。

总结

thinkphp 在国内的使用度还是很高的,大多数中小型网站建站都会考虑使用 thinkphp 进行二次开发,部分大型公司偶尔也会使用 tp 建设如临时的活动页面、宣传页面等,而一般这种站点在开发的时候对安全的重视程度也不高,在二次开发者水平良莠不齐的情况下,tp 相对来说也容易找到突破口。tp 这种框架可以形成范式化的渗透方案,而非简单的 exp 一打就结束了,这里笔者就当作抛砖引玉了。

最后多说几句:

看到这里的大佬,动动发财的小手 点赞 + 回复 + 收藏,能【 关注 】一波就更好了

我是一名渗透测试工程师,为了感谢读者们,我想把我收藏的一些网络安全/渗透测试学习干货贡献给大家,回馈每一个读者,希望能帮到你们。

干货主要有:

① 2000 多本网安必看电子书(主流和经典的书籍应该都有了)

② PHP 标准库资料(最全中文版)

③ 项目源码(四五十个有趣且经典的练手项目及源码)

④ 网络安全基础入门、Linux 运维,web 安全、渗透测试方面的视频(适合小白学习)

⑤ 网络安全学习路线图(告别不入流的学习)

渗透测试工具大全

⑦ 2021 网络安全/Web 安全/渗透测试工程师面试手册大全

各位朋友们可以关注+评论一波 然后加下 QQ 群:581499282  备注:infoq  联系管理大大即可免费获取全部资料

用户头像

Machine Gun

关注

还未添加个人签名 2021.03.28 加入

需要获取网络安全/渗透测试学习资料工具的朋友可联系V:machinegunjoe666 免费索取

评论

发布
暂无评论
别再说什么渗透学到好 牢饭少不了之类的话了。你,够格吗?(渗透tp技巧)