Quick access to articles on this page:
more on the next page...
Since it is now common custom to market a new vulnerability, here is the page: weakdh.org you will notice their lazyness in the non-use of a vulnerability logo.
The paper containing most information is here:
Imperfect Forward Secrecy: How Diffie-Hellman Fails in Practice, from a impressive amounts of experts (David Adrian, Karthikeyan Bhargavan, Zakir Durumeric,
Pierrick Gaudry, Matthew Green, J. Alex Halderman, Nadia Heninger, Drew Springall, Emmanuel Thomé, Luke Valenta, Benjamin VanderSloot, Eric Wustrow, Santiago Zanella-Béguelin, Paul Zimmermann)
Not an implementation bug, flaw lives in the TLS protocol
This is not an implementation bug. This is a direct flaw of the TLS protocol.
This is also a Man in The Middle attack. By being in the middle, the attacker can modify the ClientHello packet to force the server to use an Export Ciphersuite, i.e. Export Ephemeral Diffie-Hellman, that uses weak parameters. I already explained what is an "Export" ciphersuite when the FREAK attack happened.
The server then generates weak parameters for a public key and sends 4 messages:
- ServerHello that specifies the Ciphersuite chosen from the list the Client gave him (if the attacker did things correctly, the server must have chosen an Export ciphersuite)
- Certificate which is the server's certificate
- ServerKeyExchange which contains the weak parameters and his public key.
- ServerHelloDone which signals the end of his transmission.
The ServerKeyExchange message is here because an "ephemeral" ciphersuite is used. So the Server and the Client need extra messages to compute an "ephemeral" key together. Using an Export DHE (Ephemeral Diffie-Hellman) or a normal DHE do not change the structure of the ServerKeyExchange message. And that's one of the problem since the server only signs this part with his long term public key.

Here you can see the four messages in Wireshark, the signature is computed on the Client.Random, the Server.Random and the ECDH parameters contained in the ServerKeyExchange.
Thus, the attacker only has to modify the unsigned part of the ServerHello message to tell the Client his normal ciphersuite has been chosen (and not an Export ciphersuite).

Now all the attacker has to do is to crack the private key of either the Client or the Server. Which is easy nowadays because of the low 512bits security of the Export DHE ciphersuite.
It can then pass as the server and read any messages the client wants to send to the server

(taken from the paper)
Not an implementation bug, but implementations do help
the use of common DHE parameters is making things easier for attackers since they can do a pre-computation phase and use it to quickly crack a private key of a weak DHE parameters during the handshake.
This happens, for example when Apache hardcoded a prime for its Export DHE Ciphersuite that is now used in a bunch of servers

(taken from the paper)
Defense from the Server
Don't use common DH or DHE parameters! Generate your owns. But even more important, remove the Export Ciphersuites as soon as possible.
Defense from the Client
From a client perspective, the only defense is to reject small primes in DHE handshakes.
This is the only way of detecting this Man in The Middle attack.
You could also remove DHE in your ciphersuite list and try to use the elliptic curve equivalent ECDHE (Elliptic Curve Diffie-Hellman Ephemeral)
Another way: if you control both the server and the client, you could modify both ends so that the server signs the ciphersuite he chose, and the client verifies that as well.
1024 bits primes?
In the 1024-bit case, we estimate that such computations are plausible given nation-state resources, and a close reading of published NSA leaks shows that the agency’s attacks on VPNs are consistent with having achieved such a break. We conclude that moving to stronger key exchange methods should be a priority for the Internet community.
Seems like the NSA doesn't even need to downgrade you. So as a server, or as a client, you should refuse primes <= 1024bits
Where is TLS used?
TLS is not only used in https!
For example, what about EAP, i.e. wifi authentication? From a quick glance it looks like there are no export ciphersuite.
But weak DH and DHE parameters should be checked as well everywhere you make use of Discrete Logarithm crypto
The Hacking week just started, it's a CTF that happens over a week.
You'll find challenges about crypto, network, forensic, reverse and exploit.
And also, I have a challenge up there in the crypto challenge ^^

It's in french here: http://hackingweek.fr/challenges/ (click on "voir" next to crypto 4)
basically Alice encrypted the secret, you have to find what the secret is. What you have is a key that shares the same modulus as Alice.
The wierdness of ==
Do you know what happens when you run this code in PHP?
<?php
var_dump(md5('240610708') == md5('QNKCDZO'));
var_dump(md5('aabg7XSs') == md5('aabC9RqS'));
var_dump(sha1('aaroZmOk') == sha1('aaK1STfY'));
var_dump(sha1('aaO8zKZF') == sha1('aa3OFF9m'));
var_dump('0010e2' == '1e3');
var_dump('0x1234Ab' == '1193131');
var_dump('0xABCdef' == ' 0xABCdef');
?>
Check the answer here. That's right, everything is True.
This is because ==
doesn't check for type, if a string looks like an integer it will first try to convert it to an integer first and then compare it.
More about PHP == operator here
This is weird and you should use ===
instead.
Even better, you can use hash_equals (coupled with crypt
)
Compares two strings using the same time whether they're equal or not.
This function should be used to mitigate timing attacks; for instance, when testing crypt() password hashes.
Here's the example from php.net:
<?php
$expected = crypt('12345', '$2a$07$usesomesillystringforsalt$');
$correct = crypt('12345', '$2a$07$usesomesillystringforsalt$');
$incorrect = crypt('apple', '$2a$07$usesomesillystringforsalt$');
hash_equals($expected, $correct);
?>
Which will return True
.
But why?
the hashed strings start with 0e
, for example both strings are equals in php:
md5('240610708') = 0e462097431906509019562988736854
md5('QNKCDZO') = 0e830400451993494058024219903391
because php understands them as both being zero to the power something big. So zero.
Security
Now, if you're comparing unencrypted or unhashed strings and one of them is supposed to be secret, you might have potentialy created the setup for a timing-attack.
Always try to compare hashes instead of the plaintext!
There is a Link section here that is not very visible, I don't really know how I could show its content on the frontpage here. But here's one way:
May 21th
May 22th
May 23th
May 24th
May 25th
May 27th
May 28th
More
And you can find more on the Links section of this blog
To make it short, I did some research on the Boneh and Durfee bound, made some code and it worked. (The bound that allows you to find private keys if they are lesser than \(N^{0.292}\))
I noticed that many times, the lattice was imperfect as many vectors were unhelpful. I figured I could try to remove those and preserve a triangular basis, and I went even further, I removed some helpful vectors when they were annoying. The code is pretty straightforward (compare to the boneh and durfee algorithm here)
So what happens is that I make the lattice smaller, so when I feed it to the lattice reduction algorithm LLL it takes less time, and since the complexity of the whole attack is dominated by LLL, the whole attack takes less time.
It was all just theoric until I had to try the code on the plaid ctf challenge. There I used the normal code and solved it in ~3 minutes. Then I wondered, why not try running the same program but with the research branch?

That’s right, only 10 seconds. Because I removed some unhelpful vectors, I could use the value m=4 and it worked. The original algorithm needed m=5 and needed a lattice of dimension 27 when I successfully found a lattice of dimension 10 that worked out. I guess the same thing happened to the 59 triplets before that and that’s why the program ran way faster. 3 minutes to 10 seconds, I think we can call that a success!
The original code:

/!\ this page uses LaTeX, if you do not see this: \( \LaTeX \)
then refresh the page
Plaid CTF
The third crypto challenge of the Plaid CTF was a bunch of RSA triplet \( N : e : c \) with \( N \) the modulus, \( e \) the public exponent and \( c \) the ciphertext.

The public exponents \( e \) are all pretty big, which doesn't mean anything in particular. If you look at RSA's implementation you often see \( 3 \), \( 17 \) or other Fermat primes (\( 2^m + 1 \)) because it speeds up calculations. But such small exponents are not forced on you and it's really up to you to decide how big you want your public exponent to be.
But the hint here is that the public exponents are chosen at random. This is not good. When you choose a public exponent you should be careful, it has to be coprime with \( \varphi(N) \) so that it is invertible (that's why it is always odd) and its related private exponent \( d \) shouldn't be too small.
Maybe one of these public keys are associated to a small private key?
I quickly try my code on a small VM but it takes too much time and I give up.
Wiener
A few days after the CTF is over, I check some write-ups and I see that it was indeed a small private key problem. The funny thing is that they all used Wiener to solve the challenge.
Since Wiener's algorithm is pretty old, it only solves for private exponents \( d < N^{0.25} \). I thought I could give my code a second try but this time using a more powerful machine. I use this implementation of Boneh and Durfee, which is pretty much Wiener's method but with Lattices and it works on higher values of \( d \). That means that if the private key was bigger, these folks would not have found the solution. Boneh and Durfee's method allows to find values of private key up to \( d < N^{0.292} \)!
After running the code (on my new work machine) for 188 seconds (~ 3 minutes) I found the solution :)

Here we can see that a solution was found at the triplet #60, and that it took several time to figure out the correct size of lattice (the values of \( m \) and \( t \)) so that if there was a private exponent \( d < N^{0.26} \) a solution could be found.

The lattice basis is shown as a matrix (the ~
represents an unhelpful vector, to try getting rid of them you can use the research branch), and the solution is displayed.
Boneh and Durfee
Here is the code if you want to try it. What I did is that I started with an hypothesis \( delta = 0.26 \) which tested for every RSA triplets if there was a private key \( d < N^{0.26 } \). It worked, but if it didn't I would have had to re-run the code for \(delta = 0.27\), \(0.28\), etc...
I setup the problem:
# data is our set of RSA triplets
for index, triplet in enumerate(data):
print "Testing triplet #", index
N = triplet[0]
e = triplet[1]
# Problem put in equation
P.<x,y> = PolynomialRing(ZZ)
A = int((N+1)/2)
pol = 1 + x * (A + y)
I leave the default values and set my hypothesis:
delta = 0.26
X = 2*floor(N^delta)
Y = floor(N^(1/2))
I use strict = true
so that if the algorithm will stop if a solution is not sure to be found. Then I increase the values of \( m \) and \( t \) (which increases the size of our lattice) and try again:
solx = -1
m = 2
while solx == -1:
m += 1
t = int((1-2*delta) * m) # optimization from Herrmann and May
print "* m: ", m, "and t:", t
solx, soly = boneh_durfee(pol, e, m, t, X, Y)
If no private key lesser than \(N^{delta}\) exists, I try the next triplet. However, if a solution is found, I stop everything and display it.
Remember our initial equation:
\[ e \cdot d = f(x, y) \]
And what we found are \(x\) and \(y\)
if solx != 0:
d = int(pol(solx, soly) / e)
print "found the private exponent d!"
print d
m = power_mod(triplet[2], d, N)
hex_string = "%x" % m
import binascii
print "the plaintext:", binascii.unhexlify(hex_string)
break
And that's it!
More?
If you don't really know about lattices, I bet it was hard to follow. But do not fear! I made a video explaining the basics and a survey of Coppersmith and Boneh & Durfee
Also go here and click on the follow button.
Plaid, The biggest CTF Team, was organizing a Capture The Flag contest last week. There were two crypto challenges that I found interesting, here is the write-up of the second one:
You are given a file with a bunch of triplets:
{N : e : c}
and the hint was that they were all encrypting the same message using RSA. You could also easily see that N was the same modulus everytime.
The trick here is to find two public exponent \( e \) which are coprime: \( gcd(e_1, e_2) = 1 \)
This way, with Bézout's identity you can find \( u \) and \( v \) such that: \(u \cdot e_1 + v \cdot e_2 = 1 \)
So, here's a little sage script to find the right public exponents in the triplets:
for index, triplet in enumerate(truc[:-1]):
for index2, triplet2 in enumerate(truc[index+1:]):
if gcd(triplet[1], triplet2[1]) == 1:
a = index
b = index2
c = xgcd(triplet[1], triplet2[1])
break
Now that have found our \( e_1 \) and \( e_2 \) we can do this:
\[ c_1^{u} * c_2^{v} \pmod{N} \]
And hidden underneath this calculus something interesting should happen:
\[ (m^{e_1})^u * (m^{e_2})^u \pmod{N} \]
\[ = m^{u \cdot e_1 + v \cdot e_2} \pmod{N} \]
\[ = m \pmod{N} \]
And since \( m < N \) we have our solution :)
Here's the code in Sage:
m = Mod(power_mod(e_1, u, N) * power_mod(e_2, v, N), N)
And after the crypto part, we still have to deal with the presentation part:
hex_string = "%x" % m
import binascii
binascii.unhexlify(hex_string)
Tadaaa!! And thanks @spdevlin for pointing me in the right direction :)
The Plaid Parliament of Pwning, a security team at Carnegie Mellon University is organizing a CTF right now until tomorrow: http://play.plaidctf.com/
There are two crypto challenges at the moment, and maybe more if someone unlocks one. Have fun!