Preorder drugiego tomu książki sekuraka: Wprowadzenie do bezpieczeństwa IT. -15% z kodem: sekurak-book
Statyczna analiza bezpieczeństwa kodu aplikacji (część 2.) — CAT.NET
Zanim jednak przystąpimy do analizy narzędzia, musimy posiadać kod, w którym będziemy szukać nieprawidłowości. Zacznijmy więc od konfiguracji środowiska testowego.
Środowisko testowe aplikacji ASP.NET
Skuteczność narzędzi do analizy aplikacji .NET przetestujemy na web aplikacji ASP „Hacme Bank v2.0”. Kod tej aplikacji został udostępniony przez firmę McAfee, która przez jej publikację chciała wskazać podstawowe luki bezpieczeństwa web aplikacji ASP.NET. Aplikacja McAfee obecnie już mocno się zdezaktualizowała i obecnie trudno spotkać nowe projekty pisane w stylu Hacme Bank — jednak w kontekście statycznej analizy kodu podatna aplikacja McAfee jest jak najbardziej aktualna.
Ze strony projektu można ściągnąć kod całej aplikacji lub instalator plików binarnych dla serwera aplikacji. Dla potrzeb środowiska testowego używanego w tym cyklu wystarczy ściągnięcie samych źródeł — binarki nie muszą być wdrożone na serwer IIS.
Solucja zawiera dwa projekty — jeden jest klasyczną stroną internetową (website), drugi jest usługą internetową (webservice). Warto zaznaczyć, że do uruchomienia analizy nie potrzeba umiejętności administrowania usługami IIS oraz aplikacjami ASP.NET — tak jak opisywano w części 1., statyczna analiza kodu nie wymaga uruchamiania aplikacji. Narzędzia do analizy opisywane w części 2. oraz 3. tego cyklu wymagają uruchamiania na systemach z rodziny Microsoft Windows.
W kontekście bezpieczeństwa aplikacji ASP/MVC wystarczy wiedzieć, że kod źródłowy kompilowany jest do komponentów .NET, które są zwykłymi plikami .dll zawierającymi kod pośredni MSIL. Kod pośredni wykonywany jest przez serwer aplikacji (np. IIS). Narzędzia do statycznej analizy kodu mogą analizować albo bezpośrednio kod źródłowy, albo kod pośredni (jeśli potrafią go zrozumieć).
Po skonfigurowaniu środowiska testowego czas przejść do konkretów, czyli do opisu pierwszego narzędzia.
CAT.NET
Code Analysis Tool for .NET, w skrócie CAT.NET, jest programem do analizy kodu pośredniego aplikacji .NET. Umożliwia testy bezpieczeństwa aplikacji konsolowych, desktopowych, a nawet web aplikacji ASP. Narzędzie operuje na plikach .dll lub .exe, które zawierają kod wykonywany w maszynie CLR.
CAT.NET jest jednym z ciekawszych narzędzi do statycznej analizy kodu, ponieważ skupia się wyłącznie na temacie bezpieczeństwa aplikacji. Autorem narzędzia jest sam Microsoft, niestety Code Analysis Tool wydaje się być niechcianym dzieckiem giganta — zawiła historia narzędzia zahamowała jego rozwój. CAT.NET mógł stać się liderem wśród darmowych narzędzi do analizy bezpieczeństwa aplikacji .NET i promować bezpieczeństwo Windows SDK… Tak się niestety nie stało.
1. Skomplikowana historia narzędzia
Prace nad Code Analysis Tool rozpoczęły się w okolicach 2005 roku, jednak program został publicznie udostępniony dopiero trzy lata później. CAT.NET został bardzo ciepło przyjęty przez społeczność programistów, co zresztą zostało zauważone przez Microsoft, który często promował narzędzie na swoich blogach. Zresztą do dnia dzisiejszego CAT.NET funkcjonuje jako zalecane narzędzie do statycznej analizy kodu w aktualnych poradnikach Microsoftu, m.in. w bezpiecznej metodologii wytwarzania oprogramowania — Microsoft SDL.
Algorytmy w narzędziach tego rodzaju nie są trywialne, przez co pierwsze wersje Code Analysis Tool posiadały sporo błędów i niedociągnięć. Program — choć prosty w działaniu i zogniskowany na wąskiej tematyce — zaczął bardzo dręczyć testerów oraz inżynierów bezpieczeństwa, głównie bardzo słabą optymalizacją algorytmów. Gigant niestety był głuchy na opinie społeczności i udostępniał tylko szczątkowe aktualizacje dla narzędzia. Ostatnia udostępniona wersja, CAT.NET 1.1.1.9, pochodzi z połowy 2009 roku i nic nie wskazuje na to, aby automat miał być kiedykolwiek zaktualizowany. Problemy narzędzia — niektóre niezwykle elementarne i frustrujące — prawdopodobnie nie zostaną już nigdy naprawione.
Co ciekawe, Microsoft udostępnił wersję beta CAT.NET 2.0, która miała znacznie zwiększyć skuteczność i wydajność testów. Niestety kod aplikacji bardzo szybko zniknął z witryny Microsoftu, a sam gigant nie udziela żadnych informacji o dalszych planach związanych z rozwojem Code Analysis for .NET.
Nie wiadomo więc, jaka była do końca przyczyna „zawieszenia” projektu oraz gdzie powędrowała wiedza, skupiona wokół automatu. Część algorytmów prawdopodobnie trafiła do przystawki analizy kodu w Visual Studio, część do programu FxCop (który poznamy w części 3. tego cyklu). Gdyby tylko Microsoft udostępnił kod programu CAT.NET, społeczność z pewnością rozwinęłaby to w cudowne narzędzie… Wiadomo jednak, jakie jest stanowisko giganta odnośnie otwartości kodu. Wielka szkoda!
2. Rodzaje wykrywanych błędów
Odstawmy zawiłą historię na bok i poznajmy charakter narzędzia.
CAT.NET potrafi rozpoznawać następujące błędy bezpieczeństwa w aplikacjach konsolowych, okienkowych oraz webowych:
- błędy XSS,
- wstrzyknięcia SQL, XPath oraz LDAP,
- błędy z rodziny „File Canonicalization”,
- błędy przekierowania („Open Redirect”),
- wyciek informacji przez nieodpowiednią obsługę wyjątków,
- niepowołane wykonanie kodu procesu (Process Command Execution).
Powyższe błędy wyszukiwane są w danych, które „przepływają” przez funkcje o zwiększonym ryzyku, nazywanych „Sinks”. Zagrożone funkcje pracują na następujących zasobach:
- File,
- Network,
- Database,
- Exception,
- CommandLine,
- WebRequest,
- WebServiceResponse.
Tak jak opisano w części 1., analiza podatności polega głównie na identyfikacji zmiennych, które przychodzą z zewnętrznych źródeł (np. od użytkownika), a następnie wchodzą na wejście funkcji korzystających z niebezpiecznych zasobów — Sink. Przykładem zagrożonego przepływu danych jest użycie funkcji wypisującej dane od użytkownika w odpowiedzi web serwisu.
Powyższa idea została zobrazowana na diagramie 1., gdzie zilustrowano sposób analizy CAT.NET dla następującej linii kodu:
Response.Write(Server.HTMLEncode(textbox1.Text));
W powyższym kodzie, po stronie serwera web aplikacji, dane od użytkownika odczytywane są przez właściwość Text kontrolki textbox1. Jeżeli dane ze źródła nie zostaną odpowiednio przetransformowane (oczyszczone) przed trafieniem do Sink, wtedy cała linia kodu zostanie uznana za niebezpieczną. W opisywanym fragmencie kodu zmienna od użytkownika została zakodowana odpowiednio do swojego kontekstu, więc CAT.NET uzna użycie funkcji za bezpieczne.
Użycie narzędzia
Wiemy, jak działa narzędzie, sprawdźmy więc jego skuteczność w boju, czyli w naszym środowisku testowym.
Narzędzie CAT.NET można ściągnąć z następujących miejsc:
Nie warto zrażać się dawną datą udostępnienia — jak się za chwilę okaże, narzędzie nadal przydaje się w codziennej pracy programistów oraz inżynierów bezpieczeństwa.
Programu CAT.NET można używać na kilka sposobów. Najczęściej narzędzie uruchamiane jest z poziomu konsoli (CATNetCmd64.exe) lub przez zasady FxCop (Microsoft.ACESec.CATNet.Core.dll). Istnieje również możliwość użycia CAT.NET jako pluginu do Visual Studio — niestety Code Analysis potrafi współpracować co najwyżej z Visual Studio 2010 (po paru modyfikacjach), więc nie warto zaprzątać sobie głowy tą opcją.
W naszych testach będziemy używać wersji konsolowej, 64 bitowej. Tak jak wspomniano wcześniej, CAT.NET na wejściu oczekuje na plik .dll lub .exe. Wyjściem programu jest skrócony raport w konsoli, pliku .html lub .xml.
Po wypakowaniu kodu źródłowego aplikacji HacmeBank można zauważyć, że posiada ona dwa foldery — jeden dla projektu strony (HacmeBank_v2_Website), drugi dla web serwisu (HacmeBank_v2_WS). W każdym z tych katalogów zawarty jest podfolder bin/, z kodem pośrednim do analizy.
Przeanalizujmy najpierw samą aplikację internetową. W tym celu wystarczy, że podamy kod do analizy przy użyciu przełącznika /file. W przełączniku można wybiórczo wskazywać każdy plik do analizy lub wybrać wiele plików pasujących do wzorca, posługując się znakiem gwiazdki:
<b>E:\CAT.NET>CATNetCmd64.exe /file:"E:\Source Hacme Bank v2.0\HacmeBank_v2_Website\bin\*.dll" </b>Microsoft (R) Code Analysis Tool for .NET (CAT.NET) Version 1.1.1.9 Copyright (C) Microsoft Corporation. All rights reserved. Running in 64-bit mode 2013-12-26 18:11:17:Info : Starting analysis [3 modules] 2013-12-26 18:11:17:Info : Analyzing module FS_HttpModule... 2013-12-26 18:11:18:Info : Analyzing module HacmeBank_v2_Website... 2013-12-26 18:11:18:Info : Analyzing module ValidatorNET_GAC_Assembly... 2013-12-26 18:11:19:Info : 16 Cross-Site Scripting issues found. 2013-12-26 18:11:19:Info : 16 Exception Information issues found. 2013-12-26 18:11:19:Info : Analysis completed.
Wynikiem analizy jest plik E:\report.html, który pojawił się w katalogu bieżącym kontekstu konsoli. Raport szczegółowo opisuje wyniki analizy programu:
CAT.NET w projekcie aplikacji internetowej znalazł po 16 błędów z rodzaju XSS oraz Information Leakage. Faktyczna liczba tych błędów w raportowanych miejscach jest mniejsza — darmowe narzędzia charakteryzują się wielokrotnym zgłaszaniem tych samych błędów, które zostały znalezione innymi ścieżkami. Nie zmienia to faktu, że w przeciągu niespełna sekundy dostaliśmy informacje o poważnych błędach.
Przyjrzyjmy się teraz bezpieczeństwu usługi internetowej. Skanowanie projektu web serwisów można wykonać analogicznie jak w poprzednim kroku, wydając polecenie:
E:\CAT.NET>CATNetCmd64.exe /file:"E:\Source Hacme Bank v2.0\HacmeBank_v2_WS\bin\*.dll"
W projekcie usług podatnej aplikacji bankowej CAT.NET wykrył aż 63 błędy SQL Injection. Tak jak w poprzednim przypadku, rzeczywista liczba błędów jest dużo mniejsza, jednak faktycznie w badanym projekcie zapytania SQL nie są odpowiednio zabezpieczenie, przez co atakujący może wykonać wstrzyknięcie w wielu miejscach — podczas wykonywania przelewu, sprawdzania tematu wiadomości zwrotnej, przy zmienianiu hasła i w wielu innych miejscach.
Tak jak pokazano powyżej, CAT.NET pozwala wskazać wiele plików do analizy. Zestawy plików mogą być wskazane przez wykorzystanie znaku gwiazdki lub bezpośrednio przez wskazanie lokalizacji w przełączniku /file. Przydatnym przełącznikiem jest /reportxsloutput, pozwalający wskazać lokalizację pliku raportu oraz /verbose:<Warn|Info|Debug>, dzięki któremu dostaniemy więcej informacji dotyczących działania automatu.
Wykorzystując powyższe przełączniki, możemy w łatwy sposób przeskanować całą solucję w jednym przebiegu, co pokazano na listingu 2.:
CATNetCmd64.exe /file:"E:\Source Hackme Bank v2.0\HacmeBank_v2_Website\bin\*.dll" /file:"E:\Source Hacme Bank v2.0\HacmeBank_v2_WS\bin\*.dll" /reportxsloutput:"E:\HackmeBank Raport 2013-12-26.html" /verbose:Debug
Raport analizy całej solucji pokazuje rodzaje błędów, miejsce ich wystąpienia oraz podstawowe rady, pozwalające wyeliminować luki bezpieczeństwa. Raport z przeprowadzonych badań można ściągnąć poniżej:
Przeanalizujmy jeden z błędów, które trafiły do raportu. W celu weryfikacji, sprawdzimy błąd SQL Injection o numerze #59, który widnieje na listingu 3.:
CAT.NET wskazuje błąd wstrzyknięcia kodu SQL przez zmienną userID, kontrolowaną przez użytkownika. Stos wywołania klas, a w zasadzie przepływ niefiltrowanych danych, jest następujący: WS_AccountManagement ->DataFactory->SqlServerEngine.
Znajdźmy te klasy ze wskazanymi metodami w projekcie web–serwisów:
// AccountManagement.asmx.cs [WebMethod] public ArrayList GetUserAccounts_using_UserID(string SessionID, string userID) { return HacmeBank_v2_WS.DataFactory.GetUserAccounts_using_userID(userID); } // DataFactory.cs public static ArrayList GetUserAccounts_using_userID(string userID) { string sqlQuery = "select account_no from fsb_accounts where user_ID = " + userID; return SqlServerEngine.returnArrayListFromSQLQuery_containing_FirstFieldFromAllRows(sqlQuery); } // SqlServerEngine.cs public static ArrayList returnArrayListFromSQLQuery_containing_FirstFieldFromAllRows(string sqlQuery) { ArrayList QueryResults = new ArrayList(); SqlDataReader reader1 = executeSQLCommand_returnSqldataReader(sqlQuery); //... return QueryResults; }
Jak widać, zmienna userID jest przekazywana do fabryki danych, która tworzy zapytanie SQL przez sklejanie ciągów znaków. Następnie ciąg ten przekazywany jest do silnika SQL w postaci niefiltrowanej — mamy więc tutaj do czynienia z klasycznym przypadkiem luki SQL Injection. CAT.NET w tym wypadku poprawnie wykrył lukę w mocno zagmatwanym wywołaniu funkcji bazodanowej.
Pełna lista parametrów programu CAT.NET została przedstawiona na rysunku 3. Warto dodać, że konfiguracja programu znajduje się w katalogu config, gdzie można zdefiniować nie tylko zachowanie narzędzia, ale również edytować listę koderów czy plik szablonów XSL dla pliku raportów.
Problemy
Głównym problemem narzędzia CAT.NET jest jego wielki apetyt na zużywaną moc obliczeniową oraz pamięć. Po analizie kilkunastu projektów łatwo zauważyć, że narzędzie było pisane przez Microsoft po łebkach, bez większej dbałości o jakość algorytmów. Można zauważyć, że w ogólnym przybliżeniu, algorytmy wykazują złożoność o charakterze wykładniczym. Choć w małych projektach, przykładowo takich jak analizowany przed chwilą, czas testów wynosi kilka sekund, tak już w niedużo większych solucjach, czas analizy może wynieść godziny, a nawet dni.
Na szczęście z tym problemem można skutecznie walczyć. Przede wszystkim testy należy przeprowadzać na maszynie z dużą ilością pamięci — Microsoft zaleca 1 GB RAM na każdy 1MB danych wejściowych. Dla większości przypadków powinna wystarczyć maszyna z 8 GB pamięci.
Po drugie bardzo ważnym jest, aby maksymalnie zmniejszać rozmiar danych wejściowych. W praktyce skompilowane źródła projektów zawierają dużo bibliotek systemowych (np. Microsoft.*) oraz bibliotek twórców zewnętrznych (np. Lucene, EntityFramework, log4net, Newtonsoft.Json). Analiza statyczna takich zasobów w wypadku CAT.NET mija się z celem — często nie mamy dostępu do kodu źródłowego tych bibliotek, same narzędzia zostały już przetestowane przez twórców, społeczność lub klientów. Jeżeli chcemy przeanalizować bezpieczeństwo takich projektów, powinniśmy podjąć bardziej zaawansowane kroki, niż statyczna analiza kodu.
W każdym razie pliki .dll takich bibliotek zazwyczaj stanowią 40—80% wielkości całej solucji, więc zignorowanie ich w procesie analizy znacznie skróci czas skanowania. Po takim wykluczeniu, w dużych projektach, czas analizy CAT.NET może się skrócić z kilku dni nawet do kilku minut!
CAT.NET ogólnie boryka się z wieloma innymi problemami. Stosunkowo często zdarza się sytuacja, że program przestaje działać przy analizie konkretnej biblioteki ze względu na błędy w samym programie, które nie zostały poprawnie obsłużone. Nie pozostaje nic innego, jak ominąć analizę biblioteki powodującej problem.
Nie istnieje również prosty sposób wykluczania analizowanych bibliotek, np. nie ma możliwości dodania wszystkich bibliotek z folderu przy użyciu /file:*.dll, a następnie pominięcie jednego pliku (np. tego, który może powodować zawieszenie skanowania). Zamiast tego, należy podać wielokrotnie parametr /file, który będzie wskazywać każdą bibliotekę z osobna — jest to niestety mało wygodne.
Kolejnym problemem, w szczególności w środowiskach ciągłej integracji lub podczas automatyzacji, jest obsługa błędów aplikacji konsolowej CAT.NET. Microsoft nie postarał się o zwracanie kodów błędów w aplikacji konsolowej, więc w zasadzie nie ma prostego sposobu stwierdzenia, czy skrypt wykonujący analizę CAT.NET zwrócił dobry wynik czy wystąpiły w nim jakieś błędy (np. spowodowane złymi parametrami). Program CATNetCmd64.exe w każdej sytuacji zwraca zmienną %ERRORLEVEL% = 0, co bardzo utrudnia pisanie skryptów.
Wdrożenie do projektów
CAT.NET, mimo swoich wad, dalej jest jednym z najlepszych darmowych analizatorów kodu aplikacji pisanych w ekosystemie Microsoft. Przy odpowiednim skonfigurowaniu, można bardzo prosto go wdrożyć jako element testów automatycznych.
CAT.NET przydaje się szczególnie w systemach ciągłej integracji (ang. Continuous Integration; CI), takich jak Hudson/Jenkins, jako narzędzie sprawdzające bezpieczeństwo kodu po każdym wywołaniu maszyny budującej projekt (msbuild). W takim przypadku cały zespół programistyczny dostanie informacje o potencjalnej luce od razu po wprowadzeniu jej do kodu.
Ze względu jednak na niestabilność narzędzia i dość sporą liczbę błędów false negative/false positive raport z pracy Code Analysis for .NET powinien być każdorazowo sprawdzany przez członka zespołu mającego doświadczenie w bezpieczeństwie aplikacji .NET.
Adrian “Vizzdoom” Michalczyk