During your usual crop field stroll you were abducted by aliens. Luckily you were able to escape their grip and flee to an escape pod, but alas starting it requires a key code. Figure out how this strange mechanism works and return to earth.

**Category:** reversing

**Solver:** t0b1

**Flag:** `HTB{_3st3r31K3yP4d_}`

## Writeup

In this challenge we get a binary. We start by analyzing it in Ghidra and find the following main function (we already renamed the functions to be more readable).

```
void main(void)
{
int iVar1;
uint input;
puts("Embedded Key Pad!");
puts("Enter which button to press [1-9] and the flag may reveal itself");
setup_keypad();
do {
input = 0;
while (((int)input < 1 || (9 < (int)input))) {
iVar1 = getchar();
input = iVar1 - 0x30;
}
if (input == 1) { press_1(); }
if (input == 2) { press_2(); }
if (input == 3) { press_3(); }
if (input == 4) { press_4(); }
if (input == 5) { press_5(); }
if (input == 6) { press_6(); }
if (input == 7) { press_7(); }
if (input == 8) { press_8(); }
if (input == 9) { press_9(); }
printf("> %d\n",(ulong)input);
big_fucking_long_if_function();
} while( true );
}
```

First the `setup_keypad`

function is called which resets the corresponding global variables. Then we get to enter a number between `1`

and `9`

which is stored in the corresponding global variable. Finally the function we named `big_fucking_long_if_function`

is called. The function literally deserves this name, as the decompiled function in Ghidra is 1668 lines long and consists of mostly `if`

conditions.

Luckily, the first 35 lines of the function are sufficient.

```
int big_fucking_long_if_function(void)
{
bool bVar1;
if ((bit10 == '\0') || (bit0 != '\0')) {
bit10_and_not_bit0 = '\0';
}
else {
bit10_and_not_bit0 = '\x01';
}
if ((bit10_and_not_bit0 == '\0') || (key1_pressed != 0)) {
DAT_003050a1 = '\0';
}
else {
DAT_003050a1 = '\x01';
}
if ((DAT_003050a1 == '\0') || (key2_pressed == 0)) {
DAT_003050a2 = '\0';
}
else {
DAT_003050a2 = '\x01';
}
if (DAT_003050a2 != '\0') {
_xor_key_input = 2;
set_xor_key_to_param(&xor_key_input);
}
if (DAT_003050a2 != '\0') {
decode_flag();
}
// ... a lot of lines coming like this ...
}
```

The main functionality consists of many checks and variables being set to either `0`

or `1`

and in some cases, a position in a global array which we indentified as a key is set to a a character between `1`

and `9`

.

In one case, the `decode_flag`

function is called.

```
void decode_flag(void)
{
int local_c;
DAT_0030515a = 0;
printf(">> %s \n");
local_c = 0;
while (local_c < 0x14) {
(&flag_out)[local_c] = PTR_encrypted_flag_00305020[local_c] ^ (&xor_key)[local_c % 10];
local_c = local_c + 1;
}
DAT_00305134 = 0;
puts(&flag_out);
return;
}
```

It prints the final keycode and decrypts the flag using the XOR operator. Now we know, that this is a simple XOR encryption. We also notice, that the key is only 10 digits long, as the `% 10`

is used.

As we know the flag format, we can determine 5 of 10 key digits, by simply reversing the XOR operation. That leaves 5 digits open which results in `10^5`

combinations. As the function tells us when the key is correct, we can use it to verify our key and bruteforce the other digits. This is feasible, as its only `10^5`

combinations.

To speed things up a little, we run the bruteforce in 10 different threads, each with its own executable.

```
#!/usr/bin/python3
from pwn import *
import threading
def test_key(fname, i, ii, iii, iv, v):
r = process(fname)
rl = lambda : r.recvline()
ru = lambda x : r.recvuntil(x)
sla = lambda x,y : r.sendlineafter(x,y)
key = [8, 4, 1, 8, i, ii, iii, iv, v, 2]
payload = '\n'.join([str(k) for k in key])
sla('itself\n', payload)
answer = r.recv()
if b'>>' in answer:
print(key, answer)
r.close()
def run_10000(i):
fname = f'./keypad{i}'
context.log_level = 'error'
print(f'Starting thread {i}')
for ii in range(10):
print(f'[{i}] {ii}')
for iii in range(10):
for iv in range(10):
for v in range(10):
test_key(fname, i, ii, iii, iv, v)
threads = list()
for i in range(10):
x = threading.Thread(target=run_10000, args=(i,))
threads.append(x)
x.start()
for thread in threads:
thread.join()
print('All finished!')
```

This yields the flag and the keycode `8418946942`

.