Egy .NET-es alkalmazásból a WebRequest osztály segítségével bármikor indíthatunk HTTP kéréseket egy weboldal felé. Ha a weboldal bejelentkezést igényel, akkor a webalkalmazás a szokásos módon cookie-k segítségével fogja megoldani az állapotkezelést, és a kliensre hárul a feladat, hogy a cookie-t minden kérésnél visszaküldje a szerverre. Ha a felhasználó böngészőből és a kliens alkalmazásból is eléri az alkalmazást, akkor sajnos kétszer kell bejelentkeznie, amire csak az lehet a megoldás, ha képesek vagyunk a böngésző által eltárolt sütit megszerezni.
Firefox böngésző esetén szerencsénk van, a perzisztens sütik egy cookies.sqlite fájlban tárolódnak, csak éppen a könyvtár kiderítése problémás. Az biztos, hogy a C:\Users\felhasználónév\AppData\Roaming\Mozilla\Firefox\Profiles mappa valamelyik almappájában van, az alábbi függvény visszaadja, hogy pontosan hol:
private static string GetCookiePath()
{
string appDataPath = Environment.GetFolderPath( Environment.SpecialFolder.ApplicationData );
string profilesPath = Path.Combine( appDataPath, @"Mozilla\Firefox\Profiles\" );
DirectoryInfo di = new DirectoryInfo( profilesPath );
DirectoryInfo[] dir = di.GetDirectories( "*.default" );
if( dir.Length != 1 )
{
return String.Empty;
}
string cookiePath = Path.Combine( profilesPath, dir[ 0 ].Name + @"\" + "cookies.sqlite" );
if( !File.Exists( cookiePath ) )
{
return String.Empty;
}
return cookiePath;
}
A cookie-kat tartalmazó fájl szerencsére strukturált, konkrétan egy SQLite adatbázisról van szó, amihez szerencsére van szabadon letölthető managed provider. Miután referenciát adtunk a System.Data.SQLite.dll szerelvényre, a szokásos connection és command osztályokon keresztül érhetjük el az adatokat. A sütik a moz_cookies táblában vannak, ami name, path, host és value oszlopokat tartalmaz. Arra kell csak figyelni, hogy a host mező “www.” előtag nélküli domain neveket tartalmaz.
A WebRequest osztálynak egy CookieContainer példányt kell átadni, az alábbi függvény kiolvassa az adatbázisból a paraméterként megadott hoszt névhez tartozó sütiket és egy CookieContainer példányba csomagolva adja vissza:
public static CookieContainer GetCookieContainer( string url )
{
Uri uri = new Uri( url );
string host = uri.Host.Replace( "www.", "" );
CookieContainer container = new CookieContainer();
using( SQLiteConnection conn = new SQLiteConnection( "Data Source=" + FirefoxHelper.GetCookiePath() ) )
{
using( SQLiteCommand cmd = conn.CreateCommand() )
{
cmd.CommandText = "select * from moz_cookies where host like '%" + host + "%';";
conn.Open();
using( SQLiteDataReader reader = cmd.ExecuteReader() )
{
while( reader.Read() )
{
container.Add( new Cookie( reader[ "name" ].ToString(), reader[ "value" ].ToString(),
reader[ "path" ].ToString(), reader[ "host" ].ToString() ) );
}
}
}
}
return container;
}
Persze ha csak egyetlen süti értékére vagyunk kíváncsiak, akkor a domain név és a süti nevének ismeretében azt is megtudhatjuk:
container.GetCookies( new Uri( url ) )[ cookieName ].Value;
Internet Explorer esetén a Wininet API-n keresztül tudjuk kiolvasni a böngésző által tárolt sütiket. Az InternetGetCookie helyett célszerűbb az újabb operációs rendszert igénylő InternetGetCookieEx függvény használata, mert azzal konkrét süti értékét is megkaphatjuk, sőt a HttpOnly sütiket is engedi olvasni.
Bármily kényelmesnek is tűnik ez a programozási lehetőség, akár a felhasználó tudta nélkül vissza lehet vele élni. Hogy ez milyen biztonsági fenyegetéseket rejt magában? Megmutatom az április 29-i Ethical Hacking konferencián. Már lehet regisztrálni!