Sec Bug->Bug #76067 [Asn]: system() function call leaks php-fpm listening sockets
| From: | bukka@php.net | Date: | Sun, 14 Oct 2018 15:34:15 +0000 |
| Subject: | Sec Bug->Bug #76067 [Asn]: system() function call leaks php-fpm listening sockets | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-217555@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=76067&edit=1
ID: 76067
Updated by: bukka@php.net
Reported by: jaco at uls dot co dot za
Summary: system() function call leaks php-fpm listening
sockets
Status: Assigned
-Type: Security
+Type: Bug
Package: FPM related
Operating System: Linux
PHP Version: 5.6.34
Assigned To: bukka
Block user comment: N
Private report: Y
New Comment:
As discussed, I'm setting this as a not security issue for the reasons stated above. In
addition I have been looking through the similar bugs and the issue is already exposed in the FPM
related comment added on 2013-12-03 at 17:23 UTC to the bug about similar issue in Apache mod_php:
https://bugs.php.net/bug.php?id=38915 .
Previous Comments:
------------------------------------------------------------------------
[2018-03-22 20:55:41] bukka@php.net
I would be a bit careful about adding cloexec on stdin. At least I need to experiment with that
first to see what possible consequences are. The thing is that the fact that stdin is used causing
other issues as well (see https://bugs.php.net/bug.php?id=73342 ) so it might
be better to change that but it needs a bit more thinking and mainly testing first.
I agree that this is not really a security issue. If you can't trust a program that you run
using system function, then you have got bunch of other problems as well IMHO.
------------------------------------------------------------------------
[2018-03-18 21:37:27] stas@php.net
Looking at FPM code in fpm_stdio_init_child(), it looks like FD 0 (stdin) is always the listening
socket. This means there's no useful way for the forked process to make any legit use of it,
probably. Which means, it would probably be OK to not pass it? I am not sure though what CLOEXEC
there would result in.
@bukka, any opinion on adding CLOEXEC to listening socket somewhere in fpm_stdio_init_child() or
fpm_unix_init_child()?
That all said, since the child and the FPM process run within the same permissions framework, I am
not sure there can be a real security barrier between them. If you have full remote access to the
server, including system(), there's little you can't do (within the permissions of this
user).
------------------------------------------------------------------------
[2018-03-13 19:21:08] jaco at uls dot co dot za
I'm not familiar with the details of the code, so:
1. Yes, I only saw the one socket leaked, test environment only had one socket configured.
I've confirmed that you're right, only single socket for the pool is leaked.
2. Could perhaps be utilized to bypass certain other restrictions enforced by safe mode although
most likely external execution too would be disabled in safe mode.
3. As an attacker of a web page I could utilize an exploit to run a custom script, take over the
listening socket and start accepting connections (and re-originating them back into php-fpm for
processing but get all traffic - MITM style - including post data potentially containing usernames
and passwords, which I may not otherwise be able to get in plaintext since they'd be
*hopefully* hashed in the backing DB/datastore, or using an external authenticator service like
radius/ldap/whatever).
If you don't feel this is a security problem, please treat it as such and open it up for
general viewing, but this is still something that should be fixed either way.
------------------------------------------------------------------------
[2018-03-13 18:33:18] bukka@php.net
I would like to first clarify why this is marked as a security issue.
I'm not really sure how this can be exploited. AFAIC you can't share the listening socket
across the pools which means that it will be for a single pool and it means that the user will be
the same, right? Can you please be a more specific why this is a security issue?
------------------------------------------------------------------------
[2018-03-08 13:48:39] jaco at uls dot co dot za
Description:
------------
We've recently noticed that when some of our PHP code executes external scripts via the
system() call, those scripts have access to file descriptors that it probably should not.
Specifically we are able to tap into the PHP-FPM listening socket.
Below a simple php + shell script combo to illustrate the problem.
Note that in the below, fd 0 is the listening socket, so one could conceivable start executing
accept() calls on this file descriptor to steal connections that should have gone to the PHP FPM
master process.
A simplistic fix is presumably to set FD_CLOEXEC on the listening sockets in the master process.
Even the accept()ed connections. A more comprehensive fix is probably in the system() function to
first close all descriptors before performing the actual system() call, and setting up stdin to come
from /dev/null in the case of non-cli SAPIs. Or at the very least one could redirect fd 0 to
utilize the php://stdin stream.
This seemingly relates to bug #67383.
Test script:
---------------
<?php
header("Content-Type: text/plain");
system("ls -la /proc/self/fd/; /sbin/ss -xtap");
?>
Expected result:
----------------
I would like to see only three open file descriptors being listed in the ls statement:
0 <= /dev/null (probably)
1 => pipe()
2 => /dev/null (as per current).
(and 3 to /proc/32264/fd for the readdir cycle)
Actual result:
--------------
total 0
dr-x------ 2 nobody jkroon 0 Mar 8 15:25 .
dr-xr-xr-x 8 nobody jkroon 0 Mar 8 15:25 ..
lrwx------ 1 nobody jkroon 64 Mar 8 15:25 0 -> socket:[8376]
l-wx------ 1 nobody jkroon 64 Mar 8 15:25 1 -> pipe:[572571]
lrwx------ 1 nobody jkroon 64 Mar 8 15:25 2 -> /dev/null
lr-x------ 1 nobody jkroon 64 Mar 8 15:25 3 -> /proc/32264/fd
lrwx------ 1 nobody jkroon 64 Mar 8 15:25 4 -> socket:[572570]
Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port
...
u_str LISTEN 0 0 /var/run/php-fpm/www 8376 * 0
users:(("ss",pid=32265,fd=0),("list_fds.sh",pid=32263,fd=0),("sh",pid=32262,fd=0),("php-fpm",pid=32261,fd=0))
...
u_str ESTAB 0 0 /var/run/php-fpm/www 572570 * 0
users:(("ss",pid=32265,fd=4),("list_fds.sh",pid=32263,fd=4),("sh",pid=32262,fd=4),("php-fpm",pid=32261,fd=4))
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=76067&edit=1