Тайм-менеджмент для системных администраторов - [82]
Итак, у вас есть источник информации. Преобразуем ее так, чтобы ею можно было воспользоваться.
Во-первых, изолируем те строки вывода, которые нас интересуют. В данном случае это строки, содержащие «arp who-has»:
>$ sudo tcpdump — l -n arp | egrep 'arp who-has'
Мы можем запустить эту команду и убедиться, что она ведет себя, как ожидалось. Единственная проблема в том, что команда работает безостановочно, пока мы не нажмем CtrL–C. Мы хотим получить достаточное количество строк и затем обработать их. Ограничимся первой сотней строк:
>$ sudo tcpdump — l -n arp | grep 'arp who-has' | head -100
Снова запустим команду и убедимся, что все хорошо. Во время тестирования этой команды у меня не хватило терпения, и я изменил 100 на 10.
Это дало мне уверенность, что команда работает правильно, и в окончательном варианте я поставил 100. Вы, конечно, заметите в выводе кучу заголовков. Они направляются в поток stderr (прямо на экран) и не передаются в команду gгер.
Итак, у нас есть сто строк с интересующими нас данными. Настало время статистических подсчетов. Какие хосты генерируют больше всего ARP-пакетов? Нам нужно выделить IP-адреса всех хостов, сгенерировавших ARP-пакет, и как-то подсчитать их количество. Начнем с выделения IP-адресов. Это шестое поле каждой строки, и мы можем воспользоваться следующей командой:
>awk '{ print $6 }'
Этот маленький фрагмент кода awk является прекрасной идиомой для выделения конкретного поля из каждой строки текста.
Должен сознаться, что мне было лень подсчитывать, в каком поле находятся данные, которые я хотел выделить. Было похоже, что это пятое поле, и я сначала пробовал указать $5. Не сработало, тогда я указал $6. Конечно! Мне следовало помнить, что в awk поля нумеруются с единицы, а не с нуля. Преимущество тестирования командной строки на каждом шаге в том и заключается, что мы достаточно рано обнаруживаем такие мелкие ошибки. Представьте, что было бы, если бы я написал всю командную строку сразу, а затем стал бы искать эту ошибку!
Я ленив и нетерпелив. Мне не хотелось каждый раз ждать, пока будут собраны все сто ARP-пакетов. Поэтому я сохранил их один раз и затем использовал эти результаты.
Я сохранил результаты во временном файле:
>$ sudo tcpdump — l -n arp | grep 'arp wno-has' | head -100 >/tmp/x
Затем я применил свой код awk к этому временному файлу:
>$ cat /tip/x | awk '{ print $5 }'
>tell
>tell
>tell
>tell
Оказывается, мне нужно не пятое поле. Попробуем шестое:
>$ cat /tmp/х | awk '{ print $6 }'
>192.168.1.110
>192.168.1.10
>192.168.1.92
>…
Да, так лучше.
Как бы то ни было, впоследствии я понял, что можно ублажать свою лень другим способом. Конструкция $NF обозначает последнее поле и позволяет мне вообще ничего не подсчитывать:
>$ cat /tmp/x | awk '{ print $HF }'
>192.168.1.110
>192.168.1.10
>192.168.1.92
А почему не $LF? Ну, это было бы слишком просто. А если серьезно, NF означает «number of fields» (количество полей). То есть $NF обозначает NF-e поле слева. Но все это неважно. Просто запомните, что, если вам нужно последнее поле в строке, вы можете добавить $NF в awk:
>$ sudo tcpdump — l -n arp | egrep 'arp who-has' \
>| head -100 | awk '{ print $NF }'
Итак, на выходе мы получаем список IP-адресов. Проверьте это.
(Именно так! Проверьте. Я подожду.)
Теперь мы хотим подсчитать, сколько раз каждый IP-адрес появляется в нашем списке. Есть одна идиома, которую я всегда применяю именно для этой цели:
>sort | uniq — с
Она сортирует данные, а затем выполняет команду uniq, которая исключает повторения из отсортированного списка. (То есть технически она устраняет повторения соседних строк, а сортировка списка гарантирует, что одинаковые строки будут соседствовать.) Флаг — с включает подсчет повторений и вставляет это число в начало каждой строки. Результат выглядит так:
>…
>11 192.168.1.111
> 7 192.168.1.230
>30 192.168.1.254
> 8 192.168.1.56
>21 192.168.1.91
>…
Мы почти у цели! Мы знаем, сколько ARP-пакетов отправил каждый хост. Последнее, что мы должны сделать, — это отсортировать список, чтобы выявить самые «общительные» хосты. Для этого добавляем в конец канала конструкцию | sort — n, которая выполнит сортировку по номеру:
>$ sudo tcpdump — l -n arp | egrep 'arp who-has' | head -100 \
>| awk '{ print $NF }' | sort | uniq — с | sort — n
Выполнив эту команду, мы увидим отсортированный список. Если сеть не очень загружена, выполнение команды займет какое-то время.
В локальной сети из 50 компьютеров, когда было мало пользователей, мне понадобилось около часа. Но это было уже после обнаружения компьютеров со шпионскими программами и их очистки. Перед этим на сбор ста ARP-пакетов я потратил всего несколько минут.
В вашей домашней сети с одним или двумя компьютерами на выполнение команды может уйти несколько дней. Хосты кэшируют информацию, собранную ими с помощью ARP-запросов. Поэтому, поработав некоторое время, компьютер крайне редко отправляет ARP-пакеты,[9] если единственный компьютер, с которым он общается (в локальной сети), — это ваш маршрутизатор.
Зато в сети из ста хостов подозреваемые обнаруживаются достаточно быстро.
Теперь в вашем распоряжении имеется простой инструмент обнаружения атаки червей. Он не заменит тысячедолларовую систему распознавания атак и хорошую антивирусную программу, но, безусловно, поможет вам локализовать проблему, если она возникнет. Главное — он бесплатный, а вы узнали кое-что новое о программировании оболочки.