Tuesday, February 03, 2009

AUTH CRAM-MD5

I spent some time last weekend trying to understand the various SMTP authentication mechanisms. I found CRAM-MD5 authentication mechanism particularly interesting as it is a challenge-response authentication and involves HMAC-MD5. Let me first show a complete session with an ESMTP server before coming to CRAM-MD5. In the following session, I have selected the PLAIN authentication mechanism. Whatever I have entered appears in italic font.
susam@nifty:~$ telnet mail.susam.in 25
Trying 64.62.254.117...
Connected to sdclinux2.rdsindia.com.
Escape character is '^]'.
220 sdclinux2.rdsindia.com ESMTP
EHLO
250-sdclinux2.rdsindia.com
250-PIPELINING
250-8BITMIME
250-SIZE 11534336
250 AUTH LOGIN PLAIN CRAM-MD5
AUTH PLAIN AGZvb0BzdXNhbS5pbgBkcm93c3NhcA==
235 ok, go ahead (#2.0.0)
MAIL FROM:<foo@susam.in>
250 ok
RCPT TO:<example.recipient@gmail.com>
250 ok
DATA
354 go ahead
Date: Mon, 2 Feb 2009 10:28:00 +0530
From: Foo <foo@susam.in>
To: Example Recepient <example.recipient@gmail.com>
Subject: Test Mail

This is a test mail.
.

250 ok 1233593978 qp 15929
QUIT
221 sdclinux2.rdsindia.com
Connection closed by foreign host.
susam@nifty:~$
In the AUTH PLAIN line I have sent the base64 encoding of the string \x00foo@susam.in\x00drowssap. \x00 indicates a null character, foo@susam.in is the sender's user name and drowssap is the sender's password. Note that the user name here is in email address format. For most servers, the user name would only be 'foo' instead. If an eavesdropper intercepts this network traffic, he can easily find the user's password by simply decoding the base64 response sent by the client. This is also susceptible to replay attacks as the eavesdropper can use the AUTH PLAIN line containing the base64 encoded credentials, in future, to log into the server.

Now, let me quickly show only the relevant lines for an authentication using the LOGIN mechanism.
250 AUTH LOGIN PLAIN CRAM-MD5
AUTH LOGIN
334 VXNlcm5hbWU6
Zm9vQHN1c2FtLmlu
334 UGFzc3dvcmQ6
ZHJvd3NzYXA=
235 ok, go ahead (#2.0.0)
What is happening here becomes clear by decoding the base64 encoded messages. The following statements in Python 2.5.2 decode these messages.
>>> 'VXNlcm5hbWU6'.decode('base64')
'Username:'
>>> 'Zm9vQHN1c2FtLmlu'.decode('base64')
'foo@susam.in'
>>> 'UGFzc3dvcmQ6'.decode('base64')
'Password:'
>>> 'ZHJvd3NzYXA='.decode('base64')
'drowssap'
LOGIN authentication mechanism is susceptible to the same problems that PLAIN authentication mechanism is susceptible to. Now, let me describe the CRAM-MD5 authentication mechanism. When the client selects the CRAM-MD5 authentication mechanism, the server sends a base64 encoded challenge as shown below.
250 AUTH LOGIN PLAIN CRAM-MD5
AUTH CRAM-MD5
334 PDc0NTYuMTIzMzU5ODUzM0BzZGNsaW51eDIucmRzaW5kaWEuY29tPg==
An HMAC is calculated for this challenge with the password as the key and MD5 function. A string is formed by concatenating the user name, a space and the hex representation of the HMAC. The base64 encoding of this string is sent as the response by the client. The following statements I tried in Python 2.5.2 show how a response can be formed for the above challenge.
>>> 'PDc0NTYuMTIzMzU5ODUzM0BzZGNsaW51eDIucmRzaW5kaWEuY29tPg=='.decode('base64')
'<7456.1233598533@sdclinux2.rdsindia.com>'
>>> import hmac, hashlib
>>> hmac.new('drowssap', '<7456.1233598533@sdclinux2.rdsindia.com>', hashlib.md5).hexdigest()
'667e9fa4470dff3da9d621fe40676722'
>>> 'foo@susam.in 667e9fa4470dff3da9d621fe40676722'.encode('base64')
'Zm9vQHN1c2FtLmluIDY2N2U5ZmE0NDcwZGZmM2RhOWQ2MjFmZTQwNjc2NzIy\n'
Of course, this can be written as a small function:
import hmac, hashlib
def cram_md5_response(username, password, base64challenge):
return (username + ' ' +
hmac.new(password,
base64challenge.decode('base64'),
hashlib.md5).hexdigest()).encode('base64')
The following snippet shows the ESMTP server accepting the client-response.
250 AUTH LOGIN PLAIN CRAM-MD5
AUTH CRAM-MD5
334 PDc0NTYuMTIzMzU5ODUzM0BzZGNsaW51eDIucmRzaW5kaWEuY29tPg==
Zm9vQHN1c2FtLmluIDY2N2U5ZmE0NDcwZGZmM2RhOWQ2MjFmZTQwNjc2NzIy
235 ok, go ahead (#2.0.0)
CRAM-MD5 authentication mechanism is relatively more secure than the other two mechanisms because the password can not be retrieved by decoding the base64 encoded client-response. The password is used as the key to calculate the HMAC but the password is not present anywhere in the response. It prevents replay attacks too because the server sends an unpredictable challenge for every authentication. The client-response computed for a certain challenge is invalid for further authentications which will involve different unpredictable challenges.

References:
  1. RFC 4954 : SMTP Service Extension for Authentication
  2. RFC 4616 : The PLAIN Simple Authentication and Security Layer (SASL) Mechanism
  3. RFC 2195 : IMAP/POP AUTHorize Extension for Simple Challenge/Response
  4. RFC 2104 : HMAC: Keyed-Hashing for Message Authentication

2 comments:

Sheth Raxit said...

just randomly come to your blog. Are you based in Mumbai ? why i am asking is if yes, you may want to catchup owasp Mumbai.

Susam Pal said...

I am in Bangalore currently.

Post a Comment