Write‑up: nhdta‑793
Category: Reversing / Crypto Points: 350 (CTF‑2024) Author: pwn‑team
1️⃣ Challenge description The challenge provides a single downloadable file: nhdta-793 . Running the binary prints a short banner and then waits for user input: $ ./nhdta-793 Welcome to NHDTA #793! >
If a string is entered, the program replies either with “Correct!” (and terminates) or with “Wrong!” . The flag is hidden somewhere inside the binary – it is not printed anywhere else. The goal is to retrieve the flag (format NHDTA{…} ).
2️⃣ Initial reconnaissance $ file nhdta-793 nhdta-793: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=3c0e..., stripped
The binary is stripped , so there are no symbol names. Running it gives a simple prompt, but the “Correct!” message appears only when the exact right input is supplied. $ ./nhdta-793 Welcome to NHDTA #793! > hello Wrong!
So we need to discover what the program checks the input against.
3️⃣ Static analysis 3.1 Disassembling with Ghidra
Load the ELF into Ghidra (or IDA). The entry point quickly branches to main . main does the following (pseudo‑code after decompilation):
int main(void) { puts("Welcome to NHDTA #793!"); while (1) { printf("> "); char buf[0x80]; if (!fgets(buf, sizeof(buf), stdin)) exit(0); buf[strcspn(buf, "\n")] = '\0'; // strip newline if (check(buf)) puts("Correct!"); else puts("Wrong!"); } }
The interesting part is the check function. 3.2 The check routine Decompiling check yields: bool check(const char *input) { /* 0x40‑byte key stored in .rodata */ static const uint8_t key[0x40] = { 0x5a,0x1e,0xa7,0x33,0x88,0xd9,0x0c,0x72, 0x5b,0x0f,0x1c,0xb3,0xe1,0x44,0x9a,0x67, … (total 64 bytes) };
/* Compute SHA‑256 of the input */ uint8_t digest[32]; SHA256_CTX ctx; SHA256_Init(&ctx); SHA256_Update(&ctx, input, strlen(input)); SHA256_Final(digest, &ctx);