Pahavara: üks huvitav veebiproksi

Peeter Marvet
Jaga:

Puhastasin nädalavahetusel järjekordset veebi, kuhu oli sisse pääsetud nõrga admin-kasutaja salasõnaga. Kuna rünne oli toimunud hiljuti, oli mugav võtta ette varukoopia ning sellega võrreldes tuvastada muutunud failid. Ilmnes, et katalooge mööda oli laiali puistatud 35 erinevat tagaust või pahavaralise funktsionaalsusega faili.

Et küberkurjategijate tööd veidi laiemal tutvustada panin välja auhinnad… ja otsustasin koodi Facebookis huvilistele lammutada anda. See blogipost ongi kokku pandud osalt Zone FB-lehe postituse ja Vabakutseliste gruppi jagatu kommentaarides olevatest lahendustest – ning osalt Zone maja-sisestest tähelepanekutest.

Kui tahad enne lahenduse lugemist (või selle kõrvale) koodi vaadata, siis:

Niisiis saab kõik alguse sogastatud koodist:

Kristjan muutis (kasutatud) funktsioonide ja muutujate nimed arusaadavaks ja lisas kommentaarid – saamaks aru, mida koodijupp teeb ja kas seda on üldse ohutu oma arvutis või serveris käivitada:

Kuna muutujas $payLoad olev laeng on URL-kodeeringus mida pahavara-tuvastajatel lihtne läbi näha, on kasutataud täiendavat teisendustabelit selle sogastamiseks:

Olgu lisatud, et algses koodis näeb see eval ehk stringis olevat PHP koodi käivitav funktsioon välja alljärgnev, kurja eval() peitmiseks lihtsamate otsingute eest on funktsiooni nimi eraldi real ning lisaks üks kommentaar:

Kui asendada funktsion eval() näiteks print()’iga saame väljundiks laengu koodi – aga mulle meeldib rohkem tulemus faili kirjutada:

file_put_contents ( '_payload.php', decodePayload( $payLoad, $characterMap ) );

Ja saamegi asuda laengut uurima. Väga levinud tava on keelata ära veateadete väljastamine, aga siin on igaks juhuks võetud maha ka skripti täitmise ajapiirang (mis sisuliselt võimaldab seda kasutada ka teenustõkestusründeks andes kõigile lubatud PHP-protsessidele midagi aegavõtvat teha):

Edasi, otsime päringust maagilist küpsist – AGA Kristjani kommentaar on väikse näpukaga, nimelt väljutakse skriptist kui leitakse mõni küpsis mille väärtus EI VASTA soovitud nimele (küpsise nimi pole seejuures oluline).

Lisaks on koodis aga üks väga tore loogikaviga mille avastas Kurt Moser meie arendustiimist, vaata kas märkad:

Nojah, seda tsüklit ei täideta ja skriptist väljumist ei toimu, kui päringuga pole kaasas ühtki küpsist. Ehk sisuliselt on kogu piirang mõttetu – funktsionaalsele osale saab ligi igaüks.

Edasi läheb huvitavamaks:

Selle jupi juures tasub kindlasti “kastist välja” mõelda – php://input on tavapäraselt kasutusel POST päringute puhul, mitte miski ei keela selle kasutamist ka GET päringus. Sellisel kujul GETi kasutamise võlu seisneb aga selles, et veebiserverid päringu keha harilikult ei logi. Aga olgu siinkohal ka tõestus Elar Langilt:



$ curl -X GET -s --data "töötab ju" http://localhost/z-server.php
string(11) "töötab ju"

$ curl -X POST -s --data "töötab ju" http://localhost/z-server.php
string(11) "töötab ju"

Järgmise jupi võtan ma aga oma koodiredaktorist, sest see oskab vigu tuvastada:

Jahaa – funktsioon split() kuulutati iganenuks juba PHP versioonis 5.3 ja alates 7.0 on see eemaldatud (tx veelkord Kurtile!). Ehk PHP uuemate versioonide puhul see kood ei tööta ja annab viga – võinoh… kuna vigade väljastamine on ülalpool ära keelatud, siis on tulemuseks Error 500, nagu ilmselt avastas ka ründaja:

94.130.35.51 - - [27/Mar/2019:10:02:21 +0200] "GET /wp-admin/css/colors/sunrise/lngzdhkh.php HTTP/1.1" 500 3527 "" "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-G935F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/5.4 Chrome/51.0.2704.106 Mobile Safari/537.36" (F9F8DACB-0.001)

Pannes split() asemele explode() saab sellest murest kergesti üle.

decrypt() on sisuliselt XOR krüpteering ehk sama võtmega saab lahti ja kinni – nagu Karl-Sander Erss FBs kommentaaris demos:

> var_dump(decrypt(decrypt('asd'))==='asd');
bool(true)

Kuivõrd võtmeks on $_SERVER[‘HTTP_HOST’]  ja $_SERVER[‘REQUEST_URI’] on ka see kergesti ära-arvatav ehk nagu eelnevalt öeldud saab sellele koodi ära kasutada kesiganes tema olemasolu teab. Nii küpsis kui krüpto on täiesti mõttetud 🙂

Aga … mida see send_data1() siis teeb? Võtab saadud parameetrid (näidisandmed ülalolevas ekraanilaksus) ja teeb nendega HTTP POST või GET-päringu… ja tagastab tulemuse ehk tegu on veebiproksiga:

function send_data1( $data ) {
   $head = "";
   foreach ( $data["headers"] as $key => $value ) {
      $head .= $key . ": " . $value . "\r\n";
   }
   $params = array(
      'http' => array(
         'method'  => $data["method"],
         'header'  => $head,
         'content' => $data["body"],
         'timeout' => $data["timeout"],
      )
   );
   $ctx = stream_context_create( $params );
   $result = @file_get_contents( $data["url"], false, $ctx );
   if ( $http_response_header ) {
      if ( strpos( $http_response_header[0], "200" ) === false ) {
         $result = "HTTP_ERROR\t" . $http_response_header[0];
      }
   } else {
      $result = "CONNECTION_ERROR";
   }
   return $result;
}

Tuleb tunnistada, et file_get_contents() kasutamine koos kontekstiga HTTP-päringu parameetrite määramiseks pole minule kunagi varem ette jäänud, aga väga huvitav meetod. Lisaks: kuna paika pannakse ka timeout ning alguses on skripti täitmise ajapiirang maha võetud… siis võib see väääääga kaua aega võtta ehk olla kasutatav DOS ründeks.

Huvitavat jagub aga veelgi: nimelt EI MÄÄRATA ära HTTP protokolli versiooni ning vaikimisi on selleks HTTP/1.0 – ning minu oletuse kohaselt kasutatakse ülevõetud servereid järgmiste serverite ründamiseks. Hmm, vaatame korraks rünnatud saidi logi, filtreerides õnnestunud HTTP/1.0 päringuid:

Ja tõepoolest, need IPd pärinevad erinevatest pilve- või veebimajutusteenustest. Võib oletada, et ründajatel on oma veebiproksi, mis kasutab ülevõetud serverites olevaid veebiproksisid. See muudab võimatuks lihtsad lahendused nagu IP-põhised piirangud – mh kaitse WordPressi wp-login.php vastu suunatud paroolide jõurünnete tõrjumise “lubame vaid kolm katset samalt IPlt” meetodil.

Tänud kõigile kaasa mõtlemast, loodetavasti saime koos targemaks 🙂

Popular posts

Zone blogi 16

Pidupäev: Zone blogi 16!

Jaanus Putting
Täna 16 aastat tagasi, 3. novembril 2006 nägi ilmavalgust Zone blogi. Oma kõige-kõige esimeses postituses rõõmustasime toonase olulise verstaposti,...

Elektrivarustus eriolukorras

Ardi Jürgens
Energiavarustus on hetkel äärmiselt aktuaalne teema ja ka meie poole on korduvalt pöördutud küsimustega, mis puudutavad Zone infosüsteemide talitlusvõimet...

Zone klienditugi ehk kuidas võimas tosin aitab 200 000 kasutajat

Kaarel Urva
Mina olen Kaarel ja kirjutan seekordses blogiartiklis Zone klienditoest ning sellest, kuidas ka sina saaksid oma ettevõtte kliendituge efektiivsemaks...

SPF ja Gmail. Jälle!

Kaarel Urva
Ehk miks Gmail mu kirjad tagasi lükkab?Alates 7. juunist on Gmail hakanud tagasi lükkama kõiki e-kirju, mis saabuvad domeenidelt, millel on puudu SPF...