Ruby + OpenSSL && sprintf() == 2009-style Man-in-the-Middle?

Four years ago, a security researcher known as Moxie Marlinspike presented a paper at the Black Hat conference in Las Vegas in which he outlined a number of attacks against SSL.

As you no doubt know, SSL (secure sockets layer) and its modern incarnation TLS (transport layer security) constitute the S in HTTPS, and form the basis of online web security.

HTTPS, or HTTP-over-SSL, has two main advantages over vanilla HTTP:

  • Confidentiality. The connection is strongly encrypted, and should be incomprehensible to anyone other that the legitimate recipient.
  • Integrity. The client can verify that a server very likely does belong to the organisation it claims.

Any bug or flaw that might interfere with these aspects of SSL is of great interest, because it could punch holes in your online safety and security.

Back in 2009, one of Marlinspike’s anti-SSL tricks was to supply a digital signature that looked as though it was issued by company X, but in fact, came from company Y.

He did this by sneaking a [NUL] character (a byte with the numeric value of zero) into the name on the digital signature, something like this:

Now, SSL certificates are usually signed by a certifying authority (CA) that vouches for the company that owns the domain named in the certificate, i.e. domain.test in the example above.

The CA is supposed to contact someone official at domain.test and verify that the company really wants to issue a certificate for the server[NUL].domain.test.

And the owner of domain.test can deviously, if with apparent honesty, say, “Yes!”

Note that the CA will decompose the servername from right-to-left, in order to ensure that it uses the most significant parts of the name to work out whom to deal with when researching the veracity of the certificate.

In our example, this ensures that the CA correctly contacts domain.test, not

Later, at run-time, web clients are supposed to check that the name of the server to which they are connecting matches the name on the signed SSL certificate.

Because they need to check the entire server name, it doesn’t really matter whether they check from right-to-left or left-to-right.

But Marlinspike noticed that the checking code in some of these web clients used an old-fashioned C function such as strcmp() to do a left-to-right match.

And strcmp() treats the special character [NUL] as denoting the end of a string.

So, with strcmp()-type comparison, the following two strings match perfectly:

That’s because strcmp() doesn’t bother checking past the [NUL] in the first string.

This means you now have a way to let domain.test mint certificates that look as though they belong to

This, in turn, means that the folks at domain.test can divert‘s secure network traffic without generating a browser warning, and can thus pull off a Man-in-the-Middle attack.

This throws confidentiality and integrity right out of the window.

The fix is easy: don’t stop processing server or domain names at the first [NUL] character: process the entire string, every time.

Sadly, however, it looks as though the programming language Ruby neglected to implement such a fix until last week.

So, if you have web-facing code written in Ruby, and you support SSL (which you do, right?), be sure to patch as soon as you can, to avoid falling victim to this flaw!