ECSC - i2c & packetz

Last weekend I participated at the national phase of ECSC and I want to showcase some of the challenges that I solved and I find interesting.

Today we're going to take a look at i2c in the forensics category. It was a 475 points challenge. Unfortunately I can't show you the prompt because the challenges were made unavailable after the contest. It said something like 'the flag is in this EEPROM microcontroller.'

We were given a .dsl file. We will use DSView to open it and try to read it in some way. But first let's see what i2c is.

Okay, the definition from wikipedia for i2c:

I2C (Inter-Integrated Circuit) is a synchronous, multi-master, multi-slave, packet switched, single-ended, serial computer bus. It is widely used for attaching lower-speed peripheral ICs to processors and microcontrollers in short-distance, intra-board communication.

So, basically we are dealing with a serial communication protocol. Thus, data is transferred bit by bit along a single wire (the SDA line in this case). It is better explained in the nxp user guide.

For now, we will use a tool that is interpreting the .dsl file for us. I used DSView. So let's see what we get if we open the file in DSView.

Now we have to click on the + sign on the right side to specify which is the SDA (serial data) line and which is the SCL (serial clock) line. My guess is that the line number 1 is the clock line, if you're not sure you can always switch. After doing so, you should see something like this:

Cool! Now we can see the protocl interpreted correctly. Just as explained here at section 3. The I2C-bus protocol.

We can export this data using the right panel and clicking on the floppy disk and we can export it as a .csv file. We get this:

We see some reads and some writes. In my first try, I completely ignored the writes, because my first thought was that they are irelevant since we are reading the flag from input, that was a mistake. After some looking at those bytes, it was clear that it was trying to spell something out, if you were to print the first 8 bytes it would spell DEADBEEF. After trying to write a script to carve every read from the file and print it, it will show me a scrambled flag:

After some thinking, i've figured out that the writes were actually indexes for the reads. Then we can write a script to parse this file like so for us:

import time
import sys

f = open('exported.csv', 'r')
data =

lines = data.split('\n')

flag = bytearray('a'*86)

writes = 'Data write: '
reads = 'Data read: '

ind = 0
for i in range(len(lines)):
    if 'Data write: ' in lines[i]:
        ind = lines[i].split(' ')[-1].strip().lower()
        ind = ord(ind.decode('hex'))
    if 'Data read: ' in lines[i]:
        byte = lines[i].split(' ')[-1]
        byte = byte.decode('hex')
        flag[ind] = byte
    sys.stdout.write(flag + '\r')

print ""

And we will get the flag like so:



Now we can take a look at packetz. It was a 500 points challenge in the network category. Not many people solved this challenge, because it was a little bit guessy. Once again I can't show you the prompt. But I think it was something like 'some IP packets are more important than others'.

We were a given a .pcap file. After opening it it in wiresharking and taking a brief look at the packets, I decided to run strings on it, because most of the data in the data section of the TCP packets was text. So let's see.

We see different sha256 hashes, but they are just garbage. Literally, if you try to decrypt them with an online database they literally spell garbage. There was also a hint given on this challenge that said: Garbage is garbage. Forget it.

The strings in the data related with "Democleitus" and "Cleoxenus" were pointing out to an old cipher, it was called: Polybius square. Every sha256 hash, but one were decrypting to garbage, that was this one:


I played with this and the Polybius square for a little while, but with no luck. Also notice that "Democleitus" and "Cleoxenus" were talking about some key LOCK. So I tried different varitions of this key with the Polybius cipher but nothing really helped. After some time I gave up this idea and looked again more closely at the prompt:

some IP packets are more important than others

Now, it might have some sense to take a look at the IP header in the pcap. This is how a standard IP header would look like.

There are not so many things you can change in the IP header to still be considered valid. Those things are:

  1. The checksum field. Notice that in our case the validation of the checksum is disabled. That might be something.
  2. The Identification field.
  3. The Service field.

So I took them one by one. Extracted from like the first 4-5 packets and the last 4-5 packets, the mentioned fields. Just to see if something is repeating. Since we know the flag format: ECSC{.*?}. We get something like this:


First 4: 45 76, 5c e2, e3 7d, 3a 4e.

Last 3: 75 ab, 93 73, 25 ee.


First 4: 0d 12, 13 3a, 17 62, 32 79.

Last 4: dc a0, be d3, 2c 24, 1d 50.


31 78 73 7a 78 78 73

As you might notice, nothing really spells out "hey, i'm the flag get me". This was the last challenge I solved during the competition, 30 minutes before the end. I was feeling that I was getting closer, so at that point I would try everything, because I clearly had no time to start looking at another challenge.

So I've tried to use the given key LOCK to xor these bytes around. After xoring I would notice something werid about the service field.

The last byte it's an }. Now let's xor some service field bytes from the last packets.

Hmm. Now we're talking. We see some 'E' and 'C'. So this might be it. We can try to get every service byte, reverse the sequence and try and xor with the key, in a rolling xor manner. Notice that, we found 'E' when xoring with 'O', and 'C' when xoring with 'L'. Since those are the last bytes then if we reverse it we should xor with 'OLKC' because the key ended earlier. So writing the script in the heat of the moment I just handwritten the key rolled over the flag length.



encrypted = bytearray('0a0f180034787a277a7b2a72777f28227f2e7b7129787c722a7f7d742e7d727329282d27767c78277c7c7c252c287f702e2f28217d7c72707f2a78762a78737378787a737831'.decode('hex'))

flag = ""
for i in range(len(key)):
    print chr(encrypted[i] ^ ord(key[i])),

And this will give us the flag.