11:06
24/9/2010

Omijamy mod_rewrite

Poniższy trick nie pozwala co prawda na całkowite odsłonięcie regułki mod_rewrite używanej przez Apache’a, ale nazwa i ścieżka pliku to już coś. Przyda się pentesterom:

mod_rewrite: ujawnienie nazwy pliku

H=ha.ckers.org; echo -ne "POST /blog/category/webappsec/books/ HTTP/1.1\nHost: $H\nConnection: close\nContent-length: x\n\n" | nc $H 80 | less

Powyższe żądanie, z racji nieprawidłowej wartości Content-length: powinno zwrócić błąd HTTP/1.1 413 Request Entity Too Large, ale zaraz po nim:

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head><title>413 Request Entity Too Large</title>
</head><body><h1>Request Entity Too Large</h1>
The requested resource<br />/blog/index.php<br />
does not allow request data with GET requests, or the amount of data provided in 
the request exceeds the capacity limit. Additionally, a 404 Not Found error was 
encountered while trying to use an ErrorDocument to handle the request.
Logo mod_rewrite

O tych i innych ciekawych technikach atakowania i ochrony webaplikacji opowiadamy na naszych niebezpiecznikowych szkoleniach (śpieszcie się, zostały tylko 3 miejsca na październik).

Przeczytaj także:



43 komentarzy

Dodaj komentarz
  1. I like it :)

  2. Domyślam, ze powyższe zjawisko nie występuje w nginx, prawda?

  3. Apache nie jest zbyt sprytny (nie tylko w tym przypadku). NGINX radzi sobie wzorowo ;)

  4. ale nazwa i ścieżka pliku to już coś

    A gdzie tam… W większości przypadków jest to przecież routing do index.php. Problem, który nim nie jest, IMO ;)

    Poza tym, zawsze można własne strony błędów dodać. ;)

  5. @Rocik: w nginx nie masz mod_rewrite, więc niekoniecznie. Choć jest tam jakaś technologia zastępcza i całkiem możliwe, że zadziała w podobny sposób (wywalając adres).

    Niebezpiecznik: a co komu po prawdziwym adresie? Raczej niewiele da się z tym zdzaiałać, zwłaszcza jeśli jest zrobione przekierowanie z pierwotnych adresów na mod_rewrite (robię tak choćby dlatego, by nie zostać posądzonym o DC przez Google) :)

  6. Niezłe ;)

  7. NGINX odpowiada czystym “411 Length Required” i nie puszcza zapytania do backendu, więc niemożliwe są żadne wycieki danych z php za pomocą tej metody.
    Fakt, nie ma mod_rewrite bo niepotrzebne mu protezy a mod_rewrite jest protezą na ułomności php ;)

  8. @Kamil
    jeżeli wiem, że /nicename to w rzeczywistości /secret_path/index.php, to na szybko:
    1) wiem, że to php
    2) warto zajrzeć do /secret_path
    i pewnie jeszcze by się coś znalazło…

  9. W sumie można się pobawić i wysyłać ciekawsze zapytania (przede wszystkim poprawne). Tylko czy naprawdę warto? Prawie zawsze jest to index.php, czyż nie?

  10. Mylacy tytul artykulu. Danym sposobem dowiemy sie do jakiego pliku odnosi sie mod_rewrite… i tyle, nie omijamy mod_rewrite za bardzo

    aby ominac potrzebowalibysmy rowniez parametry jakie dany plik przyjmuje, np. index.php?controller=blog&action=index&article=1 zamiast /blog/1/

  11. “Additionally, a 404 Not Found error was encountered while trying to use an ErrorDocument to handle the request.” – no czyli nie tak trudno się zabezpieczyć przed czymś takim – wystarczy error document’y poustawiać :P i przy okazji ustawić też error document’a dla 418 :D (jakby ktoś nie znał, “418 I’m a teapot”; http://en.wikipedia.org/wiki/Hyper_Text_Coffee_Pot_Control_Protocol , http://tools.ietf.org/html/rfc2324 )

  12. @Michal – jestem w temacie prawie laikiem, ale czy parametrów pliku nie można w pewnym stopniu wywnioskować z używanego cmsu? A resztę metodą prób i błędów? (Jeśli bredzę, to przepraszam.)

    • Ci, którzy uważają, że podane wyżej zapytanie zdradzające nazwę pliku (i ścieżkę) jest do niczego nieprzydatne — pamiętajcie, dla pentestera KAŻDA informacja jest ważna (nie ma informacji nieważnych :>). To czy ktoś zrobi z niej użytek (i jak) zależy już tylko niego…

  13. @Piotr Konieczny

    Ała… ;)

  14. No, informacja dość przydatna. Jak się znajdzie jakiś LFI/AFD to można chyba coś zdziałać… a brakuje wtedy trochę takich nazw.

  15. Trochę bardziej rozbudowany przykład:

    /nicename ==> /secret_path_1/test_1.php

    1) wiemy, że php
    2) warto “zajrzeć” (zwykły index, albo bruteforcem) do /secret_path_1
    3) powtórzyć krok 2 dla /secret_path{x}/test_{x}.php

    Trochę przekombinowane, no ale podobno tylko dwie rzeczy są nieskończone,
    jedną jest wszechświat ;)

  16. a dlaczego bombardujecie akurat RSnake’a??

  17. @dariusz: wystarczy dać (przykład dla php):

    if (strpos($_SERVER[‘REQUEST_URI’], ‘.php’) === true) {
    Header(‘HTTP/1.1 301 Moved Permanently’);
    Header(‘Location: http://adres.pl/z/mod/rewrite‘);
    }

    To samo rozwiązanie można zastosować w .htaccess dla całej aplikacji i raczej na niewiele zda się wiedza o prawdziwych ścieżkach :-)

    Oczywiście wiedza o prawdziwych ścieżkach ma tą wartość dla atakującego, że mod_rewrite dodawał dodatkową warstwę ochrony aplikacji.

  18. Próbowałem to odtworzyć u siebie i jakoś mi nie idzie – “The requested resource …” pokazuje ścieżkę przed rewrite a nie tą docelową.

    Czy tu chodzi o ten flaw: Timeout detection flaw (mod_proxy_http) CVE-2010-2068 (only Windows, Netware and OS2 operating systems affected)?

  19. Sami geniusze zabezpieczeń widzę, a jak dochodzi co do czego to w katalogach znajdują się kopie configa np. config.php~, indexdir zazwyczaj włączony itd. Każdy mądry dopóki mu się ktoś w kod nie przyjrzy.

  20. …dla pentestera KAŻDA informacja jest ważna…

    …bo w końcu coś do tego raportu wpisać trzeba, a to z nich pentester żyje:
    Cytując wieszcza: ‘Pentesting sucks’ -> http://www.ranum.com/security/computer_security/editorials/point-counterpoint/pentesting.html

  21. U mnie każde zapytanie leci przez index.php Aplikacja pisana samodzielnie, bez użycia bibliotek ze względu na wymagania wydajnościowe. Jeśli skorzystał bym z popularnych frameworków php to mod_rewrite wskazywałby na (fanfary)… na index.php Hakować co się da!

    • Bartko, to podaj tu URL tego swojego webappsa ;)

  22. Popieram przedmówców – o ile faktycznie Apache nie powinien “ujawniać” takich informacji, o tyle sposób zabezpieczenia jest prosty – wystarczy tylko odpowiednia strona ErrorDocument, zamiast standardowej. Jeśli się mylę, to poprawcie mnie. ;]

  23. wydawałoby się, że wystarczy ustawić inny ErrorDocument dla 413… ale najwyraźniej nie. handler tego błędu przy mod_rewrite jest hard-coded w źródłach apacza.

    • Przy użyciu ErrorDocument 413 /… nadal wyświetla się domyślny komunikat z serwera tylko zamiast błędu 404 pojawia się “Additionally, a 413 Request Entity Too Large
      error was encountered while trying to use an ErrorDocument to handle the request.”
      Rozwiązałem problem dając wpis:
      ErrorDocument 413 “Error 413Error 413!”
      Pozdrawiam!

    • W odpowiedzi wyżej wycięło kod html-a.. :) Proszę o scalenie/edycję moich wpisów.

      Wpis powinien wyglądać tak:
      ErrorDocument 413 "<html><head><title>Error 413</title></head><body><p>Error 413!</p></body></htm>"

      Pozdrawiam!

  24. Który to ma numer w bugzilli apaczowej?

  25. @Kamil
    if (strpos($_SERVER[REQUEST_URI], ‘.php’) === true) {
    Header(‘HTTP/1.1 301 Moved Permanently’);
    Header(‘Location: http://adres.pl/z/mod/rewrite‘);
    }

    Może się nie znam, ale od kiedy strpos zwraca wartość boolowską inną niż fasle?

  26. moze zwracac pozycje 0 i 1 jako poczatek szukanego ciagu

  27. @lolek – zwraca false, jeśli nie znajdzie podanego ciągu (.php).

  28. @lolek: masz rację, wdarł się mały błąd :)

  29. @Kamil – to zadziała mimo wszystko. Każda niezerowa wartość zostanie uznana za true, natomiast 0, które zwróci gdy nie znajdzie .php będzie podciągnięte pod false;

  30. Nawet na php.net jest opisane:
    strpos – Returns the position as an integer. If needle is not found, strpos() will return boolean FALSE.

  31. Dokladnie, strpos zwróci z boolowskich wartości jedynie false, a jeśli nie to nr pozycji. Tak więc konstrukcja podana przez Kamila nigdy sie nie wykona a to za sprawą operatora ===.

  32. @Kamil: Nie to, żebym narzekał, ale sama sugestia, żeby klient przeszedł na inny adres to trochę mało – nie zaszkodziło by chociaż zakończyć aktualnego skryptu (poprzez die() lub coś sprytniejszego)

  33. Na lighthttp działa?

  34. Czepiacie się Panowie :P chciałem podać tylko pseudo-rozwiązanie, nie jest to gotowiec typu kopiuj-wklej. Poprawiając:

    if (strpos($_SERVER[REQUEST_URI], ‘.php’) !== false) {
    Header(‘HTTP/1.1 301 Moved Permanently’);
    Header(‘Location: http://adres.pl/z/mod/rewrite‘);
    exit;
    }

  35. Btw. kod ma nadal błąd ($_SERVER[REQUEST_URI]), ale już mniejsza o to ;)

  36. @Kamil
    Masz rację, mniejsza o to – nie umiesz programować więc i tak szkoda czasu

  37. @chesteroni
    tak jest! :-)

  38. @Kamil
    Sprawdź swój kod dla poniższych URLi:
    http://twoj_server/skrypt%2ephp
    na windowsie:
    http://twoj_server/skrypt.PHP

  39. A przypadkiem ustawienie własnych error page, by nie rozwiązało problemu?
    Ewentualnie, przerobiona kompilacja apacha?
    kilka linijek poprawić i z głowy. (Hmm, może to tez metoda)

Twój komentarz

Zamieszczając komentarz akceptujesz regulamin dodawania komentarzy. Przez moderację nie przejdą: wycieczki osobiste, komentarze nie na temat, wulgaryzmy.

RSS dla komentarzy: