如下controller即可触发SQL注入:

code 区域

public function test()

{

$uname = I('get.uname');

$u = M('user')->where(array(

'uname' => $uname

))->find();

dump($u);

}

为什么?

我们看看代码。我从github下载的最新源码:https://github.com/liu21st/thinkphp

/ThinkPHP/Library/Think/Db/Driver.class.php 531行:

code 区域

// where子单元分析

protected function parseWhereItem($key,$val) {

$whereStr = '';

if(is_array($val)) {

if(is_string($val[0])) {

if(preg_match('/^(EQ|NEQ|GT|EGT|LT|ELT)$/i',$val[0])) { // 比较运算

$whereStr .= $key.' '.$this->comparison[strtolower($val[0])].' '.$this->parseValue($val[1]);

}elseif(preg_match('/^(NOTLIKE|LIKE)$/i',$val[0])){// 模糊查找

if(is_array($val[1])) {

$likeLogic = isset($val[2])?strtoupper($val[2]):'OR';

if(in_array($likeLogic,array('AND','OR','XOR'))){

$likeStr = $this->comparison[strtolower($val[0])];

$like = array();

foreach ($val[1] as $item){

$like[] = $key.' '.$likeStr.' '.$this->parseValue($item);

}

$whereStr .= '('.implode(' '.$likeLogic.' ',$like).')';

}

}else{

$whereStr .= $key.' '.$this->comparison[strtolower($val[0])].' '.$this->parseValue($val[1]);

}

}elseif('bind'==strtolower($val[0])){ // 使用表达式

$whereStr .= $key.' = :'.$val[1];

}elseif('exp'==strtolower($val[0])){ // 使用表达式

$whereStr .= $key.' '.$val[1];

}elseif(preg_match('/IN/i',$val[0])){ // IN 运算

if(isset($val[2]) && 'exp'==$val[2]) {

$whereStr .= $key.' '.strtoupper($val[0]).' '.$val[1];

}else{

if(is_string($val[1])) {

$val[1] = explode(',',$val[1]);

}

$zone = implode(',',$this->parseValue($val[1]));

$whereStr .= $key.' '.strtoupper($val[0]).' ('.$zone.')';

}

}elseif(preg_match('/BETWEEN/i',$val[0])){ // BETWEEN运算

$data = is_string($val[1])? explode(',',$val[1]):$val[1];

$whereStr .= $key.' '.strtoupper($val[0]).' '.$this->parseValue($data[0]).' AND '.$this->parseValue($data[1]);

}else{

E(L('_EXPRESS_ERROR_').':'.$val[0]);

}

}else {

$count = count($val);

$rule = isset($val[$count-1]) ? (is_array($val[$count-1]) ? strtoupper($val[$count-1][0]) : strtoupper($val[$count-1]) ) : '' ;

if(in_array($rule,array('AND','OR','XOR'))) {

$count = $count -1;

}else{

$rule = 'AND';

}

for($i=0;$i<$count;$i++) {

$data = is_array($val[$i])?$val[$i][1]:$val[$i];

if('exp'==strtolower($val[$i][0])) {

$whereStr .= $key.' '.$data.' '.$rule.' ';

}else{

$whereStr .= $this->parseWhereItem($key,$val[$i]).' '.$rule.' ';

}

}

$whereStr = '( '.substr($whereStr,0,-4).' )';

}

}else {

//对字符串类型字段采用模糊匹配

$likeFields = $this->config['db_like_fields'];

if($likeFields && preg_match('/^('.$likeFields.')$/i',$key)) {

$whereStr .= $key.' LIKE '.$this->parseValue('%'.$val.'%');

}else {

$whereStr .= $key.' = '.$this->parseValue($val);

}

}

return $whereStr;

}

这就是处理where条件的函数,我们看到如下片段:

code 区域

}elseif(preg_match('/BETWEEN/i',$val[0])){ // BETWEEN运算

$data = is_string($val[1])? explode(',',$val[1]):$val[1];

$whereStr .= $key.' '.strtoupper($val[0]).' '.$this->parseValue($data[0]).' AND '.$this->parseValue($data[1]);

}

当匹配/BETWEEN/i和$val[0]时,则将strtoupper($val[0])直接插入了SQL语句。

这个匹配:preg_match('/BETWEEN/i',$val[0]),明显是有问题的。因为这个匹配没加^$也就是首尾限定,所以只要我们的$val[0]中含有between时,这个匹配就可以成立,就产生了一个SQL注入。

为了防止I函数对我们输入的过滤影响,我们看看I函数:

code 区域

function I($name,$default='',$filter=null,$datas=null) {

if(strpos($name,'/')){ // 指定修饰符

list($name,$type)     =    explode('/',$name,2);

}

if(strpos($name,'.')) { // 指定参数来源

list($method,$name) = explode('.',$name,2);

}else{ // 默认为自动判断

$method = 'param';

}

switch(strtolower($method)) {

case 'get' : $input =& $_GET;break;

case 'post' : $input =& $_POST;break;

case 'put' : parse_str(file_get_contents('php://input'), $input);break;

case 'param' :

switch($_SERVER['REQUEST_METHOD']) {

case 'POST':

$input = $_POST;

break;

case 'PUT':

parse_str(file_get_contents('php://input'), $input);

break;

default:

$input = $_GET;

}

break;

case 'path' :

$input = array();

if(!empty($_SERVER['PATH_INFO'])){

$depr = C('URL_PATHINFO_DEPR');

$input = explode($depr,trim($_SERVER['PATH_INFO'],$depr));

}

break;

case 'request' : $input =& $_REQUEST; break;

case 'session' : $input =& $_SESSION; break;

case 'cookie' : $input =& $_COOKIE; break;

case 'server' : $input =& $_SERVER; break;

case 'globals' : $input =& $GLOBALS; break;

case 'data' : $input =& $datas; break;

default:

return NULL;

}

if(''==$name) { // 获取全部变量

$data = $input;

$filters = isset($filter)?$filter:C('DEFAULT_FILTER');

if($filters) {

if(is_string($filters)){

$filters = explode(',',$filters);

}

foreach($filters as $filter){

$data = array_map_recursive($filter,$data); // 参数过滤

}

}

}elseif(isset($input[$name])) { // 取值操作

$data = $input[$name];

$filters = isset($filter)?$filter:C('DEFAULT_FILTER');

if($filters) {

if(is_string($filters)){

$filters = explode(',',$filters);

}elseif(is_int($filters)){

$filters = array($filters);

}

foreach($filters as $filter){

if(function_exists($filter)) {

$data = is_array($data) ? array_map_recursive($filter,$data) : $filter($data); // 参数过滤

}elseif(0===strpos($filter,'/')){

// 支持正则验证

if(1 !== preg_match($filter,(string)$data)){

return isset($default) ? $default : NULL;

}

}else{

$data = filter_var($data,is_int($filter) ? $filter : filter_id($filter));

if(false === $data) {

return isset($default) ? $default : NULL;

}

}

}

}

if(!empty($type)){

switch(strtolower($type)){

case 's': // 字符串

$data     =    (string)$data;

break;

case 'a':    // 数组

$data     =    (array)$data;

break;

case 'd':    // 数字

$data     =    (int)$data;

break;

case 'f':    // 浮点

$data     =    (float)$data;

break;

case 'b':    // 布尔

$data     =    (boolean)$data;

break;

}

}

}else{ // 变量默认值

$data = isset($default)?$default:NULL;

}

is_array($data) && array_walk_recursive($data,'think_filter');

return $data;

}

较前些版本有些改进:

1.加了类型强制转换$type,但在默认情况下$type是空的,强制类型转换是不存在的。

2.将is_array($data) && array_walk_recursive($data,'think_filter');放在最后一行。我们看看think_filter这个过滤函数:

code 区域

function think_filter(&$value){

// TODO 其他安全过滤

// 过滤查询特殊字符

if(preg_match('/^(EXP|NEQ|GT|EGT|LT|ELT|OR|LIKE|NOTLIKE|BETWEEN|IN)$/i',$value)){

$value .= ' ';

}

}

这个实际上就是对我之前那个漏洞的一个解决方案,将一些关键词后面加空格。但我们看到,这个正则是存在"^$"首尾限定符的。所以只有传入参数完全"等于"BETWEEN的时候才会被加上空格,而且这里加上空格也不会影响漏洞的产生,因为漏洞位置的正则没有加^$首尾限定符。

还有一个说明:之前thinkphp出了个"错误"的补丁,这个补丁已经被官方去掉了,所以不用考虑那个补丁造成的一些干扰。

漏洞证明:

那我们回到最初那段代码:

code 区域

public function test()

{

$uname = I('get.uname');

$u = M('user')->where(array(

'uname' => $uname

))->find();

dump($u);

}

这个代码,我们来测试一下:

果然是有漏洞的,我们看看具体执行的SQL语句:

就在BETWEEN处。除了BETWEEN外还有IN,我就一块说明了。

Onethink演示:

细我就不说了,和之前一样。

修复方案:

正则一定要写明确:

/^BETWEEN$/i

版权声明:转载请注明来源 phith0n@乌云

ThinkPHP最新版本SQL注入漏洞的更多相关文章

  1. ref:ThinkPHP Builder.php SQL注入漏洞(<= 3.2.3)

    ThinkPHP Builder.php SQL注入漏洞(<= 3.2.3) ref:https://www.jianshu.com/p/18d06277161e TimeSHU 2018.04 ...

  2. DedeCMS V5.7sp2最新版本parse_str函数SQL注入漏洞

    织梦dedecms,在整个互联网中许多企业网站,个人网站,优化网站都在使用dede作为整个网站的开发架构,dedecms采用php+mysql数据库的架构来承载整个网站的运行与用户的访问,首页以及栏目 ...

  3. Drupal 7.31版本爆严重SQL注入漏洞

    今早有国外安全研究人员在Twitter上曝出了Drupal 7.31版本的最新SQL注入漏洞,并给出了利用测试的EXP代码. 在本地搭建Drupal7.31的环境,经过测试,发现该利用代码可成功执行并 ...

  4. 浅析PHP框架Laravel最新SQL注入漏洞

    PHP知名开发框架Laravel,之前在官方博客通报了一个高危SQL注入漏洞,这里简单分析下. 首先,这个漏洞属于网站coding写法不规范,官方给了提示: 但官方还是做了修补,升级最新版本V5.8. ...

  5. 【漏洞分析】Discuz! X系列全版本后台SQL注入漏洞

    0x01漏洞描述 Discuz!X全版本存在SQL注入漏洞.漏洞产生的原因是source\admincp\admincp_setting.php在处理$settingnew['uc']['appid' ...

  6. DEDECMS 5.7之前版本远程SQL注入漏洞

    2012/4/29 凌晨 知道创宇安全研究团队截获到最新DEDECMS SQL注入 0day,官网目前提供下载的最新版5.7也受影响,截止本告警发出时官方尚未给出补丁或解决方案,此漏洞利用简单且ded ...

  7. DedeCMS全版本通杀SQL注入漏洞利用代码及工具

    dedecms即织梦(PHP开源网站内容管理系统).织梦内容管理系统(DedeCms) 以简单.实用.开源而闻名,是国内最知名的PHP开源网站管理系统,也是使用用户最多的PHP类CMS系统,近日,网友 ...

  8. sqlmap查找SQL注入漏洞入门

    1.安装sqlmap sqlmap是一款非常强大的开源sql自动化注入工具,可以用来检测和利用sql注入漏洞.注意:sqlmap只是用来检测和利用sql注入点的,使用前请先使用扫描工具扫出sql注入点 ...

  9. WordPress WP-Realty插件‘listing_id’参数SQL注入漏洞

    漏洞名称: WordPress WP-Realty插件‘listing_id’参数SQL注入漏洞 CNNVD编号: CNNVD-201310-499 发布时间: 2013-10-23 更新时间: 20 ...

随机推荐

  1. Light Table 编辑器修改字体 更新

    view->command->use.behaviors 加上这一句  (:lt.objs.style/font-settings "Inconsolata" 14 1 ...

  2. Android ListView分组显示

    ListView的实现方法也是普通的实现方法.只不过在list列表中加入groupkey信息.在渲染的时候要判断是否是分组的标题. 就是在使用不同的两个View的时候存在这种情况,convertVie ...

  3. 我java学习时的模样(一)

    学会敲键盘,能够实现盲打 程序员写代码,是通过键盘将程序输入到编辑器中,而码子的高效,能够让自己的思路更流畅一些.如果想从事IT工作,那面打字就必须得会,并且,如果还一个一个字母去找,上司就会认为是一 ...

  4. pyquery库简介

    html = '''<div><ul><li class="item-0">li0</li><li class="i ...

  5. ddddddeeeessssssttttrrrrrrooooooyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy

    我遥远的 POI 计划啊 https://loj.ac/problems/search?keyword=POI2011 atcoder 一套 动态 DP SAM 随便看 XSY 的题 UOJ Roun ...

  6. Entity Framework6 with Visual Studio 2013 update3 for Oracle 11g

    2014年7月的时候,写了一篇关于EF5 with visual studio 2010 for oracle 11g的博文 原文地址 :http://www.cnblogs.com/HouZhiHo ...

  7. Eclipse提示workspaces is use

    问题描述: 有时候因为强行关闭Eclipse导致再次打开出现workspace提示正在使用 解决办法: 删除workspace目录下隐藏文件夹 .metadata 中的 .lock 文件 worksp ...

  8. 读EntityFramework.DynamicFilters源码_心得_示例演示02

    上次对EntityFramework.DynamicFilters整体的项目结构有了一个认识,这次我们就通过阅读说明文档,示例项目,和单元测试,来动手构建一个我们的体验项目,通过对动态过滤器的使用,使 ...

  9. 微信公众号开发《三》微信JS-SDK之地理位置的获取与在线导航,集成百度地图实现在线地图搜索

    本次讲解微信开发第三篇:获取用户地址位置信息,是非常常用的功能,特别是服务行业公众号,尤为需要该功能,本次讲解的就是如何调用微信JS-SDK接口,获取用户位置信息,并结合百度地铁,实现在线地图搜索,与 ...

  10. div居中方式

    1. position: absolute; top:50%:left: 50%; margin-top: -高度的一半; margin-left: -宽度的一半(此方法适用于固定宽高的元素) 注: ...