命令注入新玩法:巧借環境攻擊目標

*本文作者:yangyangwithgnu,本文屬 FreeBuf 原創獎勵計劃,未經許可禁止轉載。

在一次漏洞賞金活動中,挖掘到一個不標準的命令注入漏洞,我無法用命令分 隔符、命令替換符注入新命令讓系統執行,所以,從”型態”上講,它不算是命令注入漏洞;但我又可以藉助目標環境讓載荷到達系統命令行,實現讀寫文件、執行 新命令,所以,”神態”來看,它又像是命令注入。這類藉助環境間接注入命令的利用手法,很少在常規討論命令注入的文章中看到,有必要落筆成文,與你分享。

0×00 酷趣 wargame

由於受賞金廠商保密協議所限,我無法公開原始漏洞詳情,但我更清楚 “talk is cheap, show me the code”,耗時費神,找到一個 wargame,相較賞金漏洞,不但體現了相同精髓,這個 wargame 還多了些限制條件,所以,讓它變得更加有趣、更有挑戰。

我把 wargame 源碼寫入 CMDi_lab/escaping_quotation/index.php,核心如下:

快速過下源碼。首先,用 GET 方法獲取 f1、f2 兩個參數;然後,用相同的正則過濾 f1、f2,包括過濾引號防止利用環境寫 webshell,過濾常見命令分隔符(;)、命令替換符($())防止注入新命令,過濾常見命令(ls、cat)禁止基礎操作;接着,用引號再建一道防 御工事,讓所有輸入均在引號內,讓命令行元字符失效;最後,以 f1、f2 爲命令參數執行系統命令 file。

怎麼樣!看上去是很完善的防禦體系。先正常訪問試試:

服務端執行 file 命令,正確識別出目錄和文件的類型。嘗試提交命令分隔符(;)和命令替換符(“):

由於服務端正則表達式匹配上 ; 和 “,導致提交的文件名被置爲空,所以,file 提示無法找到相關文件。

經驗主義,我將從三個層面尋找突破口:攻擊正則、攻擊引號、攻擊命令行。那麼,我就準備開動了,各位。

0×01 成敗正則

在命令注入場景下審查正則表達式,我習慣關注四個方面:是否使用多行模式修飾符(/foo/m)、是否遺漏匹配對象末尾的換行符(/^\d+$/)、是否允許空白字符(\s)、是否誤寫反斜槓匹配模式(/\\/)。

使用多行模式修飾符。把多行模式用於匹配希望允許的字符時,就會存在邏輯問題。比如,如下代碼:

原本希望只允許 xx.xx.xx.xx 格式的 IP 地址,由於使用多行模式,只要輸入中某行滿足條件即可,那麼,我可以用換行符輸入多行,第一行滿足要求 127.0.0.1、第二行任意內容,這樣輕鬆繞過正則限制:

本 wargame 未使用多行模式,所以不存在這個問題。

遺漏匹配對象末尾的換行符。某些模式在匹配時會忽略字符串末的換行符,而換行符自身又是一個有效的目錄分隔符,將導致注入新命令。如下代碼:

原意是過濾掉輸入中非字母、數字外的其他所有字符,輸入換行符試試:

果然被過濾了。但,若把換行符放至字符串末尾,正則反而無法匹配上:

這可有趣了,又能愉快地注入新命令了:

本 wargame 未能成功過濾掉換行符,但不是因爲上面的原因。

允許空白字符。空白字符包括空格、換行符、水平製表符、垂直製表符等四個,命令注入的好朋友換行符也在其中。代碼:

本意只允許字母、數字、空格等字符,但遺漏了換行符,導致命令注入漏洞:

本 wargame 未能成功過濾掉換行符,但不是因爲上面的原因。

誤寫反斜槓匹配模式。正則表達式自身是個字符串,並非直接傳遞給正則引擎,而是先由語言對字符串進行處理後再傳遞給正則引擎。我希望匹配上反斜槓 (\),逆向思考下這個過程,由於反斜槓在正則引擎是個特殊字符,所以 \\ 才能讓正則引擎正確識別到反斜槓 \;正則引擎之前,\\ 經過語言的的字符串處理,由於反斜槓在字符串中也是特殊字符,所以,一個 \ 就得用 \\ 表示、兩個 \ 就得用 \\\\ 表示。那麼,但凡用正則表達式匹配斜槓,必須得用 \\\\。這是不具備原生字符串特性(r)的腳本語言的通病,是有一點繞。比如:

 

 

訪問看看:

 

 

 

 

記得 wargame 也過濾了反斜槓,回過頭看看,哇喔,的確誤用了:

 

 

 

 

OK,在正則部分,由於誤寫匹配模式,我找到了漏網之魚,反斜槓。如何利用?不知道,走一步看一步。

 

 

0×02 引號逃逸

 

 

接着我來琢磨下 25、26 行。這兩行目的很清晰,用引號包裹輸入字符串,預防可能因正則過濾不嚴傳遞一些個特殊字符到命令行環境,思路是對的,但效果就差強人意了。

 

 

載荷一旦進入引號內,都將退化成普通字符串,好無殺傷力,唯一例外,命令替換符(“ 或 $()),遺憾的是,命令替換符被正則嚴防死守,無法到達 25、26 行。所以,下意識地想到,引號逃逸。

 

 

引號逃逸,目的是讓輸入跳脫至引號外,恢復特殊字符的身份,而不再被引號所束縛,僅僅是個普通字符。我常用兩種手法,一是閉合、二是轉義。

 

 

閉合手法逃逸引號。在輸入中添加一個引號,讓其與左引號結對,自然閉合,接着輸入中就能出現惡意字符,最後輸入中再添加一個引號,與右引號結對,或者,輸入註釋符以忽略右引號。比如:

 

 

 

 

我的所有輸入都只能留在引號內,導致命令分隔符無法被命令行正確識別:

 

 

 

 

我在輸入中增加兩個引號(②、③),這樣剛好與代碼中的引號閉合(① 和 ②、③ 和 ④),所以,我的其他輸入字符(;id;)就能出現在引號之外,成功逃逸引號:

 

 

 

 

轉義手法逃逸引號。引號自身也是個特殊字符,如果有辦法讓它變成普通字符,那麼輸入的其他特殊字符就能讓命令行正確識別。反斜槓可以辦到!如下代碼:

 

 

 

 

含有惡意字符的輸入被限定在引號內:

 

 

 

 

假設服務端生成的命令模型爲 file “foo” “;date”,這時,我利用反斜槓將 ② 號引號轉義爲普通字符,那麼 ① 和 ③ 號引號將自然結合,接着利用註釋符將 ④ 號引號註釋掉,;date 對於命令行直接可見,邏輯上我能用 file “foo\” “;id #bar” 注入任意命令,再次逃逸到引號外:

 

 

 

 

注,註釋符 # 需要 URL 編碼爲 %23。

 

 

好了,還記得前面我找到正則漏洞無法過濾反斜槓麼,wargame 中的引號已經無法束縛我,雖然當下無法直接利用,但至少又讓我向前邁出一步。

 

 

0×03 選項注入

 

 

繼續看 29、30 兩行的命令執行代碼。顯然這與命令注入漏洞多少有些關係。命令注入常見三種手法:利用命令分隔符注入命令、利用命令替換符注入命令、利用命令選項注入命令。

 

 

命令分隔符注入命令。命令分隔符包括換行符(\n)、分號(;)、邏輯與(&&、&)、邏輯或(||、|),若在 win 批處理腳本中還能用 %1A。比如:

 

 

 

 

命令替換符注入命令。shell 優先執行命令替換符內的命令,目的是便於運維人員將前個命令的輸出作爲後個命令的輸入。命令替換符包括 $(…)、反引號 `…`。比如:

 

 

 

 

命令選項注入命令。命令選項(option)和命令參數(argument)是兩個概念,國內外很多文獻都將他倆混淆。比如:

 

 

 

 

其中,-d 是命令選項、/tmp/ 是命令參數。很多時候,藍隊過濾掉所有命令分隔符、命令替換符,雖然我無法直接注入命令,但我可以注入其他命令選項,這就給我很大想像空間,某些選項可以 讀取文件、有些又能寫入文件、甚至執行其他命令。比如,有個頁面,可以將 web 目錄打包爲你指定的歸檔文件,輸入爲歸檔文件名 $archive 參數,服務端過濾所有命令注入相關字符,調用 system(“tar -cf” . $archive . “*”) 執行命令:

 

 

 

 

但我通過注入 tar 命令的 –checkpoint、–checkpoint-action=exec 兩個選項,成功執行命令 id:

 

 

1.png

 

 

wargame 中執行的是 file 命令,查看下它有哪些用得上的選項,比如,是否有選項可以讀文件,man 中搜索 read,找到 -f 選項:

 

 

 

 

仔細看下,該參數並不能讀取顯示文件內容,只是從該文件中獲取文件列表,沒意思(。・_・。)。等等,報錯信息中有啥提示:

 

 

 

 

哇噢,歷害啦,通過注入命令選項 -f,讓我可以讀取 wargame 的文件內容。

 

 

0×04 全面瓦解

 

 

管它金城湯池還是銅牆鐵壁,一顆鬆滑螺釘,它將全面瓦解。

 

 

將多個獨立漏洞組合成漏洞鏈,完成目標攻擊,絕對是我的 G 點。回顧前面的成果,由於誤寫正則表達式,導致無法過濾反斜槓;通過反斜槓,可以逃逸引號;通過引號逃逸,創造出命令選項注入的條件;通過注入 -f 選項,實現 flag 文件讀取。過濾反斜槓的正則,就是那顆鬆滑的螺釘。

 

 

現在,攻擊目標前,還剩一個問題,我並不清楚 flag 文件路徑及文件名。首先想到的是暴破。土!的確很土氣,用常見的 flag、FLAG、f14g 等等常見 flag 名暴了一遍,毫無收穫。換個手法,通配符模式匹配。這下洋氣了吧。

 

 

通配符模式匹配(globbing patterns),也叫路徑名擴展(pathname expansion),簡單來說,在表示文件名/目錄名或路徑時,你可以用 ? 代表任一可見字符、用 * 代表零或多個可見字符、用 [a-z] 代表字符範圍,唯一例外,以 . 開頭的文件或目錄、以 / 分隔的路徑必須顯式寫明,否則無法被模式匹配。

 

 

比如,我並不還知道 /tmp/ 目錄下有個名爲 FindMe 的文件,但,藉助通配符多次測試,不但刺探出該文件的存在,還成功查看到文件內容:

 

 

 

 

好,現在一切就緒,攻擊 CMDi_lab/escaping_quotation。有了前面的分析,我構造了載荷 f1=foo\&f2=-f ? bar #,將 file “foo” “bar” 轉換爲 file “foo\” “-f ? bar #”,猜解文件名只有一個字符的文件:

 

 

 

 

顯然,沒找到這樣的文件,相同思路,藉助 burp 自動查找文件名長度在 [1, 16] 的所有文件:

 

 

 

 

跑完還是沒有找到任何文件。這就奇怪了,前面說過,通配符無法匹配 .,莫非是隱藏文件,調整下載荷, f1=foo\&f2=-f .? bar #,再次暴破:

 

 

 

 

找到名爲 .f1a9_ 的目錄,繼續調整載荷 f1=foo\&f2=-f .f1a9_/.? bar #,暴破:

 

 

 

 

找到名爲 .f1a9_/.flag_15_here.txt 的文件,帶上準確路徑訪問:

 

 

 

 

WTF!不應該啊,邏輯上說不通。別急,捋一捋,莫非載荷中新增部分有被過濾的字符?回到前面的正則源碼處,的確過濾了 flag 關鍵字,我用通配符替換,載荷變成 f1=foo\&f2=-f .f1a9_/.fl?g_15_here.txt bar #,另外,命令選項 -f 前應該得加個空格,最終載荷爲 f1=foo\&f2= -f .f1a9_/.fl?g_15_here.txt bar #,來一發:

 

 

 

 

多麼愉悅的攻擊體驗!

 

 

0×05 非預期解法

 

 

絲滑般的思緒,真實而自然!思緒自然?!正則未正確過濾反斜槓、利用反斜槓逃逸引號、通配符模式猜解路徑、注入命令選項讀取文件,做作、彆扭!以上是我爲了湊字數、增篇幅寫的,真實的攻擊手法並非如此。

 

 

仔細審計正則過濾的代碼。用 \\ 而非 \\\\ 表述反斜槓,不僅無法正確過濾反斜槓,還會引發連鎖反應。你看,緊隨 \\ 其後的是 |\n:

 

 

 

 

前面提過,\\ 結果字符串轉義後到達正則引擎變成 \,它與 |\n 結合變成 \|\n,正則引擎誤解成匹配豎線與換行符的組合。當我輸入豎線與換行符的組合,確認被過濾:

 

 

 

 

換言之,服務端只過濾 |\n 而放行 \n。有換行符,我可以直接注入新命令,比如,執行命令 id:

 

 

 

 

既然能注入命令了,查看 flag 易如反掌!命令 grep -r . . 可以查看當前目錄下所有文件內容,服務端過濾了 grep,我用內部空變量輕鬆繞過(g$1rep -r . .),或者,無效轉義繞過(g\rep -r . .),或者,通配符繞過(/bin/gr?p -r . . 或 /bin/gr[d-f]p -r . .),我有 1024 種方式吊打目標。

 

 

OK,清晰,爭取一次搞定,構造載荷 ?f1=foo\&f2=%0a/bin/gr[d-f]p+-r+.+.+%23,頁面顯示:

 

 

 

 

0×06 故事尾聲

 

 

最後聊聊你關心的賞金漏洞。大致業務場景,服務端執行打包命令壓縮幾個固定目錄,允許用戶輸入歸檔文件名,多次刺探確認使用的 zip 命令,類似:

 

 

 

 

其中,歸檔文件名 archive.tar 可控。服務端正則過濾所有命令分隔符、命令替換符、其他元字符,同時,禁止出口流量,顯然無法直接注入命令。

 

 

一番嘗試,發現允許橫線(-),這就告訴我可以注入命令選項。我開始分析環境 zip 自身有哪些選項可以爲我所用。先查找關鍵字 execute,一無所獲;接着搜索關鍵字 command,找選項 –unzip-command(簡寫 -TT) 和 –test(簡寫 -T),允許用戶指定第三方程序來校驗歸檔文件的完整性:

 

 

 

 

換言之,選項 -T 和 –unzip-command 可以注入新命令 id:

 

 

 

 

成功拿到賞金。

 

 

命令注入攻擊,除了常規的命令分隔符、命令替換符之外,利用環境自身也能實現。

 

 

注一,wargame 的原型來自 Kaibro 所寫的 wargame,見 http://final.kaibro.tw:10002/

注二,escaping_quotation 源碼,以及更多命令注入相關 wargame 見 https://github.com/yangyangwithgnu/CMDi_lab

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章