Пользователь
0,0
рейтинг
7 января 2012 в 19:27

Разработка → Уязвимости серверов к медленному чтению из песочницы

Приветствую.
Хочу рассказать, чем я баловался в свободное от работы в Qualys время. Так как в англоязычном интернете на удивление много шума про Slow Read DoS attack, и уверен что получу здесь много полезной критики и дельных предложений.

В августе 2011 года написал програмку slowhttptest, которая тестирует веб-серверы на наличие уязвимостей, связанных с обработкой медленных HTTP запросов, таких как slowloris и slow HTTP Post. Цель — создать конфигурируемый инструмент, облегчающий работу разработчиков и позволить им концентрироваться на создании эффективных защит, а не ковырянии в питоне, на котором написаны большинство proof-of-concept эксплоитов.

А потом решил попробовать, как реагируют серверы на медленное чтение клиентами HTTP респонсов. На удивление плохо реагируют. Дефолтные apache, nginx, lightpd, IIS отказывают в обслуживании на ура.

А суть такова:

если найти ресурс на веб сервере, который размером больше send buffer-a, который ядро выделило для соединения, в который серверная программа пошлет ресурс, то если каким то образом вынудить ядро не принимать все данные — сервер будет пытаться послать оставшийся кусок данных, занимая ограниченную в размере очередь соединений, процессорное время, память, и свободное время сисадмина. Если забить такими соединяниями всю очередь — сервер, соответственно начнет отказывать в обслуживании быстрым клиентам.

Заставить ядро себя так вести довольно просто и описано было еще в 2008 году ребятами из Outpost24 в методе Sockstress: например, посылать в TCP пакете размер окна равным 0, т.е. у клиента нет места для приема данных. Дизайн TCP правильно подразумевает, что приложение, а не ядро обязано контролировать медленные и мертвые соеднинения. Однако за 4 года никто не пошевелил пальцем.

Sockstress вручную создает пакеты, высчитывает, когда послать очередное подтверждение, чтоб не ресетнуть persist timer на сервере, сложно короче.
Мой метод даже школьник в состоянии реализовать на практике:
Создаете сокет, задаете сравнительно малый размер receive buffer-а на клиенте, посылаете совершенно целостный и нормальный HTTP запрос на картинку размером 100Кб, например. Сервер берет картинку из памяти, дает ядру, чтоб тот передал ее в сеть. Сервер берет кусок картинки и шлет, клиент принимает первые тыщу байт, и говорит стоп, места нету. Сервер poll-ает сокет, пытаясь понять когда он будет готов к записи, а он не готов! Раз в минуту читаете пару байтов из клиентского receive buffer, чтоб TCP стек послал что то отличное от нуля, тем самым создав видимость живого соедниения для файрволов и IDS-ов.

Вот и все. Прошу сильно не пинать, первый технический пост на русском, но хабр нравится, неудержался. Детальное описание можно найти здесь.
P.S. Для предыдущей версии slowhttptest написал вики по-русски, если хоть одной душе интересно, переведу и для новой версии.

Update:
ModSecurity подсуетилась, детально показывают как защищаться:
ModSecurity Advanced Topic of the Week: Mitigation of 'Slow Read" Denial of Service Attack
Update 2:
Semy указал на ошибки сборки на BSD. Исправил в svn.
Сергей @Pushkind
карма
42,0
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Спецпроект

Самое читаемое Разработка

Комментарии (74)

  • –8
    Nginx не поможет?
    • +16
      Дефолтные apache, nginx, lightpd, IIS отказывают в обслуживании на ура.


      Но зачем же читать статью? ;)
      • 0
        Статья подразумевалась информационной, без обсуждения защиты, там по ссылке внизу есть пара советов. В кратце:
        — надо дропать соединения с ненормально маленьким advertised окном. iptables например
        — надо на уровне приложения ограничивать время соединения, в независости от состояния соединения. ModSecurity, flying frog
      • 0
        Как понять «дефолтные»?
        Это которые у большинства стоят или с какими-то настройками из коробки?
        • 0
          из коробки.
          • 0
            Вдобавок, эи самые настройки из коробки многими не особо меняются
  • 0
    Он требует меньше ресурсов для поддержания того же количества одновременных соединений, т.е. можно отдалить DoS, но глобально — не поможет.
    • 0
      И что делать с такими слоу-поками?
  • +12
    А ваш сервер уяязвииииимм к мееееееееееедлееееееннномууууу…
  • НЛО прилетело и опубликовало эту надпись здесь
    • +18
      даже школьник в состоянии реализовать данный метод на практике.
      • НЛО прилетело и опубликовало эту надпись здесь
        • –1
          исправил, спасибо
          • +32
            Зачем? Было вполне нормальное предложение.
    • +2
      Господа, позвольте спросить, а за что минусуете человека? Не поняв он вполне корректно задал вопрос в комментарии, получил ответ.
      Интересно что вопрос минусуют, а ответ нет, хотя, если расценить вопрос как недостойный хабра, то, думаю, и ответ на него тоже должен минусоваться.
      • НЛО прилетело и опубликовало эту надпись здесь
      • +18
        Думаю, причины две:
        1. Потому что это совершенно тупая придирка ко вполне легитимной языковой конструкции. В данном контексте союз «и» вполне имеет право использоваться.
        2. Потому что такие формулировки, когда человек нарочито корчит из себя идиота, пытаясь показать этим свое «превосходство» у нормальных людей вызывает страшнейшее раздражение. «Что такое „и школьник“?» — ну кем надо быть, чтобы такое спросить? Не нравится формулировка? Так и напиши, что ты считаешь союз «и» тут неуместным. И напиши в личку. А не засирай каменты своей псевдоязвительностью.
        • НЛО прилетело и опубликовало эту надпись здесь
          • +12
            1. Она может означать, теоретически, что угодно, но человеку мозг на то и дан, чтобы понимать смысл многозначных выражений в зависимости от их контекста. А уж тем более, когда в ряду стоят слова «метод» и «школьник», которые относятся к совршенно разным категориям понятий — никаких неоднозначностей тут не возникает. Что же, в таком случае, с вашим «языковым парсером» должна сделать фраза «скрипт обходит дерево»? Уж не спросите ли вы, кто такой скрипт и зачем он ходит вокруг дерева?

            2. Если эта фраза действительно вызывает у вас непонимание — вам стоит обратиться к врачу, это явно что-то неврологическое.
            • НЛО прилетело и опубликовало эту надпись здесь
              • +12
                приятного бана ))
                • НЛО прилетело и опубликовало эту надпись здесь
        • –5
          Мне не понятно вот что. Допустим вопрос идиотский, но почему же другого идиота, который на этот вопрос ответил плюсуют. Вот что мне непонятно.
          • +4
            Ну, отвечать на идиотские вопросы, вроде как, не преступление)
            • +3
              Всё-таки я ошибся, и отвечать действительно не стоило.
              • +1
                Наверное, не стоило быть таким самокритичным и называть себя идиотом в третьем лице. Не думаю, что многие минусовавшие ваши последние комменты в этом треде, смотрели что это отвечаете вы же, и не исключено, что один коммент (с ответом) плюсовали, а другие (с вопросами почему минуса изначальному вопросу), причем к минусам к комменту и в карму не поленились добавить.
                • +6
                  Да мне то не жалко, я о том что человек которого я защищал и думал что он будет вести себя адекватно перешёл на личности и оскорбления.
                  • НЛО прилетело и опубликовало эту надпись здесь
                    • 0
                      Люди которые вас оскорбляли не достойны внимания, как только оскорблять стали вы, вы им стали такими же.
                      ответить тем же

                      недостойное поведение.
  • +4
    ipfw add allow ip from any to me 80 setup limit src-addr 40
    Пусть хоть уконнектятся :).
    Ну и никто не отменял tcpdrop по таймеру.
    • +3
      это несерьезно:) Огромные конторы сидят на одном внешнем IP, браузер минимум два соединения делает (favicon), дропать соединия тоже некрасиво как то, лучше в очередь поставить.
      tcpdrop лучше, но тогда реально медленные клиенты, которые аплодять фотку у эйфелевой башни будут жаловаться.
      iptables ом можно дропать SYN пакеты с advertised window меньше чего то. Сейчас не видел систему, посылающуью менее 65К.
      • 0
        бред, отлично работает, никто не жалуется (на хостинге по-крайней мере), любой браузер будет ждать возможности открыть соединение (проверено на опере, загрузка идет последовательно), оно не дропается, просто к ip не делается подключение пока не закрыты предыдущие соединения, может отвалиться по таймауту.
        ipfw тоже имеет и tcpdatalen и tcpwin и другие прелести.
        • 0
          я так понимаю ipfw посылает или RST или FIN немедленно, если условие соблюдено. логика ставить соединение в очередь там врядли есть. Но спасибо за ipfw, я про него не знал. tcpdatalen и tcpwin тоже полезны. ipwf это только BSD?
          • +1
            ipfw ничего не посылает. ни rst ни fin, просто ждет.
            не только бсд.
          • +1
            ipfw – и на производных и в Ubuntu портировано. И даже на Windows замечено! ;-)
        • 0
          limit src-addr мне тоже кажется не совсем корректным. tcpwin тут было бы на много более правильным, но он работает только на exact match, что делает его фактически бесполезным. Надо бы добавить туда возможность range, как в tcpdatalen.
          • +2
            Отослал патч разработчикам.
    • 0
      это не спасёт от DDoS, выполненной таким способом.
  • +1
    В debian стабильном nginx отлично справляется.
    • +1
      На убунту дохнет. Если у Вас есть сетап с доступом извне — можно попробовать.
      • 0
        И на макос дохнет. Но там еще и проблема дефолтного ограничения на кол-во файл дескрипторов, и nginx упирается в него.
      • 0
        В принципе, вот: delta-z.ru. Попробовал на чистом апаче проверить как работает — дохнет.
        • 0
          Хотя вот так вот: slowhttptest -c 1000 -r 1000 -H ложится на 15-й секунде :) В прошлый раз без дополнительных параметров проверял.
          • 0
            Интересный момент: запускаю проверку, в какой-то момент Service Available меняется на NO, но при открытии проверяемого хоста в браузере всё по прежнему отлично работает…
            • 0
              Service Available меняется там на NO изза рейта соединений, -r 1000 создает 1000 соединений в секунду, сервер не справляется и ставить в очередь, но секунд за 5 разгребает ее. Пробное соединение, которое определяет наличие сервиса за эти 5 секунд не получает видать ответа и считает что сервиса нет.
          • 0
            -H генерит запрос с незаконченными заголовками. Это slowloris атака, а медленное чтение — -X!
        • +1
          короче попробовал.
          На этом сайте огромный pool одновременных соединений. Пришлось 6 экземпляров slowhttptest a запустить:

          src/slowhttptest -X -w 10 -y 500 -k 3 -u delta-z.ru/images/banner.png -c 1000 -r 200

          Видать машина мощная. Формула так такова: max_clients = worker_processes * worker_connections, где worker_processes обычно по числу ядер процессора.
          • 0
            Угу, 8-ми ядерный (4 HT) i7 на сервере. В конфиге nginx, соотвественно, 8 процессов по 1024 конекшена установлено. В принципе, тогда ясно, почему у меня не получилось положить )
  • 0
    ./slowhttptest -c 1000 -r 1000 -H пока ложит все проверяемые сайты.

    З.ы.: на Хабре не испытывал и не буду, уж очень люблю жизнь :)
    • +1
      -H это старо! -H посылает медленные запросы! slowloris атака это, slow read запускается как -X.

      Лимит в 1000 соединений изза того, что использую select(), нехочется скрипткидям жизнь облегчать, на и на epoll() переписывать лень.
      • –1
        можно на пайтоне за минуту написать более злобного буратина :)
        • 0
          написано дофига:)
      • 0
        И не надо non-posix epoll(). И так не собирается на BSD из за того, что sys/socket.h не заинклюжен и из за print_call_stack().
        • 0
          Тфу! Спасибо огромное. Поставлю щас BSD. На маке все писал, думал на BSD заработает. print_call_stack() я вроде даже и не использую… Убери нафиг.
          • +1
            конечно убрал уже :)

            void
            print_call_stack() {
            #ifdef __linux__
            ...
            #else
            return;
            #endif
            }


            B execinfo.h туда же. Собралось нормально и вроде работает. Особо не проверял.
            • 0
              хм… Тэг code какой то странный…
              • +1
                Используйте Хабратег <source lang="C"></source>
            • 0
              Пардон, имел ввиду «уберу нафиг». Мучаюсь с BSD.
            • 0
              Поставил, проверил. Зачекинил в svn, обновил вики для BSD пользователей.
              П.С. Мучался с svn ом на BSD, 21 век, а он https не поддерживал.
              • 0
                Если специально не отключать neon+openssl, то вроде должен. Я правда не проверял сам.
    • –1
      Хабр явно более 1000 соединений одновременно обслуживает.
      • +2
        не факт
      • +3
        Примерно несколько запросов в секунду на главной по вечерам. Замерял картинкой в посте и tail -f на логе :)
    • +4
      Ох чую сейчас будет обратный хаброэффект, организованный не на сторонник ресурс, а на сам хабр. :)
  • 0
    [1046041.052385] TCP: Peer 89.86.4.24:29269/35882 unexpectedly shrunk window 625419684:625424028 (repaired)

    Это не «оно»? В смысле, не борьба с оным?
    • 0
      а чей это лог?
      • 0
        $ grep -m 1 shrunk /var/log/kernel.log.1
        Jan 1 22:11:55 localhost kernel: [2573135.119374] TCP: Peer 85.242.201.187:62704/51413 unexpectedly shrunk window 109853464:109856304 (repaired)
        • 0
          О, так это ядро поймало, что кто-то (торрент? ) находу уменьшил window намного, т.е. клиент в начале соединения объявил, что он может принимать одним куском (грубо говоря) 1Кб например, принял 20 байт и сказал что у него осталось места на 100 байт, заместо 1Кб минус 20 байт.
          Интересно как сервер может это пофиксить: считать что тот ему врет и продолжать посылать куски большего размера? В любом случае slowhttptest не ведет себя так; он в самом начале говорит что он может принимать мелкие кусками данные, принимает первый кусок, и говорит стоп, места нет.
      • 0
        Это dmesg, оно (ядро) постоянно таким срёт, когда торренты запущены.
  • +1
    Спасибо за интересную статью. Проверил свои сервера.
  • 0
    Бинарником для OSX никто не поделится?
  • 0
    Не ясно, почему падает nginx. Разве там не асинхронные сокеты?
  • 0
    Мы это делали в 2005 г., зачем было палить вот так?!
  • НЛО прилетело и опубликовало эту надпись здесь

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.