Post

Multi-Factor Authentication

StoutCTF 2026 Spring Multi-Factor Authentication Challenge

Challenge description:

This program checks your password multiple times! That’s… how MFA works, right?

No. No that’s not how that works. Anyways, let’s take a look.

1
2
3
4
❯ ./main
Please enter the password
> 50
Incorrect!

Drats! Let’s open it in Ghidra and see what’s up. This one is stripped, so we need to start from entry to find main.

1
2
3
4
5
6
7
8
9
10
11
void processEntry entry(undefined8 param_1,undefined8 param_2)

{
  undefined1 auStack_8 [8];
  
  (*(code *)PTR___libc_start_main_00103fc0)
            (FUN_00101169,param_2,&stack0x00000008,0,0,param_1,auStack_8);
  do {
                    /* WARNING: Do nothing block with infinite loop */
  } while( true );
}

The first thing passed into __libc_start_main is main, so FUN_00101169 is the one we want. Let’s rename it, along with a couple other things.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
undefined8 main(void)

{
  long in_FS_OFFSET;
  uint password;
  long local_10;
  
  local_10 = *(long *)(in_FS_OFFSET + 0x28);
  printf("Please enter the password\n> ");
  __isoc23_scanf(&DAT_00102021,&password);
  if ((int)password < 0x65) {
    printf("Incorrect!");
  }
  else if ((int)password < 200) {
    if ((password & 1) == 0) {
      print_flag();
    }
    else {
      printf("Incorrect!");
    }
  }
  else {
    printf("Incorrect!");
  }
  if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) {
                    /* WARNING: Subroutine does not return */
    __stack_chk_fail();
  }
  return 0;
}

So here’s our “multi-factor authentication”. The password is a number, and it needs to get through three checks to reach a function I named print_flag, since that looks like what we want to run.

  • It can’t be below 0x65, which is 101, so it has to be at least 101
  • It has to be less than 200
  • (password & 1) == 0, so the lowest bit has to be 0, meaning it’s an even number

That last one might look a little odd if you haven’t seen it before. In binary, every odd number ends in a 1, and every even number ends in a 0. So & 1 looks at only the last bit, which makes it a quick way to check if a number is even.

So there isn’t even one password. Any even number from 102 to 198 will do. Let’s use the first one.

1
2
3
4
❯ ./main
Please enter the password
> 102
STOUTCTF{DI0J6nCNIPLXo7vRmNSq3ULJ3DQ7ba0D}

We didn’t even need to figure out how print_flag decrypts the flag, since the program is happy to do it for us.

FLAG: STOUTCTF{DI0J6nCNIPLXo7vRmNSq3ULJ3DQ7ba0D}

This post is licensed under CC BY 4.0 by the author.