Nozomi Networks  Labs による BlackMatter ランサムウェアのテクニカル分析とツール

Nozomi Networks Labs による BlackMatter ランサムウェアのテクニカル分析とツール

先週末、アイオワ州を拠点とするNEW Cooperative Inc.がランサムウェア集団BlackMatterの最新の被害者となった。農業協同組合として運営されている同社によると、この事件は積極的に処理されているが、この記事を書いている時点では、攻撃の全影響は明らかになっていない。

BlackMatterは、そのウェブサイトのメディアからの問い合わせのセクションで、悪意のある作戦の標的にしてはならない重要なインフラの標的を明確に列挙している。NEW協同組合のような規模の組織が重要インフラに分類される可能性は十分にある。もしそうなら、この攻撃は重大な結果をもたらす可能性がある。現代のサプライチェーンは突発的な混乱に対して脆弱であり、その影響の全容が理解されるのはかなり後になってからであることがしばしば見受けられる。

このブログでは、Nozomi Networks Labs が BlackMatter ランサムウェアの実行ファイルを分析するために行ったプロセス、マルウェアが分析の障害となる方法、およびそれらを克服するために行った方法について説明します。また、他の研究者がこのランサムウェアの他のインスタンスから重要な情報を抽出するのに役立つスクリプトをいくつか紹介します。

主な機能

このランサムウェアはChaCha20とRSAアルゴリズムのバージョンで被害者のファイルを暗号化する。RSAは、攻撃者側に保存されている秘密鍵なしでは復号化が不可能であることを保証するために使用されます。このマルウェアは、READMEファイルの形で、復号化するための手順を記したメモを残します。さらに、壁紙を変更して注意を喚起します:

READMEファイル
BlackMatter ランサムウェア

BlackMatterランサムウェアの実行ファイルによって変更された壁紙で、復号化手順が記載されたREADMEファイルに注意を喚起している(クリックで拡大)

さらに、このマルウェアは、以下のような一般的なランサムウェアの動作を実行する:

  • WMI クエリ SELECT * FROM Win32_ShadowCopy を使用して、最初に一覧を表示してシャドウ コピー(ローカル バックアップ)を削除します。
  • ごみ箱内のファイルを削除する
  • コンフィギュレーションで指定されたプロセスやサービスの終了
  • 壁紙が、復号化の指示のためにREADMEテキストファイルを指すように変更する。
  • Elevation:Administrator!new:{3E5FC7F9-9A51-4367-9063-A120244FBEC7} is used for UAC (user account control) bypass
  • 暗号化されたファイルは、READMEファイル名のプレフィックスに表示される被害者IDと一致する新しい拡張子を持ち、レジストリにも保存されます。この犠牲者IDは、レジストリのMachineGuid値から取得されます。

アンチデバッグ・テクニック

このマルウェアは、どのWinAPIに依存しているかを隠すことで、解析を妨害しようとしている。これを回避するために、マルウェアは必要なインポート関数の一部をハッシュによって解決する:

ハッシュ名によるWinAPI関数の識別
ハッシュ名によるWinAPI関数の識別

さらに分析を複雑にするために、ハッシュによるWinAPIアドレスの一括解決の場合、マルウェアは発見されたアドレスを保存するユニークな方法を使用する。単にテーブルに保存するのではなく、解決されたWinAPIアドレスごとに、それをエンコードする5つの異なる方法(rol、ror、xor、xor+rol、xor+ror)のうち1つをランダムに選択し、エンコードされたアドレスを、呼び出しの直前にデコードする動的に構築されたコード・スニペットとともに保存する:

各APIアドレスを動的に復号化し、そのアドレスに制御を転送するコード・スニペットを構築する。
各APIアドレスを動的に復号化し、そのアドレスに制御を転送するコード・スニペットを構築する。

プロキシのコード・スニペットのひとつを紹介しよう:

APIを呼び出すために動的にビルドされたコード・スニペット
APIを呼び出すために動的にビルドされたコード・スニペット

マルウェアが使用するもう1つのアンチデバッグ・トリックは、これらのスニペットを格納するために割り当てるプライベート・ヒープ・ブロックの末尾に0xABABABシーケンスがあるかどうかをチェックすることです。デバッガがアタッチされている場合、このシーケンスが追加され、マルウェアはスニペットのアドレスをカスタムインポートテーブルに保存しないため、後にデバッグされたサンプルがクラッシュすることになります。

マルウェアチェック
マルウェアは、デバッガを明らかにする0xABABABシーケンスの存在をチェックする。

文字列は通常、使用される直前にその場で復号化される:

ダイナミックAPI

IDAPythonの機能を使えば、そのほとんどを自動的に見つけて解読することができる:

自動復号化

SOFTWARE\Microsoft\CryptographyMachineGuid__ProviderArchitectureROOT\CIMV2IDSELECT * FROM Win32_ShadowCopyWQLWin32_ShadowCopy.ID='%s'Global\%.8x%.8x%.8x%.8xTimes New Roman.bmpControl Panel\DesktopWallPaperWallpaperStyleZ:\dllhost.exeElevation:Administrator!new:{3E5FC7F9-9A51-4367-9063-A120244FBEC7}%s.README.txtControl Panel\InternationalLocaleNamesLanguageSOFTWARE\Microsoft\Windows NT\CurrentVersionProductName%.8x%.8x%.8x%.8x%POSTABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789%s=%s%s=%s%.8x%.8x%.8x%.8x%ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789%u.%u%u.%u\\%s\LDAP://rootDSEdefaultNamingContextLDAP://CN=Computers,dNSHostName\\%s\ExchangeInstallPathProgram FilesMailboxSOFTWARE\%shScreen

構成

サンプルの暗号化されたコンフィギュレーションは.rsrcセクションに格納され、さらに圧縮され、個々のフィールドはbase64エンコードされている。復号化されたC2コンフィギュレーションを以下に示します。このサンプルは、C2のセットによって証明されるように、プレーンHTTPとHTTPSの両方のエンドポイントとやり取りすることができます。

設定の復号化とBase64エンコードされたC2
設定の復号化とBase64エンコードされたC2

マルウェアはこれらのC2と通信する際に、ランダムなHTTPクエリ値を生成する:

C2の1つとのネットワーク通信
C2の1つとのネットワーク通信

通信の安全性を確保するために、AESアルゴリズムが使用されている。

平文での対象システムの詳細
平文での対象システムの詳細

以下は抽出されたコンフィギュレーションである:

{ "SHA256_SAMPLE": "706F3EEC328E91FF7F66C8F0A2FB9B556325C153A329A2062DC85879C540839D", "RSA_KEY": "232FBA5316E1C9A3F0E603EF0ECB534A1FC1E8BA5F89DBD886D98FBF88EEDDE66CC65E00BBB827CD0262B65C505D95A008C48427A73AE6EB888EB47A8A6246B43326931A7D59DFDAD141A054B445C51FBA1E3DF3F41CBA82AF44B96F21388C00DD696F7B3B976313C662B6283C0D082B5E68F3FFD7946A72C67F8A698172BE70", "COMPANY_VICTIM_ID": "90A881FFA127B004CEC6802588FCE307", "AES_KEY": "B59C952C492BD3D1F8F5140AA2855CDE", "BOT_MALWARE_VERSION": "2.0", "ODD_CRYPT_LARGE_FILES": "false", "NEED_MAKE_LOGON": "true", "MOUNT_UNITS_AND_CRYPT": "true", "CRYPT_NETWORK_RESOURCES_AND_AD": "true", "TERMINATE_PROCESSES": "true", "STOP_SERVICES_AND_DELETE": "true", "CREATE_MUTEX": "true", "PREPARE_VICTIM_DATA_AND_SEND": "true", "PRINT_RANSOM_NOTE": "true", "PROCESS_TO_KILL": [{ "": "encsvc" }, { "": "thebat" }, { "": "mydesktopqos" }, { "": "xfssvccon" }, { "": "firefox" }, { "": "infopath" }, { "": "winword" }, { "": "steam" }, { "": "synctime" }, { "": "notepad" }, { "": "ocomm" }, { "": "onenote" }, { "": "mspub" }, { "": "thunderbird" }, { "": "agntsvc" }, { "": "sql" }, { "": "excel" }, { "": "powerpnt" }, { "": "outlook" }, { "": "wordpad" }, { "": "dbeng50" }, { "": "isqlplussvc" }, { "": "sqbcoreservice" }, { "": "oracle" }, { "": "ocautoupds" }, { "": "dbsnmp" }, { "": "msaccess" }, { "": "tbirdconfig" }, { "": "ocssd" }, { "": "mydesktopservice" }, { "": "visio" }], "SERVICES_TO_KILL": [{ "": "mepocs" }, { "": "memtas" }, { "": "veeam" }, { "": "svc$" }, { "": "backup" }, { "": "sql" }, { "": "vss" }, { "": "msexchange" }], "C2_URLS": [{ "": "https://mojobiden[.]com" }, { "": "http://mojobiden[.]com" }, { "": "https://nowautomation[.]com" }, { "": "http://nowautomation[.]com" }], "LOGON_USERS_INFORMATION": [{ "": "" }, { "": "" }, { "": "" }, { "": "" }, { "": "" }, { "": "" }], "RANSOM_NOTE": [{ "": " ~+ \r\n * +\r\n ' BLACK |\r\n () .-.,='``'=. - o - \r\n '=/_ \\ | \r\n * | '=._ | \r\n \\ `=./`, ' \r\n . '=.__.=' `=' *\r\n + Matter +\r\n O * ' .\r\n\r\n>>> What happens?\r\n Your network is encrypted, and currently not operational. \r\n We need only money, after payment we will give you a decryptor for the entire network and you will restore all the data.\r\n\r\n>>> What data stolen?\r\n From your network was stolen 1000 GB of data.\r\n If you do not contact us we will publish all your data in our blog and will send it to the biggest mass media.\r\n Blog post link: http://.onion/\何の保証?\私たちは政治的なグループではないので、あなたのお金以外は必要ありません。\お金を払えば、復号化プログラムを提供し、データを削除します。\r\n If we do not give you decrypters or we do not delete your data, no one will pay us in the future, this does not comply with our goals.\We always keep our promises. 〚私たちは常に約束を守ります〛〛〛〛どうやって私たちと連絡しますか?\1.TOR Browser (https://www.torproject.org/)をダウンロードしてインストールする。http:// を開く。.onion/\警告!回復の推奨。 \ファイルを変更したり修復したりしないことを強くお勧めします。" }] }

全体的に、被害者IDがMachineGuid値から導き出される方法、使用される暗号化技術、構成が構造化され保護される方法など、DarkSideランサムウェアファミリーと複数の類似点があります。DarkSide実行ファイルに関する詳細は、以前のブログでご覧いただけます。

BlackMatter ランサムウェア対策と侵害の兆候

Nozomi Networks 弊社のThreat Intelligence サービスをご利用のお客様は、すでにこの脅威に対してカバーされています。さらに、Nozomi Networks Labsは、この状況の進展を監視しており、お客様への補償を拡大し、主要なアップデートについてコミュニティに通知します。

重要インフラの運用を守るセキュリティ専門家にとって、ランサムウェアに対するサイバー耐性のための一般的な推奨事項は、当社の最新レポート(OT/IoT Security Report)に記載されています。

セキュリティ研究者にとって、BlackMatterがどのように分析を回避するか、そしてコードから重要な情報を抽出する方法について、このブログで提供された説明は、マルウェアが進化するにつれて役に立つはずである。

この分析からわかった妥協の指標(IOC)と、分析に使用したスクリプトは以下の通り。

IOC一覧

mojobiden.com ナウオートメーションドットコム 706f3eec328e91ff7f66c8f0a2fb9b556325c153a329a2062dc85879c540839d
// Created by Nozomi Networks Labs import "pe" rule blackmatter_ransomware : blackmatter ransomware { meta: date = "2021-09-20" name = "BlackMatter - RANSOMWARE" author = "Nozomi Networks Labs" description = "Generic detection for BlackMatter ransomware" actor = "BlackMatter" x_threat_name = "BlackMatter ransomware" x_mitre_technique = "T1486" hash1 = "706f3eec328e91ff7f66c8f0a2fb9b556325c153a329a2062dc85879c540839d" hash2 = "9cf9441554ac727f9d191ad9de1dc101867ffe5264699cafcf2734a4b89d5d6a" hash3 = "b0e929e35c47a60f65e4420389cad46190c26e8cfaabe922efd73747b682776a" hash4 = "2cdb5edf3039863c30818ca34d9240cb0068ad33128895500721bcdca70c78fd" hash5 = "f7b3da61cb6a37569270554776dbbd1406d7203718c0419c922aa393c07e9884" hash6 = "8f1b0affffb2f2f58b477515d1ce54f4daa40a761d828041603d5536c2d53539" hash7 = "e4a2260bcba8059207fdcc2d59841a8c4ddbe39b6b835feef671bceb95cd232d" nn_ts = "1632088800.0" nn_sig = "f7c69f3b527ffb3f0c2aa613e902d8d4f0e39966048bb6cfa57556115fa18ed9" nn_id = "92f90d15-9392-4076-96b5-1e42ac9874c5" condition: uint16(0)==0x5a4d and uint32( uint32(0x3c))==0x00004550 and filesize <100KB and pe.imphash()=="2e4ae81fc349a1616df79a6f5499743f" }

IDAPythonスクリプト

以下は、マルウェアによって動的に入力されたカスタムインポートテーブルを復元するスクリプトです。このスクリプトは、カーソルが一括復号化関数の位置(このサンプルの場合、RVA 0x78EC)にあるときに押される新しいホットキーZを定義します。

# Author: Alexey Kleymenov (a member of Nozomi Networks Labs) import os import struct import pefile import ida_kernwin PATH_TO_DLLS = 'c:\\windows\\system32\\' HARDCODED_XOR_KEY = 0x17019FF8 def extract_api_hashes(start): ''' Returns a dictionary where keys are import functions to write data and values are list of hashes The first hash is the DLL name's hash, the rest are WinAPI names' hashes ''' decryptor_address = start print('Bulk API decryptor address: %x' % decryptor_address) api_hashes = {} for head in Heads(): flags = GetFlags(head) if isCode(flags): prev = prev_head(head) prev_2 = prev_head(prev) if print_insn_mnem(head) == 'call' and get_operand_value(head, 0) == decryptor_address: print('Found the decryptor called: %x' % head) if print_insn_mnem(prev) == 'push' and print_insn_mnem(prev_2) == 'push': func_hashes = get_operand_value(prev_2, 0) import_table = get_operand_value(prev, 0) api_hashes[import_table] = [] for i in range(0, 0xffff, 4): api_hash = struct.unpack("> 0x0D) | (value << (0x20 - 0x0D))) & 0xFFFFFFFF value += ord(symbol) & 0xFFFFFFFF return value def build_mappings(dll_filepath, dll_hashes): ''' This function calculates API checksums for the DLLs of interest ''' dll_name = os.path.basename(dll_filepath) dll_checksum = calculate_checksum(dll_name.lower() + '\x00', 0) result = {} if dll_checksum in dll_hashes: dll = pefile.PE(dll_filepath, fast_load=True) dll.parse_data_directories(directories=[pefile.DIRECTORY_ENTRY['IMAGE_DIRECTORY_ENTRY_EXPORT']]) if hasattr(dll, 'DIRECTORY_ENTRY_EXPORT'): dll_name = dll_name.replace('.', '_') result[dll_checksum] = {'dll_name': dll_name} export_directory = dll.DIRECTORY_ENTRY_EXPORT for symbol in export_directory.symbols: if symbol.name is not None: api_name = symbol.name.decode('latin-1') api_checksum = calculate_checksum(api_name + '\x00', dll_checksum) result[api_checksum] = {'dll_name': dll_name, 'api_name': api_name} return result def parse_dlls(path_to_dlls, dll_hashes): ''' This function goes through all the files in the specified path and calculates export hashes for DLLs matching by name hashes ''' list_dlls = os.listdir(path_to_dlls) mappings = {} for dll_filename in list_dlls: full_path = os.path.join(path_to_dlls, dll_filename) mappings.update(build_mappings(full_path, dll_hashes)) return mappings def decrypt_all(): ''' The function expects the cursor to be located at the bulk decryption function ''' start = get_screen_ea() api_hashes = extract_api_hashes(start) dll_hashes = [] for _, hashes in api_hashes.items(): dll_hashes.append(hashes[0]) dll_mappings = parse_dlls(PATH_TO_DLLS, dll_hashes) for import_table, hashes in api_hashes.items(): dll_hash = hashes[0] api_hashes = hashes[1:] if dll_hash in dll_mappings: print('Found DLL hash %x = %s' % (dll_hash, dll_mappings[dll_hash]['dll_name'])) for i, api_hash in enumerate(api_hashes): if api_hash in dll_mappings: addr = import_table + (i+1)*4 print('Found API hash for %x = %s (%s)' % (addr, dll_mappings[api_hash]['api_name'], dll_mappings[api_hash]['dll_name'])) set_name(addr, dll_mappings[api_hash]['api_name']) else: print('API hash %x not found' % api_hash) else: print('DLL hash %x not found' % dll_hash) ida_kernwin.add_hotkey("z", decrypt_all)

さらに、暗号化された文字列のほとんどを自動的に検索し、復号化するスクリプトを紹介しよう:

#著者Alexey Kleymenov (Nozomi Networks Labsのメンバー) インポート構造体 インポート ida_kernwin HARDCODED_XOR_KEY = 0x17019FF8 def is_utf16_heur(string): カウンタ = 0 for val in string: if val == 0: カウンタ += 1 if counter/float(len(string))> 0.4: 真を返す 偽を返す def decrypt_string(start_addr): addr = start_addr result = b"" for i in range(0xFFFF): instr = print_insn_mnem(addr) if instr != 'mov' or 'dword ptr' in GetDisasm(addr): break 値 = get_operand_value(addr, 1) decoded_value = value ^ HARDCODED_XOR_KEY result += struct.pack(")

参考文献

  1. https://www.nozominetworks.com/blog/colonial-pipeline-ransomware-attack-revealing-how-darkside-works/
  2. https://github.com/advanced-threat-research/DarkSide-Config-Extract