# Plaid CTF 2019

Let's take a look at the binary:
```
$    file icancount
icancount: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-, for GNU/Linux 2.6.32, BuildID[sha1]=e75719f2cd90c042f04af29a0cd1263bb72c7417, not stripped
$    pwn checksec icancount
[*] '/Hackery/pod/modules/angr/plaid19_icancount/icancount'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      PIE enabled
$    ./icancount
We're going to count numbers, starting from one and
counting all the way up to the flag!
Are you ready? Go!
> 15935728
No, the correct number is 1.
But I believe in you. Let's try again sometime!
$    ./icancount
We're going to count numbers, starting from one and
counting all the way up to the flag!
Are you ready? Go!
> 1
Correct.
> 2
Yes.
> 3
Yes!
> 4
Congratz
> 5
Yep!
> 6
Right-o.
> 7
Wonderful.
> 8^C
```

So we can see that we are dealing with a `32` bit binary with `PIE`. When we run it, it prompts us for numbers that increments by `1`. When we take a look at the main function in Ghidra, we see this:

```
/* WARNING: Function: __x86.get_pc_thunk.bx replaced with injection: get_pc_thunk_bx */

void main(void)

{
  uint __seed;
  size_t len;
  size_t sVar1;
  int iVar2;
  char *compliment;
  char input [31];
 
  __seed = time((time_t *)0x0);
  srand(__seed);
  puts("We\'re going to count numbers, starting from one and");
  puts("counting all the way up to the flag!");
  puts("Are you ready? Go!");
  while( true ) {
    incr_flag();
    printf("> ");
    fflush(stdout);
    fgets(input + 1,0x1e,stdin);
    if (input[1] != '\0') {
      len = strlen(input + 1);
      if (input[len] < ' ') {
        sVar1 = strlen(input + 1);
        input[sVar1] = '\0';
      }
    }
    iVar2 = strcmp(input + 1,flag_buf);
    if (iVar2 != 0) break;
    compliment = (char *)get_compliment();
    puts(compliment);
    check_flag();
  }
  printf("No, the correct number is %s.\n",flag_buf);
  puts("But I believe in you. Let\'s try again sometime!");
                    /* WARNING: Subroutine does not return */
  exit(1);
}
```

So we can see that it prints out some text, sets the rng seed to time, then drops us into an infinite loop. The loop starts off by running the `incr_flag` function which we can see it increments `flag_buf` which is stored in the bss at address `0x13048`:

```
/* WARNING: Function: __x86.get_pc_thunk.bx replaced with injection: get_pc_thunk_bx */

void incr_flag(void)

{
  size_t sVar1;
  size_t local_10;
 
  local_10 = strlen(flag_buf);
  while( true ) {
    if ((int)local_10 < 1) {
      sVar1 = strlen(flag_buf);
      if (sVar1 != 0x13) {
        sVar1 = strlen(flag_buf);
        flag_buf[sVar1] = 0x30;
        flag_buf[0] = 0x31;
        return;
      }
                    /* WARNING: Subroutine does not return */
      exit(2);
    }
    if (*(char *)((int)&__dso_handle + local_10 + 3) != '9') break;
    *(undefined *)((int)&__dso_handle + local_10 + 3) = 0x30;
    local_10 = local_10 - 1;
  }
  *(char *)((int)&__dso_handle + local_10 + 3) =
       *(char *)((int)&__dso_handle + local_10 + 3) + '\x01';
  return;
}
```

A couple of things from this, first if we weren't sure before we can see that flag_bug is only filled with the bytes between 0x30-0x39 (ASCII `0-9`). In addition to that, since if the length of flag_buf exceeds 19 (`0x13`) the program exits, our input is probably 19 characters long (and only consists of ASCII characters between `0-9`).

Proceeding that in the main function, we see that it allows us to scan in 0x1e bytes into the stack char array `input`. It then checks if the last character in our inputted string has a value less than `0x20` (which corresponds to the space `' '` character). If it does, then that character is swapped out with a null byte.

Following that, it compares our input against `flag_buf`. If they are not equal, the infinite loop breaks and we get told what the correct number should be. If it doesn't break, then it will print a random character and run the `check_flag` function which looks like this:

```
void check_flag(void)

{
  longlong lVar1;
  uint b;
  uint x;
  uint y;
  uint z;
  uint uVar2;
  int unaff_ESI;
  ulonglong a;
  ulonglong c;
  ulonglong d;
  ulonglong uVar3;
  ulonglong uVar4;
  ulonglong e;
  ulonglong g;
  ulonglong uVar5;
  longlong f;
  int i;
  char inputChar;
 
  __x86.get_pc_thunk.si();
  i = 0;
  while( true ) {
    if (0x13 < i) {
      printf((char *)(unaff_ESI + 0x93c),unaff_ESI + 0x25f2);
                    /* WARNING: Subroutine does not return */
      exit(0);
    }
    inputChar = *(char *)(i + unaff_ESI + 0x25f2);
    x = (int)inputChar & 3;
    y = (int)(inputChar >> 2) & 3;
    z = (int)(inputChar >> 4) & 0xf;
    a = rol(x + 0xa55aa559,(uint)(0x5aa55aa6 < x) + 0xa55a,2);
    b = y - (uint)a;
    c = rol(b + 0xa55aa559,
            (-(uint)(y < (uint)a) - (int)(a >> 0x20)) + 0xa55a + (uint)(0x5aa55aa6 < b),0xd);
    c._4_4_ = (uint)(c >> 0x20);
    c._0_4_ = (uint)c;
    d = rol((z - (uint)c) + 0xa55aa559,
            (-(uint)(z < (uint)c) - c._4_4_) + 0xa55a + (uint)(0x5aa55aa6 < z - (uint)c),0x11);
    d._4_4_ = (uint)(d >> 0x20);
    uVar5 = c ^ a ^ d;
    lVar1 = a + CONCAT44((uint)((d & uVar5) >> 0x20) | ~(uint)(uVar5 >> 0x20) & c._4_4_,
                         (uint)(d & uVar5) | ~(uint)uVar5 & (uint)c);
    c._0_4_ = (uint)lVar1;
    c._4_4_ = z + (uint)c;
    uVar3 = rol(c._4_4_ + 0xf01f83c6,
                (int)((ulonglong)lVar1 >> 0x20) + (uint)CARRY4(z,(uint)c) + 0xf +
                (uint)(0xfe07c39 < c._4_4_),3);
    uVar2 = (uint)(uVar3 >> 0x20);
    lVar1 = c + CONCAT44((uint)((uVar3 & uVar5) >> 0x20) | ~uVar2 & d._4_4_,
                         (uint)(uVar3 & uVar5) | ~(uint)uVar3 & (uint)d);
    c._0_4_ = (uint)lVar1;
    c._4_4_ = x + (uint)c;
    uVar4 = rol(c._4_4_ + 0xf01f83c6,
                (int)((ulonglong)lVar1 >> 0x20) + (uint)CARRY4(x,(uint)c) + 0xf +
                (uint)(0xfe07c39 < c._4_4_),0xb);
    lVar1 = uVar5 + CONCAT44((uint)((d & uVar4) >> 0x20) | ~d._4_4_ & uVar2,
                             (uint)(d & uVar4) | ~(uint)d & (uint)uVar3);
    c._0_4_ = (uint)lVar1;
    c._4_4_ = y + (uint)c;
    e = rol(c._4_4_ + 0xf01f83c6,
            (int)((ulonglong)lVar1 >> 0x20) + (uint)CARRY4(y,(uint)c) + 0xf +
            (uint)(0xfe07c39 < c._4_4_),0x13);
    lVar1 = uVar3 + (e ^ d ^ uVar4);
    c._0_4_ = (uint)lVar1;
    c._4_4_ = y + (uint)c;
    g = rol(c._4_4_ + 0x867b8ca6,
            (int)((ulonglong)lVar1 >> 0x20) + (uint)CARRY4(y,(uint)c) + 0xb744 +
            (uint)(0x79847359 < c._4_4_),5);
    lVar1 = d + (uVar4 ^ g ^ e);
    c._0_4_ = (uint)lVar1;
    c._4_4_ = x + (uint)c;
    uVar5 = rol(c._4_4_ + 0x867b8ca6,
                (int)((ulonglong)lVar1 >> 0x20) + (uint)CARRY4(x,(uint)c) + 0xb744 +
                (uint)(0x79847359 < c._4_4_),7);
    lVar1 = e + (uVar5 ^ uVar4 ^ g);
    c._0_4_ = (uint)lVar1;
    c._4_4_ = z +