输入参数主要覆盖范围有:
HTTP 查询字符参数(GET):输入参数通过URL发送
HTTP 正文参数(POST):输入参数通过HTTP正文发送
HTTP Cookie参数:输入参数通过HTTP cookie发送
HTTP Headers:HTTP提交应用程序使用的头,包括User-agent和Referer头字段
潜在的HTTP头SQL注入有:Cookie, User-agent, Referer
1.Cookie头字段
首部字段Cookie会告知服务器,当客服端想获得HTTP状态管理支持时,就会在请求中包含从服务器接收到的Cookie.
GET / HTTP/1.1
Connection: Keep-Alive
Keep-Alive: 300
Accept:*/*
Host: host
Accept-Language: en-us
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US;
rv:1.9.2.16) Gecko/20110319 Firefox/3.6.16 ( .NET CLR 3.5.30729; .NET4.0E)
Cookie: guest_id=v1%3A1328019064; pid=v1%3A132883931113 order by 4
2.User-Agent头字段
用户代理(user agent)是记录软件程序的客户端信息的HTTP请求头字段,用于将创建请求的浏览器和用户代理名称等信息传送给服务器。
例如:
GET /index.php HTTP/1.1
Host: [host]
User-Agent: aaa' or 1/*
3.Referer头字段
Referer是另外一个当应用程序没有过滤存储到数据库时,容易发生SQL注入的HTTP头。它是一个允许客户端指定的可选头部字段,通过它我们可以判断用户是从哪个页面过来的。
例如:
GET /index.php HTTP/1.1
Host: [host]
User-Agent: aaa' or 1/*
Referer: http://www.yaboukir.com
HTTP头部详解
User-Agent:使得服务器能够识别客户使用的操作系统,游览器版本等.(很多数据量大的网站中会记录客户使用的操作系统或浏览器版本等存入数据库中)
Cookie:网站为了辨别用户身份、进行 session 跟踪而储存在用户本地终端上的数据(通常经过加密).
X-Forwarded-For:简称XFF头,它代表客户端,也就是HTTP的请求端真实的IP,(通常一些网站的防注入功能会记录请求端真实IP地址并写入数据库or某文件[通过修改XXF头可以实现伪造IP]).
Clien-IP:同上,不做过多介绍.
Rerferer:浏览器向 WEB 服务器表明自己是从哪个页面链接过来的.
Host:客户端指定自己想访问的WEB服务器的域名/IP 地址和端口号(这个我本人还没碰到过,不过有真实存在的案例还是写上吧).
HTTP头注入检测
HTTP头存在注入的话,可以使用burpsuite抓包工具,进行抓包注入.(PS:可能需要手工添加相关头参数).
通过图上,可明显看出是基于时间的sql盲注.(sqlmap 构造的payload).
在可能存在注入的http头部加上(*)星号可以理解为sqlmap跑注入时候的定位符(就是说明这个’可控参数可能存在sql注入’)[同 sqlmap -r url.txt -p “User-agent”]。
结果 (关于头注入,sqlmap可能不能直接检测出头部sql注入,可以尝试添加一些参数在进行测试)
插件可以用来进行源IP地址的伪造,也可以添加一些可能存在http头注入的参数进行抓包检测.
开启modify headers插件,使用burpsuite进行抓包时,发现截获的数据包某些HTTP字段已经按照我们想要的格式添加上去了.(host这里是个变体,根据实际情况改)。
host 头注入结果
问题在/admin/logincheck.php的19-28行
$ip=getip();
define('trytimes',20);//可尝试登录次数
define('jgsj',15*60);//间隔时间,秒
$sql="select * from zzcms_login_times where ip='$ip' and count>=".trytimes." and unix_timestamp()-unix_timestamp(sendtime)<".jgsj." ";
$rs = mysql_query($sql);
$row= mysql_num_rows($rs);
if ($row){
$jgsj=jgsj/60;
showmsg("密码错误次数过多,请于".$jgsj."分钟后再试!");
}
限制登录次数的功能,使用getip()获取IP,然后查询IP和登录时间,如果超过尝试登录次数就禁止登录
跟进一下getip()函数
/inc/function.php 69-81行
function getip(){
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);
}
首先使用CLIENT_IP获取IP(第一步就出问题了),若没有,则使用X_FORWARDED_FOR获取IP(第二步也出问题了)
以此类推。
为什么说出问题呢?因为这两个头都是可控的,我之前写过一篇关于XFF头的文章,不了解问题在哪的可以看一下。
http://www.lsafe.org/?p=481
既然可控,那么就可以输入任意字符,构造sql语句,直接标记一下丢到sqlmap
CLTENT-IP: