Flare-On 2015 Challenge 2
Challenge number 2, first thing, as always, is to unpack the zip file and see what the type of file is that is given.
According to die
it is an PE executable, so the extension .exe
can be added. The strings show a similar condition as the first challenge, a prompt and then 2 outcome strings. Opening it up in Cutter shows that it is indeed a small program, the below screenshot shows all the relevant program logic. In the screenshot all my annotations of the code are visible. I do this just by adding a comment
to the line using the ;
command.
As you might note, there is an instruction mov edi, dword [arg_8h]
, from my analysis this seems to be the flag, or key, location. I found the easiest way is to use a debugger to find the actual address that is moved around.
When entering input for the program, there is actually a check to see if the input to the program is at least 0x25
characters long.
This is a hint to how many bytes are in the key. At the key location, found using the debugger, there is a range of 37 bytes. It is safe to assume that this is the actual key that is needed.
Given the screenshot of the program logic above allows the destruction of the program in the following steps:
- Make sure the input from the user is 37 chars long (occurs just before this code)
- Put the pointer to the flag at the last byte, reading the bytes from back to front
- Move into
dx
what is inbx
(bx
turns out to be an accumulator) - Apply an
and 3
to the value indx
- Put
0x1c7
intoAX
- Using
sahf
theAH
(which is0x1
) is put into flags - Load a byte from the user input and
xor
it withal
, which is0xc7
- Rotate 1 left with the value in the accumulator (now in
cl
) - Pop
0x1
from the stack and usingadc
add it along with the result of the rotate toAL
- Add
AX
toBX
, which increments the accumulator value with the encrypted byte - scasb compare the byte in
al
with the one in the input. Note thatscasb
will increment edi (as it scans), so the counter needs tosub edi, 2
in order to keep reading backwards.
First thing is to actually grab the bytes that are part of the key. It is know that there are 37 and using the debugger they can easily be tracked down. The debugger in Cutter is not too fancy, but sufficient for the job at hand. Tracing the program to the location of the mov
instruction allows the inspection of the register. Using the Show in Hex Dump
function the bytes can be retrieved.
All that is needed is to select the bytes and copy them.
As the program logic reads them back to front they need to be reversed. There are many ways to do this, but CyberChef is yet again a quick and easy method.
Given that the first (actually last) byte is 0xa8
(decimal 168) the above program logic can be reversed by taking the byte, subtracting 1 rotated left with the accumulator (at the start it is 0), subtracting 1 again and xor
the result with 0xc7
.
>>> (168-(1<<0)-1)^0xc7
97
The result is 97. The character value of 97 is a
. So the key should start with the letter a
. Entering a password of only a
characters shows that the first loop is done perfectly, all the conditions match. The second iteration of the loop does not of course, but it validates the program logic.
So, taking the logic from above a quick Rust (yes, still learning it) program can be created. The addition to it is the & 0xFF
to only take the least significant bits. Afterwards I tried with the mask and the output was still correct, so in this case it is quite useless.
The accumulator holds a running total of the encrypted bytes, so it is added in the loop.
use std::char;
fn main() {
let encrypted: [u32; 37] = [
0xa8, 0x9a, 0x90, 0xb3, 0xb6, 0xbc, 0xb4, 0xab, 0x9d, 0xae, 0xf9, 0xb8, 0x9d, 0xb8, 0xaf,
0xba, 0xa5, 0xa5, 0xba, 0x9a, 0xbc, 0xb0, 0xa7, 0xc0, 0x8a, 0xaa, 0xae, 0xaf, 0xba, 0xa4,
0xec, 0xaa, 0xae, 0xeb, 0xad, 0xaa, 0xaf,
];
let mut acc = 0;
for (_i, elem) in encrypted.iter().enumerate() {
let decrypted = (elem - 1u32.rotate_left(acc & 3) - 1) ^ 0xc7 & 0xff;
acc += elem;
print!("{}", char::from_u32(decrypted).unwrap());
}
}
The output of the program shows the key to continue with the next challenge.
a_Little_b1t_harder_plez@flare-on.com