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

Отправляем команды. Как заставить популярный серверный почтовик выполнять произвольный код

25.07.2019 13:02
Отправляем команды. Как заставить популярный серверный почтовик выполнять произвольный код

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

  • Стенд
  • Детали уязвимости и локальная эксплуатация
  • Удаленное выполнение команд и ограничения
  • RCE при использовании конфига по умолчанию
  • Заключение

В этой статье я расскажу об уязвимости в агенте пересылки сообщений Exim. Найденная брешь позволяет атакующему выполнить произвольный код на целевой системе, что само по себе очень опасно, а если Exim был запущен от рута, то успешная эксплуатация позволяет получить максимальный контроль над системой.

Я уже дважды писал об RCE в этом почтовом сервере: один раз — в 2017 году, второй — в 2018-м. Оба раза для успешной эксплуатации нужно было разбираться со смещениями, кучами и прочей бинарщиной. В этот раз для проведения атаки достаточно просто отправить письмо через уязвимый Exim на специально сформированный адрес, содержащий пейлоад.

Если вкратце, то атака основана на внедрении произвольных сущностей в expanded strings, в заголовки RCPT TO и MAIL FROM. Она позволяет злоумышленнику передать специально сформированную строку как email-адрес, и та будет интерпретирована почтовым сервисом как системная команда.

INFO

Баг обнаружили специалисты из Qualys в конце мая этого года. Он получил номер CVE-2019-10149 и затрагивает все версии Exim с 4.87 до 4.91 включительно.

Стенд

Для создания тестового окружения воспользуемся контейнером Docker. На момент публикации уязвимости пакеты Exim, которые лежали в репозитории Debian, содержали данную брешь. Они уже запатчены, поэтому нам нужно будет собрать уязвимую версию из исходников.

$ docker run -it --rm -p25:25 --name=eximrce --hostname=eximrce --cap-add=SYS_PTRACE --security-opt seccomp=unconfined debian /bin/bash 

Расшариваем 25-й порт наружу, чтобы в дальнейшем можно было протестировать удаленную атаку. Помимо этого, добавляем флаги, чтобы можно было отлаживать приложение.

Теперь устанавливаем необходимые зависимости для успешной компиляции.

$ apt-get install -y exim4 build-essential git libdb5.3-dev libpcre3-dev libgnutls28-dev libgcrypt-dev wget netcat nano procps gdb 

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

Выполняем базовую настройку почтового сервера.

$ dpkg-reconfigure exim4-config 
Отправляем команды. Как заставить популярный серверный почтовик выполнять произвольный код
Первичная настройка Exim4

Важный параметр — Domains to relay mail for. Запомни его, я вернусь к нему на этапе удаленной эксплуатации.

Теперь воспользуемся репозиторием Exim4 на GitHub и клонируем последнюю уязвимую ветку — 4.91.

$ git clone --depth=1 -b exim-4_91 https://github.com/Exim/exim.git $ cd exim/src $ mkdir Local 

Скопируем дефолтный шаблон мейкфайла.

$ cp src/EDITME Local/Makefile 

В него нужно внести пачку изменений для того, чтобы скомпилировать максимально соответствующий существующему конфигу бинарник.
Сначала укажем имя пользователя, от которого будет работать Exim. Если ставить из репозиториев, то скрипт установки создает пользователя Debian-exim. Его и указываем.

$ sed -i 's,^EXIM_USER.*$,EXIM_USER=Debian-exim,' Local/Makefile 

Отключаем Exim Monitor, так как это графическая утилита для просмотра информации о работе демона и в консоли она нам совершенно ни к чему.

$ sed -i 's,^EXIM_MONITOR=.*$,# EXIM_MONITOR=,' Local/Makefile 

Указываем директорию, в которой лежат бинарники.

$ sed -i 's,^BIN_DIRECTORY=.*$,BIN_DIRECTORY=/usr/sbin,' Local/Makefile 

Теперь указываем путь до файла конфигурации. Я сгенерировал его через утилиту exim4-config, которая записывает его в /var/lib/exim4/config.autogenerated.

$ sed -i 's,^CONFIGURE_FILE=.*$,CONFIGURE_FILE=/var/lib/exim4/config.autogenerated,' Local/Makefile && 

Дальше идут не особенно важные настройки.

sed -i 's,^# SUPPORT_MAILDIR,SUPPORT_MAILDIR,' Local/Makefile &&  sed -i 's,^# SUPPORT_MAILSTORE,SUPPORT_MAILSTORE,' Local/Makefile &&  sed -i 's,^# SUPPORT_MOVE_FROZEN_MESSAGES,SUPPORT_MOVE_FROZEN_MESSAGES,' Local/Makefile &&  sed -i 's,^# SUPPORT_TLS=,SUPPORT_TLS=,' Local/Makefile &&  sed -i 's,^# USE_GNUTLS=,USE_GNUTLS=,' Local/Makefile &&  sed -i 's,^# TLS_LIBS=-lgnutls,TLS_LIBS=-lgnutls,' Local/Makefile &&  sed -i 's,^# LOOKUP_CDB,LOOKUP_CDB,' Local/Makefile &&  sed -i 's,^# LOOKUP_DSEARCH,LOOKUP_DSEARCH,' Local/Makefile &&  sed -i 's,^# LOOKUP_NIS,LOOKUP_NIS,' Local/Makefile &&  sed -i 's,^# LOOKUP_NISPLUS,LOOKUP_NISPLUS,' Local/Makefile &&  sed -i 's,^# LOOKUP_PASSWD,LOOKUP_PASSWD,' Local/Makefile &&  sed -i 's,^# TRANSPORT_LMTP,TRANSPORT_LMTP,' Local/Makefile &&  sed -i 's,^# AUTH_CRAM_MD5,AUTH_CRAM_MD5,' Local/Makefile &&  sed -i 's,^# AUTH_PLAINTEXT,AUTH_PLAINTEXT,' Local/Makefile &&  sed -i 's,^# HAVE_IPV6,HAVE_IPV6,' Local/Makefile 

Изменяем директорию, в которую будет складываться очередь писем для отправки.

$ sed -i 's,^/var/spool/exim,/var/spool/exim4,' Local/Makefile 

И последнее изменение — нужно добавить флаг -g, если ты хочешь отлаживать приложение.

$ printf "CFLAGS  += -gn" >> Local/Makefile 

Дальше дело за компиляцией.

$ make 
Отправляем команды. Как заставить популярный серверный почтовик выполнять произвольный код
Успешная компиляция Exim 4.91

После того как приложение успешно скомпилено, нужно заменить бинарник Exim, который я ставил из репозитория Debian.

$ mv /usr/sbin/exim4 /usr/sbin/exim4_orig && cp -f /root/exim/src/build-Linux-x86_64/exim /usr/sbin/exim4 

Стенд готов. Теперь ты можешь запускать демон Exim в качестве сервиса или напрямую из командной строки с выводом информации о работе в консоль.

$ exim4 -bdf -d+all 

Детали уязвимости и локальная эксплуатация

Сначала я расскажу о самом простом способе эксплуатации — локальном. Попутно разберем, в чем же именно причина уязвимости.

В окружении сервера Exim есть такое понятие, как String Expansion. Грубо говоря, это аналог макросов, как в разных шаблонизаторах. Строки специального вида, которые обрабатываются парсером Exim. Среди множества команд и функций, которые доступны в рамках String Expansion, имеется вызов внешней программы — run.

${run{<команда> <аргументы>}{<string1>}{<string2>}} 

Сам парсинг выполняется функцией expand_string.

src/src/expand.c
7659: uschar * 7660: expand_string(uschar * string) 7661: { 7662: return US expand_cstring(CUS string); 7663: } 
src/src/expand.c
7640: const uschar * 7641: expand_cstring(const uschar * string) 7642: { 7643: if (Ustrpbrk(string, "$\") != NULL) 7644:   { 7645:   int old_pool = store_pool; 7646:   uschar * s; 7647: 7648:   search_find_defer = FALSE; 7649:   malformed_header = FALSE; 7650:   store_pool = POOL_MAIN; 7651:     s = expand_string_internal(string, FALSE, NULL, FALSE, TRUE, NULL); 7652:   store_pool = old_pool; 7653:   return s; 7654:   } 7655: return string; 7656: } 

Среди огромного количества мест, где она вызывается, есть такое место и в deliver_message.

src/src/deliver.c
5505: int 5506: deliver_message(uschar *id, BOOL forced, BOOL give_up) 5507: { ... 6224: #ifndef DISABLE_EVENT 6225:       if (process_recipients != RECIP_ACCEPT) 6226:   { 6227:   uschar * save_local =  deliver_localpart; 6228:   const uschar * save_domain = deliver_domain; 6229: 6230:   deliver_localpart = expand_string( 6231:             string_sprintf("${local_part:%s}", new->address)); 6232:   deliver_domain =    expand_string( 6233:             string_sprintf("${domain:%s}", new->address)); 6234: 6235:   (void) event_raise(event_action, 6236:             US"msg:fail:internal", new->message); 6237: 6238:   deliver_localpart = save_local; 6239:   deliver_domain =    save_domain; 6240:   } 

Как видишь, эта ветка компилируется в случае, когда символическая константа DISABLE_EVENT не определена. Так оно и есть, начиная с версии 4.87 Events — полноправная часть Exim и используются по умолчанию.

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

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

Присоединяйся к сообществу «Xakep.ru»!

Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», увеличит личную накопительную скидку и позволит накапливать профессиональный рейтинг Xakep Score! Подробнее

1 год

7690 р.

1 месяц

720 р.

Я уже участник «Xakep.ru»

Источник

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