Представьте себе удивление администратора, который не очень понимает, что творит, казалось бы, тривиальная программа ls

X-файлы

Настроился аки Малдер, и... познакомился с продолжением предыдущей истории. Представьте себе удивление администратора, который не очень понимает, что творит, казалось бы, тривиальная программа ls:

[root@exploited home]$ which ls
/bin/ls
[root @exploited home]$ ls /bin/ls
/bin/ls
[root @exploited home]$ cd /bin
[root @exploited /bin]$ ls
...
df        dmesg          kill
nologin   su
...
awk       dnsdomainname   ln
ping	tar
...
bsh       echo           mail
red       true
...
date      gunzip         mv 
sort      zcat
[root @exploited /bin]$

В каталоге /bin было все, что угодно кроме ls. Никакая комбинация типа ls -al|fgrep ls не позволяла обнаружить сам ls. Типичное привидение. Команда ps не обнаруживала наличие каких-либо странностей в поведении системы. Команда top предпочитала выдавать невразумительную диагностику и отползала. Однако подозрение было очевидным (Малдер, однако) - ПРИШЕЛЬЦЫ. Т. е., простите, крекеры.

Подменить достаточное количество команд таким образом, чтобы скрыть абсолютно все, достаточно сложно. Однако как же жить без веры к ls? Я сам неоднократно попадал в ситуации, когда, благодаря неаккуратным действиям системного администратора, не находил ls. Естественно, сработали рефлексы:

echo *,

где «*» отрабатывает shell собственноручно. Поэтому фокусы ls не помешают нам увидеть полный список файлов (естественно, shell тоже можно подменить, но их-то в системе, как правило, много). Более того, echo *|wc и ls|wc выявляет различие в несколько файлов. Ой, а мы-то и не заметили: списки отличаются на ls, ps и netstat. Вот уж угораздило. И c каких это пор?

[root @exploited home]$ ls -al /bin/ls
-rwxr-xr-x   1 root     root
29380  Dec 23  1999 /bin/ls

Неужели с момента установки? Что бы еще спросить?

[root @exploited home]$ ls -lc /bin/ls
-rwxr-xr-x   1 root     root
29380  Nov  8 12:18 ls

Это уже несколько теплее, есть даже повод посмотреть на фрагменты регистрационного файла. Такое любопытство позволило обнаружить некоторую активность в ближайшей сети. Для поиска изменений можно воспользоваться find c ключами -mtime/-ctime:

[root @exploited home]$ find / -ctime -30
...
/bin/ls
...
/bin/netstat
...
/bin/ps
....
/usr/bin/find
....
/usr/bin/top
....

Да, доверие к find тоже падает. Просто везуха, что ls и find позволяют работать с полными именами. Как вы, вероятно, догадываетесь, среди каталогов обнаружилось несколько чрезвычайно подозрительных. Например, каталог с именем «.» — точка с двумя пробелами. Для более детальной проверки ls позволяет использовать ключ -b. По команде cd «.» заходим в этот странный каталог, и ls немедленно становится слепым, в упор не видит ничего в данном каталоге. Команда file * оказалась менее упорной и указала на ряд скриптов и программ, которые, конечно, были немедленно проверены. Видно, что на нашем компьютере поработал товарищ Снифер и составил неплохой список паролей. Тут же обнаружилось, что в списке подмены необходимо проверить и ряд демонов. Что же делать, ps-то врет, а netstat бредит? Как найти процесс? Есть несколько методов. Возможен прямой просмотр cmdline в подкаталогов proc:

[oblakov@test /proc]$ more [1-9]
*/cmdline
::::::::::::::
1/cmdline
::::::::::::::
init [3]
.....

Аналогично можно использовать fgrep, например:

[oblakov@test /proc]$ fgrep -l getty
 [1-9]*/cmdline
1647/cmdline
1649/cmdline

Для борьбы с конкретными портами подходит команда fuser -n tcp 22 и т.п. Заметим, кстати, что отсутствие процесса в списке ps не защищает его от последствий kill -9 ...

История с подключением администратора сети пока еще открыта. Мы же еще раз вернемся к теме предыдущего номера и команде debugfs.

[root@test /root]# debugfs /dev/hda3
debugfs:  ls
2 (12) .   2 (12) ..   11 (20) lost+
found   2049 (12) etc   4097 (12) tmp
...
39190 (16) cdrom   37029 (12) pub 
debugfs:cd /bin
debugfs:  ls
18433 (12) .   2 (12) ..   18451 (16)
 egrep   18452 (16) fgrep
....
18829 (980) nologin
debugfs:  stat mkdir
Inode: 18462   Type: regular    Mode:
  0755   Flags: 0x0   Version: 1
User:     0   Group:     0   Size: 8292
File ACL: 0    Directory ACL: 0
Links: 1   Blockcount: 18
Fragment:  Address: 0    Number: 0
    Size: 0
ctime: 0x369232cb — Tue Jan  5 18:42:03 1999
atime: 0x3a27e409 — Fri Dec  1 20:46:49 2000
mtime: 0x344eaddb — Thu Oct 23 05:52:27 1997
BLOCKS:
74406 74407 74408 74409 74410 74411
 74412 74413 74414
TOTAL: 9
debugfs:  dump
dump: Usage: dump_inode [-p] 
 

Как вы видите, это еще один способ все проверить и, если необходимо, что-то поправить или, для команды dump, сохранить. Для упрощения жизни debugfs имеет команду help и позволяет, достаточно просто бродить по файловой системе. Не думаю, что кто-то использует «эксплойты» для debugfs.

Для тех, кто предполагает, что лозунг кота Леопольда «Давайте жить дружно» несколько преждевременен, появилась новая книга: «Максимальная безопасность в Linux». Книга выпущена издательством DiaSoft. В ней есть ряд изъянов, но она должна быть полезна.

Из замечаний администратора пострадавшего хоста: естественно, вы не должны ограничиваться простейшими командами. Чем больше у вас утилит, тем быстрее вы обнаружите расхождение в их поведении. Дальнейший анализ при помощи mc (его никто не подменял) показал, что данное вторжение было не первым. Один только ls подменяли не менее двух раз. Машина полностью переустановлена.

Масса Солнца

Любому администратору в Unix приходится разбираться с чужими и писать собственные скрипты для массовых операций, т. е. для работы с большим количеством файлов.

Например, попробуем выполнить смену расширения у всех файлов с .h на .c и наоборот.

[oblakov@test temp]$ >a.h
[oblakov@test temp]$ >b.h
[oblakov@test temp]$ for i in *.h
> do
> mv $i `basename $i .h`.c
> done
[oblakov@test temp]$ ls
a.c  b.c
[oblakov@test temp]$ ls *.c | sed
 ?s/^(.*).c$/mv 1.c 1.h/? | sh
[oblakov@test temp]$ ls
a.h  b.h

Все выглядит достаточно пристойным. Попробуем использовать разного рода подстановки. Скажем, решим задачу по выводу информации о всех файлах, которые имеют два подряд идущих одинаковых символа в имени файла:

[oblakov@test oblakov]$ ls -l `ls | sed
 -n -e ?/(.)1/p?`
-rwxr-xr-x   1 oblakov  narod          
4166 Jul 15  1999 hello1
-rw-r—r—   1 oblakov  narod            
29 Jul 15  1999 hello1.c
-rw-r—r—   1 oblakov  narod           
120 Jun 30 17:02 uuu.tar

Отлично сработало. Правда, еще весь каталог uuu выводился - всегда-то что-то забудешь.

Должен ли скрипт подобного рода работать всегда? Ясно, что нет. Стандартная проблема с скриптами подобного рода заключается в выполняемом для команды `` преобразовании - исключение лишних пробелов и переходов на следующую строку. Попробуем показать зубы:

[oblakov@test oblakov]$ >-RR
[oblakov@test oblakov]$ >»a  b»     —
 два, заметим, пробела
[oblakov@test oblakov]$ ls -ld `ls | sed
 -n -e ?/(.)1/p?`
ls: a: No such file or directory
ls: b: No such file or directory
-rwxr-xr-x   1 oblakov  narod          
4166 Jul 15  1999 hello1
-rw-r—r—   1 oblakov  narod            
29 Jul 15  1999 hello1.c
drwxr-xr-x   2 oblakov  narod          
1024 Jun 30 17:01 uuu
-rw-r—r—   1 oblakov  narod           
120 Jun 30 17:02 uuu.tar 
[oblakov@test oblakov]$ ls | sed -n -e
 ?/(.)1/p?
-RR
a  b
hello1
hello1.c
uuu
uuu.tar
[oblakov@test oblakov]$

Как вы видите, ls -ld слопал файл -RR, поскольку принял его за ключ. Файл же «a b» вообще перекосило. Замечу, что создание «ключевых» файлов достаточно типично. Например:

[oblakov@test temp]$ tar -cf -v *
a.h
b.h
[oblakov@test temp]$ ls
-v   a.h  b.h

Вопрос об удалении подобных файлов (-f -r) мы ставили перед читателями еще в первом номере «Открытых систем» за 1999 год. Решений несколько. Один из вариантов предполагает использование множественности «имен» файла:

rm ./-f

Так, однако, с подстановкой у нас был прокол. Проехали.

Еще раз вернемся к вопросу о массовом удалении файлов. Например, удалить все .tmp файлы с модификацией более, чем неделю назад:

find . -type f -name ?*.tmp? -mtime +7
 -print -exec rm {} ;

Условие может быть более сложным. Попробуем другой вариант (только не говорите мне, что -print я пишу зря):

[oblakov@test temp]$ find . -type f -
name «*.tmp» -print | while read a; do
 rm «$a»; done

Как кажется, данный скрипт выполняет аналогичные действия, только без проверки даты. Однако это не совсем так. Если вы попытаетесь удалять данные пользователей при помощи подобного скрипта, то при соответствующем подборе структуры каталогов пользователь сможет уничтожить любой заданный файл (например, /etc/passwd). Это опять же вытекает из того, что в имени файла могут встречаться любые символы за исключением / и нулевого. Значит, возможно появление файла с именем, включающим символ перехода на другую строку — со всеми вытекающими последствиями.

Более миролюбивый пример (попытка удаление файлов с именем длиннее четырех символов):

[oblakov@test temp]$ >»a.h b.h»
[oblakov@test temp]$ ls -b
-v        a.h       a.h b.h  b.h
[oblakov@test temp]$ find . -type f -
name «????*» -print | while read a; do
 rm $a; done
[oblakov@test temp]$ ls -b
-v        a.h b.h
[oblakov@test temp]$ >a.h
[oblakov@test temp]$ >b.h
[oblakov@test temp]$ find . -type f -
name «????*» -exec rm {} ;
[oblakov@test temp]$ ls -b
-v   a.h  b.h
[oblakov@test temp]$ find . -name «-*»
 -exec rm {} ;
[oblakov@test temp]$ ls
a.h  b.h
[oblakov@test temp]$ >«a 
<- здесь мы нажали Enter> b»
[oblakov@test temp]$ ls
a?b  a.h  b.h
[oblakov@test temp]$  find . -name «*b»
 -exec rm {} ;
[oblakov@test temp]$ ls
a.h  b.h

Как вы видите, find справляется с ситуацией несколько лучше. А если возможностей find упорно не хватает, а файлы-таки обрабатывать хочется? Тогда надо либо передавать файл какому-то скрипту в качестве параметра (и очень осторожно с ним работать), либо использовать что-либо наподобие - print0:

[oblakov@test temp]$ > «a
> b»
[oblakov@test temp]$find . -name «*b»
 -print0
./a
b[oblakov@test temp]$ find . -name «*b»
 -print0 | xargs -0 rm
[oblakov@test temp]$ ls
a.h  b.h

В данном случае все работает корректно потому, что разделителем для аргументов от find поступает нулевой символ.

В принципе, find не обязан работать корректно всегда. Этот случай возможен при большой глубине вложенности каталогов. Впрочем, это относится и ко многим другим утилитам. Аналогичные проблемы встречаются и в других операционных системах. В любом случае написание скриптов требует от администратора определенной осторожности, особенно, если его скрипты общедоступны и могут быть кем-либо со всей серьезностью «проанализированы» на пробиваемость. Например, удаление данных пользователя всегда лучше выполнять с правами пользователя — мало ли что он умеет у себя устроить.

Присылайте свои X-файлы по адресу oblakov@bigfoot.com.