一路的陪伴,感谢有你
0x0 安装
我们在分析Laravel框架之前,需要先安装好,我们推荐大家使用的是 composer ,因为Laravel有 很多的插件,我们使用 composer 安装相当于一键安装,相当的方便。至于 composer 的安装不再 啰嗦,我们直接开始安装Laravel.
因为原本的 Laravel-china 已经失效,我们直接替换阿里云的镜像,在国内下载会非常快
1.composer config -g repo.packagist composer
2.https://mirrors.aliyun.com/composer/
直接执行完毕后,我们安装 Laravel ,我都是安装的5.6版本
1.composer create-project laravel/laravel=5.6.* test
2.知道看到 successfully 后安装完毕, composer 会把下载好的 Laravel 放在 test 目录
我使用的是 PHPENV 的集成开发环境,我们直接配置站点
0x1 路由与控制器
我们先来熟悉一下Laravel框架,我们拿到这个框架很明显可以发现他是 MVC 的架构,我们直接访 问这个 a.com 出现的页面他是怎么产生的?我们找到 routes 这个目录下的 web.php
我们可以看到它是指向了模板 welcome ,他的位置在 resiyrces 下的 welcome.blade.php 我们来介绍一下这个路由
我们来增加一个路由看一下
我们来增加一条这样的路由,正常情况下 funtion() 的位置是一个控制器,但是我们目前还没有 提到控制器,所以暂时写一个 function() ,这样的话我们去访问 a.com/baidu 就可以看到页面 打印出 baidu
当然路由也是可以传参的,我们直接修改一下
我们去访问 a.com/baidu/aaa 的话就会输出 baiduaaa ,这些都是可以由我们控制的。
控制器的话我们就要知道我们 Laravel 框架下有一个叫 artisan 的文件,他是可以做很多事情 的,我们使用 cmd 进入到目录,运行命令 php artisan list ,可以发现有很多功能,它可以生 成控制器、操作数据库等等。大家可以下去看一下 Laravel 的手册,我们可是使用它来生成一个 控制器来看一下:php artisan make:controller CommentController ,他就会帮我们在 app/Http/Controllers 目录下生成控制器,下面我们可以来写一下这个控制器。
当我们写了这个 index 控制器之后,我们可以去路由里面调用控制器,我们回到 web.php Route::any("index","CommentController@index"); 这样我们的控制器就和路由绑定在一起 了,我们来访问一下 a.com/index 就会发现页面返回了 index ,我们这里用的是 any ,当然也可 以用 get、post 这些,那么我们就可以来试试获取一个参数,我们在控制器的函数中写:
dump()其实是打印的意思 我们直接使用 get 请求的方式去访问一下 a.com/index?id=111 他就会打印出 111 ,但是这里要注意就是 post 直接发包过去是不行的,会触发 Laravel 的错误, 这是因为它为了防止 CSRF 漏洞,这是 Laravel 的一个规则限制。
0x2 Laravel数据库操作内核分析
首先我们在项目文件夹下有一个 .env 的文件,我们先去配置一下数据库
我们在目录下运行 php artisan -V ,来查看一下我们的 Laravel 版本我们在目录下运行 php artisan -V ,来查看一下我们的 Laravel 版本
Laravel Framework 5.6.39
然后我们来创建一个控制器来测试我们的数据库是否可以链接正常。
php artisan make:controller UserController
找到我们的 UserController.php ,然后测试一下数据库链接
然后配置 web.php 路由
Route::any("index","UserController@index");
这就是最简单的一个操作,看看是否可以查出来:
http://a.com/index?id=1
这样我们其实可以在 dump 的时候 dump($data[0]) 就好了 我们发现数据成功的查出来了。这时候我们在 $id、$data 两行下断点来进行调试,分析一下它 们。
首先我们来分析一下 input 做了什么操作,我们 F7 跟进去 来到了这个地方:
我们可以发现是 get 请求。
再接着走下去之后可以看到这个 parameters 其实就是我们传入的参数。走出去之后我们来到
此时我们就可以看到 $key 就是一个数组了。再往下是一个 array_shift ,把 $key 传给了 $segment ,然后 $segment 不等于空直接走
来到这里,这里我们走下去看一下, $target = $target[$segment]; 其实就是把我们的参数 1 赋值给了 $target ,然后直接返回掉。这就是我们的 input() ,也没有进行任何的过滤就拿过来 了,但是它底层其实是一个PDO,大家可以看一下 Laravel 的手册,他的过滤限制可以在路由里 面进行限制的(使用正则表达式)。然后我们继续分析 F7 走进去,看到 load()
他这里其实是在实例化对象。然后往下走,进入 return class_alias($this->aliases[$alias], $alias); 来到 __callStatic ,这些都是魔术方法,直接走过去
然后我们就来到了 where ,这里主要是为了得到 where 语句的,前面都是一些判断。
这些地方的 value 的值都是我们的参数。
在这边将 $type = 'Basic';
然后
这里其实是有东西的。我们可以直接看一下这个 $this
我们解这往下走,在下方看到 $this->addBinding($value, 'where'); 这里的一个加入绑定,继 续跟进,进入了 addBinding 之后看到它还是对 $this 进行了一些赋值。
继续返回到 get() ,我们看一下 get 里面是怎么回事,跟进函数 来到了 onceWithColumns 函数,我们走下去看看情况~
来到 $result = $callback(); 的时候注意,在这里下个断点。因为下面他直接 return $result 了,我们下个断点之后直接 F8 走过去看看效果
我们可以发现,这时 $result 已经被查出来了,所以我们很有必要进入这个函数看一下。我们一 直往里跟进到拼凑 SQL 语句的地方。我们来到了 compileSelect 这个函数,这里还不是核心的地方,继续 F8 往下走
走下去可以看到我们的 $sql 已经拼接完毕了 sql 语句。我们看一下这个语句
这边直接走下去看 $result 把。
走完全部循环就拿到了需要绑定的值。然后我们来到 select 语句的位置
我们前面已经把 sql 语句和绑定的值准备好了,下面就要去 select 查询了。我们跟进 run
首先去重连了一下
mysql :$this->reconnectIfMissingConnection(); 然后记录执行的开始时间:$start = microtime(true); 来到 $result = $this->runQueryCallback($query, $bindings, $callback); 这里执行完毕 就会返回执行结果,所以我们要跟进去。看到了 $result = $callback($query, $bindings); 这里的 $query 就是我们的语句, $bindings 就是我们要绑定的值。我们继续往里走,发现又到了 run ,他会首先 pretending , 然后下面的东西我们就很熟悉了
我们回顾一下PDO编译执行的三个步骤:
然后就 prepared 结束下去进行 bindValues ,绑定结束后就去 execute 执行了,然后 return $statement->fetchAll(); 就拿到结果了。然会回去
这时候数据就查询完毕了。分析完毕后我们就可以看到 Laravel 就是PDO的方式,可以有效的防 止注入,但是不规范的写法依然会造成注入
本文始发于微信公众号(Secquan圈子社区):回馈粉丝-Larave漏洞详解
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论