PHP Deserialization Vulnerability: Identity Identity

Article directory

  • refer to
  • environment
  • access modifier
      • access modifier
      • PHP and access modifiers
  • handwritten identification
      • Identity mark
      • Define identity
      • Control character NUL
          • How to represent null character in PHP?
      • An attempt was made to construct a serialized text containing a non-public property object via a null character
  • Transmission of null characters
      • Control character unprintability
      • in conclusion
      • Find another way
          • URL character encoding
            • Convert non-ASCII character text to ASCII character text
            • remove semantics
            • Convert invisible characters (such as spaces) to visible text
          • URL Encode

Reference

Project Description
Search Engine Bing, Google
AI large model Wen Xinyiyan< /strong>, Tongyi Qianwen, iFlytek Spark Cognitive Model, ChatGPT
PHP Manual PHP Manual

Environment

Project Description
PHP 8.0.0
PHP Editor PhpStorm 2023.1.1 (Professional Edition)

Access modifier

Access modifier

Access modifiers play an important role in object-oriented programming. They provide access level control to the properties and methods of a class. Access modifiers can bring the following advantages to your program:

  1. Encapsulation
    Access modifiers allow the internal implementation details of a class to be hidden, only exposing the necessary public interfaces to external use. This can effectively encapsulate data and behavior and improve the maintainability and reusability of the code.

  2. Access Control
    Access modifiers can control the visibility and accessibility of members of a class to the outside world. Different access modifiers can limit the access scope of properties and methods, allowing only specific code segments to access, thus providing better security and data protection.

PHP and access modifiers

PHP supports three access modifiers: public, protected and private. The access levels provided by these modifiers are as follows.

modifier
(Modifier)
Access level
(Access Level)
Inside the class
(Inside Class)
Subclass
(In Subclass)
External
(Outside Class)
public Public Accessible Accessible Accessible
protected Protected Accessible Accessible Inaccessible
private Private Accessible Inaccessible Inaccessible

Note:

In PHP, access modifiers can be omitted, but only for methods in classes. By default, methods are treated as public members if no access modifier is specified.

Handwritten identification

Identification

In PHP, when an object is serialized, the names of the non-public properties of the object are specially treated to indicate their visibility (access modifiers). For this, please refer to the following example:

<?php


classMyClass
{<!-- -->
    # Private properties
    private $name = 'RedHeart';
    # protected attributes
    protected $nation = 'China';
}

var_dump(serialize(new MyClass()));

Execution effect

string(82) "O:7:"MyClass":2:{s:13:" MyClass name";s:8:"RedHeart";s:9:" * nation";s:5:"China";}"

After being converted into serialized text, the private property name name in the MyClass class becomes s:13:" MyClass name;" , compared with the original name, two spaces are added (actually the control character NUL, which cannot be replaced by spaces) and the name of the class MyClass code>.

This is done so that the visibility of properties can be correctly restored when deserializing the object. When PHP encounters these special prefixes during deserialization, PHP will know how to set the property's visibility correctly. Public properties do not receive this special treatment; they retain their original property names in the serialized text.

Define identity

The identity identifier is the embodiment of the access modifier used in the object's attributes in the serialized text. The identity identifiers of private attributes and protected attributes are respectively the name of the class to which NUL belongs. NUL > and NUL*NUL, public attributes have no identity to distinguish them from the first two.

Control character NUL

The control character NUL, also known as the null character, is the first character in the ASCII table and has a decimal value is 0. In the ASCII table, control characters are a series of non-printing characters, is used to control the behavior of hardware devices or communication protocols, and the main function of NUL is to mark the end of a string .

How to represent the null character in PHP?

In PHP, you can represent the null character NUL by shifting the character \0. But it should be noted that in PHP, escape characters are only considered escape characters within double quotes. If the escape characters exist within single quotes , the escaped character will be treated as a normal character. For this, please refer to the following example:

<?php


# "Escape character" in single quotes
var_dump('\0');
var_dump('Hello\0World');

# Escape characters within double quotes
var_dump("\0");
var_dump("Hello\0World");

Execution effect

string(2) "\0"
string(12) "Hello\0World"
string(1) " "
string(11) "Hello World"

Attempt to construct serialized text containing a non-public property object via null character

Now that we know how to represent the null character in PHP, we can use this feature to handwrite (without using the serialize() function to obtain the PHP serialized text that needs to be used) Contains the serialized text of the non-public property object. For this, please refer to the following example:

<?php


class MyClass {<!-- -->}

# Construct the serialized text to be used
$serialize_text = 'O:7:"MyClass":2:{s:13:"' . "\0MyClass\0" . 'name";s:8:" RedHeart";s:9:"' . "\0*\0" . 'nation";s:5:"China";}';

# Perform deserialization operations on serialized text
var_dump(unserialize($serialize_text));

Execution effect

object(MyClass)#1 (2) {<!-- -->
  ["name":"MyClass":private]=>
  string(8) "RedHeart"
  ["nation":protected]=>
  string(5) "China"
}

Since the quotation marks in the serialized text need to use double quotation marks, and the number of quotation marks that need to be used in the serialized text is more (if it is less, you can put it in the outermost layer of the string Use double quotes to escape the double quotes inside the string), so single quotes are used on the outermost side of the serialized text. The writing of the identity mark is realized by splicing text containing escaped characters wrapped in double quotes.

Transmission of null characters

Control character non-printability

In the ASCII table, a control character is a sequence of non-printing characters that are used to control the behavior of a hardware device or communication protocol. Because the original intention of generating control characters is not to display content, when you try to perform operations such as copy and paste on control characters, different results may occur in different environments, and you should analyze them in detail. Possible situations are as follows:

  • In some text editors, these characters may be displayed as specific symbols (spaces, etc.) or not displayed at all (at this time, you cannot even copy the "control characters") .
  • In some terminal or console applications, these characters may be executed directly according to their original control function.

Conclusion

<?php


# Try to output the null character NUL
var_dump("\0");

# Output the copied null character NUL as a parameter of the ord function
var_dump(ord(' '));

Execution effect

In the PHP editor PHPStorm, I get the output of "\0" and try to copy and paste the null character in it into ord() function as a parameter of the function.

After trying twice (the first time to execute the sample code to obtain the null character, and the second time to obtain the output result of the ord() function), I got the above interface (blue The part is the copied content, which is the display effect of the empty character NUL in PHPStorm). The ord() function can get the ASCII code corresponding to a certain character. The result here is 32, and the corresponding character is the printable character space .

Therefore, the conclusion is that control characters such as null characters cannot be transmitted by copying and pasting.

Find a different approach

URL character encoding

URL character encoding is a set of conversion basis, and its functions mainly include the following three points:

  1. Convert non-ASCII character text to ASCII character text
  2. remove semantics
  3. Convert invisible characters (such as spaces) to visible text
Convert non-ASCII character text to ASCII character text

Non-ASCII characters such as Chinese in the URL need to be converted through URL encoding before transmitting through the network to make them comply with the design principles of URL (URL is designed based on the ASCII character set) .

In PHP, non-ASCII text can be converted to URL-encoded characters via the built-in function urlencode(). For this, please refer to the following example:

<?php


var_dump(urlencode('Hello World'));
var_dump(urlencode('Hello, China'));
var_dump(urlencode('Hello I am a space world'));

Execution effect

string(11) "Hello + World"
string(45) "Hello, China"
string(48) "Hello I + am + a + space world"
Remove semantics

Special characters in URLs need to be converted through URL character encoding so that they lose their special meaning in URLs.

Give me a chestnut

The query string consists of one or more parameters, each of which is separated by & amp; symbols. If a parameter in the query string contains & amp; symbols, please ask how can you let the program understand this & amp; as a parameter What about the content in rather than the connection identifier between parameters?

At this point, the role of URL character encoding removing semantics is reflected. By URL-encoding the & amp; in the parameters, the program no longer treats them as connectors between parameters but just treats them as ordinary text content.

Specifically

?username=RedHeart & amp;myflag= & amp;x & amp;

This query string contains only two parameters, the parameter value of username is RedHeart, and the parameter value of myflag is & amp ;x &.

But in fact, this query string will be understood by the program as three parameters, among which the parameter value of username is RedHeart, and myflag and x are both empty (nothing).

Solution

Convert the special characters & amp; in the parameters to their corresponding URL encoding &, so that & amp; loses its semantics That’s it.

?username=RedHeart & amp;myflag=&x&
Convert invisible characters (such as spaces) to visible text

Spaces and other whitespace characters are unreadable in URLs and can lead to confusion or misinterpretation. By converting whitespace characters into a recognizable form, you can enhance the readability and accuracy of your URL.

Note:

In URLs, spaces are converted to + , and tabs are converted to .

URL Encode

When trying to exploit PHP deserialization vulnerabilities, you often need to use URL. If the serialized text containing the identity identifier is URL-encoded, then the control characters can be transferred together with the URL. For this, please refer to the following example:

Contents in the web page source code file index.php

<?php


class MyClass {<!-- -->}

# Try to deserialize the value of the X parameter in the query string in the URL and output the result
var_dump(unserialize($_GET['X']));

In order to obtain URL-encoded serialized text, we can use the following two solutions:

Obtain serialized text by serializing the constructed object and URL encoding it

<?php


classMyClass
{<!-- -->
    private $name = 'RedHeart';
    protected $nation = 'China';
}

# URL-encode the serialization results
var_dump(urlencode(serialize(new MyClass)));

Conduct URL encoding on the constructed serialized text

<?php


# Construct the serialized text to be used
$serialize_text = 'O:7:"MyClass":2:{s:13:"' . "\0MyClass\0" . 'name";s:8:" RedHeart";s:9:"' . "\0*\0" . 'nation";s:5:"China";}';

# URL-encode the constructed serialized text
var_dump(urlencode($serialize_text));

The serialized text after URL encoding is as follows:

O:7:"MyClass":2:{s:13:"\0MyClass\0name";s:8:"RedHeart";s:9:"\0*\0nation ";s:5:"China";}

Use this text as the value of the X parameter and try to access the index.php page through the browser, and you will get the following interface: