-
Notifications
You must be signed in to change notification settings - Fork 119
Tutorial #2: DCA against Hack.lu 2009 challenge
Here is the second tutorial of our series.
Specificities of this tutorial:
- Learning how to trace a Windows executable under Linux
- Learning how to automate GUI interactions
- Learning how to use the visual trace to get information useful for the DCA attack
The corresponding materials are available at https://github.com/SideChannelMarvels/Deadpool/tree/master/wbs_aes_hacklu2009
This time we're talking about a challenge made by Jean-Baptiste Bédrune for Hack.lu 2009.
It's a Windows 32-bit graphical crackme performing an AES128 encryption over the user input. If the output is equal to "hack.lu-2009-ctf", one gets a success message.
Intel PIN works also under Windows but TracerPIN was not ported to Windows so let's run the crackme.exe under Linux via Wine. Intel PIN failing on Wine, we'll use TracerGrind. (maybe it's possible to use PIN with Wine with some tuning or memory remappings, to be investigated...)
GUI automation will be provided by xdotool, which can handle keyboard and mouse, but if possible it's always more reliable to use only the keyboard and e.g. if possible use Tab
to move along the various features of the graphical interface.
Here is one automated execution where the right input is provided:
wine32 crackme.exe &
sleep 1
xdotool - << EOF
search --sync --limit 1 --name Crackme
sleep 0.1
key Tab Tab
key 1 9 2 shift+E shift+F 9 shift+E 6 1 1 6 4 shift+B shift+D 2 8 9 shift+F 7 7 3 shift+E 6 shift+C 9 1 0 1 shift+B 8 9 shift+C
key Tab space
EOF
First step is to trace the executable with TracerGrind.
But beware! When an executable is launched via Wine, the Wine server is running in the background and we certainly don't want to instrument the whole Wine server!
So, an easy way is to start another process in a separate window and keep it open during the experiments with the crackme.
wine notepad.exe
Now we can trace our executable with an arbitrary input once we've identified the main address range, then convert the trace into a Sqlite DB:
objdump -p crackme.exe |grep Image
ImageBase 00400000
SizeOfImage 00018000
valgrind --trace-children=yes --tool=tracergrind --filter=0x400000-0x401800 --vex-iropt-register-updates=allregs-at-mem-access --output=crackme.trace wine32 crackme.exe &
sleep 1
xdotool - << EOF
search --sync --limit 1 --name Crackme
sleep 0.1
key Tab Tab
key 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
key Tab space
sleep 0.1
windowkill
EOF
sqlitetrace crackme.trace crackme.sqlite
Fire tracegraph, load the sqlite trace and rescale with the Overview zoom.
Note that if pixels are too small to get a global idea, you can change their size with keys +
and -
, e.g.:
We're looking at an AES128 so we see clearly the rounds. Actually we see only about 9 rounds and not 10. That's because in AES, there is no MixColumn step in the last round. One pecularity is that the stack got allocated at a very low address range, even before the code section at 0x400000. Let's zoom on the stack on the AES section:
If we count the blocks seen on the left of the image, we see 10 of them! Reassured? ;)
This binary is still quite small to trace entirely, nevertheless let's see how we can filter addresses to capture only the useful part.
Zoom on the instructions loop of the AES and find the address range to spy on.
0x401000-0x401243
seems a good one.
https://github.com/SideChannelMarvels/Deadpool/blob/master/wbs_aes_hacklu2009/DCA contains the scripts to perform the acquisition of a few traces.
The range 0x401000-0x401243
is configured in run.sh
, a little helper script to handle Wine and xdotool as seen above.
Remember first to have wine notepad.exe
running somewhere in the background.
Note that due to the nature of the challenge we've direct access only to the input, not the output.
The output is not needed to mount the attack, it's just nice to have to be able to verify if the found key is correct or not.
But with this challenge you can test your key to decrypt the string hack.lu-2009-ctf
and try the crackme.
Let's acquire a few traces: (obviously refrain from using the keyboard and mouse during the acquisition!)
./Tracer2bin.py
...
00000 D77EAE3D6557FDA6E4E013435B984F50 -> ?
...
00001 A7F1A463EDA8248E357CB14B2DBD74C9 -> ?
...
Convert them for Daredevil:
./bin2daredevil.py
Executing the differential analysis on the converted traces, here on addresses:
daredevil -c addr8_r_20_5888.config|egrep "INFO|Best bit"
[INFO] File LUT/AES_AFTER_SBOX not found, using /usr/local/share/daredevil/LUT/AES_AFTER_SBOX instead.
[INFO] Lookup table specified at LUT/AES_AFTER_SBOX
[INFO] Attack of byte number 0 done in 0.117227 seconds.
Best bit: 0 rank: 0. 1 0x14 130
[INFO] Attack of byte number 1 done in 0.111825 seconds.
Best bit: 0 rank: 0. 1 0x2b 554
[INFO] Attack of byte number 2 done in 0.108856 seconds.
Best bit: 0 rank: 0. 1 0xbe 410
[INFO] Attack of byte number 3 done in 0.119154 seconds.
Best bit: 0 rank: 0. 1 0xe 266
[INFO] Attack of byte number 4 done in 0.109574 seconds.
Best bit: 0 rank: 1. 1 0x2d 258
Best bit: 1 rank: 0. 1 0x2d 259
[INFO] Attack of byte number 5 done in 0.140929 seconds.
Best bit: 0 rank: 0. 1 0x22 170
[INFO] Attack of byte number 6 done in 0.118977 seconds.
Best bit: 0 rank: 1. 1 0xe4 538
Best bit: 2 rank: 0. 1 0xe4 540
[INFO] Attack of byte number 7 done in 0.121391 seconds.
Best bit: 0 rank: 0. 1 0x80 394
[INFO] Attack of byte number 8 done in 0.107881 seconds.
Best bit: 0 rank: 0. 1 0x97 386
[INFO] Attack of byte number 9 done in 0.104676 seconds.
Best bit: 0 rank: 0. 1 0x49 298
[INFO] Attack of byte number 10 done in 0.107286 seconds.
Best bit: 0 rank: 0. 1 0x7d 154
[INFO] Attack of byte number 11 done in 0.107744 seconds.
Best bit: 0 rank: 0. 1 0x5f 522
[INFO] Attack of byte number 12 done in 0.115974 seconds.
Best bit: 0 rank: 0. 1 0xac 514
[INFO] Attack of byte number 13 done in 0.114706 seconds.
Best bit: 0 rank: 0. 1 0x5b 426
[INFO] Attack of byte number 14 done in 0.138724 seconds.
Best bit: 0 rank: 0. 1 0x59 282
[INFO] Attack of byte number 15 done in 0.114543 seconds.
Best bit: 0 rank: 1. 1 0x26 138
Best bit: 1 rank: 0. 1 0x26 139
[INFO] Total attack of file LUT/AES_AFTER_SBOX done in 1.860457 seconds.
Trying on stack writes gives similar results:
daredevil -c stack8_w_20_3008.config|egrep "INFO|Best bit"
Both work equally well on 20 traces with correlations being equal to 1, which means no internal encoding was used in this white-box. It's not so surprising as it was designed as one of the few challenges for a CTF that lasted 48h ;)
As in the first tutorial we actually conducted a known key analysis and observed the right key candidates were ranked first.
To demonstrate an attack without knowing the key, one can edit e.g. the generated addr8_r_20_5888.config file to comment out the correct key and choose which key byte to break (e.g. bytenum=0 to attack the first one). Run again the attack:
daredevil -c addr8_r_20_5888.config
...
[ATTACK] Key byte number 0
[ATTACK] Target bit number 0
[INFO] 1507328 correlations computed in total.
[INFO] Global top 20 correlations.
1 0x14 218
1 0x14 250
1 0x14 186
1 0x14 130
-0.904534 0xf9 3262
0.904534 0xd5 3405
0.904534 0xd5 3437
0.904534 0x7c 2004
0.904534 0x58 759
-0.904534 0x50 3263
0.904534 0xd5 3357
-0.904534 0x84 3286
0.904534 0x72 4548
0.904534 0xd5 3365
0.902671 0x83 3082
0.902671 0x83 3090
0.902671 0x83 3170
0.902671 0x22 3999
0.902671 0x9f 3165
0.902671 0x22 4007
...
First byte best candidate is clearly 0x14. With an AES128 encryption it's easy: the first round key is the AES key and indeed 0x14 is the first byte of the AES key.
Verification:
echo 192EF9E61164BD289F773E6C9101B89C|xxd -r -p|openssl enc -e -aes-128-ecb -nopad -K 142bbe0e2d22e48097497d5fac5b5926
hack.lu-2009-ctf