# Forced Puns
Let's do a `file` as a first thing:```bash$ file ./app/forced-puns./app/forced-puns: ELF 64-bit LSB  shared object, ARM aarch64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 3.7.0, BuildID[sha1]=a677e5ead33f8ac9d3948e8157cdcfa39b3f9701, not stripped```
Aarch64, never seen its assembly before, but there's always a first time.Let's load it with r2.
```$ r2 -AA ./app/forced-puns
[0x00000e20]> e asm.emu=true[0x00000e20]> e asm.emustr=true[0x00000e20]> e asm.describe=true # this was really helpful for me to have an idea of what instructions do
[0x00000e20]> s main```
I spent a lot of time trying to run the binary. At the end I used`qemu-aarch64-static` on a Debian vagrant box, attaching gdb to do somedebugging during the exploitation.
Playing with the binary a little bit, I noticed that there was a buffer overflowwhen creating a new entry with a name longer than 232 bytes.
```$ qemu-aarch64-static -g 12345 -E LD_PRELOAD=./lib/aarch64-linux-gnu/libc.so.6 -L ./lib ./app/forced-puns$ gdb-multiarch ./app/forced-puns> target remote localhost:12345> c```
The segfault is happening in the function `end_of_entry`. Thanks to thisfunction I was able to understand a little bit the structure allocated on theheap, that was something like this:
```// size of the structure is 256struct entry {	char *large;	long small;	struct entry *next;	char name[232];}```
It seems like `end_of_entry` segfaults because my input ends up in the `next` fieldof the next entry I was going to allocate. That function is called everytimeyou set the name of a new entry to know the place the input will be copied to.So if I can put in the `next` field the address of the printf got (or anyother function) I can execute the code I want.
But first we should get some leaks, because ASLR is enabled and the binary isPIE. Setting the `large` field of an entry and printing it allows you to get theaddress of a chunk of memory in the heap. Moreover when you print an entry, thesmall value is printed as "%s" and this allows you to leak other addresses. Iused the overflow in the name to overwrite the `small` field of the next entry,so that I could get the leak when printing the entries.
But how to know where the binary was loaded? Looking at the heap I saw a pointerto `end_of_entry`, that I used to get a leak of the binary address and, afterthat, I used the got entries in the binary to leak addresses of the libc.
At this point I had every address I wanted, I just needed to find a functionpointer to overwrite. At first I tried to overflow something in .got.plt, but Irealized I couldn't do that because some requirements were needed in order forthe overwrite to work as expected. This is more or less what `end_of_entry` doesand how it's used:```struct entry *end_of_entry(struct entry *root) {	while (root->next) {		root = root->next;	}	return root;}
struct entry *p = end_of_entry(root_ptr);strcpy(p->name, input);```
The idea was to to overwrite the `next` field of an entry in such a way that`end_of_entry` would return the value where I wanted to overwrite (minus 0x18,the offset of the field name in the structure `entry`). In order for this towork, there has to be a 0 in the qword just before the address I want tooverwrite, so that it will be interpreted as the `next` field of the entry andthe fake entry would be considered the last one. So I couldn't really writeeverywhere...
I tried to overwrite the `end_of_entry` pointer at the start of the heap, butbecause of some differences in the memory layout between my local environmentand the one on the server I wasn't able to solve the challenge in this way.
After a while I found a pointer to a pointer to the `end_of_entry` function (inthe .got) and luckily it was preceeded by a 0. I then use my write primitive toput in the bss the address of the system (and the address of the bss where i putthe address of the system). Now, whenever the program calls `end_of_entry` itwould instead call system. Last thing I needed to do was to make root points tothe `/bin/sh` string, but it was quite easy at this point to overwrite the firstbytes of the first entry in the heap to insert the string.
You can find the full exploit in exp.py.
As a side note, r2 was able to get the name of the library functions called inthe binary, while IDA didn't. :P