Source
Adversaries may abuse the shell built-in source command (or its dot notation equivalent '. ') to execute arbitrary scripts in the current shell context without requiring the target file to be marked executable. This technique is deprecated in ATT&CK but the underlying behavior remains relevant on Linux and macOS systems. The source command can load malicious functions into the current shell session, execute staged payloads from world-writable directories, or run scripts pulled from remote locations via process substitution (e.g., source <(curl ...)). Because the file does not need execute permissions (chmod +x), this technique can bypass permission-based detection controls. Adversaries commonly use this to execute payloads written to /tmp or /dev/shm, load malicious shell functions into memory, or chain with other techniques such as modifying .bashrc or .profile for persistence.
let SuspiciousSourcePaths = dynamic([
"/tmp/", "/dev/shm/", "/var/tmp/", "/run/", "/proc/",
"/home/", "/root/", "/dev/fd/"
]);
let SuspiciousParents = dynamic([
"curl", "wget", "python", "python3", "perl", "ruby",
"php", "nc", "ncat", "socat"
]);
DeviceProcessEvents
| where Timestamp > ago(24h)
| where OSPlatform in ("Linux", "macOS")
| where FileName in ("bash", "sh", "zsh", "dash", "ksh", "fish")
| where ProcessCommandLine has "source " or ProcessCommandLine matches regex @"(?:^|\s)\.\s+[/~]"
| extend SourcedPath = extract(@"source\s+([^\s;|&]+)|(?:^|\s)\.\s+([^\s;|&]+)", 1, ProcessCommandLine)
| extend IsFromTempDir = ProcessCommandLine has_any (SuspiciousSourcePaths)
| extend IsProcessSubstitution = ProcessCommandLine matches regex @"source\s+<\(" or ProcessCommandLine matches regex @"\.\s+<\("
| extend SuspiciousParent = InitiatingProcessFileName has_any (SuspiciousParents)
| extend IsNonExecutable = ProcessCommandLine matches regex @"source\s+.*\.(txt|log|conf|dat|bak|tmp)"
or ProcessCommandLine matches regex @"\.\s+.*\.(txt|log|conf|dat|bak|tmp)"
| extend HasBase64Payload = ProcessCommandLine has "base64" and (ProcessCommandLine has "source" or ProcessCommandLine matches regex @"(?:^|\s)\.\s+")
| where IsFromTempDir or IsProcessSubstitution or SuspiciousParent or IsNonExecutable or HasBase64Payload
| project Timestamp, DeviceName, AccountName, FileName, ProcessCommandLine,
InitiatingProcessFileName, InitiatingProcessCommandLine, SourcedPath,
IsFromTempDir, IsProcessSubstitution, SuspiciousParent, IsNonExecutable, HasBase64Payload
| sort by Timestamp desc Data Sources
Required Tables
False Positives
- System initialization scripts and package installers legitimately source configuration files from /tmp during installation (e.g., some pip or npm install procedures)
- Developers and DevOps engineers routinely source virtual environment activation scripts (e.g., source ./venv/bin/activate) which may reside in project directories under /home/
- Configuration management tools (Ansible, Chef, Puppet) may source scripts during provisioning runs
- Shell profile management tools (oh-my-zsh, bash-it) source scripts during terminal initialization from home directories
- CI/CD pipeline agents sourcing build environment scripts from workspace directories that may match /home/ path patterns
References (8)
- https://attack.mitre.org/techniques/T1153/
- https://ss64.com/bash/source.html
- https://www.gnu.org/software/bash/manual/bash.html#Bourne-Shell-Builtins
- https://github.com/redcanaryco/atomic-red-team/blob/master/atomics/T1153/T1153.md
- https://linux.die.net/man/8/auditd
- https://github.com/SigmaHQ/sigma/tree/master/rules/linux
- https://www.cyberciti.biz/faq/bash-source-command/
- https://learn.microsoft.com/en-us/defender-endpoint/linux-support-events
Unlock Pro Content
Get the full detection package for T1153 including response playbook, investigation guide, and atomic red team tests.