Ankündigung

Einklappen
Keine Ankündigung bisher.

Local File Inclusion verhindern

Einklappen

Neue Werbung 2019

Einklappen
X
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • Local File Inclusion verhindern

    Hi,

    Hab beim rumspielen mit ein paar Joomla Erweiterungen gerade folgendes gefunden:

    PHP-Code:
    define('DS'DIRECTORY_SEPARATOR);
    $dir dirname(__FILE__);
    $files = array();
    if (isset(
    $_GET['files']) && $_GET['files']) $files $_GET['files'];

    foreach (
    $files as $file) {

        
    $ext substr($filestrrpos($file'.') + 1);
        
    $filepath $dir DS $file;
        
        if (
    is_file($filepath) and $ext === 'js') {
            include(
    $filepath);
            echo 
    "included \n";
        }
        else{
      echo 
    "nicht included";
      }
    }
    ?> 
    "is_file" Verhindert Remote File Inclusions, aber lokale Dateien können
    weiter eingebunden werde. Da wird allerdings geprüft, ob der String
    auf .js endet, wenn ja wird die Datein includet. Mit einem Nullbyte
    tricksen wir die Überprüfung der Dateiendung aus. Der String als solcher
    endet auf ".js" beim include wird aber aller inclusive %00 abgeschnitten.

    Die Erweiterung nutze ich auch für eine kleine Privatseite. Diese läuft auf einem Linux Host. Zum Testen hab ich die Seite aber auch local via XAMPP
    am laufen. In XAMPP kann ich via
    "erweiterung.php?files[]=/../../../../../../robots.txt%00.js"
    die robots.txt includen und anzeigen lassen. Im Echtsystem online klappt das, trotz gleichen Codes, aber nicht.

    Jetzt stellen sich mir 2 Fragen:
    1) Wie lass ich den Pfad variabel, sicher den Script aber ab.
    2) Warum klappt das nur im Testsystem?

  • #2
    $file=str_replace("../", "x", $file);

    Langt das so nicht schon?

    Kommentar


    • #3
      Zitat von ACiD Beitrag anzeigen
      $file=str_replace("../", "x", $file);

      Langt das so nicht schon?
      ?files[]=/var/www/foobar.php%00.js
      Also: nein.

      Einfach, effektiv, sicher:
      GET: ?files[]=abc
      Im Script:
      PHP-Code:
      $allowedFiles = array('abc' => '/var/www/myfile.js');
      if(
      array_key_exists($file$allowedFiles)) {
           include 
      $allowedFiles[$file];

      Im Übrigen: warum zum Henker includet man JS-Files?
      VokeIT GmbH & Co. KG - VokeIT-oss @ github

      Kommentar


      • #4
        Ich höre gerade (erschreckender Weise) das erste mal von diesem Hackingtrick.

        Stumpfe Idee: Vor dem Abgleich, ob .js am Ende steht alles ab einem Nullbyte selber abschneiden, oder Nullbytes entfernen.

        Ala
        PHP-Code:
        $str str_replace(urldecode('%00'''$str)); 
        Ist jetzt ungetestet

        Kommentar


        • #5
          Ist jetzt ungetestet
          Das sieht man.
          [COLOR="#F5F5FF"]--[/COLOR]
          [COLOR="Gray"][SIZE="6"][FONT="Georgia"][B]^^ O.O[/B][/FONT] [/SIZE]
          „Emoticons machen einen Beitrag etwas freundlicher. Deine wirken zwar fachlich richtig sein, aber meist ziemlich uninteressant.
          [URL="http://www.php.de/javascript-ajax-und-mehr/107400-draggable-sorttable-setattribute.html#post788799"][B]Wenn man nur Text sieht, haben viele junge Entwickler keine interesse, diese stumpfen Texte zu lesen.“[/B][/URL][/COLOR]
          [COLOR="#F5F5FF"]
          --[/COLOR]

          Kommentar


          • #6
            Mit trim kann man die Null-Bytes entfernen.

            Kommentar


            • #7
              trim tut dies aber nur am Anfang und Ende des String, nullbytes in der Mitte lässt er unberührt.

              Kommentar


              • #8
                Zitat von nikosch Beitrag anzeigen
                Das sieht man.
                Ist das hier ein Forum, wo man anderen helfen darf?
                Ich habe einfach nur einen Gedanken gehabt der vielleicht helfen kann,
                und den Beispielcode zur Verdeutlichung gepostet, nicht um ihn 1:1 in ein Produktivsystem übernehmen zu lassen...

                Ich hätte gehofft das gerade Moderatoren solche Kommentare (ohne irgendwelchen weiteren Sinn im Post) nicht nötig haben.

                --------------

                Man kann Zeichen ja auch mit chr() und den Hexadezimalen bzw. Octalen Notationen darstellen.

                Zum Beispiel:
                PHP-Code:
                // mit chr()
                $foo chr(0);

                // octal
                $foo '\000'// oder \00 bzw. \0

                // hexadezimal
                $foo '\x00'
                LG

                Kommentar


                • #9
                  Das dies nicht mal ansatzweise funktionieren kann sieht man ja wohl:
                  PHP-Code:
                  $str str_replace(urldecode('%00'''$str)); 
                  PHP-Code:
                  $str str_replace(      urldecode('%00''' $str)      ); 
                  [COLOR="#F5F5FF"]--[/COLOR]
                  [COLOR="Gray"][SIZE="6"][FONT="Georgia"][B]^^ O.O[/B][/FONT] [/SIZE]
                  „Emoticons machen einen Beitrag etwas freundlicher. Deine wirken zwar fachlich richtig sein, aber meist ziemlich uninteressant.
                  [URL="http://www.php.de/javascript-ajax-und-mehr/107400-draggable-sorttable-setattribute.html#post788799"][B]Wenn man nur Text sieht, haben viele junge Entwickler keine interesse, diese stumpfen Texte zu lesen.“[/B][/URL][/COLOR]
                  [COLOR="#F5F5FF"]
                  --[/COLOR]

                  Kommentar


                  • #10
                    Stimmt, da hast du völlig recht, entschuldige das ich dann so ausfallend geworden bin.

                    So wäre es besser:

                    PHP-Code:
                    $str str_replace(urldecode('%00'), ''$str); 

                    Kommentar


                    • #11
                      ich nutze jetzt einfach:
                      $file=str_replace(chr(0), '', $file);
                      und das funktioniert einwandfrei!

                      Jetzt hab ich allerdings noch ein Verständnisproblem. Nehmen wir an die URL
                      eines Scriptes das LFI anfällig ist sieht wie folgt aus:

                      http://www.deinserver.de/scripte/bla...ript.php?file=

                      in manchen Fällen, reicht es das jetzt ein /etc/passwd anzuhängen, um ebend diese
                      Daten angezeigt zu bekommen. Bei Anderen wiederrum muß man erst via /../ etliche Verzeichnisse runter springen. Wo und wie wird denn festgelegt, wo das root-Verzeichnis ist?

                      Bzw. die Frage warum das im Testsystem mit gleichen Scripten geht, im Echtsystem aber nicht wurde auch noch nicht beantwortet.

                      Grüße und einen schönen Feierabend

                      Kommentar


                      • #12
                        Wo das root-verzeichnis liegt, ist ja vom System festgelegt, immer auf Wurzelebene mit dem absoluten Pfad '/'.

                        Alle Pfade mit einem '/' am Anfang gehen von root aus immer weiter rein, sind also absolut.
                        Fehlt der '/' am Pfadbeginn, bezieht sich der Pfad auf das aktuelle Verzeichnis und wir von dort dann zu einem absoluten Pfad aufgelöst:

                        Code:
                        # Wir sind hier (absolut)
                        /home/homer/Documents/Downloads/../
                        
                        # Der relative Pfad (kein Slash am Anfang!)
                        ../../bart/privates/fotos
                        Das wird jetzt aufgelöst:
                        Code:
                        #Zunächst wird der absolute Pfad zu
                        /home/homer/Documents
                        
                        # Dann wird der relative Pfad von hier aufgelöst:
                        /home/bart/privates/fotos
                        Wenn du in einem PHP Code von Anfang an einen absoluten Pfad vorgibst, indem du an den Anfang einen Slash stellst, geht jeder daran angehängte Pfad von hier aus. Beginnt er mit einem Slash, wird er durch den Doppelslash ungültig:
                        PHP-Code:
                        $pfad '/home/bart/privates/fotos'// hier hat jmd. schmutzige Gedanken...

                        Include '/home/homer/Documents'.'/'.$pfad// Wird zu '/home/homer/Documents//home/bart/...' und ist durch den Doppelslash ungültig 
                        Das man in der Verzeichnisebene hoch geht um doch noch an die schmutzigen Inhalte zu kommen, kannst du ganz einfach verhindern:

                        PHP-Code:
                        // $pfad = '../../bart/privates/fotos';

                        $pfad str_replace(array('../','..\\'), ''$pfad); // Entfernt den Sprung nach oben
                        Include '/home/homer/Documents'.'/'.$pfad// Wird zu /home/homer/Documents/bart/privates/fotos, was nicht existiert 

                        Kommentar


                        • #13
                          Zitat von jw-lighting Beitrag anzeigen
                          Das man in der Verzeichnisebene hoch geht um doch noch an die schmutzigen Inhalte zu kommen, kannst du ganz einfach verhindern:

                          PHP-Code:
                          // $pfad = '../../bart/privates/fotos';

                          $pfad str_replace(array('../','..\\'), ''$pfad); // Entfernt den Sprung nach oben
                          Include '/home/homer/Documents'.'/'.$pfad// Wird zu /home/homer/Documents/bart/privates/fotos, was nicht existiert 
                          Und was ist mit diesem Pfad?
                          PHP-Code:
                          $pfad '....//....//bart/privates/fotos'
                          http://mcsodbrenner.blogspot.com/
                          Serpent PHP Template Engine: http://code.google.com/p/serpent-php-template-engine/

                          Kommentar


                          • #14
                            ich erlaube idr nur kleine buchstaben und verwende zudem noch basename. ist zwar doppelt gemoppelt aber was solls.

                            Kommentar


                            • #15
                              Zitat von ACiD Beitrag anzeigen
                              Bei Anderen wiederrum muß man erst via /../ etliche Verzeichnisse runter springen. Wo und wie wird denn festgelegt, wo das root-Verzeichnis ist?
                              Verstehe ich nicht. Aber zur Verdeutlichung:
                              Includest du so
                              PHP-Code:
                              include($file); 
                              würde es tatsächlich reichen, einen absoluten Pfad zu übergeben. Aber der Normalfall sieht eher so aus:
                              PHP-Code:
                              include('controller/' $file '.class.php'); 
                              Da hier jetzt vor deiner Variable ein Pfad steht, kannst du nicht direkt über einen absoluten Pfad einsteigen, sondern musst per Directory Traversal arbeiten, also mit '../'.
                              Zum Root des Servers zu kommen, ist dabei eigentlich ganz einfach. Du musst einfach mehr "../" angeben als du Ebenen vom aktuellen Pfad hast. Gibt du also einfach 20-mal '../' an, kannst du sicher sein, im Root zu sein.

                              So kommst du z.B. über das zweite Code-Beispiel an die etc/passwd
                              $file = "../../../../../../../../../../../../../etc/passwd\0";

                              Richtig verstanden die Frage?
                              http://mcsodbrenner.blogspot.com/
                              Serpent PHP Template Engine: http://code.google.com/p/serpent-php-template-engine/

                              Kommentar

                              Lädt...
                              X