“Hack In The Box”会议是在欧洲阿姆斯特丹举办的全球知名安全峰会。今年的会议十分有趣,其中一个由安全研究员Mikhail Egorov和Sergey Soldatov提出的议题“Java应用ORM注入开发新方法”引发了热议。
ORM是指对象映射关系,这是一种程序开发技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换。从效果上说,它其实是创建了一个可在编程语言里使用的“虚拟对象数据库”。现今这项技术在商业应用广泛。
几个著名的Java ORM数据库:
–Hibernate ORM(经常应用在Wildfly和JBoss)
–eclipselink(例如GlassFish)
–TopLink(例如Oracle WebLogic)
–OpenJPA(例如TomEE和IBM WAS)
Mikhail 和Sergey专注于Java数据库ORM注入的研究。ORM注入也叫做JPQL或者HQL 注入,它们和SQL注入十分相似。不是直接定义SQL查询,ORM库使用自己专有语言JPQL/HQL(Java Persistence Query Language/Hibernate Query Language)。这些查询被ORM库译成SQL。
他们认为这些语言是奇怪的并且受限制的。如果你找到方法注入ORM查询,你会发现你的权限是受限的,只能访问被映射到实体的数据库表(Java对象),并且不能使用sqlmap。
Mikhail和Sergey展示了如何利用这个ORM库绕过ORM语言,以及发送abritary SQL查询,还有如何使用sqlmap进行深入渗透。
Eclipselink ORM和TopLink ORM有神奇的功能,允许执行任意的SQL功能:Eclipselink有function()(原func())调用数据库的具体功能。你不仅可以执行数据库的功能,还可以使用这个“诀窍”进行正常的SQL查询:
JPQL语句:
... FUNCTION('(select count(1) from table where 1=1)>0 and length','qq')=2 ...
译成SQL语句:
... (select count(1) from table where 1=1)>0 and length('qq')=2 ...
如果是TopLink,你就不需要使用这个“诀窍”,因为它可以执行正常的SQL查询和sql()命令。
在Apache OpenJPA ORM他们发现了执行abritary SQL函数的两种方法:第一个是错误的 进程:在检查语法后,通过一个’(单引号)替换一个序列”(双引号)。 这使得在字符串中隐藏选择语句成为可能:
ORM 参见: and ’1′=’1” and (select 1 where 1=1) = ”1′ and
DBMS 获取: and ’1′=’1′ and (select 1 where 1=1) = ’1′ and
第二个方法是引号不敏感:
ORM 参见: and “a’ = ‘a’ and (select 8 where 1=1)=8 and ‘b” = ‘b’
DBMS 获取: and ‘a’ = ‘a’ and (select 8 where 1=1)=8 and ‘b’ = ‘b’
在Hibernate库里,他们已经发现了几个方法:第一种是单引号转义的方法,这种方法在MySQL里起作用,因为可以在字符串里用一个反斜杠(/’)跳过单引号:
在HQL里是一个字符串:
'abc/''or 1=(select 1)--'
在MySQL里是一个字符串和一个附加的SQL表达式:
'abc/''or 1=(select 1)--'
在PostgreSQL和H2里有可能使用两个美元符号跳过字符串($$)。他们已经将这种方法应用到$引用字符串方法中:
在HQL里相比于一个字符串则解释为变量$$:
$$='$$=concat(chr(61),chr(39)) and 1=1--'
但是在SQL里一个$美元引用字符串和contact()函数相比:
$$='$$=concat(chr(61),chr(39)) and 1=1--'
对于PostgreSQL和Oracle,他们也展示了神奇的函数方法。PostgreSQL的有一个建立在功能query_to_xml(’arbitrary SQL”)和Oracle dbms_xmlgen getXML(’sql”)。使用此功能可以执行任意的SQL语句。
第四种方法使用的是UNICODE符号: Microsoft SQL 服务器和H2转换unicode分隔符,比如将无中断空格(U+00A0, %C2%A0)作为空白,因此SELECT LEN([U+00A0](select[U+00A0](1))的功能就和SELECT LEN((SELECT(1)))相同了。HQL允许符号标识符中运用unicode(函数或参数名称)。你可以利用这一点,因为Hibernate将 [U+00A0](…) 转化成一个有效的函数名,并且将其看作是一个函数调用。
最后一个方法是 JAVA CONSTANTS ,除了MySQL之外,大多数的DBMS都可以使用这种方法。 Hibernate 重新解决了Java在HQL查询中的公共静态字段。特殊字符或是字符串字段必须在类路径的类/接口中声明。他们已经给出了几个致命的Java库,你可以在其中找到所需字符。
这个HQL语句就利用了这种方法:
...dummy' and hqli.persistent.Constants.C_QUOTE_1*X('<>CHAR(41)(select count(1) from sysibm.sysdummy1)>0 --')=1 and '1'='1...
然后在下面的SQL查询中得到解决:
...dummy' and '''*X('<>CHAR(41) and (select count(1) from sysibm.sysdummy1)>0 --')=1 and '1'=...
在最后,他们给出一个很好的列表,这十分有助于确定应用程序中所使用的ORM库:
– Hibernate: .. and 1bi = 1bd and ... – EclipseLink: ... and FUNCTION('1=1 and','2')='2' and ... – TopLink: ... and SQL('1=1') and ... – OpenJPA: ... and "1"='1' and ...
如果你想知道更多有关漏洞的具体情况和sqlmap用法的详细说明,可以看一下这份幻灯片:
D2T2 – Mikhail Egorov and Sergey Soldatov – New Methods for Exploiting ORM Injections in Java Applications.pdf (conference.hitb.org)
*参考来源:insinuator.net,FB小编极客小默编译,转载请注明来自FreeBuf黑客与极客(FreeBuf.COM)