Exploiting SQL injections in EyesOfNetwork
Tags: MySQL, Pentesting, Sql Injection, Exploit, Writeup

In a previous article, I described the discoveries I made after a pentest for a customer which had an EyesOfNetwork (EON) server; you can find it here.

Today, I will explain the different kinds of blind SQL injections and how we can use them to gain administrative privilege on EON.

I identified a few different SQL injections (SQLi) and one of them was on an authentication request, allowing an attacker to temper the output of the request to get authenticated as the admin user. It’s the one used in my previous article. This SQLi was an easy way to get authenticated as an admin, but it’s rather rare.

The two other SQL injections are not in an authentication request and thus cannot be used to bypass the authentication mechanism that easily (theses are CVE-2020–9465 and CVE-2020–27886).

W hat is a time blind SQL injection ?

The EyesOfNetwork server uses MySQL as a database server along with PHP and does not allow stacked queries. Stacked queries is a feature which allows performing multiple SQL queries at once with a semicolon character as separator. Such a feature would help an attacker to execute any SQL query of his choice with INSERT, UPDATE, DELETE, etc statements hence allowing to create a new administrator or change its password.

As a result we are constrained by the original request where the SQLi are found and in our case it was SELECT statements. This would allow us to read arbitrary data stored in the database.

Unfortunately for us, the SQLi’s didn’t return any data from the original SQL requests in the webpages; It would have helped in the extraction of information by reading it directly in the output.

In such case we are facing a so-called blind SQL injection (as we can’t see any output of our requests). To get around this issue we can perform SQL requests that would return either a True our False result. In some cases we can notice a difference between the answers given by the application (an error message, blank page) if the request returns True or False. The exploitation of these SQLi’s can be called error-based blind SQL injection.

However, EyesOfNetwork would produce the same webpage if our crafted request evaluate either true or false. As a workaround, we could call a sleep function; if our request evaluates to be true (or false) and then check the amount of time the server is taking to respond. It would be called a time based blind SQL injection.

H ow to exploit it ?

The first SQLi I found was on the user_id cookie which is sent by the browser; it's there since the version 5.1 of EON (02/2017 😬). A simple proof of concept code like the following would simply wait for 5 seconds : Cookie: user_id=1' union select sleep(5) -- ;

With this payload, we can confirm we have indeed an SQL injection if the server takes about 5 seconds to process our request.

Because we are in a SELECT statement, and we cannot perform stacked queries, we cannot UPDATE or INSERT INTO rows in the database.

By reviewing the content of the different tables made by EyesOfNetwork, I noticed an interesting one : session_id . It contains the user’s session ID’s used to authenticate the users while using the web interface.

Getting the admin session ID would allow us to directly be connected without knowing his password!

Guessing the session ID

On the screenshot below, we can see how the session ID is generated for each user in the login.php page:

session ID generation using PHP rand()

The PHP rand() function is used to generate a random number; its maximum generated number is 2147483647 (2³¹) :

Value returned by PHP getrandmax()

A common approach would be to guess each digit one by one and having to perform 10 queries at most to guess a digit. The logic would be the following:

IF the first digit of the session_id is 1 THEN sleep for 5 seconds

As a result we would have to perform 10x10=100 queries at most to guess the session ID.

But we can reduce the number of requests we have to do by converting the number in binary. As the maximum length of the number is 31 bits, we can guess each bit with a single request (0 or 1) and therefore guess the number in 31 requests 😃

Here is how it looks with SQL queries:

The actual session ID of the admin user

The session id converted in binary with MySQL CONV() function

But there is a catch; as the maximum number can be 31 bits long, it might be shorter and the PHP rand function could output small numbers such as the number 10. Here is the result in an SQL query:

The number 10 converted in binary

So we have to first guess the length of the converted number in binary in order to guess properly the session ID.

The final plan is:

Guess the length of the number in its binary representation

Guess each bit one by one

Guessing the length of the number

We know that the maximum length of the number is 31 bits; here is the SQL query which sleeps for five seconds if the number is actually 31 bits:

SELECT IF(length(conv((select session_id from sessions where user_id = 1 limit 1),10,2)) = 31, sleep(5),0);

We can try each value from 31 back to 1 and watch for the first request which is taking more time to respond to know the actual size of the session_id value.

Guessing the number

Once we know the session ID length; we just have to guess each bit one by one and convert it back from binary to base 10.

On the screenshot below, we are guessing the third bit. If it’s a one, the query will sleep for five seconds:

Guessing the third bit of the session ID

Here is the SQL request:

select if(mid(conv((select session_id from sessions where user_id = 1 limit 1),10,2),3,1), sleep(1),0;

We can do it for each bit we have to guess, hence guessing the whole session_id value.

The final result

Once we found the session_id number for the admin user, we can use it in our Cookie header to get successfully authenticated as the admin user 🎉🥳

On the animated GIF below you can see the exploit script for CVE-2020–9465 doing the following steps:

Guessing the session_id length ( ~ 1 sec)

Guessing the session_id value (~ 4 secs)

Authenticate as the admin user

Getting a reverse shell (as root 😍)

You can find more details about the CVE-2020–27886 in the GitHub issue below (in French):

As the EyesOfNetwork team has not patched it yet, I will not publish the exploit (and you have enough details to exploit it by yourself 😉).