Следующая новость
Предыдущая новость

Команда упасть. Эксплуатируем критическую уязвимость в почтовике Exim 4

07.05.2018 13:15
Команда упасть. Эксплуатируем критическую уязвимость в почтовике Exim 4

Содержание статьи

  • Готовим инструменты
  • Работа с кучей
  • На шаг ближе к уязвимости
  • Эксплуатация
  • Демонстрация уязвимости (видео)
  • Выводы

Когда софтина попадает под пристальный взгляд экспертов по безопасности, велика вероятность, что за одним багом найдутся и другие. Так и случилось с агентом пересылки сообщений Exim: вслед за прошлогодней уязвимостью в нем найдена новая опасная дыра, действующая во всех версиях вплоть до последней (4.90.1). Поскольку Exim — штука популярная, список потенциально уязвимых целей просто огромен. Давай посмотрим, как эксплуатировать эту новую находку.

Обнаруженная проблема — это своеобразное продолжение предыдущего бага, который нашел тот же исследователь под ником Meh. На этот раз он раскопал возможность переполнения буфера в функции для работы с кодировкой Base64.

Уязвимость уже обзавелась своим идентификатором CVE-2018-6789 и получила статус критической, потому что приводит к удаленному выполнению любых команд на целевой системе с правами пользователя, от имени которого работает Exim. Причем не нужна ни авторизация, ни какой-либо другой уровень доступа. Нужен только коннект к порту SMTP.

Готовим инструменты

Под эту уязвимость существует добротно настроенный докер-контейнер, так что говорим спасибо товарищу под ником Skysider и запускаем:

$ docker run -it --rm --name exim -p 25:25 --cap-add=SYS_PTRACE --security-opt seccomp=unconfined skysider/vulndocker:cve-2018-6789 

Пробрасываем из Docker стандартный порт, на котором висит SMTP.

Готовый стенд для эксплуатации Exim

Если нужна поддержка дебаггера, то не забудь его установить и перекомпилировать Exim с отладочными символами.

$ apt-get update && apt-get install -y gdb $ cd exim-4.89 $ printf "CFLAGS += -gn" >> Local/Makefile $ make 

Также нам понадобится Python с установленным pwntools для написания и тестирования эксплоита. Я просто разверну еще один докер-контейнер на основе Debian.

$ docker run -it --rm --link=exim debian /bin/bash $ apt-get update && apt-get install -y python python-pip $ pip install pwntools 

Все готово, вперед к победам!

Работа с кучей

Для начала взглянем на саму провинившуюся функцию.

/src/base64.c
153: b64decode(const uschar *code, uschar **ptr) 154: { 155: int x, y; 156: uschar *result = store_get(3*(Ustrlen(code)/4) + 1); 157: 158: *ptr = result; 

За выделение требуемого количества памяти отвечает store_get — кастомная функция из набора для менеджмента памяти, который используется в составе Exim.

/src/store.h
30: #define store_extend(addr,old,new)  31:   store_extend_3(addr, old, new, __FILE__, __LINE__) 32: 33: #define store_free(addr)     store_free_3(addr, __FILE__, __LINE__) 34: #define store_get(size)      store_get_3(size, __FILE__, __LINE__) 35: #define store_get_perm(size) store_get_perm_3(size, __FILE__, __LINE__) 36: #define store_malloc(size)   store_malloc_3(size, __FILE__, __LINE__) 37: #define store_release(addr)  store_release_3(addr, __FILE__, __LINE__) 38: #define store_reset(addr)    store_reset_3(addr, __FILE__, __LINE__) ... 43: extern BOOL    store_extend_3(void *, int, int, const char *, int); 44: extern void    store_free_3(void *, const char *, int); 45: extern void   *store_get_3(int, const char *, int); 46: extern void   *store_get_perm_3(int, const char *, int); 47: extern void   *store_malloc_3(int, const char *, int); 48: extern void    store_release_3(void *, const char *, int); 49: extern void    store_reset_3(void *, const char *, int); 

Во время работы функции выделяется буфер размером 3*(len/4)+1 байт для хранения декодированных данных, где len — длина передаваемых данных.
Такая формула не случайна, так как в стандарте Base64 каждые три исходных байта кодируются четырьмя символами. В идеальных условиях размер переданных данных всегда кратен четырем, но, к счастью, мы живем не в них, и если передать невалидную кодированную строку, то функция store_get получит неверное значение размера выделяемой памяти.

Команда упасть. Эксплуатируем критическую уязвимость в почтовике Exim 4
Размеры выделяемой памяти для валидной и невалидной строки Base64

В общем случае, когда передаем строку размером 4n – 1, Exim зарезервирует 3n + 1 байт, но после декодирования получится строка, итоговый размер которой будет равен 3n + 2 байта, и это вызовет переполнение при попытке записи в выделенный буфер.

Где используется кодировка Base64? Да практически везде. Начиная от разных типов авторизаций и заканчивая файлами, которые прикрепляются к письмам. Все эти вещи потенциально уязвимы. Авторизация нам подходит, так как для отправки сообщений чаще всего потребуется валидный логин и пароль. На тестовом стенде уже включен механизм аутентификации CRAM-MD5, но подойдет и любой другой, который работает с Base64.

Теперь немножко поговорим о работе с памятью. Как я уже писал, в Exim существует самописный набор функций для этих целей. Функция store_malloc — вызов malloc прямиком из библиотеки glibc. Она занимается выделением блока памяти нужного размера.

Продолжение доступно только подписчикам

Материалы из последних выпусков можно покупать отдельно только через два месяца после публикации. Чтобы продолжить чтение, необходимо купить подписку.

Подпишись на «Хакер» по выгодной цене!

Подписка позволит тебе в течение указанного срока читать ВСЕ платные материалы сайта. Мы принимаем оплату банковскими картами, электронными деньгами и переводами со счетов мобильных операторов. Подробнее о подписке

1 год

6790 р.

Экономия 1400 рублей!

1 месяц

720 р.

25-30 статей в месяц

Уже подписан?

Источник

Последние новости