Современные решения ИТ задач и программной инженерии

Проактивная защита веб сервера на bash и ipfw таблицах (часть 2)

08.07.2015 в разделах ОбучениеБезопасностьс тегами scriptingbashfreebsdnix
Проактивная защита веб сервера на bash и ipfw таблицах (часть 2)
Продолжаем вчерашнюю статью, завершим наш скрипт и научим его блокировать IP адреса по условиях. Не забываем настроить фаервол и какую то свободную таблицу.

По сути мы все уже сделали в предыдущей статье. Давайте рассмотрим как мы будем управлять таблицами IPFW. Опять таки, предполагаем что вы имеете некоторые знания в работе с IPWF. Нам нужна только функция добавления и очистки всей таблицы. Смотрите, мы будем точечно добавлять IP адреса в таблицу для блокировки а с очисткой не будем сильно мудрить. Очищать всю таблицу будем один раз в час. Да, таблицу заблокированных IP адресов нужно иногда очищать, так как этот адрес через некоторое время может оказаться совсем у другого человека.

Пишем небольшой скрипт и ставим его в crontab на запуск каждый час

#!/bin/sh

ipfw table 5 flush

Теперь по крону наш скрипт каждый час будет очищать таблицу 5 и тем самым открывать все заблокированным IP адресам доступ к серверу.

Рассмотрим теперь как мы будем блокировать точечные IP адреса. Воспользуемся командой:

ipfw table 5 add 255.255.255.255

Как вы уже догадались, эта запись добавит некий IP адрес 255.255.255.255 в таблицу 5. В свою очередь IPFW в режиме реального времени держит все в памяти и подчитывает все мгновенно, сразу после добавления. Выполнив данную команду, можно быть уверенным что доступ к серверу для этого IP закрыт. Конечно же при условии что вы настроили IPFW для блокировки таблицы 5 как написано было в предыдущей статье.

Все почти готово. Давайте определимся как мы будем сравнивать строки и писать условия. Можно это делать обычными IF-ами плюс воспользоваться кейсом (CASE), оператором выбора. Давайте напишем ради примера блокировку всех кто пытается обратится к главной странице панели управления сайтом на Wordpress коим сайт не является.

Немного теории. У нас сайт не на Wordpress но злоумышленники пытаются все же бездумно брутить, обращаться к главной странице панели управления, а именно к файлу "/wp-login.php". Так как у нас не Wordpress, то при обращении к такому файлу, которого нету, сервер ответит ошибкой с кодом 404. Так вот, напишем правило, которое будет блокировать все такие обращения на 1 час. Аналогичным образом можно написать и защиту от брута, если у вас тот же Wordpress, или защиту от эксплоитов, смотря на POST данные и т. д. POST данные по умолчанию не пишутся в файл логов веб сервера но это можно легко включить при надобности. Итак, приступим к практике.

#!/bin/sh

tail -f /var/log/apache-access.log | while read line; do
  param_ip=`echo "$line" | grep -o '^[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}'`

  param_protocol=`echo "$line" | grep -o '".*"'`
  param_protocol=`echo "$param_protocol" | sed 's/^"//'`
  param_protocol=`echo "$param_protocol" | grep -o '.*" [0-9]{3}'`
  param_protocol=`echo "$param_protocol" | sed 's/" [0-9]{3}$//'`

  param_method=$(echo $param_protocol | cut -f1 -d' ')

  param_query=$(echo $param_protocol | cut -f2 -d' ')

  param_version=$(echo $param_protocol | cut -f3 -d' ')

  param_code=`echo "$line" | grep -o '".*"'`
  param_code=`echo "$param_code" | sed 's/^"//'`
  param_code=`echo "$param_code" | grep -o '.*" [0-9]{3}'`
  param_code=`echo "$param_code" | sed 's/^.*" //'`

  param_reff=`echo "$line" | grep -o '".*"'`
  param_reff=`echo "$param_reff" | sed 's/^"//'`
  param_reff=`echo "$param_reff" | grep -o '".*'`
  param_reff=`echo "$param_reff" | sed 's/^" [0-9]{0,9} [0-9]{0,9} //'`
  param_reff=`echo "$param_reff" | grep -o '".*" '`
  param_reff=`echo "$param_reff" | sed 's/^"//'`
  param_reff=`echo "$param_reff" | sed 's/" $//'`

  param_useragent=`echo "$line" | grep -o '".*"'`
  param_useragent=`echo "$param_useragent" | sed 's/^"//'`
  param_useragent=`echo "$param_useragent" | grep -o '".*'`
  param_useragent=`echo "$param_useragent" | sed 's/^" [0-9]{0,9} [0-9]{0,9} //'`
  param_useragent=`echo "$param_useragent" | grep -o ' ".*"'`
  param_useragent=`echo "$param_useragent" | sed 's/^ "//'`
  param_useragent=`echo "$param_useragent" | sed 's/"$//'`

  vr_ban_ip=0
  if [ "$param_method" = "GET" ]; then
    if [ "$param_code" = "404" ]; then
      case "$param_query" in
        /wp-login.php* ) vr_ban_ip=1;;
        /wp-admin* ) vr_ban_ip=1;;
      esac
    fi
  fi

  if [ "$vr_ban_ip" = "1" ]; then
    ipfw table 5 add "$param_ip"
    echo "IP: $param_ip IS BANNED!"
  fi

  echo "IP: $param_ip"
  echo "PROTOCOL: $param_protocol"
  echo "METHOD: $param_method"
  echo "QUERY: $param_query"
  echo "VERSION: $param_version"
  echo "STATUS CODE: $param_code"
  echo "REFFERER: $param_reff"
  echo "USERAGENT: $param_useragent"
  echo ""
done

Мы модифицировали наш скрипт из предыдущей статьи и научили его блокировать по условию. Смотрим, что мы дописали. Два вложенных IF-а внутри которых кейс, оператор выбора. Кейс нам позволит сравнивать строки "со звездочкой", без точного совпадения строки.

Логика очень проста, у нас есть переменная vr_ban_ip которая по умолчанию равна нулю. Если все условия совпадают, мы записываем в эту переменную единицу. В конце смотрим, если в этой переменной записана единица, баним текущий IP, то есть записываем его в IPWF таблицу 5.

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