# Seccon 2019 Quals Sum

Let's take a look at the binary and libc:

```
$    file sum_ccafa40ee6a5a[PII_REDACTED]36292bf3c84d17264
sum_ccafa40ee6a5a[PII_REDACTED]36292bf3c84d17264: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=593a57775caa3028bd2ab72873bedaa36734cdb6, not stripped
$    pwn checksec sum_ccafa40ee6a5a[PII_REDACTED]36292bf3c84d17264
[*] '/home/guyinatuxedo/Desktop/seccon/sum/sum_ccafa40ee6a5a[PII_REDACTED]36292bf3c84d17264'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)
$    ./libc.so
GNU C Library (Ubuntu GLIBC 2.27-3ubuntu1) stable release version 2.27.
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
Compiled by GNU CC version 7.3.0.
libc ABIs: UNIQUE IFUNC
For bug reporting instructions, please see:
<https://bugs.launchpad.net/ubuntu/+source/glibc/+bugs>.
$    ./sum_ccafa40ee6a5a[PII_REDACTED]36292bf3c84d17264
[sum system]
Input numbers except for 0.
0 is interpreted as the end of sequence.

[Example]
2 3 4 0
1
5
0
6
$    ./sum_ccafa40ee6a5a[PII_REDACTED]36292bf3c84d17264
[sum system]
Input numbers except for 0.
0 is interpreted as the end of sequence.

[Example]
2 3 4 0
1
5
6
9
8
7
Segmentation fault (core dumped)
```

So we can see that it is a `64` bit elf, with a stack canary, and non-executable stack. The binary appears to add numbers together. We input the numbers one at a time, and a `0` will end the sequence. If we input 6 digits, it crashes. Let's take a look under the hood.

## Reversing

When we take a look at the `main` function in ghidra, we see this:

```
undefined8 main(void)

{
  ulong uVar1;
  long in_FS_OFFSET;
  undefined8 ints;
  undefined8 local_40;
  undefined8 local_38;
  undefined8 local_30;
  undefined8 local_28;
  long *amnt;
  long local_18;
  long local_10;
 
  local_10 = *(long *)(in_FS_OFFSET + 0x28);
  ints = 0;
  local_40 = 0;
  local_38 = 0;
  local_30 = 0;
  local_28 = 0;
  local_18 = 0;
  amnt = &local_18;
  puts("[sum system]\nInput numbers except for 0.\n0 is interpreted as the end of sequence.\n");
  puts("[Example]\n2 3 4 0");
  read_ints((long)&ints,5);
  uVar1 = sum((long)&ints,amnt);
  if (5 < (int)uVar1) {
                    /* WARNING: Subroutine does not return */
    exit(-1);
  }
  printf("%llu\n",local_18);
  if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) {
                    /* WARNING: Subroutine does not return */
    __stack_chk_fail();
  }
  return 0;
}
```

When we look at the main function, we see that it first establishes an int array `ints`, that can hold 6 integers. The sixth integer in this array is `amnt`, which is a pointer to the next integer on the stack, `local_18`. First it prints out some text, then calls `read_ints`:

```
void read_ints(long ints,long amnt)

{
  int scanfCheck;
  long in_FS_OFFSET;
  long i;
  long stackCanary;
 
  stackCanary = *(long *)(in_FS_OFFSET + 0x28);
  i = 0;
  while (i <= amnt) {
    scanfCheck = __isoc99_scanf(&DAT_00400a68,ints + i * 8,i * 8);
    if (scanfCheck != 1) {
                    /* WARNING: Subroutine does not return */
      exit(-1);
    }
    if (*(long *)(ints + i * 8) == 0) break;
    i = i + 1;
  }
  if (stackCanary == *(long *)(in_FS_OFFSET + 0x28)) {
    return;
  }
                    /* WARNING: Subroutine does not return */
  __stack_chk_fail();
}
```

So here we can see it will scan in integers into the array passed by it's first argument, until it either gets a `0` or it scans in `amnt` + 1 integers. Under the context it is called, it will scan in a maximum of `6` integers into the `ints` array. Proceeding that it calls `sum`, with the arguments being the `ints` array and `amnt`:

```
ulong sum(long ints,long *x)

{
  long in_FS_OFFSET;
  uint i;
  long canary;
 
  canary = *(long *)(in_FS_OFFSET + 0x28);
  *x = 0;
  i = 0;
  while (*(long *)(ints + (long)(int)i * 8) != 0) {
    *x = *(long *)(ints + (long)(int)i * 8) + *x;
    i = i + 1;
  }
  if (canary != *(long *)(in_FS_OFFSET + 0x28)) {
                    /* WARNING: Subroutine does not return */
    __stack_chk_fail();
  }
  return (ulong)i;
}
```

So we can see that it adds up all of the values in `ints`, and stores them in `x`. In the context that it is called, it will add up the six (or less) values stored in `ints`, and store it in `amnt`. In addition to that, there is an integer overflow bug here, since it doesn't check if the values it is adding together will cause an overflow. Since we control `amnt`, we effectively have a write what where. The value returned is the number of numbers it added together. Looking at the rest of the main function, we see that if we gave it six numbers (thus causing the write what where bug), it will call `exit`. If not it will call `printf` and return from main.

## Exploitation

So we have a write what where, with no relro or pie. The first problem is that right after our write, it will call `exit`. This can be solved by just overwriting the got address of `exit` (`0x601048`) with the start of `main` (`0x400903`). That way when it calls `exit`, it will just put us back at the start of `main`. This will give us a loop where we get multiple qword writes.

Now the next hurdle is getting a libc infoleak. At this point, one of my team-mates mksrg gave me the idea to do a stack pivot. When we take a look at the stack layout when `printf` is called (`exit` will also have this), we see something interesting:

```
gef➤  b *0x4009bf
Breakpoint 1 at 0x4009bf
gef➤  r
Starting program: /home/guyinatuxedo/Desktop/sum/sum_ccafa40ee6a5a[PII_REDACTED]36292bf3c84d17264
[sum system]
Input numbers except for 0.
0 is interpreted as the end of sequence.

[Example]
2 3 4 0
159
357
951
753
0
[ Legend: Modified register | Code | Heap | Stack | String ]
────────────────────────────────────────────────────────────────────────────────────── registers ────
$rax   : 0x0               
$rbx   : 0x0               
$rcx   : 0x0               
$rdx   : 0x20              
$rsp   : 0x00007fffffffdee0  →  0x[PII_REDACTED]00009f
$rbp   : 0x00007fffffffdf20  →  0x[PII_REDACTED]4009e0  →  <__libc_csu_init+0> push r15
$rsi   : 0x8ac             
$rdi   : 0x[PII_REDACTED]400ad5  →  0x0100000a756c6c25 ("%llu"?)
$rip   : 0x[PII_REDACTED]4009bf  →  <main+188> call 0x400620 <printf@plt>
$r8    : 0x0               
$r9    : 0x0               
$r10   : 0x00007ffff7b82cc0  →  0x[PII_REDACTED]020002
$r11   : 0x[PII_REDACTED]400a6c  →   add BYTE PTR [rax], al
$r12   : 0x[PII_REDACTED]400670  →  <_start+0> xor ebp, ebp
$r13   : 0x00007fffffffe000  →  0x[PII_REDACTED]000001
$r14   : 0x0               
$r15   : 0x0               
$eflags: [zero CARRY PARITY ADJUST SIGN trap INTERRUPT direction overflow resume virtualx86 identification]
$cs: 0x0033 $ss: 0x002b $ds: 0x0000 $es: 0x0000 $fs: 0x0000 $gs: 0x00