作者:安华金和 思成
SQL注入是在信息安全领域一种常见的攻击手段。但是大部分人理解的SQL注入就是通过把SQL命令插入到Web表单提交或在输入域名、页面请求时加入的查询字符串,最终达到欺骗服务器执行偏离预期的SQL命令。这种情况下的SQL注入,引发原因基本是网页对用户输入的信息缺乏校验而导致。
很多人认为只有网页才可以进行 SQL 注入,才有注入点。这是一个普遍对SQL 注入的错误认识。SQL注入严格来讲应该叫做数据库SQL注入。SQL注入的最终目的是获取数据库中存储的敏感信息。事实上,任何可以连接到数据库并进行 SQL 操作的程序都可以实施数据库SQL注入,比如数据库客户端、网页、带有数据库操作的程序客户端。在这三种程序中,网页注入最为常见,这和网页的开发途径相对多元化、某些网页开发人员安全经验低、网页使用量大等相关。
网页的SQL注入主要是通过改变网页发给后台数据库的SQL查询逻辑,查询一些敏感信息。但往往网页链接数据库所用的用户权限较低,并没有查询数据库中的敏感信息的权限,只能获取和网站相关的信息。攻击者想要获取目标数据库中的敏感信息就要想办法利用数据库自身的SQL注入漏洞对网站所用的低权限用户进行提权操作(低权限是针对数据库权限来说的)。攻击者拿到数据库DBA权限后可以对数据库中的敏感信息肆意获取,给数户带来不可预知经济以及名誉上的损失。
网站漏洞给攻击者入侵的机会,而数据库漏洞则会真真切切的威胁您的数据安全。安华金和攻防实验室综合多年的数据库攻防经验与积累将在下文中以目前市场份额最大的Oracle数据库为例介绍Oracle存在的SQL注入威胁和一些防护建议。
Oracle数据库SQL注入漏洞集中存在于PL/SQL编写的函数、存储过程、包、触发器中。Oracle存在SQL注入漏洞的一个重要原因是PL/SQL定义的两种调用权限导致(定义者权限和调用者权限)。定义者权限给了低权限用户在特定时期拥有高权限的可能,这就给提权操作奠定了基础。调用者权限给了低权限用户创建的SQL被高权限执行的可能。Oracle的SQL注入漏洞往往就是基于这两种权限而被攻击者所利用。
利用Oracle的SQL注入漏洞一般只进行两类操作一类是越权操作,一类是提权操纵。提权操作是越权操作中的一种,由于可利用漏洞自身的限制,某些漏洞只支持越权操作。Oracle经典的提权操作命令是GRANT DBA TO USER(给USER用户DBA权限)。越权操作的经典命令是select password from sys.user$ where name = 'SYS';(查询DBA用户的密码哈希散列)获得散列后可以通过orabf等软件离线破解出散列对应密码明文。
攻击者在Oracle注入点采用何种注入方式和获取的数据库账号具备的权限有直接关系。大体在SQL注入上数据库账号可以被分为三类:
1.被获取账号具有较高数据库权限
2.被获取账号具有创建函数或存储过程的权限
3.被获取账号只具有连接权限(最低权限的账号)
细分如下图所示:
对于第一种情况,多指入侵的攻击者具备 CREATE ANY TRIGGER权限或CREATE ANY VIEW权限甚至EXECUTE ANT PROCEDURE权限等较高权限。攻击者如果具备EXECUTE ANT PROCEDURE权限,则可以直接执行许多SYS用户以定义者模式创建的函数或存储过程。只要利用SYS用户创建的存储过程执行GRANT DBA TO USER则就完成了提权到DBA的过程。
例如:CALL SYS.INITJVMAUX.EXEC(‘GRANT DBA TO USER’,TRUE);
攻击者具有CREATE ANY TRIGGER权限的账号,也很容易提升到DBA。主要是因为具有CREATE ANY TRIGGER权限可以创建任意架构(schema)的触发器,包括 SYS。唯一的限制就是攻击者不能对 SYS 用户所拥有的对象创建触发器。这种情况下攻击者提权具体步骤可以分为以下三步:
1.发现阶段,攻击者要确定数据库中的 DBA 用户(Oracle并非只有一个DBA账号,例如SYSTEM也是个DBA),并且确定哪些表或视图攻击者拥有 INSERT,UPDATE,或 DELETE 权限(属于public)。
2.构造阶段,攻击者构造一个调用者权限的含有提全语句的存储过程,想办法让触发器调用存储过程。
3.实施阶段,攻击者针对目标DBA用户创建触发器,触发这个事件。触发器将以拥有者的权限执行,让触发器使用一个调用者权限的存储过程。执行存储过程中的提权语句。
攻击者具有CREATE ANY VIEW权限的账号,提升到DBA也不难。方法类似CREATE ANY TRIGGER。攻击者只要以数据库管理员的模式创建一个视图,然后让一个具有高权限的用户访问这个视图就可以达到提权的目的。
高权限用户提权的方式往往不被漏洞所限制,所以用户一定注意WEB访问数据库的账号权限,过高的权限会给你的数据库安全带来极大隐患。Oracle中,一个拥有CREATE ANY XXX权限的用户很可能可以获取数据库DBA权限,所以除非业务必须否则绝不授予页面链接数据库用户CREATE ANY XXX权限。
对于第二种情况,多指攻击者具备的账号具有创建存储过程、函数等权限,那么攻击者可以通过构造执行提权命令的具有调用者权限的存储过程或函数,并通过具有 SYS(或其他高权限用户)定义者权限的存储过程或函数来调用它,从而实现提权。
攻击者具有创建函数(create functions)的权限,那么等同于他们可以对数据库进行任意操作。攻击者可以将他们希望执行的 PL/SQL 代码写入他们创建的自定义函数(例如在自定义函数中加入GRANT DBA TO USER),并将该函数放入 SQL 语句。攻击者只需要将他们创造的函数设置为调用者权限(AUTHID CURRENT_USER),这样当高权限用户所定义的存储过程或函数调用攻击者创建的函数时,真正执行攻击者所创建的函数的人将是高权限用户。同时攻击者定义的函数必须使用AUTONOMOUS+TRANSACTION 的编译指示。这个编译可以向编译器表明,该函数将执行它子程序内部的事件,而与调用它的存储过程或函数无关。最后只要在数据库中寻找一个具有PUBLIC执行权限的高权限存储过程或函数即可。
对于第三种权限,同时也是最为普遍的情况,即当前数据库用户只具有较低的权限,并且不具备创建用户自定义存储过程或函数的权限。在该情况下,攻击者主要有三种手段:
1.注入匿名PL/SQL块
2.光标 snarf 攻击
3.利用DBMS_JVM_EXP_PERMS逻辑漏洞,获取JAVA执行权限,进而控制整个数据库或整个系统
第一种手段攻击者虽然不能创建存储过程或函数,只能被限制执行SELECT或DML操作但攻击者可以注入执行匿名块的存储过程或函数来达到提权的目的。匿名块是特殊的存储过程,存在内存中,只能被调用一次。攻击者可以透过这种手法绕过普通存储过程的限制,可执行 SELECT、DML、DDL等。攻击者需要的就是找到存在可以接纳异常输入的且不校验用户输入的系统函数。
可能存在漏洞的函数基本具备以下4点特征:安全人员可以对具备以下特点的函数做一些调整(例如关闭public权限,防止低权限用户调用)
1)问题函数中存在通过字符串连接符(||)连接函数,从而使注入可能正确实现。
2)问题函数中不能包含 OUT 参数,因为注入过程无法提供 OUT 类型参数。
3)问题函数中必须要返回一个简单数据类型,复杂的数据类型可能会导致错误,因为复杂的数据类型在字符串拼接过程中不能被自动转换成一个简单的数据类型。
4)问题函数中必须要提供一种机制,使得攻击者可以执行一定长度的 PL/SQL 语句。
第二种手段是David Litchfield提出的通过snarf入侵Oracle.主要出现在如果高权限用户未正常或主动关闭显式游标,会导致安全隐患。高权限用户创建的游标滞留在数据库内存中,低权限用户可以利用滞留的游标对Oracle发动攻击。最常见的方式是攻击者用loop循环猜测出悬挂游标。定位到悬挂游标后,回收它并重新绑上高权限用户,然后执行查询,可以越权获得高权限用户才可访问的敏感信息。
第三种手段是利用Oracle支持的JAVA。问题根源在于Oracle默认把DBMS_JVM_EXP_PERMS、DBMS_JAVA以及DBMS_JAVA_TEST等危险package的执行权限直接授予了PUBLIC,导致任意用户都可以执行JAVA程序,进而控制整个数据库乃至整个操作系统。这种类似问题不单出现在Oracle的JAVA服务中,在ORACLE 的其他服务中也存在类似漏洞。 如果业务不需要使用JAVA服务建议直接删除即可。关闭无用服务是一种杜绝漏洞的好办法。
无论是网站还是信息系统应用层都需要防SQL注入,与此同时数据库更需要防SQL注入,数据的安全和数据库的安全息息相关。面对数据库SQL注入的威胁,安华金和数据库攻防实验室专家给出以下三点防护建议:
首先数据库DBA限制住账号权限是最关键的防范措施。攻击者获取不同级别的账号进行后续的注入遇到的难度也不相同。账号权限越低攻击者越难利用其获取数据库中的敏感信息;
其次删除不用的Oracle默认服务有助于减少能被攻击者利用漏洞数量。
最后定期对数据库进行升级也是非常必要的。定期升级有助于修复漏洞,减少漏洞数量。由于受稳定性限制等原因约束无法及时升级的数据库也应该在数据库和应用之间架设具有VPATCH(虚拟补丁)功能的数据库防火墙。同时对敏感数据加密也是一种强化数据安全的有效手段。