<?xml version="1.0" encoding="utf-8" ?>
<?xml-stylesheet href="" type="text/css"?>

<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
         xmlns:dc="http://purl.org/dc/elements/1.1/"
         xmlns:dcterms="http://purl.org/dc/terms/"
         xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
         xmlns:rss="http://purl.org/rss/1.0/"
         xmlns:content="http://purl.org/rss/1.0/modules/content/">

    <rss:channel rdf:about="http://www.webservice.eu/pl/nowosci/security-blog">

        <rss:title>Security blog</rss:title>
        <rss:link>http://www.webservice.eu/pl/nowosci/security-blog</rss:link>

        
        <rss:description>Security blog RSS 1.0 feed.</rss:description>

        <rss:image rdf:resource="http://www.webservice.eu/logo.png"/>

        <sy:updatePeriod>daily</sy:updatePeriod>
        <sy:updateFrequency>1</sy:updateFrequency>

        <rss:items>
            <rdf:Seq>
                
                <rdf:li rdf:resource="http://www.webservice.eu/pl/nowosci/security-blog/archive/2008/07/01/kolejny-audyt-bezpieczenstwa-dla-bre-banku"/>
                
                
                <rdf:li rdf:resource="http://www.webservice.eu/pl/nowosci/security-blog/archive/2008/05/19/Bezpieczenstwo.NET"/>
                
                
                <rdf:li rdf:resource="http://www.webservice.eu/pl/nowosci/security-blog/archive/2008/04/22/blind-sql-injection"/>
                
                
                <rdf:li rdf:resource="http://www.webservice.eu/pl/nowosci/security-blog/archive/2008/04/16/kolejny-audyt-bezpieczenstwa"/>
                
                
                <rdf:li rdf:resource="http://www.webservice.eu/pl/nowosci/security-blog/archive/2008/03/31/sql-injection-mit-bezpiecznych-procedur"/>
                
                
                <rdf:li rdf:resource="http://www.webservice.eu/pl/nowosci/security-blog/archive/2008/02/15/multi-sql-injection-w-phorum"/>
                
                
                <rdf:li rdf:resource="http://www.webservice.eu/pl/nowosci/security-blog/archive/2008/02/07/persistent-xss-w-wordpress"/>
                
                
                <rdf:li rdf:resource="http://www.webservice.eu/pl/nowosci/security-blog/archive/2008/01/29/blad-persistent-xss-w-allegro"/>
                
                
                <rdf:li rdf:resource="http://www.webservice.eu/pl/nowosci/security-blog/archive/2008/01/22/sql-injections-w-allegro"/>
                
                
                <rdf:li rdf:resource="http://www.webservice.eu/pl/nowosci/security-blog/archive/2008/01/15/Dwa-audyty-bezpiczenstwa-dla-Bre-Bank-S.A"/>
                
                
                <rdf:li rdf:resource="http://www.webservice.eu/pl/nowosci/security-blog/archive/2008/01/10/witam-na-blogu-security"/>
                
            </rdf:Seq>
        </rss:items>
    </rss:channel>

    <rss:image rdf:about="http://www.webservice.eu/logo.png">
        <rss:title>Security blog</rss:title>
        <rss:link>http://www.webservice.eu/pl/nowosci/security-blog</rss:link>
        <rss:url>http://www.webservice.eu/logo.png</rss:url>
    </rss:image>

    

    <rss:item rdf:about="http://www.webservice.eu/pl/nowosci/security-blog/archive/2008/07/01/kolejny-audyt-bezpieczenstwa-dla-bre-banku">

        <rss:title>Kolejny audyt bezpieczeństwa dla BRE Banku</rss:title>

        <rss:link>http://www.webservice.eu/pl/nowosci/security-blog/archive/2008/07/01/kolejny-audyt-bezpieczenstwa-dla-bre-banku</rss:link>       

        <rss:description>Tym razem wykonaliśmy audyt bezpieczeństwa aplikacji desktopowej Windows. </rss:description>

        <content:encoded>
          <![CDATA[
          
<p>Dodatkowo przeprowadzony został audyt infrastruktury: systemu operacyjnego oraz bazy danych.</p>
<p>Całość prac potwierdzona została listem referencyjnym, uznającym wysoki poziom naszej wiedzy audytorskiej oraz profesjonalizm wykonanych przez nas prac.</p>

          ]]>
        </content:encoded>        

        <dc:date>2008-07-01T11:15:00+02:00</dc:date>

        <dcterms:modified>2010-07-12T16:07:17+02:00</dcterms:modified>

        <dc:creator>xterm</dc:creator>

        

        
            <dc:subject>audyt aplikacji</dc:subject>
        
        
            <dc:subject>audyt bezpieczeństwa</dc:subject>
        

    </rss:item>

    
    

    <rss:item rdf:about="http://www.webservice.eu/pl/nowosci/security-blog/archive/2008/05/19/Bezpieczenstwo.NET">

        <rss:title>Bezpieczeństwo .NET</rss:title>

        <rss:link>http://www.webservice.eu/pl/nowosci/security-blog/archive/2008/05/19/Bezpieczenstwo.NET</rss:link>       

        <rss:description>Przegląd po wybranych aspektach bezpieczeństwa .NET</rss:description>

        <content:encoded>
          <![CDATA[
          
<h3><strong><strong>Od redakcji ;-)<br /></strong></strong></h3>
<p>Autorem poniższego postu jest <strong>Piotr Łaskawiec. </strong>Serdecznie dziękujemy Piotrowi za umożliwienie nam publikacji tekstu <strong>:-</strong>) Jeśli ktoś chciałby opublikować <strong>swój</strong> tekst na naszym security blogu, gorąco do tego zachęcam (wystarczy wysłać e-maila na adres <a href="mailto:security@webservice.pl">security@webservice.pl</a>).&nbsp; <br />--Michał Sajdak</p>
<hr />
<p>&nbsp;</p>
<p>Aplikacje pisane w środowisku .NET mają opinię bezpiecznych
i pozbawionych błędów programów. Oczywiście końcowe bezpieczeństwo programów
zależy od programisty, procesu wdrożenia do użytku i etapu projektowania, ale
.NET zapewnia cały szereg ułatwień i mechanizmów nadzorujących pracę developera
i eliminujących możliwość wystąpienia błędów. Jednak nawet najbardziej
zaawansowana technologicznie platforma nie jest w stanie zagwarantować pełnego
bezpieczeństwa.</p>
<p>W wyniku ciągłego wzrostu popularności platformy .NET, nie
tylko jako narzędzia do tworzenia aplikacji B2B, ale także jako środowiska będącego
fundamentem wielu stron czy portali internetowych warto znać podstawowe błędy
popełniane przez programistów i metody ich wykorzystywania.</p>
<h3><strong>Słowem wstępu</strong></h3>
<p><strong>.</strong>NET Framework jest
platformą programistyczną stworzoną jako odpowiedź na język Java. W jego skład
wchodzi środowisko uruchomieniowe i cały zestaw wyspecjalizowanych bibliotek.
Środowisko uruchomieniowe odpowiedzialne jest za zarządzanie pamięcią i
obiektami oraz zapewnia nam możliwość uruchamiania programów na różnorodnych
platformach sprzętowych i systemach operacyjnych. Co więcej, programiści
piszący „pod .NET” nie są zmuszeni do korzystania z jednego języka. Framework
umożliwia korzystanie z całej gamy współpracujących języków takich ja C#,
Visual Basic .NET, Python (IronPython) czy zarządzany C++.</p>
<p>.NET można także traktować jako zbiór wielu technologii
przeznaczonych do różnych celów. W tym artykule poruszane będą głównie tematy
związane z technologią ASP.NET. ASP.NET jest frameworkiem wchodzącym w skład
platformy .NET i pozwalającym na pisanie dynamicznych stron internetowych i
aplikacji sieciowych.</p>
<h3><strong>Iluzoryczne
bezpieczeństwo</strong></h3>
<p>Jak już wiemy cała platforma .NET bazuje na środowisku
uruchomieniowym, które powinno zabezpieczać przed takimi błędami jak
przepełnienie bufora czy nieprawidłowe wykorzystanie ciągów formatujących. CLR
(Common
Language Runtime) nie pozwala na wykonanie dowolnego kodu w wyniku wystąpienia
błędów typu Buffer Overflow, ale tylko i wyłącznie podczas pracy z zarządzanym
kodem. W wielu aplikacjach pisanych pod .NET łączy się kod zarządzany z
wywołaniami WinAPI, komponentami COM czy kontrolkami ActiveX, które nie
podlegają kontroli. Wiele osób o tym zapomina i w efekcie tworzy programy
podatne na błędy związane z nieprawidłowym zarządzaniem pamięcią. W wyniku
użycia elementów niezarządzanych, całościowe bezpieczeństwo aplikacji zostaje
zredukowane. Fragmenty kodu podatne na ataki typu „Buffer overflow” czy „Format
string vulnerability” stają się najsłabszymi ogniwami programu i nie są
monitorowane przez CLR. Należy o tym pamiętać podczas tworzenia aplikacji oraz
mieć pewność, że kod niezarządzany używany w naszej aplikacji jest bezpieczny i
pozbawiony jakichkolwiek wad mogących być przyczyną włamania.</p>
<h3><strong>Pokaż mi kod a powiem
Ci kim jesteś</strong></h3>
<p>Kolejna ważna cecha
platformy .NET związana jest z procesem kompilacji kodu. Kod źródłowy aplikacji
zamieniany jest na kod wykonywalny, zapisany w języku pośrednim MSIL (<em>Microsoft</em> Intermediate Language). MSIL zawiera cały szereg metadanych
opisujących typy obiektów, implementowane interfejsy, zdarzenia itd. W czasie
wykonywania aplikacji, Common Language Runtime tłumaczy kod MSIL na kod
maszynowy procesora, na którym wykonywana jest aplikacja. Operacja ta nazywana
jest „JIT – Just-in-time compilation”. Oprócz niewątpliwych zalet takiego
rozwiązania (przenośność kodu, współpraca z różnymi architekturami, w pełni
zarządzany kod) istnieją także wady… a szczególnie jedna najpoważniejsza. MSIL
bardzo łatwo zamienić z powrotem na kod źródłowy za pomocą dekompilatorów.
Dzięki informacjom przechowywanym w MSIL jest to proces łatwy, a efekt pracy
dekompilatora jest w większości przypadków zbliżony do oryginalnego kodu
źródłowego aplikacji. Aby zobrazować ryzyko płynące z tego typu błędów warto
posłużyć się przykładem. Załóżmy, że mamy prosty program, w którym zapisane
jest hasło. Hasło jest sprawdzane dopóki użytkownik nie poda odpowiedniego
ciągu znaków. Kod naszego programiku wygląda następująco:</p>
<p>&nbsp;</p>
<blockquote>
<p><span class="visualHighlight">using System;</span></p>
<p><span class="visualHighlight">using
System.Collections.Generic;</span></p>
<p><span class="visualHighlight">using
System.Linq;</span></p>
<p><span class="visualHighlight">using
System.Text;</span></p>
<p><span class="visualHighlight">&nbsp;</span></p>
<p><span class="visualHighlight">namespace obftest</span></p>
<p><span class="visualHighlight">{</span></p>
<p><span class="visualHighlight">&nbsp;&nbsp;&nbsp; class Program</span></p>
<p><span class="visualHighlight">&nbsp;&nbsp;&nbsp; {</span></p>
<p><span class="visualHighlight">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; static string
password = "Verysecurepassword";</span></p>
<p><span class="visualHighlight">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; static void Main(string[] args)</span></p>
<p><span class="visualHighlight">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span></p>
<p><span class="visualHighlight">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Console.WriteLine("Type
the password...");</span></p>
<p><span class="visualHighlight">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (Console.ReadLine()
!= password)</span></p>
<p><span class="visualHighlight">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Console.WriteLine("Bad
password!");</span></p>
<p><span class="visualHighlight">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Console.WriteLine("Gratz!
Password is fine!");</span></p>
<p><span class="visualHighlight">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>
<p><span class="visualHighlight">&nbsp;&nbsp;&nbsp; }</span></p>
<p><span class="visualHighlight">}</span></p>
</blockquote>
<p>&nbsp;</p>
<p>Przyjmijmy, że jest to fragment większej aplikacji a
powyższe kilka linijek przedstawia proces uwierzytelniania użytkowników. Będąc
w posiadaniu już skompilowanego programu jesteśmy w stanie bezproblemowo
odtworzyć kod źródłowy i poznać wewnętrzną logikę aplikacji. W sieci istnieje
wiele dekompilatorów dla platformy .NET - .NET Reflector, Dis# czy Salamander
.NET Decompiler. Sprawdźmy jakie wyniki otrzymamy po dekompilacji naszego
przykładowego programu.</p>
<p>Wynik działania programy .NET Reflector:</p>
<blockquote>
<p>namespace obftest</p>
<p>{</p>
<p>&nbsp;&nbsp;&nbsp; class Program</p>
<p>&nbsp;&nbsp;&nbsp; {</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; static string
password = "Verysecurepassword";</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; static void Main(string[] args)</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Console.WriteLine("Type
the password...");</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (Console.ReadLine()
!= password)</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;Console.WriteLine("Bad password!");</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Console.WriteLine("Gratz!
Password is fine!");</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; }</p>
<p>}</p>
</blockquote>
<p>Wynik jest dość jednoznaczny. Uzyskaliśmy identyczny kod
źródłowy. W przypadku gdy przechowujemy w kodzie wrażliwe informacje użycie
dekompilatora doprowadzi do ich przejęcia. Łatwo sobie wyobrazić sytuację, w
której po uruchomieniu dekompilatora włamywacz staje się posiadaczem hasła do
bazy danych czy identyfikatorów użytkowników w systemie logowania. Aby zaradzić
takiej sytuacji musimy zmienić styl pisania programów i zmniejszyć
prawdopodobieństwo pozyskania danych przez potencjalnego napastnika. Oczywiście,
najprostszym wyjściem jest przetrzymywanie wrażliwych danych poza kodem, ale
nie zniweluje to ryzyka poznania logiki programu. Możemy (a nawet powinniśmy)
skorzystać z szyfrowania nazw użytkowników oraz haseł ale takie rozwiązanie
jest nieefektywne w odniesieniu do adresów internetowych itd.</p>
<p>Z pomocą przychodzą nam programy, które zamieniają kod
wynikowy na mniej czytelny i nie pozwalają na łatwe przechwycenie danych -
obfuscatory. Nawet z najprostszych kawałków kodów tworzą one nieczytelną
plątaninę i skutecznie utrudniają życie atakującemu. Prześledźmy jak wygląda
nasz testowy program po przepuszczeniu go przez wbudowany w Visual Studio
(popularne IDE Microsoftu) obfuscator (z uwzględnieniem opcji „string
encryption”). Wynik powinien być zbliżony do tego listingu:</p>
<blockquote>
<p>using System;</p>
<p>&nbsp;</p>
<p>internal class a</p>
<p>{</p>
<p>&nbsp;&nbsp;&nbsp; private static string a = "\u246d\u112a\u213k\u1128…";</p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp; private static void a(string[] A_0)</p>
<p>&nbsp;&nbsp;&nbsp; {</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Console.WriteLine("\u1272\u1273…");</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (Console.ReadLine()
!= a)</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Console.WriteLine("\u246l\u2478t\u3433…");</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Console.WriteLine("\u1234\u1289\u1273…");</p>
<p>&nbsp;&nbsp;&nbsp; }</p>
<p>}</p>
</blockquote>
<p>Można zauważyć znaczne
zmniejszenie się czytelności kodu. Teraz pozyskanie informacji nie jest już tak
banalnie proste. Jednak bezpieczeństwo komputerowe bazuje na kompromisach.
Obfuscatory kodujące łańcuchy tekstowe zawsze umieszczają w programie wynikowym
funkcję, która pozwoli na późniejsze odkodowanie znaków. Funkcja ta jest
umieszczana na stosie wywołań przed pierwszym wystąpieniem zakodowanych
łańcuchów. Nic nie stoi więc na przeszkodzie aby przy odrobienie wysiłku dostać
się do wrażliwych danych.</p>
<p>Jednak odpowiedni styl
programowania, dobre umiejscowienie danych, szyfrowanie i użycie obfuscatorów
powinno skutecznie odstraszyć leniwego włamywacza.</p>
<h3><strong>Szyfrowanie plików web.config</strong></h3>
<p>Web.config jest plikiem
używanym podczas tworzenia stron opartych o technologię ASP.NET. W pliku tym
znajdują się informacje konfiguracyjne sterujące pracą programu, łańcuchy
tekstowe umożliwiające połączenie z bazą danych oraz szereg innych ważnych
danych. Pliki web.config przechowywane są w głównym katalogu danej aplikacji,
ale mogą także występować w katalogach podrzędnych (przesłaniając wtedy
ustawienia głównego pliku konfiguracyjnego). Uzyskanie dostępu do tego pliku, w
wyniku włamania lub błędu serwera, przez osobę niepowołaną praktycznie
kompromituje całą aplikację. Wiedza zgromadzona przez włamywacza byłaby na tyle
duża, że pozwoliłaby na przejęcie kontroli nad programem. Warto więc poświęcić
czas na zaznajomienie się z techniką uniemożliwiającą efektywne wykorzystanie
zdobytych informacji. Rozwiązaniem tym jest szyfrowanie newralgicznych sekcji
pliku web.config. Przyjrzyjmy się najważniejszym miejscom &nbsp;tego pliku:</p>
<blockquote>
<p>&lt;?xml version="1.0"?&gt;</p>
<p>&lt;configuration&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;configSections&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; …</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/configSections&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;appSettings&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/appSettings&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;connectionStrings&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; …</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/connectionStrings&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;system.net&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; …</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/system.net&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;system.web&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; …</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/system.web&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;system.webServer&gt;</p>
<p>…</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/system.webServer&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; …</p>
<p>&lt;/configuration&gt;</p>
</blockquote>
<p>&nbsp;</p>
<p>Oczywiście jest to tylko skrócona wersja pliku Web.config,
nie zawierająca żadnych danych. Warto jednak zwrócić uwagę na znaczniki
&lt;appSettings&gt;, &lt;connectionStrings&gt; oraz&nbsp; &lt;system.net&gt;. To właśnie w tych
sekcjach przechowywane są informacje przydatne z punktu widzenia włamywacza. Mogą
to być np. informacje wymagane do nawiązania połączenia z bazą danych:</p>
<blockquote>
<p>&lt;connectionStrings&gt;</p>
<p>&nbsp;&nbsp;&nbsp; &lt;add name="example" connectionString="Data Source=localhost;Initial
Catalog=exampledb;User ID=root;Password=toor" providerName="System.Data.SqlClient"/&gt;</p>
<p>&lt;/connectionStrings&gt;</p>
</blockquote>
<p>&nbsp;</p>
<p>ustawienia przechowywane w
web.config i wykorzystywane w kodzie poprzez odpowiednie odwołania:</p>
<blockquote>
<p>&lt;appSettings&gt;</p>
<p>&nbsp;&nbsp;&nbsp; &lt;add key="From" value="root@localhost.com"/&gt;</p>
<p>&nbsp;&nbsp;&nbsp; &lt;add key="Subject" value="Email schema!"/&gt;</p>
<p>&nbsp;&nbsp;&nbsp; &lt;add key="SmtpServer" value="localhost"/&gt;</p>
<p>&nbsp;&nbsp;&nbsp; &lt;add key="MailUser" value="example"/&gt;</p>
<p>&nbsp;&nbsp;&nbsp; &lt;add key="MailPassword" value="example"/&gt;</p>
<p>&nbsp;&nbsp;&nbsp; &lt;add key="MailPort" value="25"/&gt;</p>
<p>&nbsp;&nbsp;&nbsp; &lt;add key="EmailFormat" value="Text"/&gt;</p>
<p>&lt;/appSettings&gt;</p>
</blockquote>
<p>&nbsp;</p>
<p>lub też ustawienia
zewnętrznych serwerów (np. SMTP):</p>
<p>&nbsp;</p>
<blockquote>
<p>&lt;system.net&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;mailSettings&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;smtp from=”<a href="mailto:root@localhost.com">root@localhost.com</a>”&gt;</p>
<p>&lt;network host="localhost" password="example" userName="example"/&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/smtp&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/mailSettings&gt;</p>
<p>&lt;/system.net&gt;</p>
</blockquote>
<p><strong>&nbsp;</strong></p>
<p>Każdy z tych przykładów przedstawia informacje, do których
nie powinny mieć dostępu osoby nieuprawnione. Aby utrudnić odczyt danych (które
przechowywane są w formie jawnej) należy zastosować szyfrowanie za pomocą
narzędzi oferowanych przez .NET. Użyjemy programu aspnet_regiis znajdującego się
w katalogu domowym Frameworka (domyślnie jest to C:\Windows\Microsoft.NET\Framework\v2.0.50727).
Posiada on opcję szyfrowania wybranych sekcji pliki Web.config. Składnia
polecenia wygląda następująco:</p>
<blockquote>
<p><em>aspnet_regiis –pef
„nazwa_sekcji” „pełna ścieżka do katalogu, w którym znajduje się plik
Web.config” </em></p>
</blockquote>
<p><em>
 
 
  
  
  
  
  
  
  
  
  
  
  
  
 
 
 

 
</em></p>
<p><img class="image-inline" src="../zdjecia/bezpieczenstwonet3.jpg/image_preview" alt="bezpieczenstwonet3" /></p>
<p>Po uruchomieniu naszego programu dla sekcji
connesctionStrings, plik Web.config będzie zawierał następujący wpis:</p>
<blockquote>
<p>&lt;connectionStrings
configProtectionProvider="RsaProtectedConfigurationProvider"&gt;</p>
<p>&nbsp;&nbsp;&nbsp; &lt;EncryptedData Type="http://www.w3.org/2001/04/xmlenc#Element"</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; xmlns="http://www.w3.org/2001/04/xmlenc#"&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#tripledes-cbc" /&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#"&gt;</p>
<p>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;EncryptedKey xmlns="http://www.w3.org/2001/04/xmlenc#"&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5" /&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#"&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;KeyName&gt;Rsa Key&lt;/KeyName&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&lt;/KeyInfo&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;CipherData&gt;</p>
<p>&lt;CipherValue&gt;E+cdLBak7iXnNSez6EvKToVIv+QB9+4WnTQwCRf05P9SA6U4pje9EOyGAlQvuMCSCioXX1tfHE4ldVHoE2i3DAmUuF3HUL6nMsCvl6bPRnGxMrBieLT0oWeYX9gTEAV+zDJS67HQgOcn0FK1ZI6CRma+2CXtSGGhfd8WxhPxkpY=&lt;/CipherValue&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/CipherData&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/EncryptedKey&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/KeyInfo&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;CipherData&gt;</p>
<p>&lt;CipherValue&gt;rQzgfu1CufYM46+DUp8kzO88mXyOvZ3sNU+6Fs/QBOH8FeQUiWq6T0m3qTMFAf7XUkS1BpjLN6PuoTqDqIi7r1d40AG3a4vCbGJ9SJWv45hbGj8Z7Dge05SW2p5qtloMq33TKfuDK6MG2IqDy6R8w4USOghMOCdEqkmpVihWVJG54/Kg9yonM7xgQF+zI1D8jFhV3JZ1hcvwE28Z/LT79bk+EOlAAH++ILXVB9YUcvJkr9gM6psDNcixg/MO0Z9GozNhgsWwb30K5MerR72o0JCLHDNijFjKtCBr7OOZArmHLU1h4hjcGWhlR6tZtkZW&lt;/CipherValue&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/CipherData&gt;</p>
<p>&nbsp;&nbsp;&nbsp; &lt;/EncryptedData&gt;</p>
<p>&lt;/connectionStrings&gt;</p>
</blockquote>
<p>Narzędzie aspnet_regiis
standardowo używa RsaProtectedConfigurationProvider do szyfrowania danych. Możemy wtedy z łatwością
wyeksportować klucz prywatny RSA i użyć go na innych komputerach (np. na farmie
połączonych ze sobą maszyn). Jeżeli nasza aplikacja ma pracować na pojedynczym
serwerze możemy użyć DataProtectionConfigurationProvider. Aby tego dokonać
wystarczy dodać parametr „-prov” do wywołania programu aspnet_regiis:</p>
<blockquote>
<p><em>aspnet_regiis –pef „nazwa_s” „ścieżka” –prov DataProtectionConfigurationProvider</em></p>
</blockquote>
<p>Szyfrowanie plików konfiguracyjnych znacznie zwiększy
bezpieczeństwo naszej aplikacji. Uzyskanie dostępu do takiego pliku przestanie
być równoznaczne z uzyskaniem dostępu do poufnych danych przechowywanych np. w
bazie danych.</p>
<h3><strong>SQL Injection</strong></h3>
<p>Termin „SQL Injection” jest już dobrze znany przez większość
programistów i specjalistów ds. bezpieczeństwa komputerowego. Napisano o nim
wiele i każdy może na własną rękę wyszukać potrzebne informacje. Niestety,
pomimo tak dużej popularności błędów polegających na wstrzykiwaniu własnego
kodu SQL, w .NET nie zaimplementowano natywnej ochrony przed ich występowaniem.
Przestrzeń nazw SQL.Data.SqlClient, która udostępnia szereg klas
odpowiedzialnych za nawiązywanie połączeń i pobieranie danych z bazy posiada
pewne mechanizmy zapobiegające atakom, ale ich poprawne wykorzystanie leży w
rękach programisty. W związku z tym warto przedstawić kilka przykładów
obrazujących, w których fragmentach kodu mogą wystąpić podatności. Dobrym
przykładem kodu podatnego na SQL Injection jest poniższy fragment:</p>
<blockquote>
<p>string userID = Console.ReadLine();</p>
<p>string conString
= WebConfigurationManager.ConnectionStrings["ExampleDB"].ConnectionString;</p>
<p>SqlConnection DBConn
= new SqlConnection(conString);</p>
<p>String sqlString
= "SELECT * FROM Users WHERE id=’" +
userID + “’”;</p>
<p>SqlCommand
sqlCmd = new SqlCommand(sqlString,
DBConn);</p>
<p>sqlCmd.CommandType = CommandType.Text;</p>
<p>DBConn.Open();</p>
<p>SqlDataReader
reader = sqlCmd.ExecuteReader(CommandBehavior.CloseConnection);</p>
</blockquote>
<p>&nbsp;</p>
<p>Listing ten jest prosty, ale
idealnie obrazuje problem. Pomimo tego, że powyższy fragment jest tylko
abstrakcyjnym modelem podatnego kodu to występują w nim elementy, na które
warto zwrócić uwagę przy audycie aplikacji pisanej pod .NET. Prześledźmy źródło
w poszukiwaniu błędów.</p>
<p>Po pierwsze, id przyjmowane
jest bezpośrednio od użytkownika. Następnie, pobierany jest ciąg odpowiedzialny
za połączenie z bazą danych. Oczywiście, ten element powinien być już
zabezpieczony zgodnie ze wskazówkami z poprzedniego rozdziału. Następnie
tworzony jest obiekt klasy SqlConnection. Kolejna linijka kodu przedstawia
zapytanie SQL. Właśnie to miejsce narażone jest na atak. Zapytanie tworzone
jest poprzez łączenie ciągów znakowych bez użycia walidacji. Włamywacz może
przekazać do userID ciąg znaków rozpoczynający się od pojedynczego apostrofu
(‘) a następnie wykonać dowolną operację na naszej bazie. Jest to dość
popularny błąd. Kolejne linijki obrazują ustawienie typu zapytania (w naszym
wypadku jest to tradycyjne zapytanie SQL) oraz wykonanie zapytania i
przekazanie wyników do instancji klasy SqlDataReader.</p>
<p>Jak można zapobiegać błędom
tego typu? Możemy zastosować walidację danych wejściowych (jest to zalecane) i
np. podwajać przekazywane apostrofy:</p>
<blockquote>
<p>&nbsp;userID = userID.Replace(“’”, “’’”);</p>
</blockquote>
<p>Jest to jednak rozwiązanie
niewystarczające. Oczywiście zapewnia podstawową ochronę, ale istnieje duże
prawdopodobieństwo złego dopasowania autorskich walidatorów i w wyniku tego
umożliwienie ataku. Aby zapewnić dodatkową ochronę należy użyć
sparametryzowanych zapytań. Pozwalają one rozgraniczyć dane przekazywane przez
użytkownika od wartości używanych przy dokonywaniu zapytania SQL oraz są
automatycznie kodowane (w celu zniwelowania niebezpiecznych znaków). Po modyfikacji kodu,
otrzymamy:</p>
<blockquote>
<p>string userID = Console.ReadLine();</p>
<p>string conString
= WebConfigurationManager.ConnectionStrings["ExampleDB"].ConnectionString;</p>
<p>SqlConnection
DBConn = new SqlConnection(conString);</p>
<p>String sqlString
= "SELECT * FROM Users WHERE id=@userID”;</p>
<p>SqlCommand
sqlCmd = new SqlCommand(sqlString,
DBConn);</p>
<p>sqlCmd.Parameters.AddWithValue(“@userID”, userID);</p>
<p>sqlCmd.CommandType = CommandType.Text;</p>
<p>DBConn.Open();</p>
<p>SqlDataReader
reader = sqlCmd.ExecuteReader(CommandBehavior.CloseConnection);</p>
</blockquote>
<p>&nbsp;</p>
<p>Drobna zmiana kodu pozwoliła
nam uniknąć wielu nieprzyjemności związanych z możliwością występowania SQL
Injection. Parametry, charakteryzujące się znakiem „@” przed nazwą przyjmują
wartości poprzez funkcję AddWithValue(). Dzięki temu unikamy procesu
konkatenacji łańcuchów znakowych, będącego przyczyną błędów.</p>
<p>Nie jest to jedyna metoda
unikania luk bezpieczeństwa. Możemy użyć także procedur zapisanych bezpośrednio
w bazie danych. Dobrze napisana procedura powinna skutecznie chronić przed
atakami typu SQL Injection. Wielu programistów uważa, że procedury
zawsze będą chronić naszą aplikację. Niestety jest to myślenie błędne.
Dlaczego? Zapraszam do zapoznania się z artykułem pod adresem <a href="../sql-injection-mit-bezpiecznych-procedur">http://www.webservice.pl/pl/nowosci/security-blog/sql-injection-mit-bezpiecznych-procedur</a>.</p>
<h3><strong>Niebezpieczny ViewState</strong></h3>
<p>ViewState jest mechanizmem
wykorzystywanym do przechowywania stanu aplikacji. Dzięki niemu możemy np.
zapamiętywać stan kontrolki (np. zaznaczone elementy na liście) pomiędzy
kolejnymi przeładowaniami witryny. ViewState wykorzystywany jest także do
przechowywania „zwykłych” danych. Aby zapamiętać wartość danej zmiennej w
ViewState wystarczy napisać krótki kawałek kodu:</p>
<blockquote>
<p>int test = 1;</p>
<p>ViewState["Test"]
= test;</p>
</blockquote>
<p>&nbsp;</p>
<p>Następnie, aby odzyskać
wartość zmiennej:</p>
<blockquote>
<p>int test = (int)ViewState["Test"];</p>
</blockquote>
<p>&nbsp;</p>
<p>Jak rozpoznać czy dana strona
korzysta z ViewState? Wystarczy podejrzeć źródło strony i wyszukać elementy,
których struktura przypomina:</p>
<blockquote>
<p>&lt;input
type="hidden" name="__VIEWSTATE" id="__VIEWSTATE"</p>
<p><strong>value="bBw3NDg2KTR5MDg56z5=" </strong>/&gt;</p>
</blockquote>
<p>Ciąg znaków przechowywanych w value określa wartość
przechowywanego elementu. Jak można zauważyć jest to wartość zakodowana.
Niestety, jej odczytanie w formie jawnego tekstu jest banalnie proste. Ciąg
umieszczony w value używa algorytmu Base64, który jest łatwy do odszyfrowania.
Istnieją także narzędzia, które automatyzują ten proces (np. ViewStateDecoder).</p>
<p><img class="image-inline" src="../zdjecia/bezpieczenstwonet1.jpg/image_preview" alt="bezpieczenstwonet1" />&nbsp;<img class="image-inline" src="../zdjecia/bezpieczenstwonet2.jpg/image_preview" alt="ViewStateDecoder w akcji" /></p>
<p>&nbsp;</p>
<p>Z uwagi na brak jakichkolwiek zabezpieczeń w domyślnej konfiguracji ViewState, nie powinno przetrzymywać się
w nim danych mogących mieć wpływ na pracę programu i jego logikę oraz danych
związanych z autoryzacją. W chwili gdy do ViewState zapiszemy informacje poufne,
odczytanie ich zajmie kilkanaście sekund.</p>
<p>ASP.NET zapewnia możliwość
szyfrowania danych znajdujących się w ViewState, ale nie jest to popularna
praktyka wśród programistów. Wykonywanie operacji szyfrowania i deszyfrowania
przy każdym przeładowaniu strony jest procesem obciążającym serwer. Jednak,
jeżeli zdecydowaliśmy się przechowywać wrażliwe informacje (co jest
niezalecane) to należy w pliku konfiguracyjnym aplikacji dodać następujący
wpis:</p>
<blockquote>
<p>&lt;configuration&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; &lt;system.web&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;pages
viewStateEncryptionMode = „Always” /&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/system.web&gt;</p>
<p>&lt;/configuration&gt;</p>
</blockquote>
<p>Domyślnie, szyfrowanie danych
uzależnione jest od opcji ustawionych dla danej kontrolki. Ustawienie
viewStateEncryptionMode na „Always” pozwala nam zapomnieć o ustawianiu
parametrów każdej kontrolki osobno, co mogłoby doprowadzić do błędu.</p>
<p>Omówiliśmy możliwość
odczytywania danych z ViewState, ale czy istnieje możliwość ich modyfikacji i
ponownego przesłania do aplikacji? Teoretycznie tak. W najnowszej wersji ASP do
zakodowanego w Base64 ciągu znaków dołączany jest także hash stworzony na
podstawie klucza przechowywanego na komputerze. Jednak wiele osób decyduje się
wyłączyć tą funkcję, mając na uwadze możliwość uruchomienia programu na farmie
serwerów i uniknięcia problemów związanych z różnymi kluczami na serwerach.
Jeżeli w pliku konfiguracyjnym znajdziemy wpis:</p>
<blockquote>
<p>&lt;configuration&gt;</p>
<p>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;system.web&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;pages enableViewStateMac =
„False” /&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/system.web&gt;</p>
<p>&lt;/configuration&gt;</p>
</blockquote>
<p>to możemy być pewni, że
aplikacja pozwoli nam na podmianę danych przechowywanych w ViewState. Jest to
sytuacja wielce niebezpieczna, będąca punktem wyjściowym do przeprowadzenia
ataku (np. <strong>Cross Site Request Forgery</strong>).</p>
<p>W trakcie pisania aplikacji
webowej należy pamiętać, że funkcjonalność takich elementów jak ViewState nie
zawsze idzie w parze z bezpieczeństwem. Programista musi sam zadbać o
odpowiedni poziom bezpieczeństwa i skonfigurować ją w należyty sposób (nie
polegając bezgranicznie na wartościach domyślnych).</p>
<h3>&nbsp;<strong>Domyślne
strony błędów </strong></h3>
<p>W razie wystąpienia błędu w
czasie wykonywania się aplikacji pisanej w ASP.NET wyświetlana jest strona
zawierająca informacje o typie błędu, ślad stosu wywołań oraz fragmenty kodu.
Na poniższym zdjęciu przedstawiona została strona przykładowego błędu
(dzielenie przez zero).</p>
<p>&nbsp;<img class="image-inline" src="../zdjecia/bezpieczenstwonet4resized.jpg/image_preview" alt="Server Error" /></p>
<p>Strony błędów domyślnie
wyświetlane są jedynie w chwili uruchomienia aplikacji na lokalnym komputerze,
jednak programiści czasami aktywują&nbsp; taką
możliwość na serwerach produkcyjnych. Jest to wysoce niebezpieczne i przy
sprzyjających warunkach (występowanie błędu w odpowiednim miejscu) może
doprowadzić do wycieku danych. Aby temu zaradzić należy zawsze ustawiać
domyślne strony błędu poprzez wpis w pliku Web.config. Wystarczy dodać jedną
linijkę, która uniemożliwi wyświetlanie stron z kodem źródłowym witryny:</p>
<blockquote>
<p>&lt;configuration&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;system.web&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;customErrors
mode=”On” defaultRedirect=”MyErrorPage.htm” /&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/system.web&gt;</p>
<p>&lt;/configuration&gt;</p>
</blockquote>
<h3><strong>XPath Injection</strong></h3>
<p>Ostatnim typem błędów jaki
opiszę w tym artykule będzie XPath Injection. Jest to podatność w dużym stopniu
zbliżona do SQL Injection, ale odnosząca się do plików XML (w SQL Injection
atak skierowany był w „tradycyjne” bazy danych).</p>
<p>Pliki XML mogą składować dane
podobnie jak normalne bazy danych. Aby ułatwić pobieranie informacji z plików
XML wymyślono język XPath, w którym wykorzystujemy odpowiednie zapytania –
analogicznie jak w SQL. Przypuśćmy, że posiadamy plik XML zawierający loginy
użytkowników, hasła i prywatne&nbsp; dane:</p>
<blockquote>
<p>&lt;?xml version="1.0" encoding="utf-8" ?&gt;</p>
<p>&lt;users&gt;</p>
<p>&nbsp; &lt;user1&gt;</p>
<p>&nbsp;&nbsp;&nbsp; &lt;login&gt;geek&lt;/login&gt;</p>
<p>&nbsp;&nbsp;&nbsp; &lt;passwd&gt;keeg&lt;/passwd&gt;</p>
<p>&nbsp;&nbsp;&nbsp; &lt;data&gt;My data&lt;/data&gt;</p>
<p>&nbsp; &lt;/user1&gt;</p>
<p>&nbsp; &lt;user2&gt;</p>
<p>&nbsp;&nbsp;&nbsp; &lt;login&gt;root&lt;/login&gt;</p>
<p>&nbsp;&nbsp;&nbsp; &lt;passwd&gt;toor&lt;/passwd&gt;</p>
<p>&nbsp;&nbsp;&nbsp; &lt;data&gt;Very
important data&lt;/data&gt;</p>
<p>&nbsp; &lt;/user2&gt;</p>
<p>&lt;/users&gt;</p>
</blockquote>
<p>W celu pobrania np. nazwy
pierwszego użytkownika za pomocą XPath musimy napisać odpowiedni kawałek kodu:</p>
<blockquote>
<p>XmlDocument doc
= new XmlDocument();</p>
<p>doc.Load("&lt;ścieżka_do_pliku&gt;");</p>
<p>XmlNodeList
nodesList = doc.SelectNodes("/users/user1/login/text()");</p>
<p>foreach(XmlNode node in
nodesList)</p>
<p>{</p>
<p>Console.WriteLine(node.InnerText);</p>
<p>}</p>
</blockquote>
<p>Program powinien zwrócić nam
oczekiwany wynik:</p>
<p>&nbsp;<img class="image-inline" src="../zdjecia/bezpieczenstwonet5.jpg/image_preview" alt="bezpieczenstwonet5" /></p>
<p>Teraz rozważmy przypadek, w
którym użytkownik podaje login i hasło i na tej podstawie zwracane są poufne
dane przekazywane w pliku XML:</p>
<blockquote>
<p>Console.WriteLine("Input your login and pass");</p>
<p>string login = Console.ReadLine();</p>
<p>string pass = Console.ReadLine();</p>
<p>XmlDocument doc
= new XmlDocument();</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; doc.Load("C:\\Users\\hellsource\\Documents\\Visual Studio
2008\\Projects\\ConsoleApplication2\\ConsoleApplication2\\XMLFile1.xml");</p>
<p>XmlNodeList
nodesList = doc.SelectNodes("//users/*[login/text()='"
+ login + "' and passwd/text()='"
+ pass + "']");</p>
<p>foreach(XmlNode node in
nodesList)</p>
<p>{</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;if(node.HasChildNodes)</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; foreach(XmlNode
nod in node)</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Console.WriteLine(nod.InnerText);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>}</p>
</blockquote>
<p>&nbsp;</p>
<p><img class="image-inline" src="../zdjecia/bezpieczenstwonet6.jpg/image_preview" alt="bezpieczenstwonet6" /></p>
<p>W tym przypadku użytkownik
może wpisać praktycznie dowolne dane na wejście. Wiąże się to z krytyczną luką
w bezpieczeństwie aplikacji. Włamywacz może dowolnie manipulować ciągiem
wejściowym i np. odczytać dane zapisane przez root’a. Wystarczy skorzystać z odpowiednio
spreparowanego ciągu. W XPath nie ma jednak odpowiednika ‘—‘ z SQL.&nbsp; Wprowadźmy następujący
ciąg znaków jako login:</p>
<blockquote>
<p><em>’ or 1=1 or ‘a’=’a</em></p>
</blockquote>
<p>a jako hasło podajmy dowolny wyraz.
W przypadku naszego programu otrzymamy dość zaskakujący wynik. Mianowicie,
zostaną zwrócone wszystkie dane umieszone w pliku XML! Czemu? Dzięki
spreparowaniu danych wejściowych zostało podmienione zapytanie do pliku XML.
Sam proces preparowania zapytań jest analogiczny do tego wykorzystywanego w przypadku
SQL&nbsp; Injection. Zmieniła się jedynie
składnia języka i przez to musimy przyjąć pewne poprawki.</p>
<p>Jak możemy zaradzić tego typu
błędom? Identycznie (znowu…) jak w przypadku zapobiegania SQL Injection –
poprzez odpowiednią walidację i parametryzowanie zapytań. Gorąco zachęcam do
zgłębiania tajników XPath Injection na własną rękę. W Internecie jest mnóstwo
materiałów na ten temat i myślę, że nie będzie problemów ze znalezieniem
potrzebnych informacji.</p>
<h3><strong>Podsumowanie</strong></h3>
<p>Żadna platforma
programistyczna nie jest pozbawiona luk w bezpieczeństwie. Dotyczy to również
.NET. W tym krótkim artykule starałem się nieco przybliżyć najczęstsze błędy
spotykane w aplikacjach pisanych pod .NET i zobrazować zagrożenia z nich
wynikające. Nie są to oczywiście wszystkie podatności – nie wspomniałem o XSS i
XSRF oraz wielu innych ciekawych technikach przełamywania zabezpieczeń
programów. Mam nadzieję, że druga część tego artykułu pozwoli na jeszcze lepsze
poznanie sekretów bezpieczeństwa .NET.</p>
<p>--Piotr Łaskawiec</p>
<p>&nbsp;</p>
<p>&nbsp;</p>

          ]]>
        </content:encoded>        

        <dc:date>2008-05-19T10:55:00+02:00</dc:date>

        <dcterms:modified>2010-07-12T16:07:17+02:00</dcterms:modified>

        <dc:creator>xterm</dc:creator>

        

        
            <dc:subject>audyt aplikacji</dc:subject>
        
        
            <dc:subject>sql injection</dc:subject>
        
        
            <dc:subject>.NET</dc:subject>
        
        
            <dc:subject>stored procedures</dc:subject>
        

    </rss:item>

    
    

    <rss:item rdf:about="http://www.webservice.eu/pl/nowosci/security-blog/archive/2008/04/22/blind-sql-injection">

        <rss:title>Blind SQL Injection</rss:title>

        <rss:link>http://www.webservice.eu/pl/nowosci/security-blog/archive/2008/04/22/blind-sql-injection</rss:link>       

        <rss:description>Ogólne rozważania o technice, czyli jak wykonać testy na Blind SQL Injection.</rss:description>

        <content:encoded>
          <![CDATA[
          
<p>&nbsp;<br />Ostatnim razem zająłem się mitem bezpiecznych procedur. Tym
razem chciałbym się zająć kolejnym mitem, czy może lepiej, niebezpiecznym
przeświadczeniem, które równie często osłabia naszą czujność. &nbsp;Być może czytając poprzedni tekst na temat
niebezpiecznych procedur&nbsp;<a title="SQLi- mit bezpiecznych procedur" class="internal-link" href="sql-injection-mit-bezpiecznych-procedur">SQLi- mit bezpiecznych procedur</a> zadałeś/łaś sobie pytanie: „No i co z tego, że
aplikacja jest podatna na SQL Injection, skoro włamywacz nie będzie znał
struktury tabel, kolumn itp. Jeżeli aplikacja nie będzie wysyłała błędów składniowych bazy danych na output
aplikacji, to nigdy nie wymyśli on zapytania, którym mógłby zaszkodzić moim danym”.
I znów to tylko niebezpieczne pozory.</p>
<p>Tak jak człowiekowi niewidomemu trudniej dotrzeć do celu niż
człowiekowi ze sprawnym wzrokiem, tak włamywaczowi, który nie będzie miał
drogowskazów będzie trudniej namieszać w naszej bazie danych. W obu przypadkach
„trudniej”, nie znaczy „niemożliwe”. Dlatego technika wykrywania podatności na
SQL Injection w sytuacji, kiedy błędy serwera są ukrywane przed klientem,
została nazwana Blind SQL Injection.</p>
<p>Na czym polega ta technika? Mówiąc najprościej, polega ona
na takim spreparowaniu zapytań, które da nam PEWNOŚĆ, że kod SQL dołączony do
przekazanego parametru się wykonuje i zwraca rezultaty, jakich oczekujemy. (<a class="external-link" href="http://www.owasp.org/index.php/Blind_SQL_Injection">http://www.owasp.org/index.php/Blind_SQL_Injection
</a>, <a class="external-link" href="http://www.cgisecurity.com/questions/blindsql.shtml">http://www.cgisecurity.com/questions/blindsql.shtml</a>, <a class="external-link" href="http://www.spidynamics.com/assets/documents/Blind_SQLInjection.pdf">http://www.spidynamics.com/assets/documents/Blind_SQLInjection.pdf</a>)</p>
<p>Przedstawię to na przykładzie. Wyobraźmy sobie, że mamy aplikację,
która przekazuje parametr „ID” w url-u i na podstawie tego parametru
wyświetlane są rozszerzone informacje o użytkowniku, np.:</p>
<blockquote>
<p><em><strong>http://app-server/userInfo.aspx?id=25</strong></em></p>
</blockquote>
<p>Mając wiedzę o SQL Injection, możliwe jest sprawdzenie, czy
aplikacja jest podatna na tego typu atak. Jeżeli jednak aplikacja ma prawidłowo
zaimplementowaną obsługę błędów, to w sytuacji, kiedy w url-u zostanie
przekazana wartość id: „<em><strong>25;select * from jakastabela</strong></em>”, zapewne wyświetlona
zostanie strona z komunikatem: „Przykro nam, ale wystąpił błąd”. Można sobie
zadać pytanie, czy błąd został wygenerowany na serwerze bazy danych, czy w
aplikacji? W tej sytuacji komunikaty o błędach niewiele pomogą.</p>
<p>Jeżeli jednak potencjalny intruz wie, jak korzystać z
techniki Blind SQL Injection, łatwo stwierdzi, czy serwer jest podatny na atak.
Można to wykonać na kilka sposobów, jednak &nbsp;cel jest jeden: takie przygotowanie zapytania
SQL, żeby rekord zwracany przez aplikację był taki sam, jak rekord, który
zostanie wyświetlony po zaaplikowaniu „zatrutej strzały”.</p>
<p>Oto kilka metod wykonywania testów na Blind SQL Injection:</p>
<ol type="1" start="1"><li>Metoda „na działanie
     arytmetyczne”. Polega ona na przekazaniu takiego ciągu znaków, który w
     wyniku przetworzenia przez serwer bazy danych wykona działanie
     arytmetyczne, które w wyniku da wartość przekazywanego identyfikatora, a
     więc w naszym przypadku może to być: id=24+1, Id=26-1 lub dla prawdziwych
     twardzieli ;-) Id=5*5. </li><li>Metoda „na oczywistość”.
     Polega ona na wprowadzeniu do zapytania elementu, które zawsze zwraca
     „true”, wskutek czego warunki filtrowania danych nie ulegną zmianie. W
     naszym przypadku może to być: Id=25 AND 1=1, lub Id=25 AND ‘biale’=’biale’
     AND ‘czarne’=’czarne’</li><li>Metoda „czekajcie, a
     będzie wam dane”. Polega ona na wysłaniu do serwera takiego zapytania,
     żeby serwer bazy danych sam zasygnalizował, że zapytanie zostało wykonane.
     Najprościej zrobić to kombinując z wywoływaniem funkcji opóźniających.
     Przykładowo w SQL Serverze do naszego parametru można dodać Id=25 WAITFOR
     DELAY '0:0:5'. Jeżeli strona, która wyświetlona była bez dodatkowych
     „wspomagaczy” wyświetlała się o 5 sekund krócej, niż po ich zastosowaniu,
     oznacza to, że dodatkowe parametry zapytania zostały przyjęte bez
     zastrzeżeń, a więc&nbsp; istnieje
     możliwość wykonania kodu SQL dołączonego do zapytań.</li><li>Metoda „Kto tam?”. Służy
     ona odpytaniu bazy danych, jakiego serwera bazodanowego (chodzi o
     rozpoznanie czy to MySQL, SQL Server, Postgresql, Oracle itp.) używa
     aplikacja. Metoda ta polega na dołączeniu do zapytania kodu SQL specyficznego
     dla wybranych serwerów. Jeżeli dołączony kod wygeneruje błąd, wówczas można
     wykluczyć tę wersję serwera. Jest to bardzo istotny element Blind SQL,
     ponieważ wydobywanie informacji na temat obiektów systemowych jest inne
     dla każdej bazy danych. &nbsp;W większości
     tekstów poświęconych bezpieczeństwu nazywana jest ona fingerprinting. (<a class="external-link" href="http://bernardodamele.blogspot.com/2007/07/more-on-database-management-system.html">http://bernardodamele.blogspot.com/2007/07/more-on-database-management-system.html</a>).
     </li><li>Metoda „Jeżeli”. Metoda
     służy do sprawdzenia, czy zapytanie wykonuje się w sytuacji, kiedy nie da
     się w prosty sposób stwierdzić, że zapytanie się wykonało i zwróciło
     oczekiwane rezultaty, ponieważ wynik zapytania SQL nie jest wyświetlany na
     ekran. Np. w sytuacji, kiedy użytkownik się loguje na stronę, a po
     poprawnym wykonaniu zapytania jest weryfikowany i przekierowywany do
     innego zasobu. Jeżeli intruz chce sprawdzić, czy zapytanie SQL przekazane
     w parametrze się wykonuje, wówczas wystarczy „wstrzyknąć” zapytanie, które
     w zależności od spełnienia warunku wykona jakąś czynność, łatwą do
     zweryfikowania, np.&nbsp; opóźnienie. A
     zatem kawałek kodu dodany do zapytania przeznaczonego do SQL Servera
     wyglądałby następująco:</li></ol>
<blockquote>
<p align="left"><strong><em>if ((select user) = 'dbo') WAITFOR DELAY '0:0:5'</em></strong></p>
</blockquote>
<p>Jeżeli po przesłaniu zapytania
do bazy danych chwila oczekiwania na wykonanie akcji będzie o 5 sekund dłuższa
niż normalnie, oznacza to, że baza danych to SQL Server, a ponadto użytkownik,
z którego prawami wykonywane jest zapytanie to „dbo”.</p>
<p>Powyższe przykłady stanowią tylko część możliwości. Więcej
można poczytać pod adresem <a class="external-link" href="http://ferruh.mavituna.com/sql-injection-cheatsheet-oku/">http://ferruh.mavituna.com/sql-injection-cheatsheet-oku/</a>.
Pod tym adresem można znaleźć bardzo dużo wskazówek na temat SQL Injection.</p>
<p>Po stwierdzeniu faktu występowania podatności na włamanie,
po raz kolejny można sobie zadać pytanie, do czego włamywacz może ją wykorzystać,
skoro nigdzie nie może wyświetlić rezultatów zapytania (co nie zawsze jest
prawdą, ponieważ przy pomocy odpowiedniego spreparowania instrukcji
wyciągnięcie danych nie stanowi problemu, ale o tym innym razem)? Otóż nawet
nie mogąc wyświetlić informacji na output można mozolnie, ale skutecznie
przepytać serwer i wyciągnąć od niego wiele cennych informacji.</p>
<p>Z samej podatności serwera bowiem jeszcze nic nie wynika.
Cały czas mamy w tyle głowy pytanie: „I&nbsp;co nam może zrobić włamywacz,
skoro nie zna struktury bazy danych”. Zwłaszcza, jeżeli projektant przewidując
ewentualne próby włamań i zgodnie z zasadą dobrych praktyk unikał standardowych
nazw obiektów bazy danych, ich właściwości itp. Zamiast nazywać obiekty
standardowo, np. tabela „Users”, z polami „username”, „password”, „id”,
pododawał prefiksy, dzięki którym dużo trudniej wymyślić zapytanie. Tabeli
nadał nazwę „AppUsers”, a polom w tabeli „AUName”, „AUPass”, „AUId”.
Zabezpieczenie takie jest o tyle dobre, że od razu odfiltruje nam wszystkich scripts
kiddies. Jednak jeżeli osoba próbująca się dostać do naszego serwera zna trochę
zaawansowane funkcjonalności bazy danych, wówczas nawet mimo najbardziej
wyrafinowanych nazw włamanie nie będzie stanowiło problemu właśnie z powodu
Blind SQL Injection.</p>
<p>Zanim pójdziemy dalej, żeby przekonać się jak to jest
możliwe, spróbujmy się przyjrzeć regułom formułowania zapytań tego typu. Przeanalizujmy
sobie jak wygląda nasze zapytanie SQL przed i po zaaplikowaniu dodatkowego kodu
SQL.</p>
<p>Jako przykład znów użyjemy naszą tabelę z użytkownikami
użytą w poprzednim wpisie[link]. W parametrze GET przekazywana jest wartość ID
i po jej otrzymaniu od serwera wykonujemy następujący kod SQL:</p>
<blockquote>
<p><strong><em>string sql = "select
Id, Username, LastLogon from AppUsers where Id=" + Request.Params["id"];</em></strong></p>
</blockquote>
<p>Jeżeli więc jako parametr ID przekażemy</p>
<blockquote>
<p><strong><em>1 AND 1=1</em></strong></p>
</blockquote>
<p>Wówczas na serwerze bazodanowym wykona się zapytanie</p>
<blockquote>
<p><em><strong>select Id, Username,
LastLogon from AppUsers where Id=1 AND 1=1</strong></em></p>
</blockquote>
<p>Przeanalizujmy sobie nasze zapytanie i zastanówmy się, jak
podzielone jest to zapytanie. Pierwsza część jest standardowym zapytaniem,
które zwraca oczekiwany rekord. Natomiast druga część mówi, czy warunek
umieszczony po „AND” jest prawdziwy. Żeby się upewnić, że druga część zapytania
nie jest ignorowana, ale na pewno się wykonuje, trzeba dodać warunek, który
zawsze jest fałszywy, czyli np.:</p>
<blockquote>
<p><strong><em>AND 1=2</em></strong></p>
</blockquote>
<p>W tej sytuacji aplikacja zwróci błąd mówiący, że nie
znaleziono podanego użytkownika.</p>
<p>Jak widać pierwsza część zapytania jest niezmienna i jest
ona gwarantem, że zapytanie umieszczone w drugiej części zawsze zwraca „True”.
Co można wyciągnąć z takiej wiedzy? Nadspodziewanie dużo, a jeżeli użytkownik,
z którego prawami jest uruchamiana aplikacja kliencka, ma odpowiednie
uprawnienia, to jeszcze więcej.</p>
<p>Włamywacz ma więc do dyspozycji tak tylko drugą część
zapytania i do dyspozycji bardzo lakoniczne odpowiedzi serwera (TAK/NIE). Co
dalej?</p>
<p>Przypomnijmy sobie zabawę z dzieciństwa w 25 pytań, kiedy
jedna osoba wymyślała jakiś przedmiot, a druga musiała odgadnąć jaki to
przedmiot, mając do dyspozycji 25 pytań i odpowiedzi tej pierwszej tylko „TAK”
lub „NIE”. Podobnie włamywacz może odpytać serwer podatny na atak typu Blind
SQL Injection.</p>
<p>Zastanówmy się, jakie pytania może on zadać serwerowi, żeby
mogli dowiedzieć się, jaką strukturę ma tabela, do której kierowane są
zapytania ze skryptu.</p>
<p>Może zadać następujące pytania (oczywiście po
przeformułowaniu ich na język SQL):</p>
<ol type="1" start="1"><li>czy użytkownik, który
     wywołuje zapytanie jest „dbo”</li><li>czy liczba tabel w bazie
     danych jest większa od [10,5,7,8]</li><li>czy pierwsza litera nazwy pierwszej
     tabeli&nbsp; przedstawiona jako mała
     litera to [m,g,d,b]</li><li>czy druga litera nazwy pierwszej
     tabeli …</li><li>czy liczba kolumn w wybranej
     tabeli jest większa od…</li><li>czy pierwsza litera nazwy
     pierwszej kolumny wybranej tabeli to…</li></ol>
<p>Wszystkie te informacje są możliwe do wyciągnięcia, jeżeli
odpowiednio zostaną spreparowane odpowiednie zapytania do tabel systemowych, wywołania
wbudowanych funkcji systemowych itp. Właściwie w ilości danych, jakie można
wyciągnąć z niezabezpieczonej aplikacji intruza ogranicza tylko czas,
wyobraźnia i potrzeby. Z takich szczątkowych informacji, jest w stanie zbudować
sobie potężną bazę wiedzy o tabelach bazy danych używanych przez aplikację. Oczywiście
opisane przeze mnie kroki, nie muszą być wykonywane ręcznie. Przygotowanie skryptu,
który wykona za niego całą pracę nie zajmie mu wiele czasu (tym łatwiej, jeżeli
będzie miał już rozpoznaną wersję serwera bazy danych), poza tym w sieci można
ściągnąć wiele aplikacji wykonujących te zadania.</p>
<p>Ze względu na to, że celem tego artykułu nie jest
przygotowanie instrukcji, jak wyciągać poufne dane z serwerów, a jedynie
ostrzeżenie przed niebezpieczeństwem, nie będę tutaj pisał tutoriala, jakie
kolejne kroki należy wykonać żeby je wyciągnąć z serwera bazodanowego,
natomiast żeby udowodnić, że zagrożenie rzeczywiście istnieje, przytoczę kilka
przykładów, które zachęcą, mam nadzieję, do lepszego zabezpieczania aplikacji
przed SQL Injection we wszystkich postaciach.</p>
<p>Wszystkie przykłady są odpowiednie dla MS SQL Server.</p>
<p>Odp. 1: Czy user jest dbo.</p>
<blockquote>
<p><strong><em>&nbsp;AND
USER_NAME()='dbo'</em></strong></p>
</blockquote>
<p>Odp 2.</p>
<blockquote>
<p><strong><em>&nbsp;AND (select
count(name) from sysobjects where type='U')&gt;10</em></strong></p>
</blockquote>
<p>Odp. 3.</p>
<blockquote>
<p><strong><em>&nbsp;AND
ascii(lower(substring((SELECT TOP 1 name FROM sysobjects WHERE
xtype='U'),1,1)))&gt;96</em></strong></p>
</blockquote>
Mam
nadzieję, że zachęciłem do zwrócenia uwagi, na to, czy mimowolnie nie dodaliśmy
do naszej aplikacji funkcjonalności konsoli SQL dla zaawansowanych
użytkowników. Warto o tym pomyśleć, kiedy piszemy warstwę obsługi dostępu do
danych w naszych aplikacjach.
          ]]>
        </content:encoded>        

        <dc:date>2008-04-22T12:20:00+02:00</dc:date>

        <dcterms:modified>2010-07-12T16:07:17+02:00</dcterms:modified>

        <dc:creator>rusk</dc:creator>

        

        
            <dc:subject>sql injection</dc:subject>
        
        
            <dc:subject>sql server</dc:subject>
        

    </rss:item>

    
    

    <rss:item rdf:about="http://www.webservice.eu/pl/nowosci/security-blog/archive/2008/04/16/kolejny-audyt-bezpieczenstwa">

        <rss:title>Kolejny audyt bezpieczeństwa</rss:title>

        <rss:link>http://www.webservice.eu/pl/nowosci/security-blog/archive/2008/04/16/kolejny-audyt-bezpieczenstwa</rss:link>       

        <rss:description>Wykonaliśmy audyt bezpieczeństwa dla firmy: BRE ubezpieczenia sp. z o.o.</rss:description>

        <content:encoded>
          <![CDATA[
          
<p>Tym razem testowaliśmy aplikację webową, opartą o technologię .NET</p>
<p>Prace zostały potwierdzone listem referencyjnym, uznającym profesjonalne wykonanie oraz bardzo wysoki poziom wiedzy inżynierskiej. Referencje są do wglądu dla naszych klientów.</p>

          ]]>
        </content:encoded>        

        <dc:date>2008-04-16T18:06:12+02:00</dc:date>

        <dcterms:modified>2010-07-12T16:07:17+02:00</dcterms:modified>

        <dc:creator>xterm</dc:creator>

        

        
            <dc:subject>audyt bezpieczeństwa</dc:subject>
        

    </rss:item>

    
    

    <rss:item rdf:about="http://www.webservice.eu/pl/nowosci/security-blog/archive/2008/03/31/sql-injection-mit-bezpiecznych-procedur">

        <rss:title>SQLi- mit bezpiecznych procedur</rss:title>

        <rss:link>http://www.webservice.eu/pl/nowosci/security-blog/archive/2008/03/31/sql-injection-mit-bezpiecznych-procedur</rss:link>       

        <rss:description>Czy Ty jesteś bezpieczny? Przed czym należy się bronić?</rss:description>

        <content:encoded>
          <![CDATA[
          
<div class="Section1">
<p class="MsoBodyText">O SQL Injection można znaleźć w Internecie wiele
materiałów, zakładam więc, że czytelnik ma już podstawową wiedzę z tego
zakresu, a mianowicie wie:</p>
<p class="MsoBodyText"><a name="f.h0"></a>- co znaczy zwrot SQL
Injection</p>
<p class="MsoBodyText"><a name="xlw7"></a>- jak manipulować
danymi w bazie danych za pomocą zapytań SQL przemycanych w przekazywanych
danych wejściowych.</p>
<p class="MsoBodyText">Jeżeli terminologia nie jest jeszcze znana,
polecam zapoznanie się z tematyką: <a class="external-link" href="http://www.owasp.org/index.php/SQL_injection">http://www.owasp.org/index.php/SQL_injection</a>,
<a class="external-link" href="http://www.owasp.org/index.php/Guide_to_SQL_Injection">http://www.owasp.org/index.php/Guide_to_SQL_Injection</a>, <a class="external-link" href="http://www.governmentsecurity.org/articles/SQLinjectionBasicTutorial.php">http://www.governmentsecurity.org/articles/SQLinjectionBasicTutorial.php</a>).<br />Szczególnie polecam strony OWASP, ponieważ nie powielają one mitu, o którym będę pisał poniżej, a który jest powielany&nbsp; na wielu forach, blogach itp.</p>
<p class="MsoBodyText"><a name="h64f"></a>Mit, którym chciałbym
się zająć, jest o tyle niebezpieczny, że daje pozorne poczucie bezpieczeństwa,
a jednocześnie jest ukrytą miną, na którą ktoś wcześniej, czy później trafi.
Tyle, że w tym przypadku ofiarą będzie umieszczający tę minę.</p>
<p class="MsoBodyText"><a name="lcq6"></a>Mit ten brzmi: <a name="jrrw"></a>„korzystanie ze Stored Procedures zabezpiecza przed SQL Injection”.</p>
<p class="MsoBodyText"><a name="sogs"></a>Dla wielu
programistów jest oczywiste, że najlepszym zabezpieczeniem przed SQL Injection
jest skorzystanie z używanych w większości serwerów bazodanowych procedur przechowywanych
w bazie danych, wywoływanych z parametrami, przekazywanymi przez klienta
wywołującego procedurę. Jest to prawda w 50% (a więc nie jest to prawda),
ponieważ błędnie napisana procedura może się okazać równie niebezpieczna, co
konkatenowany skrypt SQL zaszyty w kodzie aplikacji. Może nawet bardziej
niebezpieczna, ponieważ zapytanie generowane dynamicznie w kodzie, w
przeciwieństwie do procedury, nie sprawia wrażenia bezpiecznego.</p>
<p class="MsoBodyText">W przykładzie posłużę się procedurami składowanymi
(stored procedures) oferowanymi przez SQL Server. <a name="rz3x"></a></p>
<p class="MsoBodyText">Załóżmy, że mamy w bazie danych tabelę AppUsers:</p>
</div>
<img class="image-inline" src="../../sqli_sp01.jpg" alt="" />
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p class="MsoBodyText">Tabela przechowuje dane użytkowników naszej
aplikacji. Jedno z pól (pole IsAdmin) informuje, czy użytkownik jest
administratorem. Na podstawie flagi ustawionej w tym polu aplikacja daje dostęp
do panelu administracyjnego, w którym zalogowany użytkownik może zarządzać
aplikacją, użytkownikami, uprawnieniami itp.</p>
<p class="MsoBodyText"><a name="mbkh"></a>W części publicznej
aplikacji mamy jakąś listę użytkowników, którą można przeszukiwać. Dla
uproszczenia przykładu przyjmijmy, że będzie to wyszukiwanie według loginu
użytkownika. W sytuacji, kiedy w filtrze wyszukiwania nie zostaną wprowadzone
żadne dane, wówczas prezentowana jest lista wszystkich użytkowników. W
przeciwnym razie w bazie będą wyszukiwani użytkownicy, których login zawiera
litery podane w zapytaniu. Programista w tej sytuacji postanawia skorzystać z
procedury SQL, ponieważ jest przekonany, że to zabezpieczy go przed problemem
SQL Injection. Umieszcza więc w bazie danych procedurę:</p>
<p class="MsoBodyText"><a name="mbkh1"></a><a name="fh2z"></a></p>
<p class="MsoBodyText"><a name="paft"></a><a name="w_ib"></a><a name="du_g"></a>CREATE PROCEDURE [dbo].[USP_UsersSearchSafe]</p>
<p class="MsoBodyText"><a name="y8j1"></a><a name="znfp"></a><a name="kefd"></a>@username varchar(400) = NULL</p>
<p class="MsoBodyText"><a name="z:lh"></a><a name="g:l5"></a><a name="ot8y"></a>AS</p>
<p class="MsoBodyText"><a name="d-x_"></a><a name="r9uy"></a><a name="dona"></a>DECLARE @sql nvarchar(4000)</p>
<p class="MsoBodyText"><a name="q4xe"></a><a name="bi3f"></a><a name="o_4-"></a>SET @sql = ' SELECT Id, Username, IsAdmin, LastLogon ' +</p>
<p class="MsoBodyText"><a name="u-6x"></a><a name="i4bs"></a><a name="gz5e"></a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<a name="b4ai"></a>' FROM AppUsers '</p>
<p class="MsoBodyText"><a name="w8k6"></a><a name="w9bn"></a><a name="r.xr"></a>IF @username IS NOT NULL</p>
<p class="MsoBodyText"><a name="o4bl"></a><a name="mq.o"></a><a name="lx8h"></a>&nbsp;&nbsp;
<a name="bxhs"></a>SET @sql = @sql + ' Where Username LIKE '''+
@username +''''</p>
<p class="MsoBodyText"><a name="jas1"></a><a name="w..1"></a><a name="w5ba"></a>Exec (@sql)</p>
<p class="MsoBodyText"><a name="llc5"></a><br />Wydaje się, że
wszystko jest bezpieczne, ponieważ skorzystał z procedury, natomiast teraz
wyobraźmy sobie, że w polu tekstowym użytkownik o loginie „user1” wprowadzi
poniższy kod SQL:</p>
<p class="MsoBodyText"><a name="d06t"></a><a name="c57e"></a><a name="pup4"></a>';update AppUsers
set IsAdmin=1 where Username='user1';--</p>
<p class="MsoBodyText"><a name="trm1"></a>Po przesłaniu powyższego
zapytania do mechanizmu wyszukiwawczego, nasz mechanizm wyszukiwawczy „w
promocji” dorzuca użytkownikowi „user1” uprawnienia administratora. Gdyby
zapytanie było wykonywane 6 grudnia, można by zrezygnować z klauzuli „where” i
wówczas wszyscy użytkownicy w prezencie mikołajkowym dostaliby administracyjne
uprawnienia.</p>
<p class="MsoBodyText"><a name="p4fz"></a>Nie trzeba wyrafinowanej
analizy, żeby odkryć, co jest przyczyną podatności na SQL Injection, mimo
zastosowania procedury SQL.</p>
<p class="MsoBodyText"><a name="omin"></a>W powyższym
przykładzie procedura została napisana dokładnie w taki sam sposób, w jaki
byłaby ona zapisana, gdyby programista zaszył ją wewnątrz kodu aplikacji, tzn.
zapytanie SQL jest konkatenowane i ewaluowane , natomiast sam przekazany
parametr nie jest odseparowany od logiki zapytania. Zapytanie to nie różni się
zbytnio od zapytań typu:</p>
<p class="MsoBodyText"><a name="q:o7"></a><a name="hfl2"></a><a name="e8y6"></a>„Select * from products where
Id=” + Input[„id”]</p>
<p class="MsoBodyText"><a name="zi.i"></a>Przy korzystaniu z
procedur SQL ważne jest, żeby uświadomić sobie, że przez zagrożeniami nie
chroni sam fakt skorzystania z procedury. Przed wszelkiego rodzaju problemami
chroni tylko DOBRZE NAPISANY KOD, niezależnie od tego, czy znajduje się on w
aplikacji, czy też w bazie danych.</p>
<p class="MsoBodyText"><a name="h63i"></a>Przejdźmy więc do
tego mitycznego stworzenia o nazwie DOBRZE NAPISANY KOD. Jak powinien wyglądać
w naszym przykładzie, żeby wyeliminować podatność na SQL Injection.<a name="h63i1"></a><a name="q_b2"></a></p>
<p class="MsoBodyText"><a name="nniz"></a><a name="uk39"></a><a name="iwab"></a>CREATE PROCEDURE [dbo].[USP_UsersSearchReallySafe]</p>
<p class="MsoBodyText"><a name="fuuu"></a><a name="jhzt"></a><a name="f-ik"></a>@username varchar(400) = NULL AS</p>
<p class="MsoBodyText"><a name="w93e"></a><a name="dq1h"></a><a name="uldo"></a>DECLARE @sql nvarchar(4000)</p>
<p class="MsoBodyText"><a name="ec3-"></a><a name="e3h2"></a><a name="q7gp"></a>SET @sql = ' SELECT Id, Username, IsAdmin, LastLogon ' +</p>
<p class="MsoBodyText"><a name="sb4o"></a><a name="y-9o"></a><a name="e-a0"></a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<a name="dl_f"></a>' FROM AppUsers '</p>
<p class="MsoBodyText"><a name="yrux"></a><a name="ne9s"></a><a name="u6od"></a>IF @username IS NOT NULL</p>
<p class="MsoBodyText"><a name="bi:l"></a><a name="kgue"></a><a name="eksg"></a>&nbsp;&nbsp; <a name="a:eg"></a>SET @sql = @sql
+ ' Where Username LIKE @username '</p>
<p class="MsoBodyText"><a name="f536"></a><a name="hc2x"></a><a name="bab-"></a>Exec sp_executesql @sql, N'@username varchar(400)',@username</p>
<p class="MsoBodyText"><a name="npd2"></a><a name="gnwe"></a>&nbsp;</p>
<p class="MsoBodyText"><a name="hvxv"></a>Na czym więc polega
różnica. Otóż w tym przypadku skorzystaliśmy możliwości oferowanych przez
zapytania parametryzowane, dzięki czemu parametry przekazywane do zapytania SQL
(dane wejściowe) zostały całkowicie odseparowane od składni zapytania. Jedyną
niedogodnością jest, że w tym przypadku wywołanie przygotowanego zapytania SQL
jest trochę bardziej skomplikowane, ponieważ musimy skorzystać ze specjalnej
procedury sp_executesql, a także musimy jeszcze raz przekazać parametry do tej
procedury. W tym przypadku jednak dużo bardziej przejrzyste jest przygotowanie
samego zapytania SQL, dlatego w sumie wychodzimy na remis. Z tą różnicą, że w
tym drugim przypadku mamy naprawdę bezpieczną procedurę.</p>
<p class="MsoBodyText">Jaką konkluzję chciałbym więc zawrzeć w
podsumowaniu? Chyba taką, że nawet „the best practice” może być przyczyną
problemów, jeżeli będzie zastosowana bezrefleksyjnie...</p>
<p class="MsoBodyText">I że ŹLE NAPISANY KOD zawsze jest zagrożeniem,
niezależnie od tego, gdzie został umieszczony.</p>
<p class="MsoBodyText"><a name="x2.n"></a><a name="k3:w"></a></p>

          ]]>
        </content:encoded>        

        <dc:date>2008-03-31T16:40:00+02:00</dc:date>

        <dcterms:modified>2010-07-12T16:07:17+02:00</dcterms:modified>

        <dc:creator>rusk</dc:creator>

        

        
            <dc:subject>sql injection</dc:subject>
        
        
            <dc:subject>stored procedures</dc:subject>
        
        
            <dc:subject>sql server</dc:subject>
        

    </rss:item>

    
    

    <rss:item rdf:about="http://www.webservice.eu/pl/nowosci/security-blog/archive/2008/02/15/multi-sql-injection-w-phorum">

        <rss:title>Multi sql injection w Phorum</rss:title>

        <rss:link>http://www.webservice.eu/pl/nowosci/security-blog/archive/2008/02/15/multi-sql-injection-w-phorum</rss:link>       

        <rss:description>Używasz Phorum - Koniecznie musisz to przeczytać! </rss:description>

        <content:encoded>
          <![CDATA[
          
<p>Podczas kontroli kodu źródłowego, nasz dział software security znalazł kilka błędów typu blind sql injection w oprogramowaniu <strong>Phorum3</strong>.</p>
<p>Phorum3 ma poważną wadę konstrukcyjną, sprawiającą iż oprogramowanie to działa w trybie register_globals=on niezależnie od ustawień w php.ini.</p>
<p>Winny jest plik: include/register_globals.php (includowany z commons.php), który w całości cytuję poniżej:</p>
<p>&nbsp;</p>
<code>
</code>
<p>if (!defined("_COMMON_PHP")) return;<br />&nbsp;if(isset($_SERVER)){<br />&nbsp;&nbsp;&nbsp;&nbsp; $arrays=array(<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $_SERVER,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $_ENV,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $_GET,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $_POST,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $_COOKIE<br />&nbsp;&nbsp;&nbsp; );<br />&nbsp;} else {<br />&nbsp;&nbsp;&nbsp;&nbsp; $arrays=array(<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $HTTP_SERVER_VARS,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $HTTP_ENV_VARS,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $HTTP_GET_VARS,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $HTTP_POST_VARS,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $HTTP_COOKIE_VARS<br />&nbsp;&nbsp;&nbsp; );<br />&nbsp;}</p>
<p>foreach($arrays as $array){<br />&nbsp;&nbsp;&nbsp;&nbsp; foreach($array as $var=&gt;$val){<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if(!isset($GLOBALS[$var])){<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; $$var = $val;<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp; }<br />}</p>
<p>Komentarz w temacie za co odpowiada ten plik wydaje się być zbędny.&nbsp;</p>
<h3>Pierwszy SQLi:</h3>
<p>http://phorum/forum/search.php?f=1&amp;search=test&amp;...&amp;globalsearch=1<br />&amp;searchforums[0]=sqli<br /><br />Przy tworzeniu zapytania SQL nie jest walidowana tablica $searchforums,<br />linijka 186, plik search.php:</p>
<p>http://phorum/forum/search.php?f=1&amp;search=test&amp;...&amp;globalsearch=1<br />&amp;searchforums[0]=sqli</p>
<p>search.php:</p>
<code>
</code>
<p>183.&nbsp; if($globalsearch){<br />184.&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $SQL="Select id, name, table_name from $pho_main where";<br />185.&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(isset($searchforums)){<br />186.&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $SQL.=" id in (".implode(",", $searchforums).")";<br />187.&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else {<br />188.&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $SQL.=" (active=1 or id=$num)";<br />189.&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />190.&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(!isset($phorum_user['id'])){<br />191.&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $SQL.=" and security!=".SEC_ALL;<br />192.&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />193.&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $q-&gt;query($DB, $SQL);<br />194.&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $row = $q-&gt;getrow();<br />195.&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else {<br />196.&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $row=array("id"=&gt;$num, "name"=&gt;$ForumName, "table_name"=&gt;$ForumTableName);<br />197.&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<h3>Drugi SQLi:</h3>
<p>http://phorum/forum/search.php?f=1&amp;search=test&amp;...&amp;fields[0]=sqli</p>
<p>search.php, problem jak w pierwszym SQL injection:</p>
<code>
</code>
<p>87. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; reset($fields);<br />88.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unset($likeArray);<br />89.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (list ($key, $val) = each ($fields)) {<br />90.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $term=addslashes($term);<br />91.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(strstr($DB-&gt;type, "postgresql")){<br />92.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $likeArray[]=" upper($val) $notmod"."~~ upper('%$term%') ";<br />93.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else {<br />94.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $likeArray[]=" $val $notmod"."LIKE '%$term%' ";<br />95.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />96.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<h3>Trzeci SQLi:</h3>
<p>http://phorum/forum/read.php?f=1&amp;...&amp;ids[0]=sqli</p>
<p>Z pliku&nbsp; read.php wywolywana jest funkcja phorum_get_users()<br />bez walidacji parametru przekazywanego do funkcji.</p>
<code>
</code>
<p>Funkcja phorum_get_users() znajduje się w pliku include/userlogin.php, a interesujący fragment cytuję poniżej:</p>
<p>291.&nbsp; function phorum_get_users($ids) {<br />292.&nbsp;&nbsp;&nbsp; global $DB,$q,$PHORUM;<br />293.&nbsp;&nbsp;&nbsp;&nbsp; // Get the user info.&nbsp; I curse PG for not having Left Joins.<br />294.&nbsp;&nbsp;&nbsp;&nbsp; $SQL="select id, username, email, signature from ".$PHORUM["auth_table"]." where id in (".implode(",", $ids).")";<br />295.&nbsp;&nbsp;&nbsp;&nbsp; $q-&gt;query($DB, $SQL);<br />296.&nbsp;&nbsp;&nbsp;&nbsp; $rec=$q-&gt;getrow();<br />297.&nbsp;&nbsp;&nbsp;&nbsp; While(is_array($rec)){<br />298.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $users[$rec["id"]]=$rec;<br />299.&nbsp;&nbsp;&nbsp; $rec=$q-&gt;getrow();<br />300.&nbsp;&nbsp;&nbsp;&nbsp; }<br />301. &nbsp;&nbsp;&nbsp; return $users;<br />302.&nbsp; }</p>
<p>&nbsp;</p>
<p>Podatności były testowane na wersji 3.4.8a phorum. Jest to wersja oficjalnie oznaczona na <a class="external-link" href="http://www.phorum.org/">stronie producenta</a> jako&nbsp; niesupportowana. Vendor po zgłoszeniu przez nas błędu odmówił wypuszczenia patcha, właśnie powołując się na ww. fakt.</p>
<p>Z naszych doświadczeń wynika jednak, że phorum3 jest cały czas intensywnie wykorzystywane w Internecie, <strong>również w nowych projektach</strong> - informacja o znalezionych przez nas podatnościach może być więc przydatna.</p>
<p>&nbsp;</p>
<p>&nbsp;</p>

          ]]>
        </content:encoded>        

        <dc:date>2008-02-15T12:05:00+01:00</dc:date>

        <dcterms:modified>2010-07-12T16:07:17+02:00</dcterms:modified>

        <dc:creator>xterm</dc:creator>

        

        
            <dc:subject>sql injection</dc:subject>
        

    </rss:item>

    
    

    <rss:item rdf:about="http://www.webservice.eu/pl/nowosci/security-blog/archive/2008/02/07/persistent-xss-w-wordpress">

        <rss:title>Persistent XSS w Wordpress</rss:title>

        <rss:link>http://www.webservice.eu/pl/nowosci/security-blog/archive/2008/02/07/persistent-xss-w-wordpress</rss:link>       

        <rss:description>Krytyczne błędy w popularnym oprogramowaniu! Czy Twój blog stanowi zagrożenie?</rss:description>

        <content:encoded>
          <![CDATA[
          
<p>W ramach rutynowej analizy kodu źródłowego, znaleźliśmy 2 błędy persistent XSS w jednym z najpopularniejszych oprogramowaniań blogowych - &lt;a href="www.wordpress.org"&gt;WordPress&lt;/a&gt;.</p>
<h3>Proof of Concept (IE7)</h3>
<p>wpisanie w komentarz ciągu:</p>
<p><br />aaa@"STYLE="behavior:url('#default#time2')"onBegin="alert('XSS')"<br /><br />Aktywacja XSS-a następuje po odczytaniu komentarza przez uzytkownika blogu.<br />Aktywacja ma również miejsce w administracji aplikacji, przez co atakujący<br />może otrzymać dostęp do konta administratora (ataki typu: przejęcie sesji administratora bez znajomości hasła, CSRF).<br /><br />Drugi błąd jest podobny, PoC:<br /><br />javascript://%0a%0dalert%281%29<br /><br />aktywacja po kliknięciu w wygenerowany link.</p>
<p>Przypominam, że XSS-y persistent są wyjątkowo zjadliwe (do uruchomienia ataku nie jest jest wymagane podrzucenie linku ofierze, wystarczy że będzie ona najzwyczajniej w świecie nawigować po portalu).</p>
<h3>&nbsp;Szczegóły<br /></h3>
<p>problem istnieje w pliku:</p>
<p>wp-includes/formatting.php, a dokładniej, w funkcji<br />make_clicable().<br /><br />regexpy zamieniające wybrane kawałki tekstu&nbsp; na wersje klikalne są zbyt mało restrykcyjne. Dokładniej, chodzi o 6 i 8 linijkę poniżej.</p>
<p><br /><br /><code>1. function make_clickable($ret) {<br />2.&nbsp;&nbsp;&nbsp; $ret = ' ' . $ret;<br />3.&nbsp;&nbsp;&nbsp; // in testing, using arrays here was found to be faster<br />4.&nbsp;&nbsp;&nbsp; $ret = preg_replace(<br />5.&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; array(<br />6.&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; '#([\s&gt;])([\w]+?://[\w\#$%&amp;~/.\-;:=,?@\[\]+]*)#is',<br />7.&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; '#([\s&gt;])((www|ftp)\.[\w\#$%&amp;~/.\-;:=,?@\[\]+]*)#is',<br />8.&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; '#([\s&gt;])([a-z0-9\-_.]+)@([^,&lt; \n\r]+)#i'),<br />9.&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; array(<br />10.&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; '$1&lt;a href="$2" rel="nofollow"&gt;$2&lt;/a&gt;',<br />11.&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; '$1&lt;a href="http://$2" rel="nofollow"&gt;$2&lt;/a&gt;',<br />12.&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; '$1&lt;a href="mailto:$2@$3"&gt;$2@$3&lt;/a&gt;'),$ret);<br />13.&nbsp;&nbsp;&nbsp; // this one is not in an array because we need it to run last, for cleanup of accidental links within links<br />14.&nbsp;&nbsp;&nbsp; $ret = preg_replace("#(&lt;a( [^&gt;]+?&gt;|&gt;))&lt;a [^&gt;]+?&gt;([^&gt;]+?)&lt;/a&gt;&lt;/a&gt;#i", "$1$3&lt;/a&gt;", $ret);<br />15.&nbsp;&nbsp;&nbsp; $ret = trim($ret);<br />16.&nbsp;&nbsp;&nbsp; return $ret;<br />17.}</code></p>
<p>&nbsp;</p>
<h3>Podatne wersje <a class="external-link" href="http://www.wordpress.org/">wordpress-a</a><br /></h3>
<p>2.3.1, najprawdopodobniej również niższe.</p>
<h3>Kroki zaradcze</h3>
<p>Vendor został przez nas powiadomiony o problemie i wypuścił wersję 2.3.2 zawierającą m.in. patcha poprawiającego podatność.</p>
<p>Zalecamy więc upgrade do najnowszej wersji <a class="external-link" href="http://www.wordpress.org/">wordpress-a.</a></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>

          ]]>
        </content:encoded>        

        <dc:date>2008-02-07T11:40:00+01:00</dc:date>

        <dcterms:modified>2010-07-12T16:07:17+02:00</dcterms:modified>

        <dc:creator>xterm</dc:creator>

        

        
            <dc:subject>XSS</dc:subject>
        

    </rss:item>

    
    

    <rss:item rdf:about="http://www.webservice.eu/pl/nowosci/security-blog/archive/2008/01/29/blad-persistent-xss-w-allegro">

        <rss:title>Błąd persistent XSS w Allegro</rss:title>

        <rss:link>http://www.webservice.eu/pl/nowosci/security-blog/archive/2008/01/29/blad-persistent-xss-w-allegro</rss:link>       

        <rss:description>Tym razem znaleźliśmy błąd typu persistent XSS.</rss:description>

        <content:encoded>
          <![CDATA[
          
<p>PoC:<br /><br />&lt;P STYLE="xss:e\xpression(alert(1))"&gt;&lt;/P&gt;<br /><br />W przypadku błędów persistent XSS, odpowiednio spreparowany payload znajduje się na serwerze podlegającym atakowi (użytkownik nie musi kliknąć w spreparowany link, wystarczy że w normalnym trybie nawiguje po portalu), co zdecydowanie zwiększa drastyczność ataku.<br /><br />Błędy tego typu umożliwiają w prosty sposób m.in. przejęcie sesji użytkownika i dostęp do jego konta bez znajomości hasła/nazwy użytkownika. <br /><br />Dodam tez, że ww PoC jest klasycznym przykładem wykorzystania techniki filter evasion. <br /><br />Nie muszę chyba pisać, czym tego rodzaju błąd mógłby skutkować w serwisie typu Allegro...<br /><br />Dzięki sprawnej współpracy z działem bezpieczeństwa Allegro, błędy został w bardzo szybkim czasie poprawiony.</p>

          ]]>
        </content:encoded>        

        <dc:date>2008-01-29T17:30:00+01:00</dc:date>

        <dcterms:modified>2010-07-12T16:07:17+02:00</dcterms:modified>

        <dc:creator>xterm</dc:creator>

        

        
            <dc:subject>XSS</dc:subject>
        
        
            <dc:subject>portale</dc:subject>
        

    </rss:item>

    
    

    <rss:item rdf:about="http://www.webservice.eu/pl/nowosci/security-blog/archive/2008/01/22/sql-injections-w-allegro">

        <rss:title>Błędy SQL Injection w Allegro</rss:title>

        <rss:link>http://www.webservice.eu/pl/nowosci/security-blog/archive/2008/01/22/sql-injections-w-allegro</rss:link>       

        <rss:description>W ramach rutynowych testów, wykryliśmy błędy typu SQL Injections w serwisie allegro.pl.</rss:description>

        <content:encoded>
          <![CDATA[
          
<p>Błędów było kilka, poniżej prezentujemy jeden z nich (PoC):<br /><br />http://allegro.pl/phorum/search.php?f=259&amp;search=sprzedawca&amp;globalsearch=0<br />&amp;match=1&amp;date=30&amp;fldsubject=1&amp;fldbody=1&amp;fields[0]=Tutaj SQLi<br /><br />Dzięki sprawnej współpracy z działem bezpieczeństwa Allegro, błędy zostały w bardzo szybkim czasie poprawione.<br /><br />Dla niewtajemniczonych, przypominamy, że błędy typu SQL injections umożliwiają ataki dające atakującemu m.in:<br /><br /></p>
<ul><li>nieograniczony dostęp do bazy danych w trybie do zapisu i odczytu (umożliwia to np. umieszczenie kompromitujących informacji w portalu czy odczytanie poufnych danych)</li><li>nieograniczony dostęp do administracji aplikacji</li><li>dostęp do shell-a w systemie operacyjnym i eskalacja ataku w głąb infrastruktury</li><li>przejęcie dostępu do kont użytkowników bez znajomości haseł</li><li>wykorzystanie serwera jako zombie host do ataków na inne serwery w Internecie</li></ul>
<p><br />Nie mówimy, że tego typu konsekwencje występowały w serwisie allegro (nie sprawdzaliśmy tego), a wskazujemy jedynie na krytyczność tego typu luk.<br /><br /><br /></p>
<p>&nbsp;</p>

          ]]>
        </content:encoded>        

        <dc:date>2008-01-22T17:25:00+01:00</dc:date>

        <dcterms:modified>2010-07-12T16:07:17+02:00</dcterms:modified>

        <dc:creator>xterm</dc:creator>

        

        
            <dc:subject>sql injection</dc:subject>
        
        
            <dc:subject>portale</dc:subject>
        

    </rss:item>

    
    

    <rss:item rdf:about="http://www.webservice.eu/pl/nowosci/security-blog/archive/2008/01/15/Dwa-audyty-bezpiczenstwa-dla-Bre-Bank-S.A">

        <rss:title>Audyty bezpieczeństwa dla BRE </rss:title>

        <rss:link>http://www.webservice.eu/pl/nowosci/security-blog/archive/2008/01/15/Dwa-audyty-bezpiczenstwa-dla-Bre-Bank-S.A</rss:link>       

        <rss:description>Wykonaliśmy dwa audyty bezpieczeństwa dla BRE Banku.</rss:description>

        <content:encoded>
          <![CDATA[
          Prace te obejmowały:
<ul><li>Audyt jednego z serwisów informacyjnych Banku <br /></li><li>Wykonanie audytu aplikacji webowej <br /></li></ul>
<p>Oba audyty obejmowały część aplikacyjną oraz infrastrukturę.</p>
<p>Prace zostały potwierdzone listem referencyjnym - do wglądu dla naszych potencjalnych klientów.<br /><br />Niestety ze względu na umowy o poufności nie możemy podać więcej szczegółów.</p>

          ]]>
        </content:encoded>        

        <dc:date>2008-01-15T16:10:00+01:00</dc:date>

        <dcterms:modified>2010-07-12T16:07:17+02:00</dcterms:modified>

        <dc:creator>misa</dc:creator>

        

        
            <dc:subject>bank</dc:subject>
        

    </rss:item>

    
    

    <rss:item rdf:about="http://www.webservice.eu/pl/nowosci/security-blog/archive/2008/01/10/witam-na-blogu-security">

        <rss:title>Witam na blogu security</rss:title>

        <rss:link>http://www.webservice.eu/pl/nowosci/security-blog/archive/2008/01/10/witam-na-blogu-security</rss:link>       

        <rss:description>W tym miejscu będziemy publikować rozmaite ciekawostki ze świata web application security.</rss:description>

        <content:encoded>
          <![CDATA[
          
<p>Tematy będą przekrojowe: począwszy od opisów znalezionych przez nas luk w oprogramowaniu webowym, przez opis podatności w znanych polskich portalach, a kończąc na postach dotyczących aktualnie wykonywanych przez nas prac audytowych.<br /><br />Zapraszam do częstych odwiedzin, postaram się aby większość<br />z wpisów opisywała sytuacje o wysokim stopniu krytyczności :-)<br /><br />Michał Sajdak<br />Dyrektor IT, Kierownik działu software security<br />WebService</p>

          ]]>
        </content:encoded>        

        <dc:date>2008-01-10T17:20:00+01:00</dc:date>

        <dcterms:modified>2010-07-12T16:07:17+02:00</dcterms:modified>

        <dc:creator>xterm</dc:creator>

        


    </rss:item>

    

</rdf:RDF>
