Facebook deanonymizačný útok - Nethemba

BLOG

Facebook deanonymizačný útok

2010-06-16 19:58 Pavol Lupták

Po prečítaní článku Feasibility and Real-World Implications of Web Browser
History Detection
a A Practical Attack to De-Anonymize Social Network Users som sa rozhodol technicky navrhnúť a popísať, ako by vyzeral efektívny a rýchly deanonymizačný útok na Facebook. V prípade akýchkoľvek pripomienok, či vylepšení ma samozrejme neváhajte kontaktovať.

 

Príprava na útok

V prvom rade je potrebné získať (“zharvestovať”) zoznam všetkých Facebookových skupín – je ich viac ako 39 miliónov o veľkosti viac ako 7 GB, takže to pár dni zrejme potrvá. Podotýkam, že každá verejná skupina obsahuje zoznam ľudí, ktorí do nej patria.

Zoznam týchto skupín je verejne dostupný:

http://www.facebook.com/directory/groups/

podobne ako je dostupný zoznam všetkých používateľov Facebooku:

http://www.facebook.com/directory/people/

Downloadovací skript by ich mal uložiť v nasledujúcom formáte:

– každá skupina bude samostatný plaintextový súbor, ktorý bude mať číselný názov (príslušný GID skupiny) a bude obsahovať zoznam všetkých svojich členov (na každý jeden riadok pripadne krstné meno a priezvisko daného člena, prípadne jeho ďalšie mená)

– nakoľko tých skupín bude zrejme veľa (39 miliónov súborov v jednom adresári je predsa príliš veľa), môže sa použiť ďalšia adresárová štruktúra, kde 1. názov adresára môžu predstavovať napr. posledné 4 číslice GIDu, 2. názov podadresára budú predstavovať ďalšie 4 číslice GIDu atď. Takže napríklad súbor s GID 2227862516 bude uložený v adresárovej štruktúre:

Facebook-groups/2516/2786/2227862516 v plaintext formáte:

Meno1 Priezvisko1

Meno2 Priezvisko2 DruhéPriezvisko2

..

Aby naša deanonymizačná služba bola vždy aktuálna, tak uvedené “harvestovanie” nových členov a nových skupín je samozrejme potrebné spúštať pravidelne (napríklad raz za deň), aby sme mali vždy aktuálne skupiny s aktuálnymi členmi.

Samotná deanonymizácia je potom už triviálna, deanonymizačná služba cez CSS history hack zistí, že používateľ patrí do skupín GID1, GID2, GID3, GID4, skript vyhľadá takto získané plaintextové súbory GID1, GID2, GID3 a GID4, urobí ich jednoduchý prienik (t.j. zistí riadky, ktoré su v každom tom súbore rovnaké jednoducho pomocou “uniq -d” alebo “grep -f”) a výstupom je v lepšom prípade (ak z toho vypadne len jeden riadok) samotný deanonymizovaný Facebook používateľ, v horšom prípade (ak z toho vypadne viacero riadkov) zoznam všetkých ľudí, ktorí patria do všetkých uvedených skupin (a daný Facebook používateľ sa v nej bude určite nachádzať).

 

Útok cez CSS history hack

CSS history hack predstavuje spôsob ako vo všetkých súčasných prehliadačoch odhaliť enumerovaním, ktoré presne URL (GET žiadosti) boli v minulosti daným prehliadačom navštívené. Podotýkam, že ide o štandardnú funkcionalitu všetkých súčasných prehliadačov a pokým nepoužívate “PrivacyBrowsing” alebo “safehistory” plugin alebo si pravidelne nepremazávate históriu v prehliadači, tak ste automaticky zraniteľný na uvedený útok.

Nakoľko pridanie do Facebookovej skupiny je realizované pomocou GET žiadosti, kde v parametri gid je uvedené číslo samotnej Facebookovej skupiny, použitím CSS history hacku enumerovaním všetkých našich získaných skupín v prvom kroku, je možné detekovať, či používateľ patrí do danej skupiny alebo nie. Nakoľko uvedených skupín je viac ako 40 miliónov, je nutné uvedenú fázu špeciálne optimalizovať a používať viacúrovňové porovnávanie.

Je doležité zdôrazniť, že je možné enumerovať nielen http:// adresy, ale aj https://, ftp://, či file:///

Deanonymizačná služba v prvom rade musí detekovať verziu prehliadača samotnej obete (čo dokáže urýchliť a optimalizovať samotný útok cez CSS hack) a tiež odhaliť, či daný používateľ má v prehliadači zapnutý javascript alebo naopak vypnutý.

V prípade vypnutého javascriptu, je možné realizovať len CSS-only hack:

<style>
#foo: visited { background : url (/? yes -foo );}
#bar: link { background : url (/?no -bar );}
</style >
<a id="foo" href =" http :// foo.org" ></a>
<a id="bar" href =" http :// bar.biz" ></a>

Výhoda uvedeného útoku spočíva v tom, že funguje aj pre prehliadače, ktoré majú javascript vypnutý (napríklad cez noscript plugin), nevýhoda je, že uvedený útok ide použiť iba na enumerovanie relatívne malého množstva liniek (do 50000), nakoľko pri väčšom množstve liniek totiž prudko klesá rýchlosť detekcie (vzhľadom na veľké množstvo DOM elementov vnorených v danej stránke). Zapnutá gzip kompresia ale veľkosť celkového prenášaného HTML môže značne zmenšiť.

V prípade, že je javascript v prehliadači zapnutý, je možné realizovať podstatne flexibilnejší CSS hack v javascripte:

<script >
var r1 = ' a { color : green ;}';
var r2 = ' a:visited { color : red; }';
document.styleSheets[0].insertRule (r1,0);
document.styleSheets[0].insertRule (r2,1);
var a_el = document.createElement('a');
a_el.href = "http://foo.org";
var a_style = document.defaultView.getComputedStyle(a_el, "");

if (a_style.getPropertyValue ("color") == 'red ' ) {
// link was visited }
</script>

Na rozdiel od CSS-only hacku, ktorý je ťažko optimalizovateľný, je tu pekný priestor pre úrychlenie (rôzne prehliadače totiž používajú iné interné reprezentácie vypočítaných CSS hodnôt, napríklad červená farba môže byt interne reprezentovaná ako “red”, “#ff0000”, “f00” alebo “rgb(255,0,0)” a pre jeden konkretný prehliadač, ktorý používa práve jednu interpretáciu je zbytočné porovnávať všetky tieto hodnoty, ďalšia optimalizácia je znovupoužitie DOM elementov, kde je to len možné, čo najviac vyhýbanie sa volaniu javascript funkcií atď).

Optimalizovaná verzia CSS javascript hacku dokáže za jednu sekundu enumerovať až 30000 liniek (!), teda okamžite overiť, či boli už navštívené alebo nie. V našom prípade to znamená, že je možné behom jednej sekundy enumerovať 30000 Facebookových skupín a teda zistiť, či do nich daný Facebookový používateľ patrí alebo nie.

 

Viacúrovňové porovnávanie

V prípade, že by sme sa rozhodli použiť CSS hack a na jedenkrát “omatchovať” do ktorých z viac ako 39 miliónov Facebookových skupín daný používateľ patrí, tak máme problém – dané HTML deanonymizačnej služby (v prípade CSS only hack) má cez 0.5 GB a enumerovanie všetkých týchto skupín by v úplne ideálne prípade (30000 za sekundu) trvalo viac ako 22 minút (prakticky podstatne dlhšie). Čo je v našom prípade takmer nepoužiteľné.

Podstatne elegantnejšie, neporovnateľne rýchlejšie a menej náročne na zdroje je tzv. viacúrovňové porovnávanie, napríklad:

1. Vytvoríme zoznam 300 najpopulárnejších Facebookových skupín pre každú krajinu sveta.

2. Obetí v prvej úrovni predhodíme 300 liniek najpopulárnejších Faceboovkových skupín každého štátu, dohromady pre všetky štáty (dajme tomu, že ich je 100), je to 30000 liniek, ktoré sa u klienta vyskúšaju behom jednej sekundy. Na základe toho, ktoré sa pre daný štát najviac “namatchujú” dokážeme jednoducho identifikovať do ktorej krajiny daný používateľ patrí (pomôcť si samozrejme môžeme aj pomocou GeoIP nakoľko vieme jeho IP adresu)

3. Inteligentný AJAX na strane obete zistí, ktoré všetky z tých liniek boli reálne navštívené a túto informáciu pošle na server denanonymizačnej služby. Ten na základe toho vyhodnotí, do ktorej krajiny alebo regiónu daný používateľ patrí a pošle “na vyskúšanie” druhú várku už špecifickejších URL liniek – tam napríklad môže byť zoznam politických skupín v danej krajine alebo zoznam skupín populárnych osôb, či hudobných interpretov v danej krajine, či zoznam skupín obľúbených operačných systémov.

4. V prípade malých krajín (ako napríklad Slovensko), kde zoznam všetkých Facebookových skupín môže byť relatívne malý, je možné v druhej várke poslať zoznam všetkých Facebookových skupín v danej krajine, ktoré sa behom pár sekúnd okamžite vyskúšajú.

5. Celý tento proces je samozrejme možné opakovať do ľubovoľnej úrovne, tak aby počet liniek na vyskúšanie v danej úrovni boli relatívne nízky (a teda malý HTTP traffic) a enumerovanie liniek v danej úrovni veľmi rýchle.

Pri zvolení správnych úrovní primárnych, sekundárnych, či terciálnych liniek a vhodného spôsobu “vnárania sa”, je možné používateľa deanonymizovať behom pár sekúnd.

Osobne vidím najväčší problém v tom, ako plne automatizovane určiť, ktoré Facebook skupiny sa týkajú ktorých krajín (na detekciu jazyka podľa textu v skupine je možné zrejme použiť Google Translate), ako aj navrhnúť zoznam vhodných sekundárnych liniek (je možné na to použiť napríklad rôzne vyhľadávače).

V každom prípade uvedený útok je možné technicky realizovať tak, aby bol dostatočne rýchly a efektívny a to aj v prípade obrovského množstva skupín takej sociálnej siete ako je Facebook.

 

Málo dát

Samozrejme, že môže nastať situácia, že na úplnu deanonymizáciu budeme mať málo dát:

1. Firefox ukladá totiž históriu len 90 dní, Safari 20 dní, IE 20 dní, Opera ukladá posledných 1000 navštívených URL (v prípade Chrome ale napríklad žiadne expirovanie histórie nefunguje).

2. Počet skupín, do ktorých daný používateľ patrí môže byť príliš malý na jeho jednoznačnú identifikáciu.

V tomto prípade navrhujem nasledujúce riešenie, ktoré môžu výrazne zlepšiť jednoznačnú identifikáciu (a teda prípadnú deanonymizáciu):

1. Facebook gid v GET žiadostiach sa využíva nielen pri prihlasovaní (“joinovaní”) do skupiny, ale aj pri jej manipulácii (pridávanie príspevku apod), čo sa dá potenciálne využiť pri ďalšej identifikácii. Tu samozrejme treba počítať s tým, že používateľ si môže prezerať aj skupiny, ktorých nie je členom a teda sa nemôžu použiť na deanonymizačný útok.

2. Cez CSS hack je možné realizovať paralelne viacero útokov na rôzne sociálne siete a výsledky z nich navzájom korelovať, okrem Facebooku, útok funguje napríklad aj na LinkedIn, Xing, či iné. Informácie z nich získané je možné návzajom korelovať a teda dodatočne spresňovať identifikáciu ich používateľa s cieľom ho úplne deanonymizovať.

Ak napríklad pomocou Facebook deanonymizačného útoku získame 1000 potenciálnych kandidátov a pomocou LinkedIn deanonymizačného útoku 500 ďalších potenciálnych kandidátov, tak z ich prieniku možno vypadne jednoznačná identita (alebo podstatne menej možností). Je dôležite podotknúť, že okrem toho, že môžeme korelovať výsledky viacerých sociálnych sietí s cieľom lepšej identifikácie, je možné využiť aj ďalšie informácie (enumerovať nejaké populárne blogy, fóra apod).

 

Riešenie

1. Na strane servera (Facebooku) je nutné akékoľvek informácie (ako ID skupiny), z ktorých je možné spätne deanonymizovať používateľa vždy prenášať jedine cez POST žiadosti (nie cez GET, ktoré sa ukladajú do histórie).

Ďalšie účinne riešenie je pridávať do všetkých GET žiadosti ďalší parameter – anti-CSRF náhodný token, ktorý sa nedá pri enumerovaní URL determinovať.

2. Na strane klienta je viacero možností – buď pravidelne mazať históriu prehliadača, používať PrivateBrowsing, SafeHistory plugin alebo si počkať na Firefox 4.0, ktorý by mal znemožňovať enumerovanie navštívených liniek cez CSS hack.