Compromise Host Software Binary
Adversaries may modify host software binaries to establish persistent access to systems. Common targets include SSH clients/servers, FTP clients, web browsers, VPN daemons, and other frequently-executed system utilities. Attackers may replace a legitimate binary entirely with a trojanized version containing credential harvesting or backdoor functionality, or patch an existing binary at its entry point to redirect execution to malicious code before resuming normal operation. After modification, adversaries may use version-lock mechanisms (e.g., yum-versionlock, apt-mark hold) to prevent legitimate updates from overwriting the trojanized binary.
What is T1554 Compromise Host Software Binary?
Compromise Host Software Binary (T1554) maps to the Persistence tactic — the adversary is trying to maintain their foothold in MITRE ATT&CK.
This page provides production-ready detection logic for Compromise Host Software Binary, covering the data sources and telemetry it touches: File: File Modification, File: File Creation, Process: Process Creation, Microsoft Defender for Endpoint. The queries below are rated high severity at medium confidence, and ship for 7 SIEM platforms — KQL, SPL, Elastic, QRadar, Sumo, YARA-L, LogScale.
MITRE ATT&CK
- Tactic
- Persistence
- Technique
- T1554 Compromise Host Software Binary
- Canonical reference
- https://attack.mitre.org/techniques/T1554/
let SystemBinaryPaths = dynamic([
"C:\\Windows\\System32\\",
"C:\\Windows\\SysWOW64\\",
"C:\\Program Files\\OpenSSH\\",
"C:\\Program Files (x86)\\"
]);
let CriticalBinaries = dynamic([
"ssh.exe", "sshd.exe", "sftp.exe", "curl.exe", "wget.exe",
"putty.exe", "winscp.exe", "filezilla.exe",
"chrome.exe", "firefox.exe", "msedge.exe", "iexplore.exe",
"notepad.exe", "cmd.exe", "powershell.exe", "pwsh.exe",
"taskmgr.exe", "regedit.exe", "mstsc.exe", "lsass.exe"
]);
let LegitUpdaters = dynamic([
"msiexec.exe", "trustedinstaller.exe", "wusa.exe",
"setup.exe", "install.exe", "update.exe", "windowsupdate.exe"
]);
let VersionLockPatterns = dynamic([
"versionlock", "yum-versionlock", "apt-mark hold",
"dpkg --set-selections", "apt-mark unhold"
]);
// Arm 1: File writes to critical system binary locations from non-updater processes
let BinaryModifications = DeviceFileEvents
| where Timestamp > ago(24h)
| where ActionType in ("FileModified", "FileCreated", "FileRenamed")
| where FolderPath has_any (SystemBinaryPaths)
| where FileName has_any (CriticalBinaries)
| where InitiatingProcessFileName !in~ (LegitUpdaters)
| extend AlertReason = "SystemBinaryModification"
| project Timestamp, DeviceName, AccountName, FileName, FolderPath, ActionType,
InitiatingProcessFileName, InitiatingProcessCommandLine,
AlertReason, SHA256, MD5;
// Arm 2: Package manager version-lock commands (UNC3886 TTPs)
let VersionLockActivity = DeviceProcessEvents
| where Timestamp > ago(24h)
| where ProcessCommandLine has_any (VersionLockPatterns)
| extend AlertReason = "VersionLockDetected"
| project Timestamp, DeviceName, AccountName, FileName,
ProcessCommandLine, InitiatingProcessFileName,
InitiatingProcessCommandLine, AlertReason,
SHA256 = "", MD5 = "";
union BinaryModifications, VersionLockActivity
| sort by Timestamp desc Detects compromise of host software binaries through two complementary signals: (1) FileModified/FileCreated events in critical Windows system binary directories (System32, SysWOW64, Program Files\OpenSSH) attributed to non-legitimate updater processes, and (2) package manager version-lock commands (yum-versionlock, apt-mark hold) used by adversaries such as UNC3886 to prevent legitimate updates from overwriting trojanized binaries. SHA256 and MD5 hashes are captured in results for offline comparison against known-good vendor baselines.
Data Sources
Required Tables
False Positives
- Legitimate software updates and patching via Windows Update (TrustedInstaller) or third-party application updaters that overwrite their own executables during upgrades
- OpenSSH for Windows installation or upgrade via official installer (msiexec) replacing ssh.exe and sshd.exe in Program Files\OpenSSH
- System administrators using apt-mark hold or yum-versionlock for legitimate dependency pinning during application deployments, with corresponding change tickets
- AV/EDR product self-protection mechanisms that write modified copies of monitored binaries to staging locations as part of their own update pipeline
Sigma rule & cross-platform mapping
The detection logic for Compromise Host Software Binary (T1554) above is provided in a vendor-neutral
form so you can deploy it on any SIEM. The same logic is shipped here as native
KQL (Microsoft Sentinel / Defender), SPL (Splunk), Elastic (Elastic Security (EQL)), QRadar (IBM QRadar (AQL)), Sumo (Sumo Logic CSE), YARA-L (Google Chronicle / SecOps), LogScale (CrowdStrike LogScale (CQL)) queries. In Sigma terms, this detection targets the
following logsource:
logsource:
category: process_creation
product: windows Browse the community-maintained Sigma rules for this technique:
Platform-specific guides for T1554
References (8)
- https://attack.mitre.org/techniques/T1554/
- https://cloud.google.com/blog/topics/threat-intelligence/uncovering-unc3886-espionage-operations
- https://www.welivesecurity.com/2014/02/21/an-in-depth-analysis-of-linuxebury/
- https://www.mandiant.com/resources/blog/cutting-edge-suspected-apt-targets-ivanti-connect-secure-vpn-zero-day-exploits
- https://web-assets.esetstatic.com/wls/2021/10/eset_fontonlake.pdf
- https://github.com/redcanaryco/atomic-red-team/blob/master/atomics/T1554/T1554.md
- https://learn.microsoft.com/en-us/sysinternals/downloads/sigcheck
- https://man7.org/linux/man-pages/man8/auditd.8.html
Testing Methodology
Validate this detection against 5 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.
- Test 1Replace System Binary with Modified Copy (Windows)
Expected signal: Sysmon Event ID 11: FileCreate targeting C:\Windows\System32\notepad.exe with Image=powershell.exe. Sysmon Event ID 2: FileCreateTime change for notepad.exe if timestamps diverge. DeviceFileEvents ActionType=FileModified with FileName=notepad.exe in SystemBinaryPaths, InitiatingProcessFileName=powershell.exe. SHA256 will not match Microsoft-published hash.
- Test 2Hash Verification and Signature Check Workflow (Windows)
Expected signal: DeviceProcessEvents: powershell.exe executing Get-FileHash and Get-AuthenticodeSignature. No file modification events — this is read-only. Output provides hashes for comparison against Microsoft Security Response Center published values or NSRL hash database.
- Test 3Trojanize SSH Client Binary (Linux)
Expected signal: auditd: SYSCALL record for open(O_WRONLY) on /usr/bin/ssh by root/sudo, comm=cp. Linux syslog: sudo invocation logs showing binary replacement. 'rpm -V openssh-clients' reports 'S.5......' (size and hash mismatch). If MDE Linux agent deployed: DeviceFileEvents ActionType=FileModified for /usr/bin/ssh. After execution, /tmp/.t1554_harvest.log created (Sysmon Event ID 11 equivalent on Linux).
- Test 4Version Lock Compromised Package (Linux — UNC3886 TTP)
Expected signal: Linux syslog/secure: sudo execution of 'yum versionlock openssh-clients' or 'apt-mark hold openssh-client' with effective UID=0. DeviceProcessEvents (MDE Linux): ProcessCommandLine containing 'versionlock' or 'apt-mark hold', AccountName=root or sudo-invoked user. Auditd: EXECVE record for yum/apt-mark with full argument list.
- Test 5Browser Binary Replacement Simulation (macOS — XCSSET TTP)
Expected signal: macOS Unified Log: ES_EVENT_TYPE_NOTIFY_WRITE for /Applications/Firefox.app/Contents/MacOS/firefox from sudo/bash. macOS Gatekeeper: 'codesign --verify /Applications/Firefox.app' reports code signature invalid. If MDE macOS agent deployed: DeviceFileEvents ActionType=FileModified for browser binary path with initiating process=bash/sudo. macOS LaunchServices quarantine: application launch may trigger Gatekeeper alert when modified app is opened.
Response Playbook
Triage
- Compute the SHA256 hash of the modified binary and compare against the expected vendor hash. On Windows: 'Get-FileHash C:\Windows\System32\<binary>.exe -Algorithm SHA256'. On Linux: 'sha256sum /usr/bin/ssh'. A mismatch with the vendor-published hash is a confirmed compromise indicator.
- Verify digital signature integrity. On Windows: run 'Get-AuthenticodeSignature C:\path\to\binary.exe' — Status should be 'Valid' with SignerCertificate matching the vendor. Run 'sigcheck.exe -e -u C:\Windows\System32\' (Sysinternals) to list unsigned/modified executables. On Linux: run 'rpm -V <package>' or 'dpkg --verify <package>' — output 'S.5......' indicates size and MD5 hash mismatch.
- Identify the initiating process that performed the modification. Was it a known updater (msiexec, TrustedInstaller, yum, apt-get), or an unexpected process (bash, python, custom binary, shell)? Unexpected initiators are a strong compromise indicator requiring immediate escalation.
- Review file timestamps: creation time, modification time, last access time. Compare against the last known patch date from change management records. Discrepancies — especially creation timestamps that predate modification timestamps — suggest timestamp manipulation (T1070.006) post-binary-replacement.
- Check file size: a trojanized binary is often larger than the original due to appended malicious code (as in ThiefQuest prepending itself to executables). Compare against the size recorded in vendor documentation or a known-good system snapshot.
- Determine the exposure window — how long was the trojanized binary active? When was the modification detected vs. when did it occur? Check authentication/SSH logs during the exposure window to assess scope of potential credential harvesting.
Containment
- Immediately isolate the affected endpoint from the network via EDR isolation or emergency VLAN quarantine to prevent ongoing credential exfiltration or C2 communication through the trojanized binary.
- If an SSH binary was trojanized: disable the SSH service immediately ('systemctl stop sshd') and treat ALL SSH key pairs and passwords used on or from this host as compromised — initiate enterprise-wide credential rotation for any accounts that authenticated via this host during the exposure window.
- Restore the affected binary from a known-good source: vendor installation media, clean system snapshot, or package manager: 'yum reinstall openssh-clients' / 'apt-get install --reinstall openssh-client' / 'sfc /scannow' on Windows.
- Remove any version locks placed on affected packages to restore normal patching: 'yum versionlock delete <package>' or 'apt-mark unhold <package>'. Verify no additional packages have been inappropriately version-locked.
- Reset credentials for ALL accounts that authenticated via the compromised binary during the exposure window. Prioritize privileged accounts, service accounts, and any accounts with domain admin or root access.
- If a browser was trojanized (XCSSET-style): revoke all active web sessions and OAuth/SAML tokens for the affected user across all services; clear browser credential storage; notify user to change passwords for all services accessed from the affected machine.
Evidence Collection
- Binary hash (SHA256, MD5) of the current on-disk file — the single most critical artifact for confirming compromise. Compute before any remediation.
- File system timestamps: creation time, modification time, last access time — capture with 'stat <binary>' on Linux or '(Get-Item <binary>).LastWriteTime' on Windows before restoring from backup.
- Strings extracted from the modified binary: 'strings <binary> | grep -iE "(password|credential|token|http|connect|socket|exec|base64|/tmp|/dev/shm)"' — identify credential harvesting code or C2 network indicators.
- Linux auditd logs: /var/log/audit/audit.log — search for SYSCALL records with 'open.*O_WRONLY' or 'rename' syscalls targeting the affected binary path, capturing PID, UID, and comm fields.
- Linux package integrity reports: 'rpm -Va > /tmp/rpm_integrity.txt' or 'dpkg --verify > /tmp/dpkg_integrity.txt' — captures ALL modified package files, not just the one already identified.
- Windows Sysmon Event ID 7 (Image Loaded) records showing when the trojanized binary was loaded into processes — identifies the scope of potentially affected sessions.
- Network traffic logs filtered to connections originating from processes running the modified binary — look for outbound connections to external IPs, especially on non-standard ports or using unusual protocols.
- Process execution history from the exposure window: all processes spawned by or from the trojanized binary, including command-line arguments, network connections (Sysmon Event ID 3), and file creations (Sysmon Event ID 11).
- Memory forensics if the binary is currently running: capture a memory dump of the running process ('procdump.exe -ma <pid>' on Windows, 'gcore <pid>' on Linux) — malicious code in memory may differ from an on-disk version that was further obfuscated after initial replacement.
Escalation Criteria
- ! Hash or signature mismatch confirmed — on-disk binary does not match vendor-published hash or package manager checksum, constituting confirmed binary tampering requiring P1 incident response.
- ! Trojanized SSH binary detected — all SSH credentials used on or from this host during the exposure window should be treated as compromised; escalate for enterprise-wide SSH key rotation.
- ! Version-lock detected alongside binary modification — the adversary took deliberate steps to preserve the trojanized binary against updates, indicating a sophisticated, targeted intrusion with intent for long-term persistence.
- ! Multiple systems affected with the same modified binary hash — possible lateral movement, automated deployment of trojanized binary, or supply chain compromise requiring cross-environment investigation.
- ! Trojanized VPN appliance or network device binary (Fortinet, Pulse Secure, Ivanti Connect Secure) — network-level access provides adversary persistent foothold for enterprise-wide lateral movement; treat as critical infrastructure compromise.
- ! Evidence of active credential harvesting: outbound connections from the trojanized binary carrying encoded data, or auxiliary log files showing captured credentials (e.g., /tmp/. hidden files created by modified SSH binary).
Investigation Guide
Forensic Artifacts
- >
Linux: /var/log/audit/audit.log — auditd SYSCALL records for open()/write()/rename() syscalls on monitored binary paths with UID, EUID, comm, and exe fields - >
Linux: Package integrity reports — 'rpm -Va' output (columns: S=size, M=mode, 5=MD5, D=device, L=symlink, U=user, G=group, T=mtime, P=capabilities) or 'dpkg --verify' for Debian-based systems - >
Linux: /var/log/yum.log or /var/log/dpkg.log — package installation/update history to distinguish legitimate updates from binary replacement - >
Linux: /proc/<pid>/exe — symbolic link showing the exact on-disk path of each running process; resolve with 'readlink -f /proc/<pid>/exe' to detect renamed/replaced binaries - >
Windows: Sysmon Event Log (Microsoft-Windows-Sysmon/Operational) — Event ID 2 (file creation time changed), Event ID 11 (file created), Event ID 7 (image loaded with Hashes field for MD5/SHA256) - >
Windows: Authenticode signature verification — 'Get-AuthenticodeSignature <path>' or Sysinternals Sigcheck 'sigcheck.exe -e -u <directory>' to list modified/unsigned executables - >
Windows: C:\Windows\Prefetch\ — prefetch files (.pf) show execution history with timestamps and loaded DLLs for the binary; changes in referenced DLLs across executions may indicate patching - >
Cross-platform: Binary entropy analysis — high-entropy sections appended to normally low-entropy executables indicate embedded encrypted payload (e.g., ThiefQuest prepending encrypted code) - >
Cross-platform: Strings extraction output — compare 'strings' output of the suspicious binary against strings from a known-good version; novel strings (IPs, URLs, credential-related keywords) indicate tampering - >
Network: PCAP from the period after binary modification — filter on connections from processes running the modified binary; look for beaconing patterns, DNS for unusual domains, or data exfiltration sequences
Tuning Guidance
This detection carries significant false positive risk without environment-specific baselining. Start by establishing a hash inventory of all critical executables using a known-good system snapshot or vendor-published hashes — Microsoft publishes expected hashes for Windows system binaries via MSRC, and Linux package managers provide this via RPM/dpkg verification. Build an approved-updater allowlist using exact process paths (not just names) for your software deployment tools: SCCM content paths are typically under C:\Windows\CCM\, Puppet agent runs from C:\Program Files\Puppet Labs\. For Linux environments, deploy auditd watch rules targeting critical binary directories: '-w /usr/bin/ssh -p wa -k t1554_ssh_modify' and '-w /usr/sbin/sshd -p wa -k t1554_sshd_modify'. Enable Sysmon Event ID 2 (File Creation Time Changed) if not already active — this is not in most default Sysmon configs but is critical for detecting binary replacement with timestamp patching. The version-lock hunting query is deliberately low-sensitivity — legitimate admin version locks are rare in well-managed environments and should always correlate with documented change tickets. Consider integrating with a dedicated FIM solution (Tripwire, OSSEC/Wazuh, or Defender FIM in Azure) that maintains hash baselines and fires on deviation rather than relying solely on process-based signals.
Hunting Queries
Hunt for critical system executables modified more than once, or modified by more than one distinct initiating process, within the past 7 days. Legitimate software updates are atomic (one updater, one modification); binary trojanization attacks often produce multiple modification events — one for the initial replacement, and additional events if the adversary re-patches after a partial update or adjusts timestamps.
DeviceFileEvents
| where Timestamp > ago(7d)
| where ActionType in ("FileModified", "FileCreated")
| where FolderPath has_any (
"\\Windows\\System32\\",
"\\Windows\\SysWOW64\\",
"\\Program Files\\OpenSSH\\"
)
| where FileName endswith ".exe" or FileName endswith ".dll"
| where InitiatingProcessFileName !in~ (
"msiexec.exe", "trustedinstaller.exe", "wusa.exe",
"windowsupdate.exe", "svchost.exe"
)
| summarize
ModCount = count(),
UniqueInitiators = dcount(InitiatingProcessFileName),
Initiators = make_set(InitiatingProcessFileName),
Hashes = make_set(SHA256),
EarliestMod = min(Timestamp),
LatestMod = max(Timestamp)
by DeviceName, FileName
| where ModCount > 1 or UniqueInitiators > 1
| sort by ModCount desc index=wineventlog sourcetype="XmlWinEventLog:Microsoft-Windows-Sysmon/Operational" EventCode=11
(TargetFilename="*\\Windows\\System32\\*.exe"
OR TargetFilename="*\\Windows\\SysWOW64\\*.exe"
OR TargetFilename="*\\Program Files\\OpenSSH\\*.exe")
NOT (Image="*\\msiexec.exe" OR Image="*\\TrustedInstaller.exe"
OR Image="*\\wusa.exe" OR Image="*\\svchost.exe")
| stats
count as ModCount,
values(Image) as Initiators,
dc(Image) as UniqueInitiators,
values(Hashes) as Hashes,
earliest(_time) as EarliestMod,
latest(_time) as LatestMod
by host, TargetFilename
| where ModCount > 1 OR UniqueInitiators > 1
| sort - ModCount Hunt for package manager version-lock operations (yum-versionlock, apt-mark hold) occurring within 6 hours of a binary modification on the same host. This pattern — replace-then-lock — is the signature UNC3886 tactic used after trojanizing Fortinet TACACS+ daemons to survive firmware updates. Correlates two independent data sources; a join hit is high-confidence.
// Hunt: Version-lock commands correlated with prior binary modifications
let VersionLocks = DeviceProcessEvents
| where Timestamp > ago(7d)
| where ProcessCommandLine has_any (
"versionlock", "yum-versionlock",
"apt-mark hold", "dpkg --set-selections"
)
| project LockTimestamp=Timestamp, DeviceName, AccountName,
LockCommand=ProcessCommandLine;
let BinaryChanges = DeviceFileEvents
| where Timestamp > ago(7d)
| where ActionType in ("FileModified", "FileCreated")
| where FolderPath has_any ("/usr/bin", "/usr/sbin", "/bin", "/sbin",
"C:\\Windows\\System32\\", "C:\\Program Files\\OpenSSH\\")
| project ChangeTimestamp=Timestamp, DeviceName, FileName, FolderPath, SHA256;
VersionLocks
| join kind=inner BinaryChanges on DeviceName
| where LockTimestamp between (
datetime_add('hour', -6, ChangeTimestamp) .. datetime_add('hour', 6, ChangeTimestamp)
)
| project LockTimestamp, ChangeTimestamp, DeviceName, AccountName,
LockCommand, FileName, FolderPath, SHA256
| sort by LockTimestamp desc index=linux_secure OR index=syslog
(sourcetype=linux_secure OR sourcetype=syslog)
("versionlock" OR "apt-mark hold" OR "dpkg --set-selections")
| eval VersionLockUser=coalesce(user, src_user, "unknown")
| eval VersionLockTime=_time
| table _time, host, VersionLockUser, message
| sort - _time Hunt for network-facing and authentication binaries (SSH, curl, browsers) loading unsigned or invalidly-signed DLLs/modules. A trojanized binary will either have an invalid signature itself or will load additional unsigned malicious libraries. This query catches secondary payload loading — a common pattern where the trojanized binary drops and loads a credential-harvesting module. Use Sysmon Event ID 7 which captures image loads with signature status and hash.
// Hunt: Network-facing and authentication binaries loading unsigned or low-trust modules
DeviceImageLoadEvents
| where Timestamp > ago(7d)
| where InitiatingProcessFileName in~ (
"ssh.exe", "sshd.exe", "sftp.exe",
"curl.exe", "putty.exe", "winscp.exe",
"chrome.exe", "firefox.exe", "msedge.exe"
)
| where IsCertificateValid == false
or IsRootSignerMicrosoft == false
or SHA256 == ""
| summarize
UnsignedLoads = count(),
UnsignedDlls = make_set(FileName),
ProcessHash = take_any(InitiatingProcessSHA256)
by DeviceName, InitiatingProcessFileName, bin(Timestamp, 1d)
| where UnsignedLoads > 0
| sort by UnsignedLoads desc index=wineventlog sourcetype="XmlWinEventLog:Microsoft-Windows-Sysmon/Operational" EventCode=7
(Image="*\\ssh.exe" OR Image="*\\sshd.exe" OR Image="*\\sftp.exe"
OR Image="*\\curl.exe" OR Image="*\\putty.exe"
OR Image="*\\chrome.exe" OR Image="*\\firefox.exe" OR Image="*\\msedge.exe")
(Signed="false" OR SignatureStatus!="Valid")
| eval DllName=mvindex(split(ImageLoaded, "\\"), -1)
| eval TimeBucket=strftime(round(_time/86400)*86400, "%Y-%m-%d")
| stats
count as UnsignedLoads,
values(DllName) as UnsignedDlls,
values(Hashes) as ModuleHashes
by host, Image, TimeBucket
| where UnsignedLoads > 0
| sort - UnsignedLoads Atomic Red Team Tests
Simulates binary trojanization on Windows by appending a benign marker byte sequence to notepad.exe, producing a file with a different hash, and replacing the System32 original. Tests detection of unauthorized binary modification in protected system directories. Requires administrator privileges. Uses a non-functional modification to avoid disrupting system operation.
Command
Copy-Item C:\Windows\System32\notepad.exe C:\Temp\notepad_original_backup.exe
$bytes = [System.IO.File]::ReadAllBytes('C:\Temp\notepad_original_backup.exe')
$marker = [System.Text.Encoding]::ASCII.GetBytes('ARGUS_TEST_MARKER_T1554')
$modifiedBytes = $bytes + $marker
[System.IO.File]::WriteAllBytes('C:\Temp\notepad_modified.exe', $modifiedBytes)
Copy-Item C:\Temp\notepad_modified.exe C:\Windows\System32\notepad.exe -Force
Write-Host 'Original hash:' (Get-FileHash C:\Temp\notepad_original_backup.exe).Hash
Write-Host 'Modified hash:' (Get-FileHash C:\Windows\System32\notepad.exe).Hash Cleanup
Copy-Item C:\Temp\notepad_original_backup.exe C:\Windows\System32\notepad.exe -Force
Remove-Item C:\Temp\notepad_original_backup.exe, C:\Temp\notepad_modified.exe -ErrorAction SilentlyContinue Expected Telemetry
Sysmon Event ID 11: FileCreate targeting C:\Windows\System32\notepad.exe with Image=powershell.exe. Sysmon Event ID 2: FileCreateTime change for notepad.exe if timestamps diverge. DeviceFileEvents ActionType=FileModified with FileName=notepad.exe in SystemBinaryPaths, InitiatingProcessFileName=powershell.exe. SHA256 will not match Microsoft-published hash.
Expected Detection
KQL BinaryModifications arm fires: FileName=notepad.exe in System32 path, InitiatingProcessFileName=powershell.exe (not in LegitUpdaters list). SPL query fires on EventCode=11 with TargetFilename matching System32 pattern and Image=powershell.exe. Signature verification: 'Get-AuthenticodeSignature C:\Windows\System32\notepad.exe' will show Modified/Invalid after the append.
Demonstrates the defender verification workflow for confirming binary integrity — computes SHA256 and verifies Authenticode signature for a system binary. In real investigations, analysts run this immediately upon alert to confirm whether a binary has been tampered with. This test validates that your verification toolchain is operational and establishes a baseline hash for future comparison.
Command
$binaries = @('C:\Windows\System32\notepad.exe', 'C:\Windows\System32\cmd.exe', 'C:\Program Files\OpenSSH\ssh.exe')
foreach ($bin in $binaries) {
if (Test-Path $bin) {
$hash = (Get-FileHash $bin -Algorithm SHA256).Hash
$sig = Get-AuthenticodeSignature $bin
Write-Host "$bin"
Write-Host " SHA256: $hash"
Write-Host " SigStatus: $($sig.Status)"
Write-Host " Signer: $($sig.SignerCertificate.Subject)"
Write-Host ''
}
} Expected Telemetry
DeviceProcessEvents: powershell.exe executing Get-FileHash and Get-AuthenticodeSignature. No file modification events — this is read-only. Output provides hashes for comparison against Microsoft Security Response Center published values or NSRL hash database.
Expected Detection
No alert expected for this defensive verification step. Use SHA256 output values to compare against vendor baselines. A mismatch between this output and vendor-published hashes for the same OS patch level constitutes a confirmed compromise indicator.
Simulates replacement of the SSH client binary on Linux with a backdoored version that logs authentication credentials before passing execution to the original binary (similar to Kobalos and Ebury malware). Creates a wrapper script that mimics credential harvesting behavior using only environment variables — no actual credential theft occurs. Requires root. Run in a test environment only.
Command
sudo cp /usr/bin/ssh /tmp/ssh_original_backup_t1554
cat > /tmp/ssh_trojanized.sh << 'ARGUSEOF'
#!/bin/bash
# T1554 TEST: Simulated credential harvester (no actual credential theft)
LOGFILE="/tmp/.t1554_harvest.log"
echo "[$(date '+%Y-%m-%d %H:%M:%S')] USER=$USER DEST=$@ HOST=$(hostname)" >> "$LOGFILE"
exec /tmp/ssh_original_backup_t1554 "$@"
ARGUSEOF
chmod 755 /tmp/ssh_trojanized.sh
sudo cp /tmp/ssh_trojanized.sh /usr/bin/ssh
sudo chmod 755 /usr/bin/ssh
echo 'SSH binary replaced. Verifying:'
sha256sum /usr/bin/ssh /tmp/ssh_original_backup_t1554
rpm -V openssh-clients 2>/dev/null || dpkg --verify openssh-client 2>/dev/null Cleanup
sudo cp /tmp/ssh_original_backup_t1554 /usr/bin/ssh
sudo chmod 755 /usr/bin/ssh
rm -f /tmp/ssh_original_backup_t1554 /tmp/ssh_trojanized.sh /tmp/.t1554_harvest.log
echo 'Original SSH binary restored and verified:'
sha256sum /usr/bin/ssh Expected Telemetry
auditd: SYSCALL record for open(O_WRONLY) on /usr/bin/ssh by root/sudo, comm=cp. Linux syslog: sudo invocation logs showing binary replacement. 'rpm -V openssh-clients' reports 'S.5......' (size and hash mismatch). If MDE Linux agent deployed: DeviceFileEvents ActionType=FileModified for /usr/bin/ssh. After execution, /tmp/.t1554_harvest.log created (Sysmon Event ID 11 equivalent on Linux).
Expected Detection
KQL BinaryModifications fires if MDE Linux agent is deployed with DeviceFileEvents telemetry for /usr/bin/ssh path. Package integrity check confirms: 'rpm -V openssh-clients' shows size+MD5 mismatch. Auditd rule (if deployed) fires on write syscall to /usr/bin/ssh. SPL linux_secure query matches sudo execution writing to monitored binary path.
Simulates the post-compromise persistence tactic used by UNC3886 — after trojanizing a binary, lock the package version to prevent legitimate updates from overwriting the backdoor. Tests detection of version-lock commands that serve as a persistence indicator even when the binary modification itself is missed. Does NOT modify any binary — this tests only the version-lock signal.
Command
echo '[T1554 Test] Applying version lock to openssh package (simulating UNC3886 post-compromise TTP)'
if command -v yum &>/dev/null; then
sudo yum install -y yum-versionlock 2>/dev/null
sudo yum versionlock openssh-clients
echo 'Applied yum-versionlock to openssh-clients'
sudo yum versionlock list | grep openssh
elif command -v apt-mark &>/dev/null; then
sudo apt-mark hold openssh-client
echo 'Applied apt-mark hold to openssh-client'
apt-mark showhold | grep openssh
else
echo 'Neither yum nor apt-mark found — adjust for this distribution'
fi Cleanup
if command -v yum &>/dev/null; then
sudo yum versionlock delete openssh-clients 2>/dev/null || true
echo 'yum-versionlock removed'
fi
if command -v apt-mark &>/dev/null; then
sudo apt-mark unhold openssh-client 2>/dev/null || true
echo 'apt-mark hold removed'
fi Expected Telemetry
Linux syslog/secure: sudo execution of 'yum versionlock openssh-clients' or 'apt-mark hold openssh-client' with effective UID=0. DeviceProcessEvents (MDE Linux): ProcessCommandLine containing 'versionlock' or 'apt-mark hold', AccountName=root or sudo-invoked user. Auditd: EXECVE record for yum/apt-mark with full argument list.
Expected Detection
KQL VersionLockActivity arm fires: ProcessCommandLine contains 'versionlock' or 'apt-mark hold'. SPL linux_secure query matches syslog message for version lock commands. This is a low false-positive indicator — legitimate version locks are uncommon and should correlate with documented maintenance windows. A version lock without a corresponding change ticket is a high-confidence T1554 indicator.
Simulates the XCSSET malware technique of replacing a browser application executable with a trojanized shell wrapper that logs execution before invoking the original binary. This tests macOS code signature verification, Gatekeeper alerts, and MDE macOS file event detection. Run in a macOS test VM with Firefox installed. Requires sudo.
Command
APP_BINARY='/Applications/Firefox.app/Contents/MacOS/firefox'
if [ ! -f "$APP_BINARY" ]; then
echo 'Firefox not found at expected path. Adjust APP_BINARY for installed browser.'
exit 1
fi
cp "$APP_BINARY" /tmp/firefox_backup_t1554
cat > /tmp/firefox_trojan.sh << 'ARGUSEOF'
#!/bin/bash
# ARGUS_TEST_T1554 — Simulated XCSSET browser replacement
echo "[T1554 TEST $(date)] Exec: $USER@$(hostname) Args: $@" >> /tmp/t1554_browser_harvest.log
exec /tmp/firefox_backup_t1554 "$@"
ARGUSEOF
chmod 755 /tmp/firefox_trojan.sh
sudo cp /tmp/firefox_trojan.sh "$APP_BINARY"
echo 'Browser binary replaced. Signature verification (should show invalid):'
codesign --verify --verbose=2 /Applications/Firefox.app 2>&1 | tail -3 Cleanup
sudo cp /tmp/firefox_backup_t1554 '/Applications/Firefox.app/Contents/MacOS/firefox'
rm -f /tmp/firefox_backup_t1554 /tmp/firefox_trojan.sh /tmp/t1554_browser_harvest.log
echo 'Original Firefox binary restored. Re-verifying:'
codesign --verify --verbose /Applications/Firefox.app 2>&1 | tail -2 Expected Telemetry
macOS Unified Log: ES_EVENT_TYPE_NOTIFY_WRITE for /Applications/Firefox.app/Contents/MacOS/firefox from sudo/bash. macOS Gatekeeper: 'codesign --verify /Applications/Firefox.app' reports code signature invalid. If MDE macOS agent deployed: DeviceFileEvents ActionType=FileModified for browser binary path with initiating process=bash/sudo. macOS LaunchServices quarantine: application launch may trigger Gatekeeper alert when modified app is opened.
Expected Detection
MDE DeviceFileEvents captures modification to browser binary in /Applications path from bash (unexpected updater). 'codesign --verify --verbose /Applications/Firefox.app' output 'code object is not signed at all' or 'a sealed resource is missing or invalid' confirms tampering. KQL BinaryModifications query can be extended to cover macOS /Applications/ paths if MDE macOS agent is deployed.