Aktywne Wpisy
mirko_anonim +126
✨️ Obserwuj #mirkoanonim
Moi Drodzy, przychodzę do Was pogadać. Jestem kobietą lvl 31. Pracuje. Wynajmuje mieszkanie. Mam dziecko (4latka). Samodzielna mama. I jak widzę te wszystkie wpisy na wykopie o madkach, p0lkach itd to mnie trzęsie. Nie lubię wrzucania wszystkich do jednej kategorii. Może jakaś część dziewczyn taka jest - nie wszystkie. Nie szukam faceta do utrzymywania, nie szukam tatusia dla dziecka. Szukam faceta do związku ze mną. Wiadomo dziecko jest i siłą rzeczy relacja jest inna niż bez niego. Dla mnie to wyczekane dziecko i wymarzone. Długo się starałam. Natomiast nie mam świra bezwzględnego na jego punkcie. Fajnie byłoby poznać i pogadać z facetem który ma poczucie humoru, dystans, który nie jest maminsynkiem. Jest niezależny, inteligentny, zarabia na siebie. I chce żeby kobieta w jego towarzystwie czuła się dobrze. Tak jak ja chce żeby facet czuł się dobrze w moim towarzystwie. I na dzień dobry nie spłycać relacji do se#!u. Nie mam nic przeciwko ale nie chcę żeby relacja opierała się głównie na tym. A teraz czekam na pojazd w komentarzach że mam za duże wymagania lub madka z dzieckiem sobie wymyśliła zamiast brać pierwszego lepszego który się zdecyduje na taką jak ja. I fizycznie wyglądam bardzo dobrze - szczupła, z natury brunetka (teraz końce farbowane na blond), nie za wysoka - przeciętny wzrost. Moja największa wada? Gadulstwo.
────────
Moi Drodzy, przychodzę do Was pogadać. Jestem kobietą lvl 31. Pracuje. Wynajmuje mieszkanie. Mam dziecko (4latka). Samodzielna mama. I jak widzę te wszystkie wpisy na wykopie o madkach, p0lkach itd to mnie trzęsie. Nie lubię wrzucania wszystkich do jednej kategorii. Może jakaś część dziewczyn taka jest - nie wszystkie. Nie szukam faceta do utrzymywania, nie szukam tatusia dla dziecka. Szukam faceta do związku ze mną. Wiadomo dziecko jest i siłą rzeczy relacja jest inna niż bez niego. Dla mnie to wyczekane dziecko i wymarzone. Długo się starałam. Natomiast nie mam świra bezwzględnego na jego punkcie. Fajnie byłoby poznać i pogadać z facetem który ma poczucie humoru, dystans, który nie jest maminsynkiem. Jest niezależny, inteligentny, zarabia na siebie. I chce żeby kobieta w jego towarzystwie czuła się dobrze. Tak jak ja chce żeby facet czuł się dobrze w moim towarzystwie. I na dzień dobry nie spłycać relacji do se#!u. Nie mam nic przeciwko ale nie chcę żeby relacja opierała się głównie na tym. A teraz czekam na pojazd w komentarzach że mam za duże wymagania lub madka z dzieckiem sobie wymyśliła zamiast brać pierwszego lepszego który się zdecyduje na taką jak ja. I fizycznie wyglądam bardzo dobrze - szczupła, z natury brunetka (teraz końce farbowane na blond), nie za wysoka - przeciętny wzrost. Moja największa wada? Gadulstwo.
────────
erebeuzet +1361
Ostatnio rzuciłem wyzwanie, żeby wykorzystując błąd typu SQL Injection, wykraść hasło użytkownika admin ze strony http://hakerium.cba.pl/zad1/.
Niestety, wyniki okazały się dość słabe, stąd podsyłam krok po kroku jak mógłby wyglądać tok myślenia osoby, która chciałaby przełamać zabezpieczenie tej strony.
Przede wszystkim, w przypadku testowania normalnej strony nie ma takiej sytuacji, jaka była tutaj, tj. że z góry było wiadomo, że podatność na SQL Injection istnieje. Najpierw trzeba ją zweryfikować i w tym celu trzeba będzie wykonać kilka prostych zapytań.
Mamy pewność, że istnieje użytkownik
admin
, a więc wpiszmy taką nazwę użytkownika z dowolnym hasłem.
W odpowiedzi dostaniemy Nieudane logowanie.
Wpiszmy zatem inną nazwę użytkownika; taką, która z całą pewnością w systemie nie będzie istnieć, np.
abcsfds
.
W odpowiedzi dostaniemy Nieudane logowanie
Zauważamy, że w poprzednim przypadku na końcu komunikatu była kropka, a teraz jej nie ma. Wniosek z tego jest taki, że strona odpowiada innym komunikatem o błędzie w zależności od tego jaka jest przyczyna.
Nie wiemy jak wygląda zapytanie SQL-owe po stronie serwera, ale możemy się spodziewać, że będzie w nim kod podobny do:
SELECT * FROM users WHERE username='$username'
Gdyby jako nazwę użytkownika podać
ad'+'min
to zapytanie zamieni się w:
SELECT * FROM users WHERE username='ad'+'min'
. Okazuje się, że w tym przypadku też dostaniemy Nieudane logowanie. a więc odpowiedź z kropką na końcu.
Wpiszmy jako nazwę użytkownika coś co zawiera jakiś większy fragment zapytania SQL-owego np.
admin' OR '1'='1
, wówczas mamy zapytanie
SELECT * FROM users WHERE username='admin OR '1'='1'
. Ten drugi warunek będzie zawsze prawdziwy. Kolejny raz będzie odpowiedź z kropką na końcu. A co się stanie, gdy damy zamiast tego
admin' AND '1'='2
(a więc zapytanie zawsze fałszywe)? Odpowiedź będzie Nieudane logowanie czyli znów bez kropki.
Możemy już spokojnie wyciągnąć wniosek: strona zwraca Nieudane logowanie. gdy zapytanie SQL-owe zwróciło co najmniej jeden wiersz lub Nieudane logowanie gdy zapytanie zwraca zero wierszy. Kolejnym krokiem jest jeszcze sprawdzenie jak się strona zachowa dla zapytań, które nie są poprawnym SQL-em, wpiszmy np.
admin' ANDdd '1'='2
z czego będzie zapytanie
SELECT * FROM users WHERE username='admin' ANDdd '1'=2'
. Po raz kolejny mamy Nieudane logowanie - komunikat bez kropki.
MySQL ma taką specyfikę, że jeśli zapytanie jest poprawne syntaktycznie, ale zawiera na przykład nieistniejącą nazwę kolumny, to też wtedy zwraca błąd. Możemy takie zachowanie wykorzystać do sprawdzenia jakie kolumny istnieją w naszej tablicy. Pokażę to na przykładzie, jeśli mamy zapytanie:
SELECT * FROM users WHERE username='admin' OR 1=1 OR ''
, dostaniemy wtedy wynik z kropką (a więc zostanie coś zwrócone). Jeśli zamienimy
1=1
na
user=user
to zapytanie ma dokładnie taki sam sens z jedną różnicą - nie wykona się, jeśli nie istnieje kolumna
user
. A zatem wpiszmy
admin' OR user=user OR'
co da komunikat bez kropki - a więc taka kolumna nie istnieje. Jednak już dla
admin' OR username=username OR '
dostajemy odpowiedź z kropką - czyli trafiliśmy z nazwą kolumny. Na podobnej zasadzie możemy potwierdzić istnienie kolumny
password
, poprzez wpisanie
admin' OR password=password OR'
.
No to przejdźmy wreszcie do konkretów :) Może na początek poznajmy długość hasła tego użytkownika? Skorzystamy z metody
LENGTH
i wpisujemy
admin' AND LENGTH(password)=8 OR '
, z tego powstaje zapytanie:
SELECT * FROM users WHERE username='admin' AND LENGTH(password)=8 OR ''
. Jeśli warunek z długością będzie prawdą to zapytanie zwróci wynik, w przeciwnym przypadku nie zwróci nic. A więc jedziemy:
admin' AND LENGTH(password)=8 OR '
- zwraca Nieudane logowanie
admin' AND LENGTH(password)=9 OR '
- zwraca Nieudane logowanie
admin' AND LENGTH(password)=10 OR '
- zwraca Nieudane logowanie.. Bingo! Wiemy już, że hasło ma 10 liter!
Do wyciągania pojedynczych liter hasła użyjemy metody
SUBSTRING
. Przyjmuje ona trzy parametry: pierwszy określa z czego wyciągamy podciąg (np. nazwę kolumny), drugi parametr określa początek podciągu (indeksowane od 1), trzeci parametr zaś to długość. No to jedziemy:
admin' AND SUBSTRING(password,1,1)='q' OR '
- jeśli pierwszy znak hasła to q - dostaniemy wynik z kropką, w przeciwnym wypadku bez kropki. Okaże się, że pierwszy znak to nie jest q, gdy jednak damy zapytanie:
admin' AND SUBSTRING(password,1,1)='w' OR '
- jest odpowiedź Nieudane logowanie.. Pierwszy znak hasła to w. Warto jednak zdać sobie sprawę z tego, że porównywanie ciągów znaków w MySQL domyślnie jest niewrażliwe jak wielkość liter. Nie wiemy więc, czy pierwszy znak to W czy w. Aby to naprawić, dodajmy słówko
BINARY
.
admin' AND SUBSTRING(password,1,1) = BINARY 'w' OR'
- Nieudane logowanie
admin' AND SUBSTRING(password,1,1) = BINARY 'W' OR'
- Nieudane logowanie. - a więc tak naprawdę pierwszą literą hasła jest duże W. Gdy będziemy teraz chcieli wyciągnąć drugi znak hasła, to zmieniamy drugi parametr w
SUBSTRING
na
2
. Oczywiście wyciąganie całych haseł w ten sposób ręcznie jest bardzo pracochłonne i długotrwałe, stąd znacznie prościej napisać sobie do tego skrypt. Oto prosty skrypt w Pythonie, który napisałem w tym celu. Po jego odpaleniu dowiemy się, że całe hasło to WyKoP!@123 i że skrypt potrzebował wykonać 398 zapytań HTTP, by je odkryć (nie jest to strasznie duża liczba).
A więc wracamy na stronę, wpisujemy user: admin, pass: WyKoP!@123 i udało się! Zalogowany jako admin! :)
Jeśli macie jakieś pytania, pytajcie bez skrępowania ;)
Dodatkowe zadanie dla chętnych: w bazie istnieje jeszcze jeden użytkownik. Jaką ma nazwę i jakie ma hasło? :)
@Konalio: Zalinkowane threats.pl jest dość dobre, bardzo popularnym źródłem informacji jest OWASP, polecam zacząć od OWASP TOP 10.
Komentarz usunięty przez autora
LIKE
i raczej używaj
SELECT * FROM users WHERE username='$username'
(tak naprawdę wygląda inaczej, ale jest to uproszczenie, które spokojnie może być tutaj użyte), Twoja propozycja tworzy coś takiego:
SELECT * FROM users WHERE username='admin' AND username like
Tak naprawdę istotą tej zagadki było pokazanie, że nawet jeśli informacje ze strony serwera są skąpe, to na podstawie obserwacji jego zachowania w różnych sytuacjach można z bazy wyciągnąć dane jeśli istnieje podatność na SQL Injection.
A jak się przed SQL Injection bronić? Zawsze mówiło się o potrzebie odpowiedniego enkodowania danych przed wrzuceniem ich do bazy. Najlepszą jednak metodą i najpewniejszą jest stosowanie parametryzowanych zapytań (prepared statements). Każdy liczący się język i silnik bazy danych ma mechanizmy do tego. Wówczas wy już praktycznie nie musicie się przejmować odpowiednim filtrowaniem danych, ale zrobi to za was silnik baz danych. Ogólnie rzecz biorąc polega to na tym, że wy przygotowujecie zapytanie SQL-owe gdzie w miejsce parametrów wpisuje się pytajniki (lub nazwy tych parametrów, zależy od konkretnej implementacji) i potem podpinacie odpowiednie wartości. Przykład oparty na PHP:
$stmt