User Tools

Site Tools


deserializacija

This is an old revision of the document!


Nesigurna deserijalizacija

Serijalizacija je proces pretvaranja složenijih tipova podataka u jednostavniji oblik. Svrha je zapisati podatke u obliku u kojem se oni mogu zapisati u datoteku, slati mrežom ili pohraniti u bazu podataka. Primjeri formata u koji se pohranjuju podatci su binarni zapis, JSON (JavaScript Object Notation) i XML (Extensible Markup Language).
Deserijalizacija je obrnut proces. Iz sažetog zapisa podataka rekonstruira se objekt koji je nekad prije bio serijaliziran. Deserijalilziran objekt mora biti jednak originalnom, obuhvatiti sve njegove funkcionalnosti i mora moći obavljati sve interakcije s web stranicom kao i original.

Nesigurna deserijalizacija (eng. Insecure deserialization) javlja se na web stranicama koje deserijaliziraju podatke koje unose korisnici. U idealnom slučaju, nikad se ne bi trebao izravno koristiti korisnički unos jer svaki korisnik može biti zlonamjeran i unijeti podatke koji će izazvati štetu. Usprkos tomu što stranice provode različite provjere nad unesenim podatcima, vrlo je teško pokriti sve moguće slučajeve. Osim toga, često web stranica mora barem početi deserijalizaciju podataka prije nego što prepozna da je uneseno nešto maliciozno, a tad već može biti prekasno. Dodatan je problem što moderne stranice, kako bi imale što više funkcionalnosti, implementiraju velik broj biblioteka. Zbog toga već samo na razini jedne stranice postoji velik broj klasa i metoda. Teško je pokriti sve njihove sigurnosne rupe. Isto tako, ne može se uvijek predvidjeti koja će se od tih brojnih metoda pozvati nad deserijaliziranim podatcima (jer oni mogu biti različitih klasa), što znači da ne možemo predvidjeti ponašanje web stranice ako krene deserijalizirati nesigurne podatke. Zato su i posljedice vrlo širokog spektra. Napadač može dobiti mogućnost remote code executiona, a u slučaju da stranica ima dobru zaštitu protiv toga, i dalje može doći do eskalacije privilegija, pristupa nasumičnim datotekama i DOS (Denial-of-Service) napada.

Jedna od ranjivosti PHP-a koja se koristi pri deserijalizaciji je činjenica da postoji operator “==” koji je manje strog od klasičnog operatora jednakosti “===”. Pokazat ćemo razliku na ovom primjeru:

5 === "5"  //vraća False
5 == "5"  //vraća True

Operator “===” uspoređuje vrijednost lijeve i desne strane, ali i tipove podataka. Budući da je na lijevoj strani broj (integer), a na desnoj niz znakova (string), operator vraća False, iako su vrijednosti iste. S druge strane, operator “==” uspoređuje samo vrijednosti lijeve i desne strane te zato vraća True. Ovakva razlika između dvaju operatora jednakosti postoji u još nekim programskim jezicima, primjerice u JavaScriptu. Međutim, ovdje je ta razlika izraženija. Naime, ove će dvije tvrdnje rezultirati istinom, iako intuitivno ne bi trebale:

5 == "5 i još nešto"
0 == "nešto"

Prvi string donekle se može shvatiti istinom jer barem početak desne strane jednak je lijevoj strani. Međutim, drugi slučaj je nelogičan i stvara veće sigurnosne probleme. Naime, PHP će ovdje string “nešto” tretirati kao integer 0 jer u njemu nema brojeva. Uzmimo napadača koji je na web stranici koja deserijalizira podatke. Kreirao je varijablu $password takvu da ne sadrži brojeve. Ako lozinka korisnika kojemu provaljuje u račun ne sadrži brojeve, izjednačavanje te lozinke s varijablom $password će vratiti istinu, odnosno sustav bi mogao tretirati varijablu $password kao ispravnu lozinku, iako je zapravo možda potpuno različita od prave. Na ovaj će se način napadač bez problema ulogirati kao neki drugi korisnik bez da pogodi njegovu lozinku:

$login = unserialize($_COOKIE)
if ($login['password'] == $password) {
// uspjeh
}

Magične metode

U PHP-u i još nekim programskim jezicima postoje tzv. magične metode. To su metode koje se automatski pozivaju u određenim situacijama. Objektno orijentirani jezici (primjerice Java), kao što im naziv kaže, koriste objekte kao spremišta za neku programsku logiku. Objekti se mogu stvarati i uništavati te svako stvaranje objekta potakne pozivanje metode - konstruktora. U Pythonu je to __init__, u PHP-u construct() itd. Sâmo postojanje magičnih metoda ne predstavlja ranjivost, no problem je kad se izravno koriste podatcima koje unose korisnici jer se pozivanje tih metoda ne može spriječiti. Još je veći problem kad postoje magične metode prilikom deserijalizacije podataka kao što je slučaj u PHP-u. Metoda unserialize() automatski poziva metodu __wakeup(). Dakle, čak i ako neki podatci neće proći deserijalizaciju (primjerice, ako metoda unserialize() prepozna grešku), i dalje je moguće da se pokrene poziv metode __wakeup() i da se napravi šteta.

Umetanje nasumičnih objekata

U objektno orijentiranim jezicima objekt pripada nekoj klasi. Klasa se može shvatiti kao vrsta objekta, a objekt je instanca klase. Primjerice, drveće bi se moglo modelirati klasom, a svako drvo za sebe jednim objektom. Drveće ima neke zajedničke atribute (grane, listove, deblo…) te svako drvo može raditi iste stvari (stvarati grane, pupove listova, odbaciti listove, promijeniti boju lista…) i zato ga smatramo jednom klasom. Na isti način, svaka klasa u programskom jeziku ima definirane atribute (osobine) i metode koje se mogu zvati nad objektima koji pripadaju toj klasi. Manipuliranjem klase objekta koji se šalje na deserijalizaciju napadač može napraviti štetu. Uobičajeno programski jezici imaju mehanizme prepoznavanja neočekivanih tipova podataka pa će slanje objekta neke druge klase obično izazvati grešku ili iznimku (exception). Nekad to nije dovoljno jer je objekt već ušao u sustav i može raditi štetu.


PRIMJER: Zadatak s Hacknite platforme - Autentifikacija bez lozinke

Istražujući internet, Ana je otkrila inovativan način kako se prijaviti u sustav kao admin bez potrebnog 
korisničkog imena ili lozinke. Zadovoljna svojim otkrićem, spremila je vrlo zanimljivu informaciju na 
/usr/local/flag.txt, no za pristup toj informaciji potrebno je prijaviti se u sustav kao admin.

Flag je u formatu CTF2021[brojevi]

http://chal.platforma.hacknite.hr:10014

U prilogu se nalazi i php datoteka stranice. Važan dio koda je:

<?php 
if (!isset($_COOKIE["message"])) {
        $defaultFileAccess = new FileAccess();
        $defaultFileAccess->set_filename("/usr/local/default.txt");
        setcookie("message", base64_encode(serialize($defaultFileAccess)), 
        [ "path" => $_SERVER["REQUEST_URI"] ]);
}
?>

Klasa FileAccess definirana je u istoj datoteci. Iz ovih linija vidimo da, ako nije postavljem message parametar kolačića, atribut filename varijable $defaultFileAcess postavlja se na vrijednost “/usr/local/default.txt”, a u message parametar ulazi taj objekt koji je serijaliziran i čija je vrijednost kodirana s base64.
Da razjasnimo prirodnim jezikom, datoteka kojoj gost ima pristup (default.txt) zadaje se unutar nekog objekta koji se serijalizira i zatim kodira. Na taj način presretaču zahtjeva nije na prvu vidljivo značenje tog podatka, već ima još jedan dodatan korak da bi ga razumio. Pokušajmo poslati zahtjev i presresti ga koristeći Burp Suite da vidimo kako izgleda kolačić. Otvorimo njegov ugrađeni preglednik te uključimo opciju Intercept. Zatim odaberimo “Flag” s navigacije na vrhu stranice.

Napišimo sad php skriptu s pomoću koje ćemo kodirati preko base64. Za provjeru ćemo kodirati vrijednost “/usr/local/default.txt” i usporediti ju s ovime što vidimo u message parametru. Skripta treba izgledati ovako:

<?php
class FileAccess {
        private $filename;
        function set_filename($filename){
                $this->filename=$filename;
        }
        function get_file(){
                return file_get_contents($this->filename);
        }
}
$defaultFileAccess = new FileAccess();
        $defaultFileAccess->set_filename("/usr/local/default.txt"); 
        //zasad ostavimo zadanu putanju radi provjere kako skripta radi
        echo base64_encode(serialize($defaultFileAccess));
?>

Implementacija klase FileAccess prepisana je iz datoteke koja je priložena zadatku.
Rezultat ove skripte identičan je onome što vidimo u message parametru našeg zahtjeva. Promijenimo sad parametar funkcije set_filename() u “/usr/local/flag.txt”. Dobili smo:

TzoxMDoiRmlsZUFjY2VzcyI6MTp7czoyMDoiAEZpbGVBY2Nlc3MAZmlsZW5hbWUiO3M6MTk6Ii91c3IvbG9jYWwvZmxhZy50eHQiO30

Točno to ćemo unijeti u message parametar i tek sad poslati zahtjev. Na stranici se pojavio flag.
Savjet: Za izvođenje ovakvih jednostavnijih programa mogu se koristiti i online prevoditelji, primjerice https://www.programiz.com/php/online-compiler/.


Mjere zaštite

Za sigurniju deserijalizaciju preporučljivo se koristiti formate koji već imaju definiranu logiku deserijaliziranja, primjerice JSON ili XML. Na taj način smanjuje se vjerojatnost da će netko unijeti neku dodatnu logiku prilikom deserijalizacije koja bi mogla napraviti štetu jer je već sve vrlo jasno definirano.
Poželjno je i složiti logiku aplikacije da ona već pri serijalizaciji podatka zna da će ga morati deserijalizirati te da tada označi nekom vrstom potpisa. Zatim prije deserijalizacije treba provjeriti postoji li taj potpis te, ako ga nema, odbaciti podatak jer je vjerojatno maliciozan. Na taj način može se spriječiti umetanje štetnih podataka od strane napadača.
Neki jezici implementiraju zaštitu podataka koji se serijaliziraju. Primjerice, u Javi u klasi koja implementira sučelje Serializable podatci koji se ne bi trebali serijalizirati trebaju se označiti kao private transient. Private znači da se taj podatak ne bi trebao vidjeti ni u jednoj klasi izvan te u kojoj je definiran. Transient je ono što zapravo sprečava serijalizaciju podatka.
Postoje mnogi alati i biblioteke čija je zadaća osigurati deserijalizaciju, primjerice Javini SerialKiller i NotSoSerial te Serial Whitelist Application Trainer (SWAT) i mnogi drugi.

Izvori

deserializacija.1701432325.txt.gz · Last modified: 2025/12/01 11:40 (external edit)

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki