Sunday, April 22, 2007

Preventing username enumeration

Most people know how to do username enumeration, but not everyone knows how to prevent it. Indeed it is often asserted, incorrectly, that eliminating username enumeration altogether cannot be achieved.

The first step in preventing username enumeration in an application is to identify all of the relevant attack surface. This includes not only the main login but also all of the more peripheral authentication functionality such as account registration, password change and account recovery. It is very common to encounter applications in which username enumeration is not possible in the main login function, but can be trivially performed elsewhere.

The second step is to ensure, in every piece of relevant functionality, that the application does not provide a means for an attacker to confirm the validity or otherwise of an arbitrarily chosen username. This is not just a matter of fixing obvious failure messages such as "username incorrect" vs. "password incorrect", but also of checking every aspect of the application's behaviour. For example, if the same literal on-screen failure message is generated by different code paths, then subtle differences may arise within the HTML source. Alternatively, the application may manifest timing differences when processing valid and invalid usernames, because different database queries and computational operations are performed when a valid username is supplied.

Of the various points of attack surface, account registration functionality can seem to be the most difficult area in which to eliminate username enumeration, If an existing username is chosen, surely the application must reject the registration attempt in some manner, enabling an attacker to infer which usernames have been registered? Using CAPTCHA controls and other hurdles may slow down the process, but they do not prevent it.

In fact, there are two ways in which an account registration function can be implemented which avoid introducing enumeration vulnerabilities:
  • The application can specify its own usernames. When an account applicant has supplied their required details and initial password, the application generates a unique username for them. Of course, to avoid a different type of vulnerability, the usernames generated should not be predictable.

  • The application can use email addresses as usernames. The first step of the registration process requires the applicant to supply their email address, to which a message is then sent. If the username is not yet registered, the message contains a one-time URL which can be used to complete the registration process. If the username is already registered, the message informs the user of this, and perhaps directs them towards the account recovery function. In either case, an attacker can only verify a username's status if they control the relevant email account.

Wednesday, April 11, 2007

Out-of-band input channels

When we think about attacking web applications, it is natural to focus on the core means by which we can interact with a target application - that is, using HTTP requests generated by a web browser or other client software. In many applications, however, there are other channels through which we can introduce our input into the application’s processing. These out-of-band channels represent a significant, and often buggy, area of attack surface.

Here are some examples in applications which I have encountered:

  • Web mail applications, in which data received via SMTP is processed by the application and ultimately rendered in-browser to other users.

  • A web interface to a network monitoring solution, in which data sniffed off the wire in a large number of different protocols is collated by the application and displayed in various forms.

  • Portal applications which use RSS mash-ups to render data retrieved from third parties.

  • A web authoring application which allows users to import external web pages by specifying a URL; the application retrieves these via HTTP and processes the contents.

Another example, which I have not encountered and which probably falls into the category of bar-room apocrypha, concerned an application used to process the photographed images of speeding motorists. Reputedly, the application used OCR to read the car’s registration number, and placed this into a SQL query to update its records. Of course, it was vulnerable to SQL injection, but this could only be exploited by printing your attack string onto a registration plate and then driving quickly past a camera. Furthermore, the bug was completely blind, with minimal opportunities for retrieving the results of an arbitrary query. It was mooted that time delays might provide a solution - for example, by triggering very long conditional delays and monitoring the time taken to receive a ticket. However, with only 12 available points on your license, retrieving one bit of data at a time is unlikely to succeed. In this situation, therefore, perhaps the most effective PoC attack string would be:

'; drop table offenders--

Thursday, April 5, 2007

Using recursive grep for harvesting data

Talking to someone the other day I realised that even many experienced users of burp don’t know what the "recursive grep" payload source is used for.

This payload source is different from all the others, because it generates each attack payload dynamically based upon the application’s response to the previous request. In some situations, this can be extremely useful when extracting data from a vulnerable application.

A typical situation is where you have an SQL injection bug that enables you to retrieve a single item of data at a time. To extract the entire contents of a table, you can use recursion to extract each value in turn on the basis of the previous value. For example, suppose you are attacking an MS-SQL database and have enumerated the structure of the table containing user credentials. Supplying the following input returns an informative error message containing the username which appears alphabetically first in this table:

' or 1 in (select min(username) from users where username > 'a')--

Microsoft OLE DB Provider for ODBC Drivers error '80040e07'
[Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the nvarchar value 'abigail' to a column of data type int.

This gives you the username 'abigail', which you can place into your next input to retrieve the username which appears alphabetically second:

' or 1 in (select min(username) from users where username > 'abigail')--

Microsoft OLE DB Provider for ODBC Drivers error '80040e07'
[Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the nvarchar value 'adam' to a column of data type int.

To extract all usernames, you can continue this process, inserting each discovered username into the next request until no more values are returned. However, performing this attack manually may be very laborious. You could write a script to do it in a few minutes. Or in a few seconds, you can configure the "recursive grep" function to perform the attack for you.

The first step is to capture the vulnerable request in burp proxy, and choose the "send to intruder" action. Then type your attack string into the vulnerable field, and position the payload markers around the part which you need to modify:

Next, in order to use "recursive grep" as a payload source, you need to configure "extract grep" to capture the username which is disclosed in each response. To do this, you tell intruder to capture the text following the error message

Syntax error converting the nvarchar value '

and to stop capturing when it reaches a single quotation mark:

Finally, you need to select the "recursive grep" payload source, select the single "extract grep" item you have configured, and specify the first payload as 'a':

That's it! Launching the attack will cause intruder to send 'a' in the first request, and in each subsequent request send the username which was extracted from the previous error message. Within seconds, you can dump out all of the usernames in the table:

You can select save/results table to export the username list. Equipped with this list, you can then use it as a conventional payload source to retrieve all of the passwords and other data, for example using requests of the form:

' or 1 in (select password from users where username = 'abigail')--

There are other cases where recursive grep can be useful, but this kind of attack was the one I mainly had in mind when I wrote it.