sql注入
sql注入
数字型:
当输入的参数为整形时,若存在注入漏洞,则是数字型注入。
如:https://blog.csdn.net/aboutus.php?id=1
此时后台语句:$sql=“SELECT 123 FROM abc WHERE id=’1 ‘“
检测方法:URL输入 and 1=1 / and 1=2 报错则说明有注入
字符型
当输入参数为字符串时,称为字符型注入。
它与数字型的区别:数字型不需要单引号来闭合,而字符串需要单引号来闭合。
例:https://blog.csdn.net/aboutus.php?id=1’
此时后台语句:$sql=“SELECT 123 FROM abc WHERE id=’1 ’ ’ “
此时多出了一个单引号,破坏了原本的SQL语句结构,数据库无法处理,于是会报错,证明这条语句成功被带进数据库查询,存在字符型注入。
此时通过 –+把后面的单引号注释掉,SQL语句也会形成闭合。
联合查询(union注入)
联合查询适合于有显示位的注入,即页面某个位置会根据我们输入的数据的变化而变化。
页面观察
输入id=1和id=2,若页面中值有变化,说明输入与数据库有交互
注入点判断
直接输入?id=1’若有报错则存在注入,开始判断可以从哪里注入,?id=2’1=2–+页面显示不正常,说明此处存在SQL注入,注入点在引号。
接下来开始使用SQL语句进行攻击。
使用order by判断当前表的字段个数
例:?id=1 order by n –+
若n超过当前表的列数,就会报错,说明表中只有n-1列
判断显示位
判断显示位时,要使用 ?id=-1 或者改为0 让前面的select语句查询为空错误,然后采用后面的select语句去查询:
1 |
|
观察页面在哪里回显我们的输入,就可以用那个地方测试接下的语句。
爆数据库的名字
1 |
|
在之前回显2的地方会回显database数据库的名字。
爆数据库中的表
1 |
|
爆表中的字段
1 |
|
爆相应字段的所有数据
1 |
|
报错注入
在mysql中使用指定函数来制造报错,查询的时候加一些格式错误的信息,它会提示你格式错误,可以在中间加入一些其他信息,比如select database(),报错信息后面也会出现数据库信息.
group by 重复键冲
1
and (select 1 from (select count(*),concat((select 查询的内容 from information_schema.tables limit 0,1),floor(rand()*2))x from information_schema.table group by x)a) --+
extractvalue() 函数
extractvalue(xml_frag,xpath_expr);
函数接受两个参数,第一个为XML标记内容,也就是查询的内容,第二个为XPATH路径,也就是查询的路径。
如果没有匹配的内容,不管出于何种原因,只要路径有效并且查询的内容由正确嵌套和关闭的元素组成,返回空字符串。
但如果路径写入错误格式,就会报错并且返回我们写入的非法内容。
1
?id=1' and extractvalue(1,concat('^',(select database()),'^')) *--+//获取数据库名字*
updatexml() 函数
updatexml(xml_target,xpath_expr,new_xml);
此函数将XML标记的给定片段的单个部分替换为xml_target新的XML片段new_xml,然后返回更改的XML。
xml_target替换的部分 与xpath_expr 用户提供的XPath表达式匹配。如果未xpath_expr找到表达式匹配 ,或者找到多个匹配项,则该函数返回原始 xml_targetXML片段。
所有三个参数都应该是字符串。与extractvalue()类似,如果XPATH写入错误格式,就会报错,并且返回我们写入的非法内容。
and updatexml(1,concat(‘^’,(需要查询的内容),’^’),1)
获取数据库名字
1 |
|
获取当前数据库中表的名字
1 |
|
在 table_schema=’security’ 后加上 limit 0,1,显示第一行(显示第0行的往下一行,不包括第0行)如果要看第二行则,limit1,1(第一行的往下一行,不包括第一行,即显示第二行),看第三行则limit2,1。
爆表中的字段
1 |
|
爆字段中的内容
?id=1' and updatexml(1,concat('^',(select group_concat(username,"--",password) from users limit 0,1 ),'^'),1) --+
?id=1"||(updatexml(1,concat(0x7e,(select(group_concat(real_flag_1s_here))from(users)where(real_flag_1s_here)regexp('^f'))),1))#
?id=1"||(updatexml(1,concat(0x7e,reverse((select(group_concat(real_flag_1s_here))from(users)where(real_flag_1s_here)regexp('^f')))),1))#
基于布尔的盲注
布尔盲注,即在页面没有错误回显时完成的注入攻击。此时我们输入的语句让页面呈现出两种状态,相当于true和false,根据这两种状态可以判断我们输入的语句是否查询成功。以less-8关为例
基于时间的盲注
也叫延时注入。通过观察页面,既没有回显数据库内容,又没有报错信息也没有布尔类型状态,那么我们可以考虑用“绝招”–延时注入。延时注入就是将页面的时间线作为判断依据,一点一点注入出数据库的信息。我们以第9关为例,在id=1后面加单引号或者双引号,页面不会发生任何改变,所以我们考虑绝招延时注入。
HTTP头注入
常见的sql注入一般是通过请求参数或者表单进行注入,而HTTP头部注入是通过HTTP协议头部字段值进行注入。http头注入常存在于以下地方
产生注入的条件:
能够对请求头消息进行修改
修改的请求头信息能够带入数据库进行查询
数据库没有对输入的请求信息做过滤
- User-Agent注入
User-Agent:使得服务器能够识别客户使用的操作系统,浏览器版本等。(很多数据量大的网站中会记录客户使用的操作系统或浏览器版本等然后将其存入数据库中)。这里获取User-Agent就可以知道客户都是通过什么浏览器访问系统的,然后将其值保存到数据库中。
以sqli-labs less-18关为例,登录用户密码:dumb ,0
1.1 判断注入点:user-agent值后面加上’,引发报错,确定存在sql注入
1.2 采用报错注入函数获取当前数据库名
‘ and updatexml(1,concat(‘^’,(database()),’^’),1) and ‘
- cookie注入
cookie:服务器端用来记录客户端的状态。由服务端产生,保存在浏览器中。以sqli-labs less-20关为例,登录后
2.1 首先判断注入点,加 ‘ 单引号报错
2.2 采用报错注入函数获取当前数据库名
‘ and updatexml(1,concat(‘^’,(database()),’^’),1) and ‘
- Referer注入
Referer:是HTTP header的一部分,当浏览器向web服务器发送请求的时候,一般会带上Referer,告诉服务器该网页是从哪个页面链接过来的,服务器因此可以获得一些信息用于处理。
以19关为例
判断输入点,加单引号引发报错
使用报错注入函数:
‘ and updatexml(1,concat(0x7e,(database()),0x7e),0) and ‘
- X-Forwarded-For 注入 详情
X-Forwarded-For(XFF):用来识别客户端最原始的ip地址。
宽字节注入
宽字节是指多个字节宽度的编码,GB2312、GBK、GB18030、BIG5、Shift_JIS等这些都是常说的宽字节,实际上只有两字节。转义函数在对这些编码进行转义时会将转义字符 ‘\’ 转为 %5c ,于是我们在他前面输入一个单字符编码与它组成一个新的多字符编码,使得原本的转义字符没有发生作用。
由于在数据库查询前使用了GBK多字节编码,即在汉字编码范围内使用两个字节会被编码为一个汉字(前一个ascii码要大于128,才到汉字的范围)。然后mysql服务器会对查询语句进行GBK编码,即下面所说的
我们在前面加上 %df' ,转义函数会将%df’改成%df\’ , 而\ 就是%5c ,即最后变成了%df%5c',而%df%5c在GBK中这两个字节对应着一个汉字 “運” ,就是说 \ 已经失去了作用,%df ' ,被认为運' ,成功消除了转义函数的影响。
‘ %27
\ %5c
%df' %df%5c’ =》 運’
宽字节注入方法
- 黑盒
就是上面所述的,在注入点后面加%df,然后按照正常的注入流程开始注入即可。如果我们需要使用sqlmap进行检测注入的话也需要在注入点后面加%df然后再用sqlmap跑,否则是注入不出来的,如
sqlmap.py -u “http://localhost/sqli-labs-master/Less-32/?id=1%df%27“
- 白盒
查看mysql是否为GBK编码,且是否使用preg_replace()把单引号转换成'或自带函数addslashes()进行转义
堆叠查询
堆叠查询也叫堆叠注入,在SQL中,分号(;)是用来表
示一条sql语句的结束。试想一下我们在 ; 结束一个sql语句后继续构造下一条语句,会不会一起执行?因此这个想法也就造就了堆叠注入。而union injection(联合注入)也是将两条语句合并在一起,两者之间有什么区别么?区别就在于union 或者union all执行的语句类型是有限的,可以用来执行查询语句,而堆叠注入可以执行的是任意的语句。以sqli-labs第38关为例
执行id=1’;update users set password=’123456’ where id=1; –+
更新id=1的用户密码为123456。如下成功执行了更新密码的语句
二阶注入
二次注入漏洞是一种在Web应用程序中广泛存在的安全漏洞形式。相对于一次注入漏洞而言,二次注入漏洞更难以被发现,但是它却具有与—次注入攻击漏洞相同的攻击威力。
黑客通过构造数据的形式,在浏览器或者其他软件中提交HTTP数据报文请求到服务端进行处理,提交的数据报文请求中可能包含了黑客构造的SQL语句或者命令。
服务端应用程序会将黑客提交的数据信息进行存储,通常是保存在数据库中,保存的数据信息的主要作用是为应用程序执行其他功能提供原始输入数据并对客户端请求做出响应。
黑客向服务端发送第二个与第一次不相同的请求数据信息。
服务端接收到黑客提交的第二个请求信息后,为了处理该请求,服务端会查询数据库中已经存储的数据信息并处理,从而导致黑客在第一次请求中构造的SQL语句或者命令在服务端环境中执行。
服务端返回执行的处理结果数据信息,黑客可以通过返回的结果数据信息判断二次注入漏洞利用是否成功
总结,二次注入就是由于将数据存储进数据库中时未做好过滤,先提交构造好的特殊字符请求存储进数据库,然后提交第二次请求时与第一次提交进数据库中的字符发生了作用,形成了一条新的sql语句导致被执行。
sql注入绕过
注释符号绕过
常用的注释符有
1 |
|
大小写绕过
常用于 waf
的正则对大小写不敏感的情况,一般都是题目自己故意这样设计。
例如:过滤了关键字select
,可以尝试使用Select
等绕过。
内联注释绕过
内联注释就是把一些特有的仅在MYSQL上的语句放在 /*!...*/
中,这样这些语句如果在其它数据库中是不会被执行,但在MYSQL中会执行。
双写关键字绕过
在某一些简单的waf
中,将关键字select
等只使用replace()
函数置换为空,这时候可以使用双写关键字绕过。例如select
变成seleselectct
,在经过waf
的处理之后又变成select
,达到绕过的要求。
特殊编码绕过
- 十六进制绕过
- ascii编码绕过
空格过滤绕过
一般绕过空格过滤的方法有以下几种方法来取代空格
1 |
|
过滤or and xor not 绕过
1 |
|
过滤等号=绕过
like: 不加通配符
的like
执行的效果和=
一致,所以可以用来绕过。
rlike: 模糊匹配,只要字段的值中存在要查找的 部分 就会被选择出来
用来取代=
时,rlike
的用法和上面的like
一样,没有通配符效果和=
一样
regexp: MySQL中使用 REGEXP 操作符来进行正则表达式匹配
使用大小于号来绕过
<>: 等价于 !=,所以在前面再加一个!
结果就是等号了
过滤大小于号绕过
·greatest(n1, n2, n3…):返回n中的最大值
·least(n1,n2,n3…):返回n中的最小值
·strcmp(str1,str2):若所有的字符串均相同,则返回STRCMP(),若根据当前分类次序,第一个参数小于第二个,则返回 -1,其它情况返回 ·in关键字
·between a and b:范围在a-b之间
过滤引号绕过
·使用十六进制
1 |
|
·使用宽字节
常用在web应用使用的字符集为GBK
时,并且过滤了引号,就可以试试宽字节。
1 |
|
过滤逗号绕过
如果waf过滤了逗号,并且只能盲注(盲注基本离不开逗号啊喂),在取子串的几个函数中,有一个替代逗号的方法就是使用from pos for len
,其中pos代表从pos个开始读取len长度的子串
例如在substr()
等函数中,常规的写法是
1 |
|
如果过滤了逗号,可以这样使用from pos for len
来取代
1 |
|
过滤函数绕过
·sleep() –>benchmark()
·ascii()–>hex()、bin()
替代之后再使用对应的进制转string即可
·group_concat()–>concat_ws()
·substr(),substring(),mid()可以相互取代, 取子串的函数还有left(),right()
·user() –> @@user、datadir–>@@datadir
·ord()–>ascii():这两个函数在处理英文时效果一样,但是处理中文等时不一致。
·information_schema.tables->mysql.innodb_table_stats / mysql.innodb_index_stats表下分别是database_name,table_name,index_name
sys数据库中的以下三个视图中存储了表名table_name:
- sys.schema_auto_increment_columns #存在自增主键的表会出现在此视图
- sys.schema_table_statistics_with_buffer #数据来源视图
- sys.x$schema_table_statistics_with_buffer #数据来源视图
(注:部分内容借鉴于这位大佬的博客点我跳转)