Keypad

Author

0x42697262

Play Date

2025/06/16 - 2025/06/16

Details

Author

D4RKFL0W

Language

C/C++

Upload

7:51 PM 07/08/2021

Platform

Unix/linux etc.

Difficulty

4.0

Quality

4.0

Arch

x86-64

Description

Gave a GUI crackme a go, let me know what you think. :)

What to expect?

  1. A stripped GUI binary

  2. A type of Constraint satisfaction problem

  3. No Anti-Debugging

Steps

file

I always start with file out of habit:

$ file keypad
keypad: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=cbb1c416b7663436b715621f209e58ac8b02f042, for GNU/Linux 3.2.0, stripped

A stripped binary this time.

strings

Ran strings to look for hardcoded password:

$ strings keypad
...
[]A\A]A^A_
clicked
Delete
Confirm
KEYPAD
destroy
Well Done
That's Unfortunate...
;*3$"
...

Looks empty.

Running

Since this is my first GUI app, I’ll try running to see what it does.

1 running
Figure 1. Running the GUI

Oh, it’s a vault. I thought it’s a calculator.

Looks like putting the correct PIN sequence is the goal.

Figuring out the decompiled code

I tried reverse engineering with radare2 but it was quite confusing and it crashed when i tried pdg (second time). So I went back to Ghidra :)

I kind like radare’s decompiling but I don’t quite understand assembly yet.

Since the binary is stripped from its labels, I didn’t find the main function easily. Went ahead and looked for the entry point and started from there.

Then I found the main function.

2 main
Figure 2. main() function

There was a lot to uncover. I had to figure out which variables and functions that are related to graphics. I had to ignore them.

After some reading and renaming the variables and functions, I noticed that each button corresponds to an action.

3 actions
Figure 3. Button actions

Each function contains an algorithm to manipulate the PIN.

Such as Button 4:

4 btn4
Figure 4. Button 4 PIN Manipulation Algorithm

Each button action has different PIN calculation.

This makes me wonder where the PIN is used for. Although one could already guess it’s for successfully reverse engineering the binary.

There is a Confirm button and as expected it also contains a function that verifies the PIN:

5 verify
Figure 5. Verify PIN

The PIN value of the vault is 0x1746e.

But where did the PIN come from?

6 pin
Figure 6. .data PIN

It’s located (probably?) in the .data section of the binary as 8 bytes uninitialized.

It’s accessed by the functions of each numerical buttons (and a function that randomizes the value of the pin but never gets called).

Bruteforcing the PIN

At first, I thought I could use Z3 Theorem Prover but I had issues with it that signed values does not wrap-around. It’s a Python quirk and I never figured out how to implement wrapping around the maximum bytes.

Thus, I wrote this code in C that will bruteforce the PIN.

Then I ran the code after compiling it.

7 cracked
Figure 7. Cracked the PIN within a second

Hooray! I found the PIN!

Time to test it.

Checking the PIN

Ran the GUI application again and voila!

8 win
Figure 8. Well Done

Challenge complete.

Conclusion

This challenge would have only taken me at most 3 hours if not for the wrap-around issues. Because in C/C++, when a variable exceeds the maximum data it holds, it goes all the way back to 0.

If I had a 4-byte integer with the value of 0xFFFFFE, adding 0x12 will result it to 0x00000010.

This does not happen in Python. Nor I could figure out how to implement this in Z3. Although the wrap-around worked sometime that I probably didn’t notice, there’s also an issue with modulo arithmetic and I decided to not deal with it. Also bruteforcing was almost in an instant so there’s that.