如何使用Packj檢測惡意或高風險的開源軟體包

語言: CN / TW / HK

關於Packj

Packj是一款功能強大的程式碼安全檢測工具,該工具本質上是一個命令列介面工具套件,可以幫助廣大研究人員檢測軟體程式碼包中潛在的惡意或高風險程式碼,旨在緩解軟體供應鏈攻擊。該工具支援識別當前熱門開源軟體管理工具中提供的軟體程式碼包,比如說NPM、RubyGems和PyPI等。在該工具的幫助下,我們可以持續審查軟體包並獲取免費的風險評估報告。

工具下載

由於該工具基於Python 3開發,因此我們首先需要在本地裝置上安裝並配置好Python 3環境。接下來,使用下列命令將該專案原始碼克隆至本地:

git clone https://github.com/anil-yelken/Vulnerable-Soap-Service.git

Packj提供了下列工具:

Audit:用於檢測軟體程式碼包中的高位風險屬性;

Sandbox:用於安全安裝軟體包的環境;

$ python3 main.py --help

usage: main [options] args

 

options:

    audit          Audit a package for malware/risky attributes

    sandbox        Sandbox package installation to mitigate risks

工具使用

審計一個程式碼包

Packj可以審計開源軟體包的“高風險”屬性,即可能會讓其容易受到供應鏈攻擊的各種因素。比如說,包含過期電子郵件的包(缺少2FA)、釋出時間間隔太長、敏感API或訪問許可權問題等。

工具支援審計下列內容:

多個軟體包:

python3 main.py -p pypi:requests rubygems:overcommit

依賴檔案:

python3 main.py -f npm:package.json pypi:requirements.txt

我們還可以在一個Docker/Podman容器中執行審計操作:

$ docker run -v /tmp:/tmp/packj -it ossillate/packj:latest audit --trace -p npm:browserify

 

[+] Fetching 'browserify' from npm...OK [ver 17.0.0]

[+] Checking version...ALERT [598 days old]

[+] Checking release history...OK [484 version(s)]

[+] Checking release time gap...OK [68 days since last release]

[+] Checking author...OK [[email protected]]

[+] Checking email/domain validity...ALERT [expired author email domain]

[+] Checking readme...OK [26838 bytes]

[+] Checking homepage...OK [https://github.com/browserify/browserify#readme]

[+] Checking downloads...OK [2.2M weekly]

[+] Checking repo_url URL...OK [https://github.com/browserify/browserify]

[+] Checking repo data...OK [stars: 14077, forks: 1236]

[+] Checking repo activity...OK [commits: 2290, contributors: 207, tags: 413]

[+] Checking for CVEs...OK [none found]

[+] Checking dependencies...ALERT [48 found]

[+] Downloading package 'browserify' (ver 17.0.0) from npm...OK [163.83 KB]

[+] Analyzing code...ALERT [needs 3 perms: process,file,codegen]

[+] Checking files/funcs...OK [429 files (383 .js), 744 funcs, LoC: 9.7K]

[+] Installing package and tracing code...OK [found ['process', 'files', 'network'] syscalls]

=============================================

[+] 5 risk(s) found, package is undesirable!

 

=> Complete report: /tmp/packj_54rbjhgm/report_npm-browserify-17.0.0_hlr1rhcz.json

{

    "undesirable": [

        "old package: 598 days old",

        "invalid or no author email: expired author email domain",

        "generates new code at runtime",

        "reads files and dirs",

        "forks or exits OS processes",

    ]

}

軟體包沙箱安裝

Packj提供了一個輕量級沙箱環境,可以用於安全地安裝和測試軟體包。具體而言,它可以防止惡意軟體包提取敏感資料、訪問敏感檔案(如SSH金鑰)以及植入持久化惡意軟體等。操作命令如下:

$ python3 main.py sandbox gem install overcommit

 

Fetching: overcommit-0.59.1.gem (100%)

Install hooks by running `overcommit --install` in your Git repository

Successfully installed overcommit-0.59.1

Parsing documentation for overcommit-0.59.1

Installing ri documentation for overcommit-0.59.1

 

#############################

# Review summarized activity

#############################

 

[+] Network connections

[+] DNS (1 IPv4 addresses) at port 53 [rule: ALLOW]

[+] rubygems.org (4 IPv6 addresses) at port 443 [rule: IPv6 rules not supported]

[+] rubygems.org (4 IPv4 addresses) at port 443 [rule: ALLOW]

[+] Filesystem changes

/

└── home

    └── ubuntu

        └── .ruby

            ├── gems

            │   ├── iniparse-1.5.0 [new: DIR, 15 files, 46.6K bytes]

            │   ├── rexml-3.2.5 [new: DIR, 77 files, 455.6K bytes]

            │   ├── overcommit-0.59.1 [new: DIR, 252 files, 432.7K bytes]

            │   └── childprocess-4.1.0 [new: DIR, 57 files, 141.2K bytes]

            ├── cache

            │   ├── iniparse-1.5.0.gem [new: FILE, 16.4K bytes]

            │   ├── rexml-3.2.5.gem [new: FILE, 93.2K bytes]

            │   ├── childprocess-4.1.0.gem [new: FILE, 34.3K bytes]

            │   └── overcommit-0.59.1.gem [new: FILE, 84K bytes]

            ├── specifications

            │   ├── rexml-3.2.5.gemspec [new: FILE, 2.7K bytes]

            │   ├── overcommit-0.59.1.gemspec [new: FILE, 1.7K bytes]

            │   ├── childprocess-4.1.0.gemspec [new: FILE, 1.8K bytes]

            │   └── iniparse-1.5.0.gemspec [new: FILE, 1.3K bytes]

            ├── bin

            │   └── overcommit [new: FILE, 622 bytes]

            └── doc

                ├── iniparse-1.5.0

                │   └── ri [new: DIR, 119 files, 131.7K bytes]

                ├── rexml-3.2.5

                │   └── ri [new: DIR, 836 files, 841K bytes]

                ├── overcommit-0.59.1

                │   └── ri [new: DIR, 1046 files, 1.5M bytes]

                └── childprocess-4.1.0

                    └── ri [new: DIR, 272 files, 297.8K bytes]

 

[C]ommit all changes, [Q|q]uit & discard changes, [L|l]ist details:

惡意軟體檢測

在測試該工具的時候,我們成功地在PyPI上搜索出了40個惡意軟家包,其中有部分已經被下架了:

$ python3 main.py audit pypi:krisqian

[+] Fetching 'krisqian' from pypi...OK [ver 0.0.7]

[+] Checking version...OK [256 days old]

[+] Checking release history...OK [7 version(s)]

[+] Checking release time gap...OK [1 days since last release]

[+] Checking author...OK [[email protected]]

[+] Checking email/domain validity...OK [[email protected]]

[+] Checking readme...ALERT [no readme]

[+] Checking homepage...OK [https://www.bilibili.com/bangumi/media/md140632]

[+] Checking downloads...OK [13 weekly]

[+] Checking repo_url URL...OK [None]

[+] Checking for CVEs...OK [none found]

[+] Checking dependencies...OK [none found]

[+] Downloading package 'KrisQian' (ver 0.0.7) from pypi...OK [1.94 KB]

[+] Analyzing code...ALERT [needs 3 perms: process,network,file]

[+] Checking files/funcs...OK [9 files (2 .py), 6 funcs, LoC: 184]

=============================================

[+] 6 risk(s) found, package is undesirable!

{

    "undesirable": [

        "no readme",

        "only 45 weekly downloads",

        "no source repo found",

        "generates new code at runtime",

        "fetches data over the network: ['KrisQian-0.0.7/setup.py:40', 'KrisQian-0.0.7/setup.py:50']",

        "reads files and dirs: ['KrisQian-0.0.7/setup.py:59', 'KrisQian-0.0.7/setup.py:70']"

    ]

}

=> Complete report: pypi-KrisQian-0.0.7.json

=> View pre-vetted package report at https://packj.dev/package/PyPi/KrisQian/0.0.7

其中,Packj將KrisQian(v0.0.7)標記為可疑,因為在包安裝期間(在setup.py中)缺少原始碼庫和使用敏感API(用於網路通訊、程式碼生成)。經過進一步研究和分析,我們驗證了這個程式碼包確實是存在安全問題的。

許可證協議

本專案的開發與釋出遵循AGPL-3.0開源許可證協議。

專案地址

Packj:【GitHub傳送門】

參考資料

https://packj.dev/

https://www.you*tube.com/watch?v=Rcuqn56uCDk

https://speakerdeck.com/ashishbijlani/pyconus22-slides

https://www.blackhat.com/asia-22/arsenal/schedule/#mitigating-open-source-software-supply-chain-attacks-26241

https://www.blackhat.com/us-22/arsenal/schedule/#detecting-typo-squatting-backdoored-abandoned-and-other-risky-open-source-packages-using-packj-28075

https://osseu2022.sched.com/overview/type/SupplyChainSecurityCon

https://nullcon.net/goa-2022/unearthing-malicious-and-other-risky-open-source-packages-using-packj

https://www.you*tube.com/watch?v=PHfN-NrUCoo?

https://speakerdeck.com/ashishbijlani/mitigating-open-source-software-supply-chain-attacks