24/9/2010
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.
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).
I like it :)
Domyślam, ze powyższe zjawisko nie występuje w nginx, prawda?
Apache nie jest zbyt sprytny (nie tylko w tym przypadku). NGINX radzi sobie wzorowo ;)
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ć. ;)
@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) :)
Niezłe ;)
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 ;)
@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…
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?
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/
“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 )
@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…
@Piotr Konieczny
Ała… ;)
No, informacja dość przydatna. Jak się znajdzie jakiś LFI/AFD to można chyba coś zdziałać… a brakuje wtedy trochę takich nazw.
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 ;)
a dlaczego bombardujecie akurat RSnake’a??
@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.
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)?
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.
…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
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 ;)
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. ;]
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!
Który to ma numer w bugzilli apaczowej?
@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?
moze zwracac pozycje 0 i 1 jako poczatek szukanego ciagu
@lolek – zwraca false, jeśli nie znajdzie podanego ciągu (.php).
@lolek: masz rację, wdarł się mały błąd :)
@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;
Nawet na php.net jest opisane:
strpos – Returns the position as an integer. If needle is not found, strpos() will return boolean FALSE.
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 ===.
@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)
Na lighthttp działa?
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;
}
Btw. kod ma nadal błąd ($_SERVER[REQUEST_URI]), ale już mniejsza o to ;)
@Kamil
Masz rację, mniejsza o to – nie umiesz programować więc i tak szkoda czasu
@chesteroni
tak jest! :-)
@Kamil
Sprawdź swój kod dla poniższych URLi:
http://twoj_server/skrypt%2ephp
na windowsie:
http://twoj_server/skrypt.PHP
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)