Authentication Timing Attack
Background
Non-constant string comparison time can be a vulnerablity of Basic web authentication. If a web developer did not set up constant response time, attackers may get the password by comparing response time of requests. In this article, we will use Web for Pentester II authentication exercise 2 as an example.
Basics
The process of authenticating is as the following:
- The browser sends a HTTP authentication request.
- The server compares the strings, and sends response.
There are other types of auth requests than Basic, such as Digest and custom authentication. The username and password are concealed in the HTTP header. This is the header of Basic Authentication, which is the type of authentication in this example.
dXNlcm5hbWU6cGFzc3dvcmQ=
is the base64 code of username:password
. The response will give you the status, which is whether you are authenticated or not, and some other content. Status code 200 is success, and 401 is fail.
How to
Suppose the actual password is abcde
. Comparing abcde
with ab123
and abc123
, the second one takes more time than the first one. With ab123
, it compares 3 characters, and stops at the third letter. With abc123
, it compares 4 letters, and stops at the fourth character. Based on this time difference, you could get the correct characters by comparing the response time of auth requests.
Details
Write a script to send authentication requests, and jot down the response time automatically. For example, this is a part of my ouput.
The output 0 p40 1.809672
means Index password response_time
. In the first loop, I send requests with one character as password. āpā took longer to respond, which indicated that p is likely to be contained in the password. With the correct bit confirmed, we can then test the next byte. It stops when it finds the correct password (getting response 200).
Script
In this example, Python 2.7 was used to send requests and count time. Requests: HTTP for Humans
is an easy-to-use library for HTTP requests. time.time() is used to measure the response time. Note that time.clock() and time.time() is different. clock() counts the processing time with respect to the CPU clock, while time() counts the wall clock time, considering other factors such as network latency.
Prevention
To prevent this vulnerability, either have a constant response time or use a more secure authentication technique.