Friday, August 05, 2011

Anatomy of OpenSSL and Penetration Testing - Breaking Benjamin

SSL is one of the most attractive and shocking protocol in myriad of ways. There is always something different about this protocol. Considering the real time security testing, you might encounter tricky scenarios while handling sessions with the SSL. OpenSSL is widely used to deploy the SSL as a open source platform. Apache configured with mod_ssl is used heavily for this purposes. During open research and technical verification, we (me and my friends) came across a domain ( having bad SSL implementation. So I thought to write a detailed post on this issue. The aim of this post is to understand the unexpected variance in the responses of the remote server when SSL connection is initiated using different OpenSSL versions

Target check : [ For educational purposes only].

A simple host discovery gives the following information which suggests that DNS load balancer is in place. Since it is a heavy eCommerce website, one must expect this.

root@bt:~# host has address has address mail is handled by 10 mail is handled by 10 mail is handled by 10

root@bt:~# host is an alias for is an alias for has address has address

This website is accessible over HTTP and HTTPS, this gives a straight forward information regarding the open ports 80/443. One can expect redirection parameters defined on server side to automatically redirect the incoming HTTP requests to HTTPS.
Further, when a simple GET request is issued to the server, it responds back with the following HTTP responses

(Status-Line) HTTP/1.0 200 OK
Server Apache-Coyote/1.1
Content-Encoding gzip
Content-Type text/html;charset=UTF-8
Content-Length 9986
Vary Accept-Encoding
Expires Fri, 05 Aug 2011 18:08:39 GMT
Cache-Control max-age=0, no-cache, no-store
Pragma no-cache
Date Fri, 05 Aug 2011 18:08:39 GMT
Connection keep-alive
Set-Cookie ebay=%5Esbf%3D%23%5E;; Path=/
Set-Cookie dp1=bu1p/QEBfX0BAX19AQA**501d6527^spref/20351fe98a7^;; Expires=Sun, 04-Aug-2013 18:08:39 GMT; Path=/
Set-Cookie cssg=9b21f5741310a02652e39d83ffdf018c;; Path=/
Set-Cookie s=CgAD4ACBOPYMnOWIyMWY1NzQxMzEwYTAyNjUyZTM5ZDgzZmZkZjAxOGPrM83K;;Path=/; HttpOnly
Set-Cookie nonsession=CgADKACBXojMnOWIyMWY1NzQxMzEwYTAyNjUyZTM5ZDgzZmZkZjAxOGYAywABTjw4rzGpIP/j;; Expires=Sat, 04-Aug-2012 18:08:39 GMT; Path=/

The Server header points to the Apache-Coyote/1.1 which may be running this flavor of Apache. Usually, it is true in number of cases.

The first three tests are conducted using OpenSSL, cURL and SSLScan in general. This host is a backtrack machine with an OpenSSL 0.9.8k 25. In this , the aim is to verify the presence of SSLv2

root@bt:~# openssl version / OpenSSL 0.9.8k 25 Mar 2009

root@bt:~# curl --version
curl 7.19.7 (i486-pc-linux-gnu) libcurl/7.19.7 OpenSSL/0.9.8k zlib/ libidn/1.15
Protocols: tftp ftp telnet dict ldap ldaps http file https ftps
Features: GSS-Negotiate IDN IPv6 Largefile NTLM SSL libz

Test 1: Using OpenSSL, following response is detected which shows the acceptance of SSLv2.
root@bt:~# openssl s_client -connect -ssl2
subject=/C=US/O=Akamai Technologies, Inc./
issuer=/C=US/O=GTE Corporation/OU=GTE CyberTrust Solutions, Inc./CN=GTE CyberTrust Global Root
No client certificate CA names sent
Ciphers common between both SSL endpoints:
SSL handshake has read 995 bytes and written 236 bytes
New, SSLv2, Cipher is DES-CBC3-MD5
Server public key is 1024 bit
Secure Renegotiation IS NOT supported

Compression: NONE
Expansion: NONE
Protocol : SSLv2
Cipher : DES-CBC3-MD5

Session-ID: E03D2C3CCD43347B13383DA55F2FD326
Master-Key: 16011C613D2E862A91FD0A069AF1FFAE5058F0BFEADB87F0
Key-Arg : A9D372330CD89517
Start Time: 1312569173
Timeout : 300 (sec)
Verify return code: 21 (unable to verify the first certificate)

Test 2: Using cURL to verify the state.
root@bt:~# curl -v -2 -k
* About to connect() to port 443 (#0)
* Trying connected
* Connected to ( port 443 (#0)
* successfully set certificate verify locations:
* CAfile: none
CApath: /etc/ssl/certs
* SSLv2, Client hello (1):
* SSLv2, Server hello (4):
* SSLv2, Client key (2):
* SSLv2, Client finished (3):
* SSLv2, Server verify (5):
* SSLv2, Server finished (6):
* SSL connection using DES-CBC3-MD5

* Server certificate:
* subject: C=US; O=Akamai Technologies, Inc.;
* start date: 2010-10-06 16:41:56 GMT
* expire date: 2011-10-06 16:40:47 GMT

Test 3: Using SSLScan to verify the state.
root@bt:~# sslscan
Version 1.8.2
Testing SSL server on port 443

Supported Server Cipher(s):
Accepted SSLv2 168 bits DES-CBC3-MD5
Accepted SSLv2 56 bits DES-CBC-MD5
Accepted SSLv2 40 bits EXP-RC2-CBC-MD5
Accepted SSLv2 128 bits RC2-CBC-MD5
Accepted SSLv2 40 bits EXP-RC4-MD5
Accepted SSLv2 128 bits RC4-MD5

It has been verified that this particular domain is accepting SSLv2 and all the testing output has confirmed this. Note , in this OpenSSL version 0.9.8k is used.

Now moving on to second set of tests with same tools having updated version of OpenSSL as follows

user@ubuntu:~$ openssl version / OpenSSL 0.9.8o 01 Jun 2010

curl 7.21.3 (i686-pc-linux-gnu) libcurl/7.21.3 OpenSSL/0.9.8o zlib/ libidn/1.18
Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtsp smtp smtps telnet tftp
Features: GSS-Negotiate IDN IPv6 Largefile NTLM SSL libz

The versions are different. In order to conduct security testing of SSL, the same tests are conducted again.

Test 4: Verifying the SSLv2 (updated OpenSSL)
user@ubuntu:~$ openssl s_client -connect -ssl2
2543:error:140A90C4:SSL routines:SSL_CTX_new:null ssl method passed:ssl_lib.c:1453:

The connection over SSLv2 fails. Let's move on to next case

Test 5: Verifying the SSLv2 (updated cURL)
user@ubuntu:~$ curl -s -v -k -2
* About to connect() to port 443 (#0)
* Trying connected
* Connected to ( port 443 (#0)
* SSL: couldn't create a context!
* Closing connection #0

cURL also fails for the SSLv2. Jumping on to next and final test

Test 6: Verifying the SSLv2 (SSLScan)
user@ubuntu:~$ sslscan
Version 1.8.2

ERROR: Could not create CTX object.

Testing SSL server on port 443

Supported Server Cipher(s):
Rejected SSLv3 256 bits ADH-AES256-SHA
Rejected SSLv3 256 bits DHE-RSA-AES256-SHA
Rejected SSLv3 256 bits DHE-DSS-AES256-SHA
Accepted SSLv3 256 bits AES256-SHA
Rejected SSLv3 128 bits ADH-AES128-SHA
Rejected SSLv3 128 bits DHE-RSA-AES128-SHA
Rejected SSLv3 128 bits DHE-DSS-AES128-SHA

In this test, no SSLv2 output (rejected/accepted) is there. However, one can see that "ERROR: Could not create CTX object" notification which primarily is an outcome of the fact that SSLScan fails to instantiate context for SSLv2.

As it is known in the wild that all the newer version of browser hardly initiate connection using SSLv2. It looks like OpenSSL 0.9.8o 01 is doing the same way. Hardening the client straight away so that only updated version of protocol are used to do that.

Note: for penetration testing, my personal advise is to use OpenSSL 0.9.8k 01 or any version less than <= k for strong testing. It is also a good choice to use <=k versions and also > k versions to differentiate the output.

Giving a final check on the certificates (, it has been noticed that certificate is already expired

and the amazing result is also presented below

So overall, this situation is really bad for an eCommerce website. For verification tests of SSL one should not rely on single tool. It is preferable to use OpenSSL, cURL and SSLScan as an overall tool set and the protocol should be fuzzed appropriately. Be sure of the OpenSSL version you are using.

NOTE: Additionally, declarative security can also be used to prevent MITM attacks. I will be releasing Mozilla Firefox addon soon (under review). This addon is capable of detecting Strict-Transport-Security parameter in HTTP response header and notify the penetration tester about the usage of declarative security (whether the server wants to harness the browser protection)

Stay tuned. Enjoy !