Раскрыты детали критической уязвимости в утилите beep. Изначально проблема была представлена в начале апреля в шуточной форме под именем Holey Beep и была воспринята многими как первоапрельская шутка с сатирой на современные тенденции продвижения информации об уязвимостях. Для Holey Beep был создан отдельный сайт, подготовлен видеоклип, упомянута возможность исправления антивирусами и необходимость обновления браузера. Описание было изложено очень поверхностно в общих словах.
На деле проблема оказалась реальной уязвимостью CVE-2018-0492, позволяющей повысить привилегии до прав root. Функции утилиты beep сводятся к выводу гудка при запуске, при этом во многих дистрибутивах, включая Debian и Ubuntu, утилита установлена с флагом suid root (требуется для доступа к текущему tty при удалённом входе). Найденная уязвимость вызвана состоянием гонки, которое инициируется через обработчик сигналов в момент манипуляции с файловыми дескрипторами консоли и, в случае успеха, позволяет записать 4 байта в любой файл в системе.
В ходе атаки создаётся символическая ссылка на /dev/input/event0, которая передаётся в качестве аргумента опции «—device» (устройство консоли для получения события о начале гудка), инициируется гудок и через очень маленькую специально подобранную задержку символическая ссылка заменяется ссылкой на другой файл, через ещё одну небольшую задержку процессу отправляются сигналы SIGINT и SIGKILL. При обработке сигнала SIGINT происходит вызов функции do_beep() для записи в консоль команды для остановки воспроизведения гудка («write(console_fd, &e, sizeof(struct input_event))»).
Рассчитав задержку так, чтобы вызов SIGINT совпал с выполнением участка кода, в котором содержимое console_fd и console_type (первое поле структуры «e») указывает на некорректные значения, можно записать произвольные 4 байта в файл. Функция play_beep открывает файл с именем console_device, а через несколько строк кода выполняет проверку, что файловый дескриптор открытого файла является устройством («ioctl(console_fd, EVIOCGSND(0)»). Так как один запуск утилиты beep позволяет выполнить несколько гудков и при каждом гудке заново открывается консоль, можно найти такой момент, при котором в console_fd будут отражены параметры нового гудка (дескриптор подменённого файла), а в console_type останется старое значение. При удачном стечении обстоятельств в уже подменённый файл будет записано 4-байтовое значение со временем, содержимое которого можно контролировать через опцию «-l».
Операции повторяются в цикле пока не удастся поймать состояние гонки. Для получения прав root, в ходе работы эксплоита ссылка на /dev/input/event0 подменяется ссылкой на файл /etc/profile или /etc/bash/bashrc и производится запись 4 символов «/*/x», которые при запуске очередного root-сеанса приведут к выполнению заранее подготовленного скрипта /tmp/x. Для тестирования подготовлен рабочий эксплоит. Для исправления проблемы подготовлен патч. Дистрибутивам рекомендуется убрать флаг suid с утилиты beep или последовать примеру дистрибутива SUSE и заменить beep на shell-заглушку с командой ‘echo -en «