The HITBSecConf or “Hack In The Box” in Amsterdam is a well known security conference in Europe. We also attended this year too, and there were quite some interesting talks at the HITBSecConf16 conference. One of the talks was about “New Methods for Exploiting ORM Injections in Java Applications” by the security researchers Mikhail Egorov and Sergey Soldatov.
I. What is Object-Relational Mapping (ORM)?
ORM stands for Object-Relational Mapping, which is a technique that automatically converts data from a relational database management system (RDBMS) into objects. This is often used in business applications of today.
There are serveral well-known ORM libraries in Java:
– Hibernate ORM (often used in WildFly and JBoss)
– EclipseLink (e.g. Glassfish)
– TopLink (e.g. Oracle WebLogic)
– OpenJPA (e.g. TomEE and IBM WAS)
II. SQL vs. ORM injections
Mikhail and Sergey focused their researches about ORM injections on these Java libraries. ORM injections are also called JPQL or HQL injections and they are very similar to SQL injections. Instead of defining SQL queries directly, this ORM libraries are using its own language JPQL/HQL (Java Persistence Query Language/Hibernate Query Language). These queries are translated to SQL by ORM library:
They described these languages as weird and limited. If you find a way to inject into ORM queries, you have only a limited set of functions for exploiting it, can only access database tables that are mapped to entities (Java objects) and can’t use sqlmap.
III. Exploitation techniques
Mikhail and Sergey showed how to exploit this ORM libraries to bypass the ORM language and send abritaries SQL queries and use sqlmap for further exploitation.
EclipseLink and TopLink ORM
EclipseLink ORM and TopLink ORM have both a magic function which allows executing arbitrary SQL functions: EclipseLink has the FUNCTION() (formerly FUNC()) to call DB specific functions. You can not only execute DB functions, but also normal SQL queries with this ‘trick’:
JPQL statement:
... FUNCTION('(select count(1) from table where 1=1)>0 and length','qq')=2 ...
This is translated into this SQL statement:
... (select count(1) from table where 1=1)>0 and length('qq')=2 ...
In TopLink you don’t have to use a ‘trick’, because it’s indeed to execute normal SQL queries with the SQL() command.
OpenJPA
In Apache OpenJPA ORM they have found two methods to execute abritary SQL functions: The first is the WRONG SINGLE QUOTE PROC: It substitutes a sequence of ” (two single quotes) by one ‘ (single quote) after it checks the syntax. With this behavior it’s possible to hide SELECT-statements within a string:
ORM sees: and '1'='1'' and (select 1 where 1=1) = ''1' and
DBMS gets: and '1'='1' and (select 1 where 1=1) = '1' and
The second method is the QUOTES INDIFFERENCE:
ORM sees: and "a' = 'a' and (select 8 where 1=1)=8 and 'b" = 'b'
DBMS gets: and 'a' = 'a' and (select 8 where 1=1)=8 and 'b' = 'b'
Hibernate
In the Hibernate library they have found several methods: The first one is the SINGLE QUOTE ESCAPING method, which works in MySQL because it’s escapes single quotes in strings with a backslash (\’):
In HQL it is a string:
'abc\''or 1=(select 1)--'
In MySQL it is a string and a additional SQL expression:
'abc\''or 1=(select 1)--'
In PostgresSQL and H2 it’s possible to escape strings with two dollar quotes ($$). They’ve used this behavior to exploit it in the $-QUOTED STRINGS method:
In HQL it’s interpreted as the variable $$ is compared to a string:
$$='$$=concat(chr(61),chr(39)) and 1=1--'
but in SQL it’s a dollar quoted string compared to the concat() function:
$$='$$=concat(chr(61),chr(39)) and 1=1--'
For PostgresSQL and Oracle they’ve showed also the MAGIC FUNCTIONS method. PostgresSQL has a build in function query_to_xml('Arbitrary SQL')
and Oracle DBMS_XMLGEN.getxml('SQL')
. It’s possible to use this function to execute arbitrary SQL statements.
The fourth method is using UNICODE symbols: Microsoft SQL Server and H2 interpretes unicode delimiters, like the no-break space (U+00A0, %C2%A0
) as whitespace, so SELECT LEN([U+00A0](select[U+00A0](1))
works the same as SELECT LEN((SELECT(1)))
. HQL allows unicode symbols in identifiers (function or parameter names). You can exploit this, because Hibernate interpretes [U+00A0](...)
as a valid function name and think this is a function call.
The last one is the JAVA CONSTANTS method and works for most DBMS except MySQL. Hibernate resolves Java public static fields in HQL queries. The special characters or string fields must declared in classes/interfaces in the classpath. They’ve presented serveral well-known Java libraries, which can be used get those.
This HQL statement exploits this method:
...dummy' and hqli.persistent.Constants.C_QUOTE_1*X('<>CHAR(41)(select count(1) from sysibm.sysdummy1)>0 --')=1 and '1'='1...
And is resolved to the following SQL query:
...dummy' and '''*X('<>CHAR(41) and (select count(1) from
sysibm.sysdummy1)>0 --')=1 and '1'=...
IV. How to identify ORM?
At the end they’ve presented a nice list, which is very helpful for identifying the ORM library the application is using:
– 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 ...
More
For a detailed explanation of the vulnerabilities and further information on the sqlmap usage, take a look at the slides posted here: D2T2 – Mikhail Egorov and Sergey Soldatov – New Methods for Exploiting ORM Injections in Java Applications.pdf (conference.hitb.org)
Thanks for reading,
Sven