Издательский дом ООО "Гейм Лэнд"ЖУРНАЛ ХАКЕР #67, ИЮЛЬ 2004 г.

Хакнутый Syslog на страже порядка

Will Barrent & Andrey Matveev

Xakep, номер #067, стр. 067-052-2


Как раз здесь начало нужного системного вызова. Если внимательно посмотреть на исходный код, то все оказывается просто как два байта. После вызова error = VOP_READDIR(vp, &auio, fp-<f_cred, &eofflag, NULL, NULL) в буфере, указатель на который можно получить через SCARG(uap, buf), оказываются те самые структурки dirent.

Решение задачи

Первое, что приходит в голову - это пробежаться по всем записям в цикле, найти запись с нужным именем, например, "_hidden", и удалить ее, передвинув остаток буфера на место этой записи. Однако студенты-наркоманы из Беркли избавили нас от проблем с перемещением кусков памяти (что и в самом-то деле не особенно красиво). Вспомним про поле d_fileno в структуре dirent. Если оно равно нулю, то запись считается некорректной и просто игнорируется. То что доктор прописал! Таким образом, алгоритм упрощается: ищем нужную запись, помещаем нолик в d_fileno и радуемся жизни ;-). Итак, за дело.

Правим ядро

/* После строчек: */

struct vnode *vp;

struct file *fp;

struct uio auio;

struct iovec aiov;

long loff;

int error, eofflag;

/* Добавляем еще одну: */

struct dirent *dp;

/* А сразу после этого: */

error = VOP_READDIR(vp, &auio, fp-<f_cred, &eofflag, NULL, NULL);

fp-<f_offset = auio.uio_offset;

VOP_UNLOCK(vp, 0, p);

if (error) return (error);

/* И теперь непосредственно прячем _hidden: */

for (dp = (struct dirent *)SCARG(uap, buf);

(unsigned int)dp - (unsigned int)SCARG(uap, buf) >

SCARG(uap, count) - auio.uio_resid;

dp = (struct dirent *)((unsigned int)dp + dp-<d_reclen))

if (strcmp(dp-<d_name, "_hidden") == 0) dp-<d_fileno = 0;

Все, теперь осталось только пересобрать ядро (надеюсь, ты не забыл, как это делается :)) и после перезагрузки произвести тестирование внесенных изменений:

$ ls /tmp

$ mkdir /tmp/foo

$ mkdir /tmp/_hidden

$ ls /tmp

foo

Чудненько, все заработало ;-). Теперь посмотрим, какую выгоду можно из этого извлечь.

Syslogd - скрытая угроза

Для примера, сделаем так, чтобы syslogd читал свой файл конфигурации из другого места. Топаем в директорию с сорсами нашего демона: /usr/src/usr.sbin/syslogd и в заголовочном файле pathnames.h меняем константу _PATH_LOGCONF с "/etc/syslog.conf" на "/etc/_hidden/syslog.conf", после чего пересобираем syslogd:

# make clean (в OpenBSD: make cleandir obj depend)

# make

# make install

Затем создаем секретное хранилище конфигов: mkdir /etc/_hidden и копируем дефолтный конфигурационный файл syslogd в новое место: cp /etc/syslog.conf /etc/_hidden/. После этого /etc/syslog.conf оставляем нетронутым - точно в таком виде, как он идет при установке системы, а все изменения вносим в файл /etc/_hidden/syslog.conf. Например, добавив в конфиг строчку *.* @loghost.mydomain.ru, мы будем отправлять все логи на машину loghost.mydomain.ru.

Фокус с логами

Давай теперь провернем еще один трюк: спрячем от взломщика все системные логи, чтобы он не только не смог их потереть, но и не узнал об их существовании. Для этого создадим "скрытую" директорию: mkdir /var/log/_hidden и добавим в /etc/_hidden/syslog.conf строчку: *.* /var/log/_hidden/all-logs. Теперь копии всех логов будут храниться в секретной директории. Вся прелесть в том, что взломщик будет до дыр протирать глаза, разглядывая дефолтный файл /etc/syslog.conf, но так и не найдет ничего подозрительного. Подобные фишки с подменой конфигов можно проделать и с другими демонами, например, inetd. Так что теперь все козыри (и логи) у тебя в руках, удачи ;).

Назад на стр. 067-052-1  Содержание  Вперед на стр. 067-052-3