标题配图来源于:https://www.php.cn/sql/419233.html
SQL
注入是危害非常大的安全漏洞,常年在OWASP
(The Open Web Application Security Project)中危险系数靠前,SQL
注入可以完全的毁掉一个网站,严重的SQL
注入可以通过注入接口输入一些操作系统命令,从而让黑客可以在目标服务器上做他想要做的任何事。
去年四月份在某个13年创业的知名网站上闲逛的时候,突然看到了一个报错,告诉我SQL
语句有问题,这个报错引起了我的警觉,这就意味着我所访问的这个接口一定存在SQL
注入,到今年他们居然还没有改掉。
这一定又是哪个不负责任的程序员写出来的代码,还好被没有攻击行为的我发现了,万一这个接口让黑客发现,整个网站就废掉了。更别说网站上说的刚拿到了什么融资,老板也只好拿着融资去哭了。
很多面试官喜闻乐见的问题是怎么做SQL
优化,怎么让系统高可用等等,但是我却在他们系统中找到了很多的注入漏洞,从他们的代码中找到了可以执行10多秒的集合处理,对这些垃圾代码却避而不谈。
SQL
注入到底有多么大的危害,为什么非常有必要警觉它,我想用一点基础性的东西去谈一谈。
SQL注入的基本原理
在刚了解SQL的时候就学到了SQL注入的基本形式如下:
"select first_name, last_name from users where id='" + id + "'";
这个时候在id的位置写成' or 1=1 -- 注释
就会产生下面的语句:
select first_name, last_name from users where id='' or 1=1 -- 注释'
很明显,这就把一张表查出来了,但如果只查了这一张表,那么SQL注入也构不成什么威胁。
拿出owaspbwa
靶机来做下测试。
union关键字
既然之前只能查询一张表,现在可以在后面添加一个union
关键字,来连接另一个查询语句,不就可以查询出来另外一张表的信息了吗?
select user, password from mysql.user
union
select user_login, user_pass from wordpress.wp_users;
上面这条SQL
语句就可以把wordpress
中的账户名称和密码查询出来了。
union
关键字有一个特征就是两个查询语句的字段数量必须是相同的,于是就导致一个问题,如果字段数量不相同,就会报错的。
我们可以通过试探的方式来确定到底有多少个字段,可以利用一个数字或者一个可以执行的语句或者其他东西来模拟出来一个字段:
select user, password, host from mysql.user
union
select user_login, user_pass, 1 from wordpress.wp_users;
# 上面这里用1来表示一个字段
这种方式可以用来测试目标注入语句中到底有多少个字段。
当然也可以使用order by
来试探
select user, password, host from mysql.user order by 1
# 后面的这个数字代表的是列索引,如果没有这个索引就会报错
试探出字段的数量后,如果查询目标表中的字段比SQL
注入语句中字段的数量少,我们可以用1,2,3这样的数字来填补,但是如果目标查询字段数量比原来的SQL
注入语句中的字段多呢,可以使用下面的方式:
select password, concat(first_name, ' ', last_name, ' ', user) from users
上面这条语句是把字段全部拼接起来了。
如果说只想保留wordpress
表中的记录,就可以用不成立的语句来限制前面的SQL
:
# 下面的1=2就把前面的表的内容给剔除掉了
select user, password, host from mysql.user where 1=2
union
select user_login, user_pass, 1 from wordpress.wp_users;
遇到的问题
虽然知道了注入的地方,还有字段的数量,但是不知道DBMS中有几个数据库,每个数据库中又几张表,每个表中有几个属性
这个时候可以用到information_schema
表了,相当于是一个数据库字典,每个数据库用户都会有这个表,用法大致如下:
查看所有的表信息:
select * from information_schema.TABLES\G
只看拥有什么数据库:
select DISTINCT TABLE_SCHEMA from information_schema.TABLES;
# show databases
查询哪个库中有哪个表:
select TABLE_SCHEMA, GROUP_CONCAT(TABLE_NAME) # 这里用到了组连接
from information_schema.TABLES
GROUP BY TABLE_SCHEMA\G
查询某个库有有什么表:
select TABLE_NAME from INFORMATION_SCHEMA.tables where TABLE_SCHEMA = '库名';
# show table
查询某张表中有哪些字段:
select COLUMN_NAME
from information_schema.columns
where TABLE_SCHEMA = '库名' and TABLE_NAME = '表名'
是否有SQL注入
上面知道了可以使用union
来查询其他表,也知道了可以通过试探的方式知道SQL
注入语句中有几个字段。还有一个问题,就是怎么判断是否有SQL
注入。
-
基于布尔的盲注
可以使用
or
关键字连接一个成立的条件来确定是否是SQL
注入,这个在上面也说过了,这个方法简单,但是测试的并不理想。 -
基于错误
可以通过填写可能会让
SQL
语句发生错误的语句来进行测试,如果出错了,那么就意味着这里一定存在SQL
注入,还有一个反例,就是在参数中写入注释比如说/*注释*/
,这个很明显是SQL
的注释,如果后台把这个注释真的当成SQL
注释了,那么意味着这个一定存在SQL
注入漏洞的。 -
基于时间的盲注
大部分的接口还是没有报错的,这个时候可以使用
sleep(5)
这样的时间盲注,但是这样的语句是有条件的。
其他还有些方法,通过搜索引擎就可以搜索到。
SQL
注入可以执行一些特性的函数来得知目标使用的数据库的信息,甚至是系统信息,比如说下面弱弱的列举了一些:
select user()
获取当前用户,select database()
查询的是当前的数据库select version()
查询数据库的版本@@version_compile_os
操作系统的信息
自动化注入SQLMap
就是这个工具让我感觉到SQL注入的恐怖之处了。
SQLMap是一个开源的SQL渗透工具,它可以自动完成对接口的SQL注入,功能非常的强大,这个工具算是SQL注入的老大了,支持的数据库种类相当多。
用法什么的都不聊了,网上一堆的教程,基本的用法截图在这里
附上一张用SQL注入操作OS命令的截图: