Actually, we want to break right after the function (offset 0x1386).
pwndbg> breakrva 0x1386
Breakpoint 1 at 0x555555555386
pwndbg> run
****************************************
* Welcome to SecureBank *
* Your trusted partner in security *
****************************************
========================================
= SecureBank Superadmin Login System =
========================================
Enter superadmin PIN: 1337
Breakpoint 1, 0x0000555555555386 in main ()
─────────────────────────────────────────[ DISASM / x86-64 / set emulate on ]─────────────────────────────────────────
0x555555555381 <main+112> call generate_2fa_code <generate_2fa_code>
â–º 0x555555555386 <main+117> mov dword ptr [rbp - 4], eax [0x7fffffffda8c] <= 0x568720
0x555555555389 <main+120> lea rax, [rip + 0xe7b] RAX => 0x55555555620b ◂— 'Enter your 2FA code: '
0x555555555390 <main+127> mov rdi, rax RDI => 0x55555555620b ◂— 'Enter your 2FA code: '
0x555555555393 <main+130> mov eax, 0 EAX => 0
0x555555555398 <main+135> call printf@plt <printf@plt>
See the value being moved from the EAX register onto the stack? 0x568720 in decimal is 5670688, let's try it!
./secure_bank
****************************************
* Welcome to SecureBank *
* Your trusted partner in security *
****************************************
========================================
= SecureBank Superadmin Login System =
========================================
Enter superadmin PIN: 1337
Enter your 2FA code: 5670688
Access Granted! Welcome, Superadmin!
Here is your flag: INTIGRITI{pffft_what_2fa?!}
Solve.py
Another option is to make a solve script according to the decompiled code. I like to copy/paste from ghidra to ChatGPT and get a python script to run.
def obscure_key(key):
key ^= 0xA5A5A5A5
# Make sure it stays within 32 bits
key = (key << 3) & 0xFFFFFFFF | (key >> 29)
key *= 0x1337
key &= 0xFFFFFFFF # Keep it within 32-bit unsigned integer bounds
key ^= 0x5A5A5A5A
return key
def generate_2fa_code(pin):
key = pin * 0xBEEF
key &= 0xFFFFFFFF # Ensure it's 32-bit
code = key
for i in range(10):
key = obscure_key(key)
code ^= key
code = (code << 5) & 0xFFFFFFFF | (
code >> 27) # Rotate and ensure 32 bits
code += (key >> (i % 5)) ^ (key << (i % 7))
code &= 0xFFFFFFFF # Keep it within 32-bit unsigned integer bounds
code &= 0xFFFFFF # Ensure the 2FA code is 24 bits (6 digits)
return code
if __name__ == "__main__":
pin = 1337 # The superadmin PIN
expected_code = generate_2fa_code(pin)
print(f"Expected 2FA Code: {expected_code}")
python solve.py
Expected 2FA Code: 5670688
Flag: INTIGRITI{pfff7_wh47_2f4?!}
There's a lot of different ways to solve the challenge from here. One easy way might be to run the binary in a debugger like gdb (I like ) and set a breakpoint around the generate_2f_code function (or validate_2fa_code).