Hello 各位小伙伴周末晚上好~
话说最近有小伙伴在公众号留言问我:
“小编,怎么盗QQ号?”
“小编,在某某网站用什么代码就可以免费充值?”
“小编,能不能帮我攻击一下某某网站?”
第一步,首先目标得有可以利用的漏洞才行,不存在什么万能代码的…
我们要做遵纪守法,维护国家网络安全的白帽子~
好啦,言归正传,其实早就写完了这篇SQL注入总结,但一直没有发布。因为SQL注入可以写的东西实在太多了,所以还是先发出来吧,后期继续丰富。
目录
一、SQL概述
二、SQL注入点的类型
三、常见的注入方式
四、存在SQL注入的点
五、一些WAF的绕过方法
六、SQL注入的防护
一、SQL概述
1、什么是SQL注入?
利用web应用程序对用户输入验证上的疏忽,攻击者在输入的数据中包含对某些数据库系统有特殊意义的符号或命令。通过将这些恶意命令拼接到正常的SQL执行语句中一并执行,达到对后台数据库系统直接下达命令的攻击方式。
为什么可以把构造的SQL命令插入到正常的SQL执行语句中一并执行呢?
SQL查询支持and、or、union等多种查询方法,攻击者可以通过这些方法,将恶意执行语句拼接到正常的查询语句中去。
例如:
http://x.x.x.x/dy_show.php?dy_id=42 union select 1,version(),user(),4
通过union拼接恶意查询语句,查出了数据库版本,和当前管理员账号:
因此,SQL注入攻击的本质,其实就是把用户输入的数据当作代码执行了。
注入攻击需要满足两个条件:
根据后端服务器传递到SQL数据库的查询语句的不同,我们可以分为两类:
1、数字型注入
SELECT name FROM users WHERE user_id = $id
数字型注入,直接在后面拼接我们构造的SQL语句即可。
2、字符型注入
SELECT name FROM users WHERE user_id = ‘$id’
字符型注入,如果直接拼接SQL语句,拼接的语句并不会被执行,也不会报错,需要将我们构造的语句从’ ’ 中逃逸出来才行。
比如下面这个例子:
//and 1=2 没有生效,如果生效应该什么都查不出来才对。
逃逸方法:
如果传入的参数是被’ ‘引起来的,我们可以传入id = 1’ and 1=2 #
SELECT name FROM users WHERE user_id = ‘1’ and 1=2 # ’
//第一个’ 使 and 1=2 逃逸出来,#注释掉后面多余的’号。
//注释符也可以用–空格,但在URL中输入时,如果在最后加上-- ,浏览器在发送请求的时候会把URL末尾的空格舍去,所以我们用–+代替-- ,原因是+在URL被URL编码后会变成空格
1、报错注入
2、联合查询注入
报错注入 + 联合注入就可以爆出一些简单的数据库的字段内容了,具体实战内容请参考之前的文章:
【SQL注入】通过实战教你手工注入MySql数据库
3、盲注:
很多时候,Web服务器不显示数据库中查询的内容,只反馈对错,此时就可以根据逻辑判断是否正确利用盲注来获取信息。
以sqli-labs的第5关为例:
http://192.168.211.174/sqli-labs-master/Less-5/?id=11 注入点为?id,当我们输入可查询到的id时,页面只显示you are in … ,不显示查询到的内容,如下:
当我们输入一个查询不到的id时,页面什么都不显示,例如输入:
http://192.168.211.174/sqli-labs-master/Less-5/?id=110000
可以看出正确查询时,只返回 You are in…
该页面不存在显示点,我们只能采用盲注的方法进行猜测。
输入http://192.168.211.174/sqli-labs-master/Less-5/?id=1’
语法报错如下:
输入:http://192.168.211.174/sqli-labs-master/Less-5/?id=1’ and 1=1 --+
现在知道注入格式了,但是union联合查询在这里肯定是不适用的,因为当查询到数据时,该页面只会显示一个You are in …
此时,就需要我们用到盲注了,这里介绍几个盲注可以用到的函数。
一个汉字是算三个字符,一个数字或字母算一个字符。
http://192.168.211.174/sqli-labs-master/Less-5/?id=1’ and length(database())=8 --+
可以看出数据库名长度为8,这时我们再来一个字符,一个字符进行猜解
如:http://192.168.211.174/sqli-labs-master/Less-5/?id=1’ and left(database(),1)=‘s’ --+
如果显示 you are in ,则说明第一个字符是s,接着猜第二个字符,直到猜出完整数据库名为止。
利用以上函数,我们可以构造如下payload进行猜解
and ascii(substr((select table_name from information_schema.tables where tables_schema=database() limit 0,1),1,1))>100–+
如果输入 >100 显示you are in…,输入>101则什么都不显示,则表示第一个字符ASCII值为101,即英文字母 e。
通过以上盲注方法,我们就可以逐步猜解出数据库名等一系列我们需要的敏感信息,但是通过手工注入,效率也是非常繁琐的,此时就需要配合我们的自动化工具来帮助我们完成这个过程了,例如sqlmap。
输入:root@kali:~# sqlmap -u "http://192.168.211.174/sqli-labs-master/Less-5/?id=1’ 即可。
但有时候,Web服务器不但不显示数据库中查询的内容,甚至连错误回显都关闭了,无论我们输入的数据能否在数据库中查询到,页面都不返回任何信息。
这个时候就需要用到时间盲注了。
时间盲注可以利用sleep()函数或者benchmark() 函数
构造注入语句:id=1’and if(ascii(substr(database(),1,1))=115,1,sleep(5))–+
当查询失败时会有5秒的时间延迟
benchmark() 函数:
id=1’ union select (if(substring(current,1,1)=char(115),benchmark(50000000,encode(‘MSG’,‘by 5 seconds’)),null)),2,3 from (select database() as current) as tb1–+
当结果正确的时候,运行encode(‘MSG’,‘by 5 second’)操作500000000次,会占用一定的时间,以此来判断查询是否正确。
同样,使用sqlmap可以快速完成注入。
在MS SQL Server和Oracle数据库中,有着大量内置的存储过程。存储过程为数据库提供了强大的功能,存储过程需要使用CALL或者EXEC来执行。
存储过程也就是SQLServer为了实现特定任务,而将一些需要多次调用的固定操作语句编写成程序段。
例如在SQL Server中,我们可以利用xp_cmdshell执行系统命令:
EXEC master.dbo.xp_cmdshell ‘cmd.exe dir c:’
1、GET
SQL注入常见的注入点就是GET,我们通过输入的URL进行注入。
例如:
前端代码通过GET方法,将username&password传入到后端服务器:
后端服务器再通过GET方法接收数据,并调用到sql查询语句中去。
POST方法不同于GET方法,传输的内容并不会在URL中进行显示
前端使用POST方法,代码如下:
后端使用$_POST进行数据接收:
抓包可发现传递的参数在HTTP请求的正文中:
3、HTTP 文件头注入
除了用户主动提交的数据以外,有时候,服务器会读取HTTP头部的中的信息存入到数据库中去。
常见的HTTP文件头注入点如下:
例如,PHP后端会使用KaTeX parse error: Double subscript at position 17: …_SERVER[‘HTTP_X_̲FORWARDED_FOR’]…_SERVER[‘HTTP_HOST’]来获取Host头,如果没有对这些输入点进行过滤就存入数据库中,就会存在SQL注入风险。
1、大小写绕过
例如WAF拦截了union,可以使用大写UNION的方式
2、编码绕过
如果大小写都过滤了,可以采用编码的方式进行绕过。
例如用16进制代替U,就是%55nion,当然还有char(ASCII码)等多种方式来替换字符。
3、注释符绕过
(1)WAF过滤了一次危险语句的情况
例如: ?id=1 union select 1,2,3 可以写成:
(2)绕过空格过滤
在WAF采用了正则表达式的情况下,使用注释符充当分隔符
例如:
同样是在WAF只过滤了一次的情况下,我们可以使用重写来进行绕过
例如:?id=1 ununionion selselectect 1,2,3
在注入攻击中,我们常常会使用单引号’,或者双引号"进行注入点判断。
因此,开发者为了安全,一般会使用转义字符 \ 对我们输入的特殊字符进行转义。转义后的特殊字符,就变成了我们查询的内容,失去了他们原本的作用。
但是,当Mysql数据库使用了GBK编码时,会认为两个字符为一个汉字,例如%bf%5c就是一个汉字(前一个ascii码大于128才能到汉字的范围)。
因此经过转义后,%bf%5c(%5c为 \)就会变成一个汉字,把转义符吃掉。
我们在构造注入语句时,需要写成:
id=-1%df%27union select 1,user(),3 --+
防护方法:统一数据库、操作系统、Web应用所使用的字符集,以避免各层对字符的理解存在差异,例如都设置为utf-8。
1、SQL注入的危害
通过前面的总结,SQL注入漏洞存在的原因有两个:
SQL注入带来的危害:
(此处准备再开一篇文章通过案例进行说明,先挖个坑~~)
我们来看看SQL注入的防护方式有哪些。
使用预编译语句后,SQL语句的语义不会发生改变,我们直接来看一个例子:
我们来分析一下代码:
第一行使用?表示变量,我们可以将?替换为整型,字符串,双精度浮点型和布尔值。
第三行绑定了 SQL 的参数,且告诉数据库参数的值。其中 “sss” 参数列处理其余参数的数据类型,告诉数据库后面三个参数的类型为字符串。
通过这种方法,SQL语句的结构已经被固定,即使攻击者输入?firstname=li’ and ‘1’='1这样的字符串,也只会被当作firstname整体来进行查询。
(1)检查数据的类型
在将变量代入到sql语句之前,先检查变量的数据类型是否正确。
例如输入?id=1,我们可以使用is_numeric( i d ) 检 查 id)检查 id)检查id的值是不是一个数字,不是的话则报错。
又比如输入的是时间、日期时,也必须严格按照时间、日期的格式进行输入。
(2)使用安全函数
如果用户提交的时字符串,那么检查数据类型的方法可能就不好用了。此时我们需要配合一些安全函数,对输入的字符进行过滤。
例如,使用mysql_real_escape_string()、addslashes()、str_replace()等函数,对敏感字符进行过滤。
从数据库的角度来说,应该避免web应用直接使用root等最高权限直接连接数据库。
web应用使用的数据库账户,也不应该有创建自定义函数、操作本地文件的权限。
这就是今天的全部内容了,再次强调大家不可以干违法乱纪的事哦~
最后,欢迎关注我的个人微信公众号。
Peace !