Directory Enumeration Killer 2 June 2010

Od czasu do czasu widzę jakieś skanowanie mojej strony (nie bloga, tylko http://tdhack.com). Przeważnie kończy się po kilku minutach, ale i tak jest irytujące. Poza tym, niepotrzebnie zajmuje miejsce w logach, więc chyba lepiej się tego pozbyć.

Przykładowy – nazwijmy to – atak wygląda tak:

** IP ** - - [02/Jun/2010:14:35:59 +0200] "HEAD /index.html HTTP/1.1" 404 - "-" "-"
** IP ** - - [02/Jun/2010:14:35:59 +0200] "HEAD /index.shtml HTTP/1.1" 404 - "-" "-"
** IP ** - - [02/Jun/2010:14:35:59 +0200] "HEAD /index.aspx HTTP/1.1" 404 - "-" "-"
** IP ** - - [02/Jun/2010:14:36:00 +0200] "HEAD /index.cgi HTTP/1.1" 404 - "-" "-"
** IP ** - - [02/Jun/2010:14:36:00 +0200] "HEAD /index.php3 HTTP/1.1" 404 - "-" "-"
** IP ** - - [02/Jun/2010:14:36:00 +0200] "HEAD /index HTTP/1.1" 404 - "-" "-"
** IP ** - - [02/Jun/2010:14:36:00 +0200] "HEAD //cgi.cgi// HTTP/1.1" 404 - "-" "-"
** IP ** - - [02/Jun/2010:14:36:01 +0200] "HEAD //webcgi// HTTP/1.1" 404 - "-" "-"
** IP ** - - [02/Jun/2010:14:36:01 +0200] "HEAD //cgi-914// HTTP/1.1" 404 - "-" "-"
** IP ** - - [02/Jun/2010:14:36:01 +0200] "HEAD //cgi-915// HTTP/1.1" 404 - "-" "-"
** IP ** - - [02/Jun/2010:14:36:01 +0200] "HEAD //bin// HTTP/1.1" 404 - "-" "-"
** IP ** - - [02/Jun/2010:14:36:01 +0200] "HEAD //cgi// HTTP/1.1" 404 - "-" "-"
** IP ** - - [02/Jun/2010:14:36:02 +0200] "HEAD //mpcgi// HTTP/1.1" 404 - "-" "-"
** IP ** - - [02/Jun/2010:14:36:02 +0200] "HEAD //cgi-bin// HTTP/1.1" 404 - "-" "-"
** IP ** - - [02/Jun/2010:14:36:02 +0200] "HEAD //ows-bin// HTTP/1.1" 404 - "-" "-"
** IP ** - - [02/Jun/2010:14:36:02 +0200] "HEAD //cgi-sys// HTTP/1.1" 404 - "-" "-"

Smutne, prawda? Taki skan wykonuje przeważnie jakiś automat, rzadziej pentester. Jednym z narzędzi, które skanują w taki sposób jest indir. Program jest dostępny na stronie uw-team pod linkiem: http://indir.uw-team.org/. OK, na początek zmienimy domyślne strony błędów w Apache-u:

ErrorDocument 401 "/error/index.html"
ErrorDocument 403 "http://website.com/error/index.html"
ErrorDocument 404 "http://website.com/error/index.html"
ErrorDocument 405 "http://website.com/error/index.html"
ErrorDocument 413 "http://website.com/error/index.html"
ErrorDocument 500 "http://website.com/error/index.html"
ErrorDocument 414 "http://website.com/error/index.html"

Można to też wpisać lokalnie, do pliku .htaccess o ile jest respektowany przez web serwer. Niestety kod 401 nie może zostać zastąpiony w ten sposób. Dlaczego? Wytłumaczenie jest tutaj.

Co się teraz stanie, jeśli klient trafi na nieistniejący element? Oczywiście otrzyma ustawiony przez nas index.html, ale zanim to nastąpi po drodze będzie jeszcze redyrekcja (302). Dzieje się tak dlatego, że dyrektywa ErrorDocument korzysta od teraz z pełnej ścieżki dokumentu, a nie relatywnej.

OK, od teraz każdy błąd będzie miał kod 302. Przy okazji – było by fajnie napisać jakiś wrapper na wszystkie kody, zamiast wpisywać pojedyncze pliki *.html do konfiguracji. Zastanowię się nad tym i jak coś z tego wyjdzie, zaktualizuję tego posta.

Czy to już wszystko, co możemy zrobić, by powstrzymać takie skany? Oczywiście, że nie. Teraz trzeba się pozbyć skanowania metodą “HEAD”. Jeśli nie używać SVN via HTTP(s), to potrzebujesz do szczęścia tylko GET i POST. Ograniczymy nasz webserwer tylko do tych metod używając mod_rewrite:

RewriteEngine on
RewriteCond %{REQUEST_METHOD} !^(GET|POST)
RewriteRule ^(.*)$ - [F,L]

Łatwe, niewymagające wytłumaczenia rozwiązanie. HEAD już nie zadziała, użytkownik dostanie forbidden, ale tak na prawdę zamiast 403 dostanie 302 (pamiętacie o wymuszonej redyrekcji?). To skutecznie powtrzyma brudne łapy indira od naszego serwera. Indir będzie myślał, że na każde błędne żądanie odpowiadamy jako 302. Indir używa HEAD, widać to w pliku indir/core/connect.pl:

# line 17
if (!$head_get) {
   $head_get = "HEAD";
}

Tylko dlaczego? Większość skanerów używa tej techniki do szukania różnic w odpowiedzi. Aby skanowanie miało sens, musimy jakoś rozróżnić dobrą odpowiedź (200) od złej (404, 403, 401 itp) by wskazać, że dany zasób istnieje na skanowanym serwerze, lub nie. Trick z indirem polega na tym, że on nawet nie zacznie skanowania, jak trafi na zmanipulowane odpowiedzi. I dobrze, o to nam chodziło. Czyli na starcie Indir wykrzaczy się z tekstem, że nie potrafi odróżnić kodów odpowiedzi ;)

Przypominam, zawsze można przestawić skanowanie z HEAD na GET. I wtedy co? Indir znowu zacznie działać, ale my możemy znowu napisać rewrite i wysyłać kody 200 nawet na nieistniejące pliki. Taki rodzaj trolowania ;)

RewriteEngine On
RewriteBase     /
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*) http://website.com/$1 [R=200]

Rozwiązanie sprytne, ale będziemy mieć problemy z troubleshootingiem, jeśli trafimy na błąd w naszej aplikacji. Będzie nam tak samo jak Indirowi trudno odróżnić, które pliki istnieją. Z rozwiązaniem mógłby przyjść własnej roboty handler do kodów HTTP, wspomniany wyżej, wywoływany np tak::

RewriteRule ^(.*) http://website.com/handler.php?type=$1 [R=200]

Myślę, że złapaliście, o co w tym wszystkim chodzi.

To wszystko, dzięki za uwagę ;) Jeśli macie jakieś własne przemyślenia na ten temat, to podzielcie się nimi w komentarzach.

Tagi: , , , , , , ,


Odpowiedzi: 4 do wpisu “Directory Enumeration Killer”

  1. condis says:

    Nice tricks, really.

    I’m wondering if You’ll keep posting notes on Apache, or maybe some other http daemons, like lighttpd and nginx? IMHO It will be nice to read some good stuff about securing thoes two, from real sysadmin, not some teenage wannabe hehe :)

    Anyway, keep up the good work. I’ll be watching You :p

    • d2 says:

      Well I have some stuff to post on nginx, but actually nothing on lighttpd. Second one is not my favorite ;)

      Good to know anyone is interested in sysadmin stuff these days ;)

  2. Daniel says:

    great post, thanks for sharing

  3. Pratcher says:

    thanks for your share

Zostaw odpowiedź do Pratcher