Skip to content
T1027.018 CrowdStrike LogScale · LogScale

Detect Invisible Unicode in CrowdStrike LogScale

Adversaries may abuse invisible or non-printing Unicode characters to conceal malicious content within files, scripts, or text. By inserting characters that do not visibly render, such as zero-width spaces, zero-width joiners, bidirectional control characters or the Hangul filler, adversaries may hide data, alter how content is interpreted, or make malicious code appear as benign text or whitespace. Payloads can be encoded as runs of these characters and decoded at execution time by a script that is itself short and innocuous looking.

MITRE ATT&CK

Tactic
Stealth
Technique
T1027 Obfuscated Files or Information
Sub-technique
T1027.018 Invisible Unicode
Canonical reference
https://attack.mitre.org/techniques/T1027/018/

LogScale Detection Query

CrowdStrike LogScale (LogScale)
cql
// df00tech DF00-9f9c08e410 · https://df00tech.com/detections/T1027.018 · licence: https://df00tech.com/detections/licence
#event_simpleName=ProcessRollup2
| CommandLine = /[\x{200B}-\x{200F}\x{2060}-\x{2064}\x{202A}-\x{202E}\x{2066}-\x{2069}\x{3164}\x{115F}\x{1160}\x{FEFF}]/
| table([timestamp, ComputerName, UserName, ImageFileName, CommandLine, ParentBaseFileName, ParentCommandLine])
| sort(field=timestamp, order=desc)
medium severity medium confidence

Detects invisible or bidirectional-control Unicode characters in process command lines in CrowdStrike LogScale (Humio) using Falcon ProcessRollup2 events and their CommandLine, ImageFileName and ParentBaseFileName fields. The regex character class is applied directly to the command line.

Data Sources

CrowdStrike Falcon sensor telemetry (ProcessRollup2 events ingested into LogScale/Humio)

Required Tables

ProcessRollup2 (#event_simpleName=ProcessRollup2)

False Positives & Tuning

  • Command lines pasted from chat or web content that carry stray zero-width spaces
  • Right-to-left language file names or arguments that use directional marks
  • Unicode test tooling that passes such characters as arguments

Other platforms for T1027.018


Testing Methodology

Validate this detection against 3 adversary techniques from Atomic Red Team. Each test below lists the behaviour to exercise and the telemetry you should expect to see. Executable commands and cleanup steps are available with Pro.

  1. Test 1 Zero-width characters in a PowerShell command line

    Expected signal: Sysmon Event ID 1: Process Create with Image=powershell.exe and a CommandLine containing five U+200B characters. Security Event ID 4688 (if command line auditing is enabled) with the same details. PowerShell ScriptBlock Log Event ID 4104 with the script text.

  2. Test 2 Invisible characters inside a script file

    Expected signal: PowerShell ScriptBlock Log Event ID 4104 with ScriptBlockText containing U+200D and U+3164. Sysmon Event ID 1 for the child powershell.exe with -File pointing at the script. Sysmon Event ID 11 for the script file creation.

  3. Test 3 Zero-width characters in a Linux shell command line

    Expected signal: Process creation telemetry from auditd EXECVE records, Sysmon for Linux Event ID 1 or an EDR sensor, with an argument containing the UTF-8 bytes E2 80 8B three times.


Response Playbook

Triage

  1. Print the command line with the invisible characters made visible (for example escape every code point above U+007F) and identify which characters are present: U+200B-U+200D zero-width, U+2060-U+2064 word joiner and invisible operators, U+202A-U+202E and U+2066-U+2069 bidirectional controls, U+3164 Hangul filler
  2. Check whether the characters sit inside a string literal, a variable name or between tokens — runs inside a long string usually mean an encoded payload, a lone character inside an argument suggests filename or argument spoofing
  3. Identify the process and its parent — was it a script host (powershell.exe, wscript.exe, python, bash) started from a document, archive or browser download?
  4. Check the user and device context — would this user normally run scripts? Do they use right-to-left languages or paste from rich-text sources?
  5. Find the script file or text that the command line references and look for the same characters in its contents
  6. Look for follow-on activity from the same process: network connections, child processes, file writes

Containment

  1. If the decoded payload is malicious: isolate the endpoint using EDR network isolation
  2. Quarantine the script, document or archive that carried the invisible characters and block its hash
  3. If a user account ran the payload: reset credentials and revoke active sessions and tokens
  4. Block the delivery source (sender, URL or domain) at mail gateway and proxy
  5. Search other endpoints for the same character run or file hash before closing the incident

Evidence Collection

  1. PowerShell Script Block Logging (Event ID 4104) — the ScriptBlockText field preserves the exact characters executed
  2. Process Creation Events — Sysmon Event ID 1 or Security Event ID 4688 with command line auditing enabled
  3. The script or document file itself, collected with a hash, for byte-level inspection of the code points
  4. File Creation Events — Sysmon Event ID 11 for scripts written by the suspicious process
  5. Network Connection Events — Sysmon Event ID 3 for connections from the same process
  6. Mail or proxy logs identifying how the file was delivered

Escalation Criteria

  • !Invisible characters decode to executable code or a second-stage payload
  • !The same character run appears on multiple endpoints within a short window
  • !The process making use of the characters also made outbound connections to non-corporate addresses
  • !Execution under a privileged or service account with no change ticket
  • !Evidence of other defense evasion alongside it, such as AMSI tampering or disabling of security tools

Investigation Guide

Forensic Artifacts

  • >Event Log: Microsoft-Windows-PowerShell/Operational (Event ID 4104 script block text)
  • >Event Log: Microsoft-Windows-Sysmon/Operational (Event ID 1 command lines)
  • >File System: $env:APPDATA\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txt — typed command history
  • >File System: the carrier script, document or text file, kept for hex inspection
  • >File System: ~/.bash_history and ~/.zsh_history on Linux and macOS hosts

Tuning Guidance

Start by baselining how often invisible characters appear in command lines in your environment. In organisations with right-to-left language users, exclude U+200E, U+200F and U+202A-U+202E by account group or narrow the character class to the zero-width and filler characters (U+200B-U+200D, U+2060, U+3164). Raise the InvisibleCount threshold above 3 for noisy fleets, but never exclude by process name alone, since attackers choose the host process. A lone U+FEFF at the start of an argument is a byte order mark and usually benign. The most reliable second signal is a script host that both carries the characters and makes a network connection or spawns a child process. Enable PowerShell Script Block Logging so the decoded stage can be examined.


Hunting Queries

Hunt for PowerShell script blocks that contain many invisible characters. A script that hides a payload as a long run of zero-width characters usually has to decode it in memory, which Script Block Logging records.

Hunting — KQL
kql
// df00tech DF00-9f9c08e410 · https://df00tech.com/detections/T1027.018 · licence: https://df00tech.com/detections/licence
DeviceEvents
| where Timestamp > ago(7d)
| where ActionType == "PowerShellCommand"
| where AdditionalFields has_any ("\\u200b", "\\u200c", "\\u200d", "\\u2060", "\\ufeff", "\\u3164")
| project Timestamp, DeviceName, AccountName, InitiatingProcessFileName, InitiatingProcessCommandLine, AdditionalFields
| sort by Timestamp desc
Hunting — SPL
spl
``` df00tech DF00-9f9c08e410 · https://df00tech.com/detections/T1027.018 · licence: https://df00tech.com/detections/licence ```
index=wineventlog sourcetype="XmlWinEventLog:Microsoft-Windows-PowerShell/Operational" EventCode=4104
| rex max_match=0 field=ScriptBlockText "(?<InvisibleChar>[\x{200B}-\x{200D}\x{2060}\x{FEFF}\x{3164}])"
| eval InvisibleCount=mvcount(InvisibleChar)
| where InvisibleCount >= 10
| table _time, host, UserID, InvisibleCount, ScriptBlockText
| sort - InvisibleCount

Baseline which accounts and parent processes launch commands containing any invisible character. Low-volume, repeated sources are usually benign copy-paste habits, while a rare parent such as a script host or an Office process warrants review.

Hunting — KQL
kql
// df00tech DF00-9f9c08e410 · https://df00tech.com/detections/T1027.018 · licence: https://df00tech.com/detections/licence
DeviceProcessEvents
| where Timestamp > ago(7d)
| where ProcessCommandLine matches regex @"[\x{200B}-\x{200F}\x{2060}-\x{2064}\x{202A}-\x{202E}\x{2066}-\x{2069}\x{3164}\x{FEFF}]"
| summarize Count=count(), Devices=dcount(DeviceName), Earliest=min(Timestamp), Latest=max(Timestamp) by AccountName, InitiatingProcessFileName
| sort by Count desc
Hunting — SPL
spl
``` df00tech DF00-9f9c08e410 · https://df00tech.com/detections/T1027.018 · licence: https://df00tech.com/detections/licence ```
index=wineventlog sourcetype="XmlWinEventLog:Microsoft-Windows-Sysmon/Operational" EventCode=1
| regex CommandLine="[\x{200B}-\x{200F}\x{2060}-\x{2064}\x{202A}-\x{202E}\x{2066}-\x{2069}\x{3164}\x{FEFF}]"
| stats count as Count, dc(host) as Devices, earliest(_time) as Earliest, latest(_time) as Latest by User, ParentImage
| sort - Count

Atomic Red Team Tests

Test 1 Zero-width characters in a PowerShell command line
windows

Runs a benign PowerShell command whose string argument has a run of five zero-width spaces (U+200B) inserted, which is the shape of an invisible-payload marker. The command only writes text to the console.

Command

powershell
powershell.exe -NoProfile -Command "Write-Output 'df00tech​​​​​test'"

Expected Telemetry

Sysmon Event ID 1: Process Create with Image=powershell.exe and a CommandLine containing five U+200B characters. Security Event ID 4688 (if command line auditing is enabled) with the same details. PowerShell ScriptBlock Log Event ID 4104 with the script text.

Expected Detection

Alert fires because the command line holds at least three characters from the invisible class. KQL: InvisibleCount=5. SPL: InvisibleCount=5.

Test 2 Invisible characters inside a script file
windows

Writes a small PowerShell script whose variable value carries zero-width joiners and a Hangul filler, runs it, then deletes it. The characters reach the logs through script block text instead of the process command line.

Command

powershell
Set-Content -Path $env:TEMP\df00tech-invisible.ps1 -Value "`$s = 'a‍‍‍ㅤㅤb'; Write-Output `$s.Length" -Encoding UTF8; powershell.exe -NoProfile -ExecutionPolicy Bypass -File $env:TEMP\df00tech-invisible.ps1

Cleanup

powershell
Remove-Item $env:TEMP\df00tech-invisible.ps1 -ErrorAction SilentlyContinue

Expected Telemetry

PowerShell ScriptBlock Log Event ID 4104 with ScriptBlockText containing U+200D and U+3164. Sysmon Event ID 1 for the child powershell.exe with -File pointing at the script. Sysmon Event ID 11 for the script file creation.

Expected Detection

The process rule does not fire because the characters are in the file, not the command line. The 4104 hunting query counts five invisible characters in the script block (lower its threshold to 5 for this test).

Test 3 Zero-width characters in a Linux shell command line
linux

Uses command substitution so that the shell passes an argument containing three zero-width spaces to sh. The command only echoes a string.

Command

bash
sh -c "$(printf 'echo df00tech\xe2\x80\x8b\xe2\x80\x8b\xe2\x80\x8btest')"

Expected Telemetry

Process creation telemetry from auditd EXECVE records, Sysmon for Linux Event ID 1 or an EDR sensor, with an argument containing the UTF-8 bytes E2 80 8B three times.

Expected Detection

Alert fires on platforms that ingest Linux process command lines into the same fields: the command line holds three characters from the invisible class.

Related Detections