Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

Example Analysis of PHP deserialization vulnerability

2025-01-18 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Network Security >

Share

Shulou(Shulou.com)06/01 Report--

This article will explain in detail the sample analysis of PHP deserialization vulnerabilities, Xiaobian thinks it is quite practical, so share it with you as a reference, I hope you can gain something after reading this article.

0x01 Principle

The php program provides serialization methods for saving and dumping objects. Php serialization is created to dump objects during program execution. Serialization converts an object to a string, but only retains the member variables in the object, not the function methods.

The serialize function in php converts member variables in an object to strings.

The deserialized function is unserialize, which restores strings generated by serialize to member variables in the object.

The deserialization of user-controlled data is a PHP deserialization vulnerability.

serialization

The purpose of serialization is to facilitate data transmission and storage.

In PHP applications, serialization and deserialization are commonly used as caches, such as session caches, cookies, etc.

Common serialization formats:

binary format

byte array

JSON string

XML string

The output is:

C:\phpstudy_pro\WWW\s1.php:11:string 'O:4:"Test":3:{s:1:"a";s:5:"ThisA";s:4:"�*�b";s:5:"ThisB";s:7:"�Test�c";s:5:"ThisC";}' (length=84)

The actual serialized string is

:O:4:"Test":3:{s:1:"a";s:5:"ThisA";s:4:"�*�b";s:5:"ThisB";s:7:"�Test�c";s:5:"ThisC";}

The serialized structure of the object is:

O: Length of object name:"Object name": Number of object attributes:{s: Length of attribute name:"Attribute name";s: Length of attribute value:"Attribute value";}

As you can see, the result of serialization is string.

Test is a class and new Test() represents the object that created the Test class.

O means object, 4 means class name has 4 characters, Test is class name.

3 means there are 3 member variables in the object. The parenthesis contains the type, name, and value of each member.

Variable names and variable values are separated by semicolons.

a is a variable of type public, s is a string, 1 is the length of the variable name, and a is the variable name.

b is a variable of protected type, and its variable name length is 4, that is, b is preceded by *. Therefore, the protected attribute is represented by prepending the variable name with a *.

c is a variable of type private, and the class name is added before the variable name of c. Therefore, the private attribute is represented by prepending the variable name with the class name.

Although the Test class has a test1 method, the serialized string only stores the public variable a, the protected variable b, and the private variable c, and does not store the methods in the class. You can also see that serialization does not save methods.

to deserialize

The output reads as follows:

C:\phpstudy_pro\WWW\s2.php:13:object(Test)[2]public 'a' => string 'ThisA' (length=5)protected 'b' => string 'ThisB' (length=5)private 'c' => string 'ThisC' (length=5)

Class member variables are restored, but class methods are not. Because there is no way to save classes when serialized.

Magic methods that may be used in PHP deserialization vulnerabilities

Php classes may contain magic methods named with the symbol__, such as__construct, __destruct, __toString, __sleep, __wakeup, etc. These functions are called automatically in some cases.__ construct(): Classes with a constructor call this method first each time they create a new object.__ destruct(): The destructor is executed when all references to an object have been deleted or when the object has been explicitly destroyed.__ The toString() method is used to determine how a class should respond if it is treated as a string. For example echo $obj; what should be displayed. This method must return a string, otherwise a fatal error of E_RECOVERABLE_ERROR level will be issued.__ The sleep() method is called before an object is serialized;__wakeup():unserialize( ) checks to see if there is a_wakeup( ) method. If it exists, the_wakeup method will be called first to prepare the resources needed by the object in advance.__ construct() #__destroy () is called when an object is created #Call__toString() when an object is destroyed #Use__sleep() when objects are treated as strings #Calling__wakeup() before an object is serialized #Calling new before an object is deserialized, the object is created, executing__constructconstruct runserialize an object, the object is serialized, executing__sleep first, then serializing sleep run__wakeup():unserialize( ) checks if there is a_wakeup( ) method. If it exists, the_wakeup method is called first to prepare the resources needed by the object in advance. wakeup run Use the Test object as a string, execute__toStringtoString run, the object will be destroyed automatically, execute__destructdestruct rundestruct run

Now the order of execution of the five magic functions is clear.

Executes__construct when an object is created.

Serialize objects using serialize(). Perform__sleep first, then serialize.

unserialize( ) checks to see if there is a_wakeup( ) method. If it exists, the_wakeup() method is called first to prepare the resources needed by the object in advance.

Using an object as a string, such as concatenating an object with a string, or outputting an object using echo, will execute__toString

When the program is finished, the object is automatically destroyed and__destruct is executed.

security issues

How the deserialization vulnerability is exploited depends on the logic of the application, available classes, and magic functions. The parameters of unserialize are user-controllable, allowing attackers to construct malicious serializing strings. When an application deserializes a malicious string into an object, it performs an attacker-specified operation, such as code execution, arbitrary file reading, and so on.

PHP Anti-Sequence Vulnerability Defense Methods

Do not allow user control over parameters of the unserialize function

CVE-2016-7124

Impact Version:

PHP5

< 5.6.25 PHP7 < 7.0.10 反序列化时,如果表示对象属性个数的值大于真实的属性个数时就会跳过__wakeup( )的执行。 __destruct # 当对象被销毁时调用__wakeup # 在对象被反序列化之前调用 漏洞示例代码如下: 获取序列化字符串的脚本如下: 正常的序列化字符串为:O:1:"A":1:{s:6:"target";s:4:"test";}。注意:这里target变量的值是test,长度为4。当我们修改target变量的值时,对应的,也要将值的长度进行修改。 在线计算字符串长度 程序从GET请求中获取test参数的值,然后将test参数进行反序列化。 ?test=O:1:"A":1:{s:6:"target";s:18:"";} 代码正常的执行逻辑,应该是:unserialize( )会检查是否存在一个_wakeup( )方法。本例中存在,则会先调用_wakeup()方法,预先将对象中的target属性赋值为"wakeup!"。注意,不管用户传入的序列化字符串中的target属性为何值,__wakeup()都会把$target的值重置为"wakeup!"。最后程序运行结束,对象被销毁,调用__destruct()方法,将target变量的值写入文件shell.php中。这样shell.php文件中的内容就是字符串"wakeup"。 对象序列化后的结构为:O:对象名的长度:"对象名":对象属性个数:{s:属性名的长度:"属性名";s:属性值的长度:"属性值";} 反序列化时,如果表示对象属性个数的值大于真实的属性个数时就会跳过__wakeup( )的执行。构造如下对象作为payload: ?test=O:1:"A":2:{s:6:"target";s:18:"";} 这里真实属性个数是1,只有1个target属性。我们在构造序列化字符串时,将表示对象属性个数的值写成任何大于1的整数,就可以跳过__wakeup()的执行。现在,程序执行的逻辑变为:直接使用unserialize()函数将用户传递的参数进行反序列化。程序执行结束,对象被销毁,调用__destruct()方法,将target变量的值写入文件shell.php中。而target变量的值就是我们用户构造的phpinfo()函数,成功getshell。 注意,如果要序列化protected类型的属性,需要在变量名前加上*。序列化private类型的属性,需要在变量名前加上类名。 得到的序列化字符串为: O:1:"A":1:{s:9:"�*�target";s:4:"test";} 构造的payload为: ?test=O:1:"A":2:{s:9:"*target";s:18:"";} 得到的序列化字符串为: O:1:"A":1:{s:9:"�A�target";s:4:"test";} 构造的payload为: ?test=O:1:"A":2:{s:9:"Atarget";s:18:"";}二、CVE-2017-6920:Drupal远程代码执行漏洞 Drupal Core 8 PECL YAML 反序列化任意代码执行漏洞(CVE-2017-6920) CVE-2017-6920:Drupal远程代码执行漏洞分析及POC构造 本例子代码审计中分析反序列化漏洞的方法 通过diff有漏洞的版本和漏洞修复的版本,发现漏洞的触发点。 在漏洞所在函数的触发点代码中,通过阅读官方文档,找到外部可控的参数,明确漏洞的触发原理。 定位漏洞所在函数的调用位置,如果该函数还调用了其它函数,继续跟踪其它函数。 最后定位外部可控的输入点。找到漏洞的数据触发点。 要利用该漏洞进行远程代码执行,需要一个可以利用的类。如有应用程序使用命名空间的方式来管理类,可以全局实例化一个类,也可以反序列化一个类;该漏洞利用了反序列化,因此需要找一个反序列类。通过__destruct以及__wakeup来定位类,全局搜索可以找到几个可利用的类。 通过反序列化这些类,可以造成任意文件删除、写入webshell、任意无参数函数执行等危害。 漏洞描述 2017年6月21日,Drupal官方发布了一个编号为CVE-2017- 6920 的漏洞,影响为Critical。这是Drupal Core的YAML解析器处理不当所导致的一个远程代码执行漏洞,影响8.x的Drupal Core。 漏洞验证 漏洞环境 执行如下命令启动 drupal 8.3.0 的环境: docker-compose up -d 环境启动后,访问http://your-ip:8080/将会看到drupal的安装页面,一路默认配置下一步安装。因为没有mysql环境,所以安装的时候可以选择sqlite数据库。 漏洞复现 先安装yaml扩展 # 换镜像源,默认带vim编辑器,所以用cat换源,可以换成自己喜欢的源cat >

sources.list >/usr/local/etc/php/conf.d/docker-php-ext-yaml.ini#exit container exit#restart container, CONTAINER replace with own container IDdocker restart CONTAINER

1. Log in to an administrator account

2. Visit http://127.0.0.1:8080/admin/config/development/configuration/single/import

3. As shown in the figure below, select Simple configuration for Configuration type, fill in Configuration name arbitrarily, and fill in PoC as follows for Paste your configuration here:

POC of arbitrary parameterless function is constructed.

! php/object "O:24:\"GuzzleHttp\\Psr7\\FnStream\":2:{s:33:\"\0GuzzleHttp\\Psr7\\FnStream\0methods\";a:1:{s:5:\"close\";s:7:\"phpinfo\";}s:9:\"_fn_close\";s:7:\"phpinfo\";}"

4. Click Import to see that the vulnerability was triggered successfully and the phpinfo page pops up.

bug fixes

This vulnerability has been fixed in the latest release of Drupal 8.3.4, and can be defended against versions earlier than 8.3.4 by upgrading the decode function in the Drupal file/core/lib/Drupal/Component/Serialization/YamlPecl.php

public static function decode($raw) {# ================================================== isset($init)) {// We never want to unserialize ! php/object.ini_set ('yaml.decode_php', 0);$init = TRUE;}# ================================================== trim($raw)) {return NULL;}......}

vulnerability detection

There are two ways to detect this vulnerability:

Method 1: Log in to the Drupal management background and check that the kernel version is 8.x and the version number is lower than 8.3.4, then the vulnerability exists; otherwise, the vulnerability does not exist;

After logging in to an administrator account, http://127.0.0.1:8080/admin/reports/updates, the current kernel version is 8.3.0.

Method 2: Find the file/core/lib/Drupal/Component/Serialization/YamlPecl.php in the Drupal root directory and locate the function public static function decode($raw), if the function code does not contain " ini_set ('yaml.decode_php', 0);" call, the vulnerability exists; otherwise, the vulnerability does not exist.

root@a3aafd8a0fc8:/var/www/html/core/lib/Drupal/Component/Serialization# cat YamlPecl.php | grep "decode" -A 10

Joomla 3.4.5 deserialization vulnerability (CVE-2015-8562)

Vulnerability environment: Joomla 3.4.5 deserialization vulnerability (CVE-2015-8562)

Reference: Joomla Remote Code Execution Vulnerability Analysis (Summary)

profile

The vulnerability is rooted in PHP versions before 5.6.13, when reading stored sessions, if deserialization errors skip the current segment of data and deserialize the next segment of data. Joomla stores sessions in Mysql, encoded utf8, which causes truncation when we insert 4 bytes of utf8 data. Truncated data fails to deserialize, triggering a deserialization vulnerability.

Gadget in Joomla can cause arbitrary code execution results.

affected version

Joomla 1.5.x, 2.x, and 3.x before 3.4.6

PHP 5.6 < 5.6.13, PHP 5.5 < 5.5.29 and PHP 5.4 < 5.4.45

Vulnerability--deserializing session

This vulnerability exists in the deserialization of sessions. The vulnerability lies in libraries/joomla/session/session.php, the_validate function, which sets User-Agent and X_FORWARDED_FOR call set methods into sessions. Eventually, they are saved to the session table of the database.

using| Character forgery, controlling the entire deserialization string

Joomla also does not use php's own session processing mechanism, but uses a variety of ways (including database, memcache, etc.) to write its own storage container (storage). It is stored in the format of "key name + vertical line + value processed by serialize() function", which does not correctly handle multiple vertical lines. So, we can do this here by injecting| The sign, think of all the parts before it as name, and| Later I can insert arbitrary serialize strings to construct deserialization vulnerabilities. But there is a problem. After we construct the deserialized string, there is its original content, which must be truncated. Use the "

About "PHP deserialization vulnerability sample analysis" This article is shared here, I hope the above content can be of some help to everyone, so that you can learn more knowledge, if you think the article is good, please share it to let more people see.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Network Security

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report