Blind HQL Injection in REST API using H2 DMBS

This post deals with some research I just did regarding (Blind) HQL injections with H2 as the DataBase Management System.

First, you should read this post which gives some really useful information regarding HQL injections in general: HQL for pentesters.

During the assessment, I checked the API calls by using Burp as a proxy and one call was:

http://application/API/Users/?req=id=1

The output was a JSON response, such as:

[{user: "admin", id: "1", firstName:"Admin"}]

If you changed the id with the numeric value 2, and so on.. it was working.

On the back-end system, the request should have been something like :

select * from users where id = '<id>'

By inserting a single-quote character, I raised an exception and I got the SQL statement. Nice, because it was the same one as below.

Some special characters/words were banned such as ‘=’, etc. But there was still the operator ‘LIKE’ remaining. Then, I started to insert conditions to see how the system was reacting such as:

http://application/API/Users/?req=id=1' AND '1' LIKE '1

The output was the same:

[{user: "admin", id: "1", firstName:"Admin"}]

However, when the condition was false, such as:

http://application/API/Users/?req=id=1' AND '1' LIKE '2

The JSON response was empty.

[]

So, if the condition is false the output is empty.

(Blind) HQL injections are similar to (Blind) SQL injections but due to HQL syntax, this is really limited. Moreover, exploitation techniques depends on the dbms system behind. For this example, H2 Database website is the reference where you can find out what you’re allowed to do.

Basically, what you’ll be able to do is:

  • Enumerate tables, columns by bruteforcing it
  • And use built-in functions

I listed here some (useful) built-in functions that you can use:

  • user(): returns the user which is used
  • database_path(): returns the path of the database on the filesystem
  • FILE_READ(FILE, NULL): read FILE on the filesystem. (hint: /etc/passwd)

Quick example, I managed to retrieve the current user() this way:

First, let’s get the length of the user:

http://application/API/Users/?req=id=1' AND length(user()) LIKE '2

Then, we can use substring() to iterate on each characters using LIKE operator.

http://application/API/Users/?req=id=1' AND substring(user(), 1,1) LIKE 'S

As you know, process to extract those information is quite long. I will update my HQLmap Project to automate the process in the next few days. (So far, it supports HQL Injections)

I hope it might have helped you during your assessment and feel free to contact me if you have other techniques for h2 database, I’ll update this blog post.

Cheers,