From 7269873b0c7d4761e1047c97f4c20e70db63e9ca Mon Sep 17 00:00:00 2001 From: Still / Azaka Date: Sat, 22 Mar 2025 00:15:28 +0800 Subject: [PATCH] Add rules for detecting donut-related features (#997) * Initial additions for detecting donut features Signed-off-by: Still Hsu * Lint rules Signed-off-by: Still Hsu * Update ATT&CK for donut rule Signed-off-by: Still Hsu * Fix comment for dynamic scope on donut loader Signed-off-by: Still Hsu * Require at least one donut function match for donut rule Signed-off-by: Still Hsu * Add offset for examples Signed-off-by: Still Hsu * Add indirect call for IAssembly matching Signed-off-by: Still Hsu * Match known vtable offsets for assembly loading * Remove loop matching --------- Signed-off-by: Still Hsu --- .../decompress-data-using-aplib.yml | 5 +- .../chaskey/encrypt-data-using-chaskey.yml | 42 ++++++++++++ .../speck/encrypt-data-using-speck.yml | 37 +++++++++++ .../dotnet/load-assembly-via-iassembly.yml | 39 +++++++++++ .../donut-loader/load-shellcode-via-donut.yml | 64 +++++++++++++++++++ 5 files changed, 186 insertions(+), 1 deletion(-) create mode 100644 data-manipulation/encryption/chaskey/encrypt-data-using-chaskey.yml create mode 100644 data-manipulation/encryption/speck/encrypt-data-using-speck.yml create mode 100644 load-code/dotnet/load-assembly-via-iassembly.yml create mode 100644 malware-family/donut-loader/load-shellcode-via-donut.yml diff --git a/data-manipulation/compression/decompress-data-using-aplib.yml b/data-manipulation/compression/decompress-data-using-aplib.yml index 6f6f4b58..a782688e 100644 --- a/data-manipulation/compression/decompress-data-using-aplib.yml +++ b/data-manipulation/compression/decompress-data-using-aplib.yml @@ -6,6 +6,7 @@ rule: - "@r3c0nst (Frank Boldewin)" - moritz.raabe@mandiant.com - cdong49@gatech.edu + - still@teamt5.org description: detects decompression function of library aPLib scopes: static: function @@ -25,7 +26,9 @@ rule: - instruction: - description: line 138, if (offs >= 32000) - mnemonic: cmp - - number: 32000 + - or: + - number: 31999 + - number: 32000 - instruction: - description: line 144, if (offs < 128) - mnemonic: cmp diff --git a/data-manipulation/encryption/chaskey/encrypt-data-using-chaskey.yml b/data-manipulation/encryption/chaskey/encrypt-data-using-chaskey.yml new file mode 100644 index 00000000..7b9d5847 --- /dev/null +++ b/data-manipulation/encryption/chaskey/encrypt-data-using-chaskey.yml @@ -0,0 +1,42 @@ +rule: + meta: + name: encrypt data using chaskey + namespace: data-manipulation/encryption/chaskey + authors: + - still@teamt5.org + scopes: + static: function + dynamic: unsupported # requires characteristic, mnemonic features + att&ck: + - Defense Evasion::Obfuscated Files or Information [T1027] + mbc: + - Defense Evasion::Obfuscated Files or Information::Encryption-Standard Algorithm [E1027.m05] + references: + - https://mouha.be/chaskey/ + - https://github.com/TheWover/donut/blob/47758d787209dd1744f58c140102ac91b649df16/encrypt.c#L37 + examples: + - d890c1c67d83f1131c065b5eb5f263cbf54559dbcdb4562c3bde3dc30d1a3205:0x19495 + features: + - and: + - count(characteristic(nzxor)): 6 or more + - match: contain loop + - instruction: + - or: + - mnemonic: rol + - mnemonic: shl + - number: 13 + - instruction: + - or: + - mnemonic: rol + - mnemonic: shl + - number: 8 + - instruction: + - or: + - mnemonic: rol + - mnemonic: shl + - number: 7 + - instruction: + - or: + - mnemonic: rol + - mnemonic: shl + - number: 5 diff --git a/data-manipulation/encryption/speck/encrypt-data-using-speck.yml b/data-manipulation/encryption/speck/encrypt-data-using-speck.yml new file mode 100644 index 00000000..844c0b89 --- /dev/null +++ b/data-manipulation/encryption/speck/encrypt-data-using-speck.yml @@ -0,0 +1,37 @@ +rule: + meta: + name: encrypt data using speck + namespace: data-manipulation/encryption/speck + authors: + - still@teamt5.org + scopes: + static: function + dynamic: unsupported # requires characteristic, mnemonic features + att&ck: + - Defense Evasion::Obfuscated Files or Information [T1027] + mbc: + - Defense Evasion::Obfuscated Files or Information::Encryption-Standard Algorithm [E1027.m05] + references: + - https://github.com/maxmouchet/gfc/blob/8d818b0fe2023c92cbf8d7eb89674916bdc78f62/src/gfc.c#L15 + - https://github.com/TheWover/donut/blob/47758d787209dd1744f58c140102ac91b649df16/hash.c#L35 + examples: + - d890c1c67d83f1131c065b5eb5f263cbf54559dbcdb4562c3bde3dc30d1a3205:0x1929D + features: + - and: + - 2 or more: + - mnemonic: rol + - mnemonic: ror + - mnemonic: shl + - mnemonic: imul + - count(characteristic(nzxor)): 2 or more + - match: contain loop + - instruction: + - mnemonic: cmp + - or: + - number: 0x1A = encryption loop + - number: 0x1B = encryption loop + - instruction: + - mnemonic: cmp + - or: + - number: 0x3 = master key copy loop + - number: 0x4 = master key copy loop diff --git a/load-code/dotnet/load-assembly-via-iassembly.yml b/load-code/dotnet/load-assembly-via-iassembly.yml new file mode 100644 index 00000000..c1c2bb0a --- /dev/null +++ b/load-code/dotnet/load-assembly-via-iassembly.yml @@ -0,0 +1,39 @@ +rule: + meta: + name: load assembly via IAssembly + namespace: load-code/dotnet + authors: + - still@teamt5.org + scopes: + static: function + dynamic: unsupported + references: + - https://github.com/TheWover/donut/blob/master/loader/inmem_dotnet.c + examples: + - d890c1c67d83f1131c065b5eb5f263cbf54559dbcdb4562c3bde3dc30d1a3205:0x1641B + features: + - and: + - 3 or more: + - instruction: + - description: _MethodInfoVtbl->Invoke_3 + - or: + - mnemonic: call + - mnemonic: mov + - or: + - operand[1].offset: 0x128 + - operand[1].offset: 0x94 + - instruction: + - description: _AssemblyVtbl->InvokeMember_3 + - or: + - mnemonic: call + - mnemonic: mov + - or: + - operand[1].offset: 0xE4 + - operand[1].offset: 0x88 + - instruction: + - mnemonic: mov + - number: 0x2008 = VT_ARRAY | VT_BSTR (for passing args) + - instruction: + - mnemonic: mov + - number: 0x118 = BindingFlags_InvokeMethod | BindingFlags_Static | BindingFlags_Public (InvokeMember_3) + - characteristic: indirect call diff --git a/malware-family/donut-loader/load-shellcode-via-donut.yml b/malware-family/donut-loader/load-shellcode-via-donut.yml new file mode 100644 index 00000000..fbe7000f --- /dev/null +++ b/malware-family/donut-loader/load-shellcode-via-donut.yml @@ -0,0 +1,64 @@ +rule: + meta: + name: load shellcode via donut + namespace: malware-family/donut-loader + authors: + - still@teamt5.org + scopes: + static: file + dynamic: unsupported # requires mnemonic features + att&ck: + - Defense Evasion::Obfuscated Files or Information [T1027] + - Defense Evasion::Obfuscated Files or Information::Software Packing [T1027.002] + - Execution::Native API [T1106] + - Execution::Command and Scripting Interpreter::Visual Basic [T1059.005] + - Execution::Command and Scripting Interpreter::JavaScript [T1059.007] + - Execution::Inter-Process Communication::Component Object Model [T1559.001] + examples: + - d890c1c67d83f1131c065b5eb5f263cbf54559dbcdb4562c3bde3dc30d1a3205 + features: + - and: + - 3 or more: + - match: encrypt data using chaskey + - match: encrypt data using speck + - match: load assembly via IAssembly + - match: decompress data using aPLib + - or: + - function: + - and: + - description: match donut DownloadFromHTTP + - 3 or more: + - number: 0x3380 = SECURITY_FLAG_IGNORE_UNKNOWN_CA | SECURITY_FLAG_IGNORE_CERT_DATE_INVALID | SECURITY_FLAG_IGNORE_CERT_CN_INVALID | SECURITY_FLAG_IGNORE_WRONG_USAGE | SECURITY_FLAG_IGNORE_REVOCATION + - number: 0x84600200 = INTERNET_FLAG_KEEP_CONNECTION | INTERNET_FLAG_DONT_CACHE | INTERNET_FLAG_NO_UI | INTERNET_FLAG_PRAGMA_NOCACHE | INTERNET_FLAG_NO_AUTO_REDIRECT + - number: 0x20000013 = HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER + - number: 0x20000005 = HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER + - instruction: + - mnemonic: or + - or: + - number: 0x800000 = INTERNET_FLAG_SECURE + - number: 0x3000 = INTERNET_FLAG_IGNORE_CERT_CN_INVALID | INTERNET_FLAG_IGNORE_CERT_DATE_INVALID + - number: 0x803000 = INTERNET_FLAG_SECURE | INTERNET_FLAG_IGNORE_CERT_CN_INVALID | INTERNET_FLAG_IGNORE_CERT_DATE_INVALID + - instruction: + - mnemonic: cmp + - number: 200 = HTTP_STATUS_OK + - instruction: + - mnemonic: cmp + - number: 3 = DONUT_ENTROPY_DEFAULT + - function: + - and: + - description: match donut MainProc + - and: + - description: calculate allocation size based on DONUT_MODULE size + - instruction: + - mnemonic: add + - number: 0x530 = DONUT_MODULE struct size # not super reliable if donut ever changes the struct or different arch + - and: + - description: get required DLLs by splitting DLL names + - instruction: + - mnemonic: cmp + - number: 0x3B = ';' + - instruction: + - mnemonic: cmp + - or: + - number: 259 = MAX_PATH + - number: 260 = MAX_PATH