CrowdStrike Blog:ウクライナを標的にしたと報じられた PartyTicketランサムウェア、復号可能と判明 | ScanNetSecurity
2024.04.18(木)

CrowdStrike Blog:ウクライナを標的にしたと報じられた PartyTicketランサムウェア、復号可能と判明

本日、ウクライナの標的に対してデプロイされたランサムウェア「PartyTicket」に関する詳細情報をブログで紹介します。

脆弱性と脅威 脅威動向
CrowdStrike Blog:ウクライナを標的にしたと報じられた PartyTicketランサムウェア、復号可能と判明
CrowdStrike Blog:ウクライナを標的にしたと報じられた PartyTicketランサムウェア、復号可能と判明 全 2 枚 拡大写真

 2022 年 2 月 23 日、ウクライナの組織を標的とした破壊的な攻撃が行われました。業界のレポートによると、被害に遭ったいくつかの企業や組織において、PartyTicket(または HermeticRansom)という Go言語で書かれたランサムウェアが検知されました(注1)。他に、CrowdStrike のインテリジェンスチームが DriveSlayer(HermeticWiper)として追跡する同系の高度なワイパー型攻撃も確認されています。

 PartyTicketランサムウェアを分析したところ、ファイルの暗号化は表面的なもののようです。暗号化キーの初期化を正しく行っていないため、拡張子が .encryptedJB の暗号化ファイルであれば復元できることがわかりました。

●技術分析

 PartyTicketランサムウェアの検体には、4dc13bb83a16d4ff9865a51b3e4d24112327c526c1392e14d56f20d6f4eaf382 という SHA256ハッシュがあります。cdir.exe、cname.exe、connh.exe、intpub.exe というファイル名と関連があることが確認されています。

 Go言語の 1.10.1バージョンで書かれたランサムウェアの検体には、voteFor403、C:/projects/403forBiden/wHiteHousE、primaryElectionProcess といった米国の政治システムを示す記号が多数含まれています。

 このランサムウェアはすべてのドライブレターで実行を繰り返し、各ドライブ内とサブフォルダー内のファイルを再帰的に列挙します。ただし、Windows および Program Files の文字列を含むファイルパスや、C:\Documents and Settings(Windows XP より新しい Windowsバージョンでは、C:\Users)のフォルダパスは除きます。以下の拡張子の付いたファイルを暗号化の対象として選びます。

acl、avi、bat、bmp、cab、cfg、chm、cmd、com、contact、crt、css、dat、dip、dll、doc、docx、dot、encryptedjb、epub、exe、gif、htm、html、ico、in、iso、jpeg、jpg、mp3、msi、odt、one、ova、pdf、pgsql、png、ppt、pptx、pub、rar、rtf、sfx、sql、txt、url、vdi、vsd、wma、wmv、wtv、xls、xlsx、xml、xps、zip

 前述のパスに該当しない、これらの拡張子の各ファイルパスについて、ランサムウェアが自身のインスタンスを実行元と同じディレクトリにコピーしてコマンドラインで実行し、ファイルパスを引数として渡します。親のランサムウェアプロセスは、クローンにランダムな UUID で名前を付けます。これはパブリックライブラリ(注2)が生成したもので、現在のタイムスタンプおよび感染したホストのネットワークアダプターの MACアドレスが使用されます。

 マルウェアの開発者は Go の WaitGroup処理で並列処理機能を実装しようとしたようですが、おそらくコーディングエラーのため、ランサムウェアは大量のスレッド(列挙したファイルパスごとに 1 つ)を作成し、選択したファイルの数と同じ回数分、自身のバイナリをカレントディレクトリにコピーします。すべての暗号化スレッドの終了後、コマンドラインから元のバイナリが消去されます。

 検体がファイルパスを引数として受け取ると、Galois/Counter Mode(GCM)の AES を使用してファイルを暗号化します。AESキーは Go の randパッケージの Intn関数で生成されます。文字列 1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ 内のオフセットを選択することで 32バイトのキーを生成します。もう 1 つ別のコーディングエラーと思われますが、キーの生成後に Intn関数のシードが更新されています。つまり、バイナリとクローンが実行されるたび、同じ AESキーが生成されています。ホスト上で暗号化されたすべてのファイルには同じ暗号化キーが使用されており、対応する PartyTicket の検体のキーで復号化が可能です。このエラーを活用して暗号化ファイルを復元するためのスクリプトを GitHub の CrowdStrike のレポジトリに掲載しています。

 AES暗号化キーはファイルごとに RSA-OAEP で暗号化されており、以下のパラメータのパブリックRSAキーを使用しています。

Modulus (N): 0xcbb94cb189a638b51e7cfe161cd92edb7145ecbd93989e78c94f8c15c61829286fd834d80c931daed4ac4aba14835fd3a6721602bcaa7193245fc6cf8e1d3261460ff3f1cbae3d44690beb989adee69ac486a932ee44dbdf0a44e772ab9822a16753cd08bdbb169f866f722114ee69c0cf1588fdaf8f7efd1c3ed243786078593f9b0cd867bab2b170c1843660d16e2181ae679137e2650551a41631398e027206e22a55858c741079ceafd50d5bd69546d4d52f5a33b0a576e1750d3f83afa1ce4403d768cbd670b443f61794b44705a8b1132c0c0ce77dbd04053ba20aec9baf23944270f10d16ad0727ed490c91c7f469278827c20a3e560f7c84015f7e1b
Exponent (E): 0x10001

 暗号化の前に、ランサムウェアは
<original file name>.[vote2024forjb@protonmail[.]com].encryptedJB というフォーマットでファイル名を変更しています(バイナリに含まれているその他の政治的な内容からすると、「JB」はおそらく米国大統領、Joseph Biden のイニシャルでしょう)。その後、ランサムウェアはコンテンツを暗号化されたデータで上書きします。PartyTicket はファイルの最初の 9437184バイト(9.44 MB)だけを暗号化するでしょう。引数として渡されたファイルがこの容量を超えている場合は、超過分は暗号化されません。ファイルのコンテンツを暗号化した後、PartyTicket は RSA で暗号化された AESキーをファイルの最後に追加します。

 このランサムウェアはファイルの暗号化が開始する前に、read_me.html という名前の HTML の脅迫メモをユーザーのデスクトップディレクトリに残します(図1)。メモの文章は、文法ミスが意図的なものでない限り、英語が堪能な人物によって書かれたものでも、チェックされたものでもないようです。

図1:脅迫メモ

●評価

 CrowdStrike のインテリジェンスチームは、現時点では PartyTicket攻撃が名の知れた攻撃者によって行われたとは考えていません。

 このランサムウェアには実装エラーが含まれており、暗号化が遅く、復号化することができます。このエラーから、マルウェアの作成者は Go で書くのに慣れていない、または、おそらく開発時間が限られていたためにマルウェアを十分にテストしていないということが示唆されます。特に PartyTicket は、低レベルの NTFS の構文解析アルゴリズムを使用した DriveSlayer のレベルにさえ達していません。相対的に完成度が低く、政治的なメッセージを含むこと、デプロイのタイミング、ウクライナの組織を標的としたものであることから、通常のランサムウェアのような身代金要求としてではなく、DriveSlayer攻撃に便乗して使用されたと思われます。

●YARAシグネチャ

 以下の YARAルールを使用して PartyTicket を検知することができます。

rule CrowdStrike_PartyTicket_01 : ransomware golang
{
meta:
copyright = "(c) 2022 CrowdStrike Inc."
description = "Detects Golang-based crypter"
version = "202202250130"
last_modified = "2022-02-25"
strings:
$ = ".encryptedJB" ascii
$start = { ff 20 47 6f 20 62 75 69 6c 64 20 49 44 3a 20 22 }
$end = { 0a 20 ff }
condition:
uint16(0) == 0x5A4D and uint32(uint32(0x3C)) == 0x00004550 and
for 1 of ($end) : ( @start < @ and @start + 1024 > @) and
all of them
}

rule CrowdStrike_PartyTicket_02 : PartyTicket golang
{
meta:
copyright = "(c) 2022 CrowdStrike Inc."
description = "Detects Golang-based PartyTicket ransomware"
version = "202202250130"
last_modified = "2022-02-25"
strings:
$s1 = "voteFor403"
$s2 = "highWay60"
$s3 = "randomiseDuration"
$s4 = "subscribeNewPartyMember"
$s5 = "primaryElectionProces"
$s6 = "baggageGatherings"
$s7 = "getBoo"
$s8 = "selfElect"
$s9 = "wHiteHousE"
$s10 = "encryptedJB"
$goid = { ff 20 47 6f 20 62 75 69 6c 64 20 49 44 3a 20 22 71 62 30 48 37 41 64 57 41 59 44 7a 66 4d 41 31 4a 38 30 42 2f 6e 4a 39 46 46 38 66 75 70 4a 6c 34 71 6e 45 34 57 76 41 35 2f 50 57 6b 77 45 4a 66 4b 55 72 52 62 59 4e 35 39 5f 4a 62 61 2f 32 6f 30 56 49 79 76 71 49 4e 46 62 4c 73 44 73 46 79 4c 32 22 0a 20 ff }
$pdb = "C://projects//403forBiden//wHiteHousE"
condition:
(uint32(0) == 0x464c457f or (uint16(0) == 0x5a4d and uint16(uint32(0x3c)) == 0x4550)) and 4 of ($s*) or $pdb or $goid

●PartyTicket で暗号化されたファイルを復号化するためのスクリプト

 AESキー生成における前述の実装エラーにより、PartyTicket による暗号化に使用された AESキーを復元することができます。以下の Go のスクリプトによって、PartyTicket の検体
4dc13bb83a16d4ff9865a51b3e4d24112327c526c1392e14d56f20d6f4eaf382 を使って暗号化されたファイルを復号化できます。このスクリプトは“-p”フラグによって複合化するファイルを引数として受け取り、復号化した出力を同じディレクトリ内の“decrypted.bin”に保存します。このスクリプトはコンパイルして実行することも、Go の実行パッケージで実行することもできます。Go の go1.16.6 のバージョンを使用してテストされました。

package main

import (
"crypto/aes"
"crypto/cipher"
"encoding/hex"
"fmt"
"os"
"flag"
)

func main() {

encrypted_filepath := flag.String("p", "encrypted.bin", "Path to encrypted file")
flag.Parse()

fmt.Printf("Decrypting file : %s\n", *encrypted_filepath)
key_bytes := []byte("6FBBD7P95OE8UT5QRTTEBIWAR88S74DO")
key := hex.EncodeToString(key_bytes)
fmt.Printf("Decryption key : %s\n", key_bytes)

dat, err := os.ReadFile(*encrypted_filepath)
if err != nil {
fmt.Println("Unable to open file, please supply path of encrypted file with flag -p, default file path is ./encrypted.bin")
os.Exit(3)
}

decrypted_filepath := "decrypted.bin"
filecontents := dat
encrypted_contents := filecontents[:len(filecontents) - 288]
enc_size := len(encrypted_contents)
bsize := 1048604
cycles := enc_size / bsize

if cycles == 0{

encrypted := hex.EncodeToString(encrypted_contents)
decrypted := decrypt(encrypted, key)
write_output(decrypted_filepath, decrypted)
} else {
for i:=0; i<cycles; i++ { if i >= 9 {
start := 9 * bsize
end := enc_size
data := string(encrypted_contents[start:end])
write_output(decrypted_filepath, data)
break
}
block_start := i * bsize
block_end := (i+1) * bsize
if block_end > enc_size{
block_end := enc_size
encrypted:=hex.EncodeToString(encrypted_contents[block_start:block_end])
decrypted := decrypt(encrypted, key)
write_output(decrypted_filepath, decrypted)

}

encrypted:=hex.EncodeToString(encrypted_contents[block_start:block_end])
decrypted := decrypt(encrypted, key)
write_output(decrypted_filepath, decrypted)
}
}

fmt.Printf("Decrypted file written to : %s\n", decrypted_filepath)

}

func write_output(filepath string, data string) {
f, err := os.OpenFile(filepath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
panic(err)
}
byte_data := []byte(data)
f.Write(byte_data)
f.Close()
}

func decrypt(encryptedString string, keyString string) (decryptedString string) {

key, _ := hex.DecodeString(keyString)
enc, _ := hex.DecodeString(encryptedString)

block, err := aes.NewCipher(key)
if err != nil {
panic(err.Error())
}
aesGCM, err := cipher.NewGCM(block)
if err != nil {
panic(err.Error())
}
nonceSize := aesGCM.NonceSize()
nonce, ciphertext := enc[:nonceSize], enc[nonceSize:]
plaintext, err := aesGCM.Open(nil, nonce, ciphertext, nil)
if err != nil {
panic(err.Error())
}

return fmt.Sprintf("%s", plaintext)
}

[注]

1.https[:]//symantec-enterprise-blogs.security[.]com/blogs/threat-intelligence/ukraine-wiper-malware-russia

2.https[:]//pkg.go.dev/github[.]com/satori/go.uuid#NewV1

●追加のリソース

・ウクライナに対するサイバー攻撃の詳細については、こちらをご覧ください。Lessons Learned From Successive Use of Offensive Cyber Operations Against Ukraine and What May Be Next(ウクライナに対する一連のサイバー攻撃の教訓と今後の予測)

・CrowdStrike Falcon が DriveSlayer およびワイパー型攻撃に対して継続的に行っている防御については、こちらをご参照ください。CrowdStrike Falcon Protects from New Wiper Malware Used in Ukraine Cyberattacks(CrowdStrike Falcon、ウクライナへのサイバー攻撃で使用された新たなワイパー型マルウェアから保護)

・WhisperGate に関する CrowdStrike Intelligence のブログ記事をご覧ください。Technical Analysis of the WhisperGate Malicious Bootloader(WhisperGate不正ブートローダーの技術分析)

・パワフルでクラウドネイティブな CrowdStrike Falconプラットフォームをウェブサイトの製品のページでご紹介しています。

完全な機能を搭載した CrowdStrike Falcon Prevent の無料トライアルで最も高度な脅威に対抗する次世代アンチウイルスをご体験ください。

※この資料は、米国時間 2022 年 3 月 1 日に発表された CrowdStrike のインテリジェンスチームによるブログの抄訳です。

*原文は CrowdStrike Blog サイト掲載 :https://www.crowdstrike.com/blog/how-to-decrypt-the-partyticket-ransomware-targeting-ukraine/

《Intelligence Team Research & Threat Intel (CrowdStrike)》

関連記事

この記事の写真

/

特集

PageTop

アクセスランキング

  1. 東芝テックが利用するクラウドサービスに不正アクセス、取引先や従業員の個人情報が閲覧された可能性

    東芝テックが利用するクラウドサービスに不正アクセス、取引先や従業員の個人情報が閲覧された可能性

  2. 「引っかかるのは当たり前」が前提、フィッシングハンターが提案する対策のポイント ~ JPAAWG 6th General Meeting レポート

    「引っかかるのは当たり前」が前提、フィッシングハンターが提案する対策のポイント ~ JPAAWG 6th General Meeting レポート

  3. 転職先で営業活動に活用、プルデンシャル生命保険 元社員 顧客情報持ち出し

    転職先で営業活動に活用、プルデンシャル生命保険 元社員 顧客情報持ち出し

  4. マリンネットサイトに SQL インジェクション攻撃、メールアドレス流出

    マリンネットサイトに SQL インジェクション攻撃、メールアドレス流出

  5. プルーフポイント、マルウェア配布する YouTube チャンネル特定

    プルーフポイント、マルウェア配布する YouTube チャンネル特定

  6. 山田製作所にランサムウェア攻撃、「LockBit」が展開され複数のサーバのデータが暗号化

    山田製作所にランサムウェア攻撃、「LockBit」が展開され複数のサーバのデータが暗号化

  7. Windows DNS の脆弱性情報が公開

    Windows DNS の脆弱性情報が公開

  8. 委託事業者が回収処理した国民健康保険証、拾得物として警察署に届く

    委託事業者が回収処理した国民健康保険証、拾得物として警察署に届く

  9. バッファロー製無線 LAN ルータに複数の脆弱性

    バッファロー製無線 LAN ルータに複数の脆弱性

  10. 警察庁、サイバー事案通報の統一窓口を設置

    警察庁、サイバー事案通報の統一窓口を設置

ランキングをもっと見る