【PHP 反序列化漏洞】


描述

反序列化漏洞是一种严重的安全漏洞,常见于应用程序在处理用户输入时(身份验证、文件读写、数据传输等功能点)将对象从字节流或其他格式还原为对象时,未对反序列化接口做访问控制,未对反序列化数据做加密和签名,加密密钥使用硬编码(如 Shiro 1.2.4),使用不安全的反序列化框架库(Fastjson 1.2.24)。这种漏洞可能导致远程代码执行、数据篡改或拒绝服务等问题。

演示

序列化

<?php
	class S{
		var $test = "pikachu";
		function __construct(){
			echo $this->test;
		}
	}
	$c = new S();
	echo serialize($c); 

在这里插入图片描述

<?php
	class S{
		var $test = "<script>alert(123)</script>";
		function __construct(){
			echo $this->test;
		}
	}
	$c = new S();
	echo serialize($c);

在这里插入图片描述

反序列化

<?php
	class S{
		var $test = "pikachu";
		function __construct(){
			echo $this->test;
		}
	}
	$c = new S();
	$u=unserialize($_GET['url']);
	echo $u->test;

在这里插入图片描述

魔术方法

<?php
  class Str3am{
    public $var1 = 'abc';
    public $var2 = '123';
    public function echoP(){
      echo $this->var1.'<br>';
    }
    public function __construct(){  // 当一个对象创建时被调用
      echo "__construct<br>";
    }
    public function __destruct(){  // 当一个对象销毁前被调用 
      echo "__destruct<br>";
    }
    public function __toString(){  // 当一个对象被当做字符串使用时被调用 
      return "__toString<br>";
    }
    public function __sleep(){  // 在对象被序列化前被调用
      echo "__sleep<br>";
      // 注意返回带类中所有变量名称的数组
      return array('var1', 'var2');
    }
    public function __wakeup(){  // 将在反序列化之后立即被调用 
      echo "__wakeup<br>";
    }
}
  // 创建对象,输出__construct
  $obj = new Str3am();
  // 调用 echoP 方法
  $obj->echoP();
  // 把类当做字符串输出,输出__toString
  echo $obj;
  // 序列化对象,输出__sleep
  $s = serialize($obj);
  // O:6:"Str3am":2:{s:4:"var1";s:3:"abc";s:4:"var2";s:3:"123";}
  echo $s.'<br>';
  // 反序列对象,输出__wakeup
  unserialize($s);
  // 脚本结束,对象被销毁,输出两个 __destruct,还有一个是 unserialize 恢复的对象
?>

在这里插入图片描述

demo1

思路
test5.php的魔术方法中有一个删除文件的操作;
test6.php包含了test5.php,并且接受一个传参,进行反序列化。
既然这样,我们是不是可以序列化一个delete类放入payload中,然后去访问test6.php,在test6.php中把detele类反序列化出来,调用构造方法__destruct()去删除1.txt文件。
test5.php

<?php

class delete
{
  public $filename = 'error';
  function __destruct()
  {
    echo $this->filename.'was deleted<br/>';
    unlink(dirname(__FILE__).'/'.$this->filename);  // 删除文件
  }
}

?>

test6.php

<?php

include 'test5.php';

class Person
{
  public $name='';
  public $age=0;
  public function Information()
  {
    echo 'Person:'.$this->name.' is '.$this->age.' years old.<br />';
  }
}
$per = unserialize($_GET['per_serialized']);

?>

POC.php

<?php

class delete
{
  public $filename='error';
}

$test=new delete();
$test->filename='1.txt';
echo serialize($test);

?>

// 得到:O:6:"delete":1:{s:8:"filename";s:5:"1.txt";}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

demo2

思路:
test8.php中的类定义了__toString()函数,该函数返回一个文件内容;
我们是不是可以利用该类来读取任意文件?比如读2.html
那么这需要一个可控的unserialize,还要有个触发__toString()函数的机会;
于是乎,我们在test9.php中发现,它包含了test8.php,存在可控的反序列化参数,并以字符串打印输出。
test8.php

<?php

class red
{
  public $filename='error';
  function __toString()
  {
    return  file_get_contents($this->filename);
  }
}

?>

test9.php

<?php

include 'test8.php';

class Person
{
  public $name='';
  public $age=0;
  public function Information()
  {
    echo 'Person: '.$this->name.' is '.$this->age.' years old.<br/>';
  }
}
$per=unserialize($_GET['per_serialized']);
echo $per;

?>

POC2.php

<?php

class red
{
  public $filename='error';
}
$test=new red();
$test->filename='2.html';
echo serialize($test);

?>

// O:3:"red":1:{s:8:"filename";s:6:"2.html";}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Typecho 反序列化漏洞 RCE

描述

  1. install.php的第 230 行,有一个用户可控参数__typecho_config被反序列化了;
  2. 在第 232 行,实例化了一个对象,敏锐的意识到,有没有什么包含危险函数的构造方法会被调用呢?
  3. 那我们进入到这个类中(/Typecho/Db.php)去寻找,发现了__construct()函数,但这个函数中没什么危险函数。那我们换一个思路吧:能否利用这个__construct()函数去调用一些其他类,然后再利用其中的构造方法的危险函数呢?
  4. 这时在 120 行发现了程序将一个字符串与一个变量adapterName进行拼接。该变量对应config中的adapter,如果我们用adapter来实例化一个类,就会触发__toString()方法。(PHP 是弱类型语言,把一个字符串和一个类拼接时会强制吧类转换成字符串,此时就会触发__toString()方法。)接下类第思路就是找一个类,其中有__toString()方法。
  5. 按照这个思路,我们在Typecho_Feed类中找见了__toString()方法。但是这里的__toString()并没有危险函数可供利用。但是发现这里会遍历一个数组赋值到screenName,这个数组用户是可控的。如果我们在遍历数组赋值时,把类赋值给变量,而且呢,这个类中未定义screenName变量,那么在赋值时就会创建一个类,从而自动调用__get()方法。这样我们的思路就变成了:找一个类使用了__get()构造方法,并且存在危险函数可供利用。
  6. 于是乎,我们在Typecho/Request.php中发现Typecho_Request类重写了__get()构造方法。我们在该构造方法中发现_applyFilter()函数被调用了,我们点进去看一看。
  7. 该函数使用了两个危险函数:array_map($filter, $value)call_user_func($filter, $value),其中的参数是否可控呢?
  8. 对这个问题分析发现,filter参数可控!那value值是否可控呢?答,经过跟踪发现也是可控的!
  9. 综上,存在构造方法可以调用,并且有危险函数,其中的参数是可控的,那这样就可以任意代码执行了
    总结:
    数据的输入点为install.php文件中的参数__typecho.config,从外部读入我们构造的序列化数据,使程序会进入的类Typecho_Db类的__construct()函数,然后进入Typecho_Feed类的__toString()函数,再依次进入typecho_request类的__get(),get(),_applyfilter函数,最后由calluserfunc()或者array_map()函数实现任意代码执行。
    在这里插入图片描述
    在这里插入图片描述

参考:https://www.bilibili.com/video/BV1Ft41187ZX/

防御

1. 避免反序列化不可信的数据
最有效的解决方案是避免反序列化来自不可信源的数据。如果可能,使用安全的序列化机制,避免使用能执行代码的序列化格式。
2. 使用安全的反序列化库
选择使用经过审计并且安全的序列化库。这些库设计时考虑了安全性,并避免了常见的反序列化漏洞。
3. 实施严格的输入验证
在反序列化之前,对输入数据进行严格的验证。确保数据符合预期的格式和结构,并且不包含恶意数据。
4. 使用类白名单
限制反序列化过程中可以构造的对象类型。例如,在 PHP 中,可以使用 allowed_classes 选项来限制允许的类:
d a t a = u n s e r i a l i z e ( data = unserialize( data=unserialize(input, [“allowed_classes” => [“MyClass1”, “MyClass2”]]);
5. 更新和修补
确保使用的库和框架是最新的,并应用所有安全补丁。许多反序列化漏洞是由于已知的漏洞未得到修补。

  • 33
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值