# Csaw 2018 doubletrouble Pwn 200 (The Floating)

This writeup is dedicated to Pennywise the Dancing Clown. We all float down here:
https://www.youtube.com/watch?v=wHbpWtMOJTI

Let's take a look at the binary:

```
$ ./doubletrouble 
0xff930988
How long: 5
Give me: 15935728
Give me: 75395128
Give me: 95135728
Give me: 35715928
Give me: 82753951
0:1.593573e+07
1:7.539513e+07
2:9.513573e+07
3:3.571593e+07
4:8.275395e+07
Sum: 304[PII_REDACTED]00
Max: 95[PII_REDACTED]00
Min: 15[PII_REDACTED]00
My favorite number you entered is: 15[PII_REDACTED]00
Sorted Array:
0:1.593573e+07
1:3.571593e+07
2:7.539513e+07
3:8.275395e+07
4:9.513573e+07
$  pwn checksec doubletrouble 
[*] '/Hackery/csaw18/pwn/doubletrouble/doubletrouble'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX disabled
    PIE:      No PIE (0x8048000)
    RWX:      Has RWX segments
$  file doubletrouble 
doubletrouble: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=b9a11827e910481da3ed76a1425d4c110fd0db97, not stripped
```

So we can see a couple of things. It appears to prompt us for a number of inputs, then it takes in those inputs and converts them to doubles. Proceeding that it does some arithmetic on those doubles, then sorts the doubles least to greatest. We can also see that we get what looks like to be a stack infoleak, but we confirm that it is a stack infoleak with gdb:

```
gdb-peda$ r
Starting program: /Hackery/csaw18/pwn/doubletrouble/doubletrouble 
0xffffcd68
How long: ^C

.  .  .

gdb-peda$ vmmap
Start      End        Perm Name
0x08048000 0x0804b000 r-xp /Hackery/csaw18/pwn/doubletrouble/doubletrouble
0x0804b000 0x0804c000 r-xp /Hackery/csaw18/pwn/doubletrouble/doubletrouble
0x0804c000 0x0804d000 rwxp /Hackery/csaw18/pwn/doubletrouble/doubletrouble
0x0804d000 0x0806f000 rwxp [heap]
0xf7dd5000 0xf7faa000 r-xp /lib/i386-linux-gnu/libc-2.27.so
0xf7faa000 0xf7fab000 ---p /lib/i386-linux-gnu/libc-2.27.so
0xf7fab000 0xf7fad000 r-xp /lib/i386-linux-gnu/libc-2.27.so
0xf7fad000 0xf7fae000 rwxp /lib/i386-linux-gnu/libc-2.27.so
0xf7fae000 0xf7fb1000 rwxp mapped
0xf7fcf000 0xf7fd1000 rwxp mapped
0xf7fd1000 0xf7fd4000 r--p [vvar]
0xf7fd4000 0xf7fd6000 r-xp [vdso]
0xf7fd6000 0xf7ffc000 r-xp /lib/i386-linux-gnu/ld-2.27.so
0xf7ffc000 0xf7ffd000 r-xp /lib/i386-linux-gnu/ld-2.27.so
0xf7ffd000 0xf7ffe000 rwxp /lib/i386-linux-gnu/ld-2.27.so
0xfffdd000 0xffffe000 rwxp [stack]
```

here we can see that the infoleak is from the stack (which starts at `0xfffdd000` and ends at `0xffffe000`). Also some other important things we can see about the binary, it has a stack canary and `RWX` segments (regions of memory that we can read, write, and execute). We can also see that it is a `32` bit elf

## Reversing

So starting off we have the main function (which we use Ghidra to decompile):

```
/* WARNING: Type propagation algorithm not settling */

undefined4 main(void)

{
  int canary;
  
  canary = __x86.get_pc_thunk.ax(&stack0x00000004);
  setvbuf((FILE *)(*(FILE **)(canary + 0x27da))->_flags,(char *)0x0,2,0);
  game();
  return 0;
}
```

From our perspective, the only thing we need to worry about here is that it calls `game()` which we can see here:

```
int game()
{
  int index; // esi@5
  long double sum; // fst7@7
  long double max; // fst7@7
  long double min; // fst7@7
  int favorite; // eax@7
  int result; // eax@7
  int v6; // ecx@7
  int heapQt; // [sp+Ch] [bp-21Ch]@1
  int i; // [sp+10h] [bp-218h]@4
  char *s; // [sp+14h] [bp-214h]@5
  double ptrArray[64]; // [sp+18h] [bp-210h]@1
  int canary; // [sp+21Ch] [bp-Ch]@1

  canary = *MK_FP(__GS__, 20);
  printf("%p\n", ptrArray);
  printf("How long: ");
  __isoc99_scanf("%d", &heapQt);
  getchar();
  if ( heapQt > 64 )
  {
    printf("Flag: hahahano. But system is at %d", &system);
    exit(1);
  }
  i = 0;
  while ( i < heapQt )
  {
    s = (char *)malloc(0x64u);
    printf("Give me: ");
    fgets(s, 100, stdin);
    index = i++;
    ptrArray[index] = atof(s);
  }
  printArray(&heapQt, (int)ptrArray);
  sum = sumArray(&heapQt, ptrArray);
  printf("Sum: %f\n", (double)sum);
  max = maxArray(&heapQt, ptrArray);
  printf("Max: %f\n", (double)max);
  min = minArray(&heapQt, ptrArray);
  printf("Min: %f\n", (double)min);
  favorite = findArray(&heapQt, (int)ptrArray, -100.0, -10.0);
  printf("My favorite number you entered is: %f\n", ptrArray[favorite]);
  sortArray(&heapQt, (int)ptrArray);
  puts("Sorted Array:");
  result = printArray(&heapQt, (int)ptrArray);
  if ( *MK_FP(__GS__, 20) != canary )
    _stack_chk_fail_local(v6, *MK_FP(__GS__, 20) ^ canary);
  return result;
}
```

So we can see how this game goes down. It first starts by printing the address of `ptrArray` for the infoleak, which we later see is where our input is stored as a double. scanning in an integer into `heapQt`. Proceeding that it checks to make sure it isn't greater than `64` (this is because `ptrArray` is only big enough to hold `64` doubles). If it is, the program exits and prints the address of system to taunt us for being bad. Proceeding that it enters into a for loop which runs `heapQt` times, which each time it scans in `100` bytes of data into the heap, then converts it into a double, and stores it in the array `ptrArray`.  Proceeding that, it runs a number of sub functions with `heapQt` and `ptrArray` as arguments.

Looking at the `sumArray`, `maxArray`, and `minArray` functions, they do pretty much what we would expect them to do. However when we get to `findArray`, that's when we see something interesting:

```
int __cdecl findArray(int *heapQt, int ptrArray, double a3, double a4)
{
  int v5; // [sp+1Ch] [bp-4h]@1

  _x86_get_pc_thunk_ax();
  v5 = *heapQt;
  while ( *heapQt < 2 * v5 )
  {
    if ( *(double *)(8 * (*heapQt - v5) + ptrArray) > (long double)a3
      && a4 > (long double)*(double *)(8 * (*heapQt - v5) + ptrArray) )
    {
      return *heapQt - v5;
    }
    *heapQt += (int)&GLOBAL_OFFSET_TABLE_ + 0xF7FB4001;
  }
  *heapQt = v5;
  return 0;
}
```

Particularly this line is interesting:

```
  *heapQt = v5;
```

This dereferences a ptr to `heapQt` and writes a value to it. This is interesting to us, since it will allow us to change the value of `heapQt`, which is then passed as an argument to `sortArray`. Looking at the condition (since `a3` is `-10` and `a4` is `-100`), it appears that a value between `-10` and `-100` will trigger the write (I used `-23`). The write appears to increase the value of `heapQt`. Next up we have the `sortArray` function:

```
signed int __cdecl sortArray(_DWORD *heapQt, int ptrArray)
{
  double v2; // ST08_8@4
  int i; // [sp+0h] [bp-10h]@1
  int j; // [sp+4h] [bp-Ch]@2

  _x86_get_pc_thunk_ax();
  for ( i = 0; i < *heapQt; ++i )
  {
    for ( j = 0; j < *heapQt - 1; ++j )
    {
      if ( *(double *)(8 * j + ptrArray) > (long double)*(double *)(8 * (j + 1) + ptrArray) )
      {
        v2 = *(double *)(8 * j + ptrArra