Introduction

The given tasks gives us only one file:

  • chall.exe

Chall Description:

Our agents captured some North Korean military software. Your task: find the correct launch code!

This is a rev challenge so the flag has to be found reverse engineering the program. The program is not stripped but its writtn in Nim , thanks to Nimfilt it was pretty simple to get a decent output out of the disassembly.

Solution

Without getting too much into the disassembly this is the pseudocode of what is happening inside the binary:

iv = [...]
targets = [...]
for idx in range(42):
    curr_char = readchar()
    buff = curr_char * 69

    sum = md5Sum(buff, iv)

    if sum == targets[idx]:
        iv = sum
    ...

Here it is also the ghidra summarized version (thanks AI <3):

// Load the 42 target‐MD5 pointers by copying 0x54 entries:
puVar9   = &TM__zC9bY5JD6g9aIk7nnSsyaj7A_2;
puVar11  = &targets__chal_u496;
for (lVar5 = 0x54; lVar5 != 0; lVar5 = lVar5 - 1) {
    *puVar11 = *puVar9;
    puVar9++;
    puVar11++;
}

// Read your 42‐byte flag from stdin into DAT_14002e2a8:
readLine__stdZsyncio_u453(&local_88, stdin);
flag__chal_u498 = CONCAT44(iStack_84, local_88);
DAT_14002e2a8  = (ulonglong **)CONCAT44(uStack_7c, uStack_80);

// The main per‐byte loop:
uVar8 = 0;
do {
    i__chal_u509 = uVar8;

    // curr_char = flag[idx]:
    fc__chal_u510 = *(undefined *)((longlong)DAT_14002e2a8 + uVar8 + 8);

    // buff = curr_char * 69
    nsuRepeatChar(&local_88, fc__chal_u510, 0x45);

    // sum = md5Sum(buff, iv)
    md5Sum__chal_u47(
      (ulonglong *)&local_88,          // pointer to your 69‐byte buffer
      (ulonglong *)&iv__chal_u508,     // pointer to the 16‐byte CURR_IV
      (undefined8 *)&digest__chal_u672 // out: your 16‐byte result
    );

    // CURR_IV = sum
    iv__chal_u508 = _digest__chal_u672;

    // if hexString(sum) == targets[idx] then res++ else res--
    memcmp_ok = memcmp(
        DAT_14002e278 + 1,
        (void *) ((&DAT_14002e2c8)[i__chal_u509 * 2] + 8),
        (size_t)hexString__chal_u673,
    ) == 0;

    if ( (hexString__chal_u673 == (undefined1 *)(&targets__chal_u496)[i__chal_u509 * 2])
        && (hexString__chal_u673 == (undefined1 *) 0x0 ) || memcmp_ok ) {
        res__chal_u507 = res__chal_u507 + 1;
    } else {
        res__chal_u507 = res__chal_u507 - 1;
    }

    uVar8 = uVar8 + 1;
} while (uVar8 != flag__chal_u498);

Basically the binary:

  1. asks the next char
  2. repeat it 69 times
  3. make the md5sum with the current_iv
  4. check if the digest is equal to the current target

After knowing this what we need to do is implement the “custom” md5 function and check the printable characters against the targets array, easly retrievable from the binary.

flag = []
curr_iv = ORIG_IV
for idx in range(41, -1, -1):
    target = binascii.unhexlify(TARGETS[idx])

    for c in string.printable:
        buff = c * 69
        sum = md5Sum(buff.encode(), curr_iv)
        if target == sum:
            flag.append(c)
            curr_iv = target
            break
print(f"FLAG: {"".join(flag)}")