新聞中心
前言
PHP文件包含漏洞的產(chǎn)生原因是在通過PHP的函數(shù)引入文件時(shí),由于傳入的文件名沒有經(jīng)過合理的校驗(yàn),從而操作了預(yù)想之外的文件,就可能導(dǎo)致意外的文件泄露甚至惡意的代碼注入。最常見的就屬于本地文件包含(Local File Inclusion)漏洞了。

在丹江口等地區(qū),都構(gòu)建了全面的區(qū)域性戰(zhàn)略布局,加強(qiáng)發(fā)展的系統(tǒng)性、市場(chǎng)前瞻性、產(chǎn)品創(chuàng)新能力,以專注、極致的服務(wù)理念,為客戶提供網(wǎng)站設(shè)計(jì)制作、網(wǎng)站制作 網(wǎng)站設(shè)計(jì)制作定制網(wǎng)站建設(shè),公司網(wǎng)站建設(shè),企業(yè)網(wǎng)站建設(shè),品牌網(wǎng)站制作,網(wǎng)絡(luò)營銷推廣,成都外貿(mào)網(wǎng)站建設(shè)公司,丹江口網(wǎng)站建設(shè)費(fèi)用合理。
常見漏洞代碼
if ($_GET['method']) {
include $_GET['method'];
} else {
include 'index.php';
}一般情況下,程序的執(zhí)行過程是當(dāng)用戶提交url為 https://xianzhi.aliyun.com/sth.php?method=search.php 時(shí),調(diào)用search.php里面的樣式內(nèi)容和功能。直接訪問 https://xianzhi.aliyun.com/search.php 則會(huì)包含默認(rèn)的index.php里面的樣式內(nèi)容和功能。那么問題來了,如果我們提交),且1.jpg是由黑客上傳到服務(wù)器上的一個(gè)圖片,并在圖片的末尾添加了惡意的php代碼,那么惡意的代碼就會(huì)被當(dāng)前文件執(zhí)行,以此觸發(fā)本地文件包含漏洞。
有趣的發(fā)現(xiàn)
我和我的好朋友Mike Brooks一直致力于對(duì)一些開源的Web框架進(jìn)行代碼審計(jì)工作,在對(duì)這些Web開源框架代碼審計(jì)的過程中,我們找到了一種將本地文件包含漏洞(LFI)轉(zhuǎn)換為遠(yuǎn)程文件包含漏洞(RFI)的方法。并且依賴于我們駐留在Web服務(wù)器上的JAR包文件,我們發(fā)現(xiàn)了一個(gè)能夠執(zhí)行任意代碼的方法。通常情況下,當(dāng)以特定方式配置Web應(yīng)用程序時(shí),它將能夠加載Web服務(wù)器上的JAR包文件并在文件中搜索實(shí)現(xiàn)的java類。有意思的是,在Java類中,我們可以在正在被執(zhí)行的java類上定義一個(gè)靜態(tài)代碼塊,具體如下所示:
public class LoadRunner {
static {
System.out.println("Load runner'ed");
}
public static void main(String[] args) {
}
}我們首先編譯這個(gè)java類,然后在代碼中加載它,具體實(shí)現(xiàn)如下圖所示:
現(xiàn)在,我們已經(jīng)有了兩個(gè)有趣的發(fā)現(xiàn):一個(gè)是可以在加載的JAR文件中插入執(zhí)行代碼,另一個(gè)是在Web服務(wù)器上找到一個(gè)合適的文件路徑來加載JAR包文件。因此,我們現(xiàn)在必須找到的一種方式來讓應(yīng)用程序以某種方式引用我們駐留在服務(wù)器上的JAR包文件。在這個(gè)探索的過程中,我們嘗試了很多的方法,包括去查看應(yīng)用程序中的所有請(qǐng)求處理程序以確定能否進(jìn)行文件上傳;甚至嘗試尋找可以在服務(wù)器上毒化文件的方法,以便將其轉(zhuǎn)化為JAR包文件,但是這些方法卻都沒有能夠奏效。盡管這樣,我們?nèi)匀粵]有放棄去研究和探索,最終Mike Brooks想出了一個(gè)好主意。
文件描述符
? 一般情況下,大多數(shù)Web開源框架都會(huì)將上傳的文件落地到服務(wù)器的某個(gè)磁盤上,但文件的路徑是不可猜測(cè)的(通常使用GUID或其他隨機(jī)標(biāo)識(shí)符來表示),如果我們不知道文件路徑,那又該如何去訪問上傳的文件呢?在Linux中,當(dāng)一個(gè)進(jìn)程有一個(gè)文件被打開時(shí),它將在其 /proc/ 目錄中打開一個(gè)指向該文件的文件描述符。因此,如果我們有一個(gè)PID為1234的進(jìn)程,并且該進(jìn)程打開了磁盤上的某個(gè)文件,那么我們可以通過**/proc/1234/fd/***文件描述符來訪問該文件。這意味著,我們不需要猜測(cè)GUID或其他隨機(jī)值,我們只需要猜測(cè)HTTP請(qǐng)求處理程序的PID和上傳文件的文件描述符即可。因而用于訪問上傳文件的搜索空間就會(huì)大幅減少。不僅如此,如果我們已經(jīng)有了LFI,加上磁盤上那些經(jīng)常出現(xiàn)的、可以預(yù)測(cè)的PID(Web服務(wù)器上HTTP請(qǐng)求處理程序的PID)文件,因此獲取PID和文件描述符編號(hào)要比想象中簡(jiǎn)單得多。
加載文件描述符
? 為了實(shí)現(xiàn)上面的方法,我們首先需要在程序中找到那些處理文件上傳的請(qǐng)求,之后嘗試通過Web開源框架中的LFI漏洞來查看所有PID文件描述符,并通過文件描述符來訪問我們?cè)赪eb服務(wù)器上上傳的文件。在我們測(cè)試過的Web框架中,當(dāng)訪問FILES字典時(shí),這些文件描述符總是被緩慢加載,而Flask Web框架直接在HTTP GET請(qǐng)求填充了FILES字典字段,以下是超簡(jiǎn)單的Flask應(yīng)用程序:
# -*- coding: utf-8 -*-
import os
from flask import Flask, request
UPLOAD_FOLDER = "/tmp"
app = Flask(__name__)
app.config["UPLOAD_FOLDER"] = UPLOAD_FOLDER
@app.route("/", methods=["GET"])
def show_me_the_money():
x = request
import code
code.interact(local=locals())
if __name__ == "__main__":
app.run()在這個(gè)應(yīng)用程序中,我們有一個(gè)單一的處理程序,該處理程序允許在URL上掛載HTTP GET請(qǐng)求。然后我們?cè)赨buntu VM中運(yùn)行這個(gè)程序,并通過HTTP GET請(qǐng)求將文件上傳到該服務(wù)器上。對(duì)于以前沒有使用過 import code 技巧的人來說,這是一個(gè)很好的方法來調(diào)試Python代碼和庫,因?yàn)樵?nbsp;code.interact 被調(diào)用時(shí)你將進(jìn)入到python的REPL環(huán)境中去。
以下是通過HTTP GET請(qǐng)求上傳文件的簡(jiǎn)單腳本:
# -*- coding: utf-8 -*-
import requests
response = requests.get(
"http://127.0.0.1:5000/",
files={
"upload_file": open("/tmp/hullo", "rb"),
},
)而在 /tmp/hullo 的文件中,我們可以看到很多的“Hello World”:
然后,我們首先運(yùn)行服務(wù)器,之后上傳文件,并進(jìn)入Flask請(qǐng)求處理程序上下文中的python REPL環(huán)境,具體如下圖所示:
通過使用請(qǐng)求處理程序的PID,我們可以查看到磁盤上打開的文件描述符:
然后我們返回到REPL并訪問上傳的文件:
現(xiàn)在該文件已經(jīng)在Web服務(wù)器中被訪問過了,此刻我們回到 /proc 目錄,看看是否可以找到上傳文件的內(nèi)容:
果然,我們找到了上傳的文件!因此,對(duì)于我們正在評(píng)估的Web應(yīng)用程序來說,我們確認(rèn)通過這種上傳和引用文件的方法可以正常訪問到我們駐留在Web服務(wù)器中的JAR包文件!
我們可以通過 多次上傳相同的文件 來進(jìn)一步減少文件路徑搜索空間,因此我修改了文件上傳的代碼使得可以上傳相同的九個(gè)文件:
# -*- coding: utf-8 -*-
import requests
response = requests.get(
"http://127.0.0.1:5000/",
files={
"upload_file": open("/tmp/hullo", "rb"),
"upload_file2": open("/tmp/hullo", "rb"),
"upload_file3": open("/tmp/hullo", "rb"),
"upload_file4": open("/tmp/hullo", "rb"),
"upload_file5": open("/tmp/hullo", "rb"),
"upload_file6": open("/tmp/hullo", "rb"),
"upload_file7": open("/tmp/hullo", "rb"),
"upload_file8": open("/tmp/hullo", "rb"),
},
)運(yùn)行此腳本后,訪問處理程序中的 FILES 字典,并查看請(qǐng)求處理程序PID目錄中的 fd 目錄內(nèi)容,我們看到所有上傳的文件都有打開的文件描述符:
因此,通過使用這種方法,我們可以保證具有特定號(hào)碼的文件描述符終將會(huì)指向我們上傳的文件。如果我們提交100個(gè)上傳文件的請(qǐng)求,可能文件描述符50指向的就是我們的文件!反過來,我們現(xiàn)在需要猜測(cè)的唯一值就是PID。
如何實(shí)施攻擊利用?
? 總而言之,為了引用上傳文件以達(dá)到攻擊的目的,這是一種大大減少搜索空間的方法,這在許多情況下可以使LFI成為RFI。如果你要使用此方法進(jìn)行攻擊利用,請(qǐng)考慮以下事項(xiàng):
-
通過我們對(duì)多個(gè)Web框架(Django和Flask)的分析發(fā)現(xiàn),當(dāng)訪問FILE字典時(shí)框架會(huì)延遲加載文件引用。因此,我們必須定位 訪問FILES字典的 請(qǐng)求處理程序 。一旦請(qǐng)求處理程序訪問了FILES字典,文件描述符將在請(qǐng)求處理期間一直保持打開狀態(tài)。
-
默認(rèn)情況下,其他框架可能會(huì)填充這些文件描述符,而這正是我們下一步將要研究的內(nèi)容。
-
當(dāng)處理請(qǐng)求體中上傳的文件時(shí),有些框架不區(qū)分不同的請(qǐng)求方式,這在一定程度上說明這種攻擊方法不僅限于非冪等的HTTP verbs。
-
PID并不意味著隨機(jī)化。無論我們的目標(biāo)是什么(Ubuntu上的Apache,F(xiàn)edora上的Nginx等),如果我們希望將其轉(zhuǎn)化為漏洞,那么我們可以創(chuàng)建一個(gè)本地設(shè)置,并查看與Web服務(wù)器和請(qǐng)求處理程序相關(guān)聯(lián)的PID。一般來說,當(dāng)我們將服務(wù)安裝到*nix時(shí),它們將在機(jī)器重新啟動(dòng)時(shí)以類似的順序啟動(dòng)。由于PID也按順序分配,這意味著我們可以大大減少PID搜索空間。
-
請(qǐng)求處理程序需要訪問 所有要處理的上傳文件 的FILES字典 。這就是說,如果處理程序中的功能期望上傳的文件是PDF,以執(zhí)行請(qǐng)求處理程序的中代碼,而此時(shí)我們也準(zhǔn)備上傳一個(gè)JAR包文件,那么只要同時(shí)上傳這兩個(gè)文件即可,它們都將被賦予文件描述符。
-
嘗試找到加載文件描述符的請(qǐng)求處理程序,為了我們的代碼審計(jì)工作能夠順利進(jìn)行,我們發(fā)現(xiàn)有一個(gè)處理程序會(huì)逐行處理一個(gè)文件的全部?jī)?nèi)容,所以我們上傳了一個(gè)巨大的文件,該巨大的文件中當(dāng)然也包含了我們想要執(zhí)行的JAR包文件。
- 請(qǐng)注意,如果您上傳的文件較小,則可能只讀入內(nèi)存,并且不會(huì)打開任何文件描述符。當(dāng)對(duì)Flask Web框架進(jìn)行測(cè)試時(shí),我們發(fā)現(xiàn)1MB以下的文件會(huì)被直接加載到內(nèi)存中,而1MB以上的文件則放在磁盤上。因此,我們需要在JAR包文件中額外填充任何可供攻擊利用的有效載荷。
后續(xù)更新
? 后續(xù)我們對(duì)多個(gè)框架緩慢加載文件描述符這一問題進(jìn)行了深入的研究和分析。最后我們發(fā)現(xiàn)對(duì)于Flask和Django來說,并不是FILES 被緩慢加載,而是請(qǐng)求體的內(nèi)容只有在被訪問時(shí)才會(huì)被處理。因此,根據(jù)這個(gè)結(jié)論我們可以輕松定位那些訪問HTTP請(qǐng)求體數(shù)據(jù)的任何請(qǐng)求處理程序。一旦請(qǐng)求處理程序訪問了包含在請(qǐng)求體中的數(shù)據(jù),文件描述符就會(huì)被填充。
Django框架中訪問請(qǐng)求體數(shù)據(jù)代碼如下所示:
通過此訪問請(qǐng)求填充的文件描述符如下所示:
Flask Web框架中訪問請(qǐng)求體數(shù)據(jù)的代碼如下所示:
通過此訪問請(qǐng)求填充的文件描述符如下所示:
當(dāng)前標(biāo)題:應(yīng)對(duì)安全漏洞:如何將LFI變?yōu)镽FI
網(wǎng)頁鏈接:http://www.dlmjj.cn/article/cdjsigc.html


咨詢
建站咨詢
