{"id":225,"date":"2018-02-13T23:03:11","date_gmt":"2018-02-13T22:03:11","guid":{"rendered":"https:\/\/brozanski.net\/?p=225"},"modified":"2018-02-14T01:06:35","modified_gmt":"2018-02-14T00:06:35","slug":"historia-pewnego-zadania-sql-injection-i-zepsute-uwierzytelnianie","status":"publish","type":"post","link":"https:\/\/brozanski.net\/index.php\/2018\/02\/13\/historia-pewnego-zadania-sql-injection-i-zepsute-uwierzytelnianie\/","title":{"rendered":"Historia pewnego zadania &#8211; SQL Injection i zepsute uwierzytelnianie"},"content":{"rendered":"<p>Dzisiaj chcia\u0142bym opisa\u0107 rozwi\u0105zanie jednego z zada\u0144 pokazuj\u0105cych przyk\u0142ad z\u0142ej implementacji autoryzacji w aplikacji webowej. Zadanie polega\u0142o na zalogowaniu si\u0119 na konto admina w celu zdobycia odpowiedniej flagi.<\/p>\n<p>Po wej\u015bciu na stron\u0119 naszym oczom ukazuje si\u0119 prosty formularz logowania z polami do wpisania u\u017cytkownika i has\u0142a. Pierwszy krok to analiza kodu \u017ar\u00f3d\u0142owego, gdzie zauwa\u017cam komentarz wskazuj\u0105cy, \u017ce formularz mo\u017cna przetestowa\u0107 loguj\u0105c si\u0119 na wskazane konto z podanym has\u0142em. Przeprowadzam test i faktycznie uda\u0142o si\u0119 zalogowa\u0107. Na stronie pojawia si\u0119 komunikat o poprawnym zalogowaniu, ale tylko do konta zwyk\u0142ego u\u017cytkownika.<\/p>\n<p>Idziemy dalej. Pr\u00f3buj\u0119 tym razem wpisa\u0107 inn\u0105 (dowoln\u0105) nazw\u0119 u\u017cytkownika. Otrzymuj\u0119 komunikat: &#8222;U\u017cytkownik nie istnieje&#8221;. Hmm&#8230; . Spr\u00f3bujmy z kontem &#8222;admin&#8221; i dowolnym has\u0142em. Bingo &#8211; &#8222;Niepoprawne has\u0142o&#8221;. Pierwszy podstawowy b\u0142\u0105d uwierzytelniania &#8211; komunikaty umo\u017cliwiaj\u0105ce weryfikacj\u0119, czy konto w og\u00f3le istanieje. Daje to atakuj\u0105cemu mo\u017cliwo\u015b\u0107 iteracji kont i atakowania tylko tych, kt\u00f3re faktycznie istniej\u0105.<\/p>\n<p>Mam jednak inny pomys\u0142. Konta pewnie sk\u0142adowane s\u0105 w bazie danych, spr\u00f3bujmy wi\u0119c testu na wstrzykni\u0119cie polecenia SQL. Z do\u015bwiadczenia wiem jak mniej wi\u0119cej powinno wygl\u0105da\u0107 zapytanie do bazy danych, je\u015bli mia\u0142oby by\u0107 podatne na atak SQL Injection:<\/p>\n<pre>select * from users where username= ' + $username + ' and password=' + $password + ';<\/pre>\n<p>Pr\u00f3bujemy, wi\u0119c taki payload: <code> login.php?username=user'&amp;password=P@ssw0rd<\/code> . Po nazwie u\u017cytkownika dodaj\u0119 apostrof i &#8230; dostaj\u0119 b\u0142\u0105d HTTP 500. Co\u015b si\u0119 wysypa\u0142o \ud83d\ude09 Zapewne przedwcze\u015bnie zamkni\u0119ty apostrof w parametrze <em>username<\/em> zepsu\u0142 zapytanie SQL. <\/p>\n<p>Spr\u00f3bujmy, wi\u0119c naprawi\u0107 zapytanie wykomentowuj\u0105c wszystko po warunku dla pola <em>username<\/em> :<br \/>\n<code>login.php?username=user'#&amp;password=P@ssw0rd<\/code> . Okazuje si\u0119, \u017ce teraz uda\u0142o mi si\u0119 zalogowa\u0107 na testowe konto. Robi\u0119 kolejny test i wysy\u0142am inne has\u0142o dla tego u\u017cytkownika. Niestety has\u0142o jest nieprawid\u0142owe. Z powy\u017cszych czynno\u015bci wynika, \u017ce zapytanie SQL pobiera rekord u\u017cytkownika z bazy, a dopiero potem w kodzie sprawdzana jest poprawno\u015b\u0107 has\u0142a.<br \/>\nWiemy, \u017ce mo\u017cliwe jest wstrzykni\u0119cie kodu SQL i znamy procedur\u0119 weryfikacji. W zwi\u0105zku z tym mo\u017cemy sprawi\u0107, aby zapytanie zwr\u00f3ci\u0142o taki rekord jaki chcemy. Aby to zrobi\u0107 mo\u017cemy wykorzysta\u0107 klauzul\u0119 UNION i doda\u0107 tam w\u0142asne zapytanie. Problem w tym, \u017ce nie wiemy ile kolumn zwraca pierwotne zapytanie o u\u017cytkownika. Mo\u017cna to jednak \u0142atwo przetestowa\u0107 dodaj\u0105c kolejne kolumny w do\u0142\u0105czonym zapytaniu.<br \/>\n<code> 1. login.php?username=user' UNION select '1';#password=P@ssw0rd <\/code> daje HTTP 500<br \/>\n<code> 2. login.php?username=user' UNION select '1','2';#password=P@ssw0rd <\/code> daje HTTP 200 i komunikat o poprawnym zalogowaniu. Wynika z tego, \u017ce pierwsze zapytanie zwraca dwie kolumny zapewne z nazw\u0105 u\u017cytkownika i has\u0142em.<\/p>\n<p>Jeste\u015bmy ju\u017c blisko. Tworzymy docelowy payload:<br \/>\n<code>login=' union select 'admin','P@ssw0rd';#&password=P@ssw0rd<\/code>.<br \/>\nUruchamiam zapytanie i klops &#8211; nie dzia\u0142a. Chwila namys\u0142u i jest. Przecie\u017c hase\u0142 nie nale\u017cy trzyma\u0107 w postaci jawnej i tworzy si\u0119 z nich hash&#8217;e, a jaka jest najpopularniejsza funkcja hasuj\u0105ca w PHP? Oczywi\u015bcie MD5 (sic!). Szybkie obliczenia i tym razem payload wygl\u0105da tak:<br \/>\n<code>login=' union select 'admin','098f6bcd4621d373cade4e832627b4f6';#&password=P@ssw0rd<\/code><\/p>\n<p>Sukces. Flaga zdobyta.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Dzisiaj chcia\u0142bym opisa\u0107 rozwi\u0105zanie jednego z zada\u0144 pokazuj\u0105cych przyk\u0142ad z\u0142ej implementacji autoryzacji w aplikacji webowej. Zadanie polega\u0142o na zalogowaniu si\u0119 na konto admina w celu zdobycia odpowiedniej flagi. Po wej\u015bciu na stron\u0119 naszym oczom ukazuje si\u0119 prosty formularz logowania z polami do wpisania u\u017cytkownika i has\u0142a. Pierwszy krok to analiza kodu \u017ar\u00f3d\u0142owego, gdzie zauwa\u017cam komentarz\u2026 <span class=\"read-more\"><a href=\"https:\/\/brozanski.net\/index.php\/2018\/02\/13\/historia-pewnego-zadania-sql-injection-i-zepsute-uwierzytelnianie\/\">Read More &raquo;<\/a><\/span><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[11],"tags":[26],"class_list":["post-225","post","type-post","status-publish","format-standard","hentry","category-security","tag-miroburn_challenge"],"_links":{"self":[{"href":"https:\/\/brozanski.net\/index.php\/wp-json\/wp\/v2\/posts\/225","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/brozanski.net\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/brozanski.net\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/brozanski.net\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/brozanski.net\/index.php\/wp-json\/wp\/v2\/comments?post=225"}],"version-history":[{"count":7,"href":"https:\/\/brozanski.net\/index.php\/wp-json\/wp\/v2\/posts\/225\/revisions"}],"predecessor-version":[{"id":232,"href":"https:\/\/brozanski.net\/index.php\/wp-json\/wp\/v2\/posts\/225\/revisions\/232"}],"wp:attachment":[{"href":"https:\/\/brozanski.net\/index.php\/wp-json\/wp\/v2\/media?parent=225"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/brozanski.net\/index.php\/wp-json\/wp\/v2\/categories?post=225"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/brozanski.net\/index.php\/wp-json\/wp\/v2\/tags?post=225"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}