# 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

Also this is a revised version of an older writeup I made, back when I used peda as a wrapper instead of Gef. 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 IDA to decompile):

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

undefined4 canary(void)

{
  int iVar1;
 
  iVar1 = __x86.get_pc_thunk.ax(&stack0x00000004);
  setvbuf((FILE *)(*(FILE **)(iVar1 + 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:

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

void game(void)

{
  char *__s;
  int iVar1;
  int in_GS_OFFSET;
  float10 fVar2;
  double dVar3;
  int heapQt;
  int local_21c;
  double ptrArray [64];
  int canary;
  int stackCanary;
 
  stackCanary = *(int *)(in_GS_OFFSET + 0x14);
  printf("%p\n",ptrArray);
  printf("How long: ");
  __isoc99_scanf(&DAT_0804a01f,&heapQt);
  getchar();
  if (0x40 < heapQt) {
    printf("Flag: hahahano. But system is at %d",system);
                    /* WARNING: Subroutine does not return */
    exit(1);
  }
  local_21c = 0;
  while (local_21c < heapQt) {
    __s = (char *)malloc(100);
    printf("Give me: ");
    fgets(__s,100,stdin);
    dVar3 = atof(__s);
    ptrArray[local_21c] = dVar3;
    local_21c = local_21c + 1;
  }
  printArray(&heapQt,ptrArray);
  fVar2 = (float10)sumArray(&heapQt,ptrArray);
  printf("Sum: %f\n",SUB84((double)fVar2,0),(int)((ulonglong)(double)fVar2 >> 0x20));
  fVar2 = (float10)maxArray(&heapQt,ptrArray);
  printf("Max: %f\n",SUB84((double)fVar2,0),(int)((ulonglong)(double)fVar2 >> 0x20));
  fVar2 = (float10)minArray(&heapQt,ptrArray);
  printf("Min: %f\n",SUB84((double)fVar2,0),(int)((ulonglong)(double)fVar2 >> 0x20));
  iVar1 = findArray(&heapQt,ptrArray,0xc[PII_REDACTED]00000,0,0xc0240000);
  printf("My favorite number you entered is: %f\n",SUB84(ptrArray[iVar1],0),
         (int)((ulonglong)ptrArray[iVar1] >> 0x20));
  sortArray(&heapQt,ptrArray);
  puts("Sorted Array:");
  printArray(&heapQt,ptrArray);
  if (stackCanary != *(int *)(in_GS_OFFSET + 0x14)) {
    __stack_chk_fail_local();
  }
  return;
}
```

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. Then it scans 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 findArray(int *heapQt,int ptrArray,undefined4 a3,undefined4 a4,undefined4 param_5,
             undefined4 param_6)

{
  int iVar1;
 
  __x86.get_pc_thunk.ax();
  iVar1 = *heapQt;
  while( true ) {
    if (SBORROW4(*heapQt,iVar1 * 2) == *heapQt + iVar1 * -2 < 0) {
      *heapQt = iVar1;
      return 0;
    }
    if (((double)CONCAT44(a4,a3) < *(double *)(ptrArray + (*heapQt - iVar1) * 8)) &&
       (*(double *)(ptrArray + (*heapQt - iVar1) * 8) < (double)CONCAT44(param_6,param_5))) break;
    *heapQt = *heapQt + 1;
  }
  return *heapQt - iVar1;
}
```


Looking at the code, we can see it 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