Quick Info
There are 2 required arguments for qangr, a good address and binary.
❯ qangr -g 0x1337 chall
A good address would look something like a "Key Correct!" in a CrackMe or Binary.
Most CrackMe's or CTF Binaries will also output something like "Key Incorrect" if the key doesn't match the condition, this your bad address.
❯ qangr -g 0x1337 -b 0x892e2 chall
If the binary is PIE enabled, use -B
to specify a base address. You can also use -B auto
to automatically determine a base address. If you forget to specify a base address and PIE is enabled, qangr will warn you.
❯ qangr -g 0x1337 -b 0x892e2 -B auto chall
These will be the options of most use when using qangr to quickly pwn a CrackMe. Let's try pwning some challenges!
Example 1
Our first challenge is from CSDCTF.
Decompiled it looks like this.
It looks pretty complex to reverse, qangr can buzz through it easy though.
00400247 syscall(sys_write {1}, fd: 1, buf: "Correct! The flag is: csd{", count: 0x1b)
This would be our good address as it says we are correct and we want to get to that.
❯ time qangr -g 0x400247 ctf/re/practice-challs/mecrack2
[*] Exploring ts (this) 💔...
[*] Solution found: b'\xfa\xac\x01\xab\rGG\xf9'
qangr -g 0x400247 ctf/re/practice-challs/mecrack2 2.18s user 0.26s system 109% cpu 2.226 total
❯ echo '\xfa\xac\x01\xab\rGG\xf9' | ctf/re/practice-challs/mecrack2
Enter the password: Correct! The flag is: csd{Cr4CkI35}
Nice, it found the solution and we got the flag! Reversing that manually would have been a challenge but the angr framework's incredible binary analysis and qangr's simplicity made it easy. Let's try another one!
Example 2
This challenge is from 247CTF.
The title gives us a not so subtle hint towards using angr.
The function is massive and Binja doesn't even want to analyze it but we know we want to get to the flag function, so that will be our good address.
❯ qangr -g 0x8048596 ~/ctf/re/practice-challs/angr-y_binary --binary-info
INFO | 2025-01-12 15:40:50,314 | pwnlib.elf.elf | '/home/vipin/ctf/re/practice-challs/angr-y_binary'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x8048000)
Stripped: No
ELF('/home/vipin/ctf/re/practice-challs/angr-y_binary')
[*] Exploring ts (this) 💔...
WARNING | 2025-01-12 15:40:50,506 | angr.storage.memory_mixins.default_filler_mixin | The program is accessing register with an unspecified value. This could indicate unwanted behavior.
WARNING | 2025-01-12 15:40:50,507 | angr.storage.memory_mixins.default_filler_mixin | angr will cope with this by generating an unconstrained symbolic variable and continuing. You can resolve this by:
WARNING | 2025-01-12 15:40:50,507 | angr.storage.memory_mixins.default_filler_mixin | 1) setting a value to the initial state
WARNING | 2025-01-12 15:40:50,507 | angr.storage.memory_mixins.default_filler_mixin | 2) adding the state option ZERO_FILL_UNCONSTRAINED_{MEMORY,REGISTERS}, to make unknown regions hold null
WARNING | 2025-01-12 15:40:50,507 | angr.storage.memory_mixins.default_filler_mixin | 3) adding the state option SYMBOL_FILL_UNCONSTRAINED_{MEMORY,REGISTERS}, to suppress these messages.
WARNING | 2025-01-12 15:40:50,507 | angr.storage.memory_mixins.default_filler_mixin | Filling register edi with 4 unconstrained bytes referenced from 0x86286f1 (__libc_csu_init+0x1 in angr-y_binary (0x86286f1))
[*] Solution found: b'wgIdWOS6Df9sCzAfiK\x00\x00'
❯ nc b7738e66a7b03881.247ctf.com 50405
Enter a valid password:
wgIdWOS6Df9sCzAfiK\x00\x00
247CTF{a3bbb9d2e648841d99e1cf4535a92945}
Example 3
This is another challenge from 247CTF but this time we need to crack a license key checker.
Let's decompile the binary.
Our good address will be the win()
function and our bad address will be the "Invalid Product Key!".
We will also use Depth First Search and since the binary is PIE enabled, we will also use -B auto
.
❯ time qangr -g 0x143f -b 0x144d -B AUTO --DFS ~/ctf/re/practice-challs/flag_keygen
[*] Exploring ts (this) 💔...
[*] Solution found: b'BMMLFZMZZZL@MPPULC@@UYQ@MNWMHHOM\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
./qangr.py -g 0x143f -b 0x144d -B AUTO --DFS 120.42s user 1.55s system 100% cpu 2:01.59 total
❯ nc 86e9406c4b786e8b.247ctf.com 50252
Enter a valid product key to gain access to the flag:
BMMLFZMZZZL@MPPULC@@UYQ@MNWMHHOM
Valid product key!
247CTF{fb88b9fe80e969e73a27541f62d6f89c}
I’d say qangr is a quick and efficient tool for solving simple reverse engineering challenges. However, for more complex challenges, scripting with angr is a better approach.