Files
S12cybersecurity-YaraRules/Speck_CBC_KeyWrapping_Shellcode_Loader.yar
S12cybersecurity bbb60001f8 Add YARA rule for Speck CBC key wrapping detection
This rule detects the usage of the Speck block cipher in CBC mode with session key wrapping, which is common in custom shellcode loaders and encryptors. It includes various patterns for identifying Speck operations, CRC32 implementations, and debug artifacts.
2026-02-23 10:13:41 +01:00

96 lines
4.8 KiB
Plaintext

rule Speck_CBC_KeyWrapping_Shellcode_Loader
{
meta:
author = "0x12 Dark Development"
description = "Detects Speck block cipher usage with CBC mode and session key wrapping — common in custom shellcode loaders/encryptors"
category = "malware/crypter"
reference = "https://cocomelonc.github.io/malware/2025/05/29/malware-cryptography-42.html"
date = "2026-02-23"
strings:
// ── Speck-128 rotation constants (ROL 3 / ROR 8) ──────────────────
// These are the defining operations of Speck-128 key schedule and round function.
// Compiler usually emits these as immediate shift values in tight loops.
// ROR 8 on 64-bit: shr rax, 8 + shl rcx, 56 pattern (or ror rax, 8)
$speck_ror8_x64 = { 48 C1 E? 08 } // shr/shl reg64, 8
$speck_rol3_x64 = { 48 C1 E? 03 } // shr/shl reg64, 3
$speck_ror8_x86 = { C1 E? 08 } // shr/shl reg32, 8
$speck_rol3_x86 = { C1 E? 03 } // shr/shl reg32, 3
// ── CRC32 software table-driven implementation ─────────────────────
// The standard reflected polynomial 0xEDB88320 — appears as a 32-bit
// immediate in the conditional XOR inside the table generation loop.
$crc32_poly = { 20 83 B8 ED } // 0xEDB88320 little-endian
// CRC32 init value 0xFFFFFFFF and final XOR (same value)
$crc32_init = { FF FF FF FF }
// ── CBC mode XOR-before-encrypt pattern ───────────────────────────
// block[0] ^= prev[0]; block[1] ^= prev[1]; before calling encrypt
// Results in back-to-back 64-bit XOR instructions on memory operands
$cbc_xor_x64 = { 48 33 ?? ?? ?? ?? ?? 48 33 ?? ?? ?? ?? ?? }
// ── Key wrapping pattern ───────────────────────────────────────────
// Session key encrypted with master key (ECB, single block).
// Typically: two sequential speckEncrypt calls or a single ECB call
// before the main CBC loop. We look for two consecutive encrypt
// round-loop entries within close range.
// ── Blob header layout fingerprint ────────────────────────────────
// BLOB_PAYLOAD_OFFSET = 36 (0x24): memcpy(..., buf+36, ...) appears
// as an add/lea with immediate 0x24 feeding into a memcpy/mov sequence
$blob_offset_36 = { 83 C? 24 } // add reg, 0x24
$blob_offset_36b = { 8D ?? 24 } // lea reg, [reg+0x24]
// ── Blob header: IV at offset 16 (0x10) ───────────────────────────
$blob_offset_16 = { 83 C? 10 } // add reg, 0x10
$blob_offset_16b = { 8D ?? 10 } // lea reg, [reg+0x10]
// ── rand() seeded with time(NULL) — common IV/key generation ──────
$srand_time = { FF 15 ?? ?? ?? ?? 50 FF 15 ?? ?? ?? ?? } // call time; push eax; call srand
// ── calloc(1, n) + memcpy pattern — padded buffer allocation ──────
$calloc_1 = { 6A 01 } // push 1 (calloc first arg)
// ── Strings / debug artifacts that survive stripped binaries ───────
$str_session_key = "Session key" ascii wide nocase
$str_wrapped_key = "Wrapped" ascii wide nocase
$str_crc32_ok = "CRC32" ascii wide nocase
$str_decrypt_ok = "Decryption OK" ascii wide nocase
$str_decrypt_fail = "Decryption FAIL" ascii wide nocase
$str_encrypt_mode = "ENCRYPT_MODE" ascii wide
$str_decrypt_mode = "DECRYPT_MODE" ascii wide
condition:
uint16(0) == 0x5A4D // MZ header — PE file
and filesize < 5MB
and (
// Confident hit: rotation constants + CRC polynomial + CBC XOR
(
( $speck_ror8_x64 and $speck_rol3_x64 ) or
( $speck_ror8_x86 and $speck_rol3_x86 )
)
and $crc32_poly
and $cbc_xor_x64
)
or (
// Debug/non-stripped binary with telltale strings
2 of ($str_session_key, $str_wrapped_key, $str_crc32_ok,
$str_decrypt_ok, $str_decrypt_fail)
and $crc32_poly
)
or (
// Blob layout fingerprint: both key offset (0x10) and
// payload offset (0x24) present alongside Speck rotations
( $blob_offset_36 or $blob_offset_36b )
and ( $blob_offset_16 or $blob_offset_16b )
and ( $speck_ror8_x64 or $speck_ror8_x86 )
and $crc32_poly
)
}