Detect Malicious Library in IBM QRadar
Adversaries may rely on a user installing a malicious library to facilitate execution. Threat actors upload malware to package managers such as NPM and PyPI, or backdoor existing popular libraries through supply chain compromise. Users install these libraries without realizing they are malicious, bypassing initial access controls. Execution occurs via setup.py install-time scripts (Python), postinstall/preinstall lifecycle hooks (NPM/yarn), or malicious code embedded in library modules that executes on import. Common delivery vectors include typosquatting (e.g., 'reqeusts' vs 'requests'), dependency confusion attacks, compromised maintainer accounts, and first-use namespace squatting. Threat actors including Contagious Interview have leveraged malicious NPM and Python packages published to public registries to deliver infostealers, remote access tools, and BeaverTail/InvisibleFerret malware targeting software developers.
MITRE ATT&CK
- Tactic
- Execution
- Technique
- T1204 User Execution
- Sub-technique
- T1204.005 Malicious Library
- Canonical reference
- https://attack.mitre.org/techniques/T1204/005/
QRadar Detection Query
-- Branch 1: Package manager spawning suspicious child processes
SELECT
DATEFORMAT(devicetime, 'yyyy-MM-dd HH:mm:ss') AS event_time,
'PackageInstallSpawnedSuspiciousProcess' AS detection_branch,
logsourceid,
"username" AS account_name,
"hostname" AS device_name,
QIDNAME(qid) AS event_name,
"sourceip",
UTF8(payload) AS raw_payload
FROM events
WHERE LOGSOURCETYPEID = 12 -- Microsoft Windows
AND devicetime > (CURRENT_TIMESTAMP - 86400000)
AND eventid = 1 -- Sysmon Process Create
AND (
LOWER("ParentImage") LIKE '%\pip.exe'
OR LOWER("ParentImage") LIKE '%\pip3.exe'
OR LOWER("ParentImage") LIKE '%\python.exe'
OR LOWER("ParentImage") LIKE '%\python3.exe'
OR LOWER("ParentImage") LIKE '%\node.exe'
OR LOWER("ParentImage") LIKE '%\npm.cmd'
OR LOWER("ParentCommandLine") LIKE '%pip install%'
OR LOWER("ParentCommandLine") LIKE '%pip3 install%'
OR LOWER("ParentCommandLine") LIKE '%npm install%'
OR LOWER("ParentCommandLine") LIKE '%npm ci%'
OR LOWER("ParentCommandLine") LIKE '%yarn add%'
OR LOWER("ParentCommandLine") LIKE '%setup.py%'
)
AND (
LOWER("Image") LIKE '%\cmd.exe'
OR LOWER("Image") LIKE '%\powershell.exe'
OR LOWER("Image") LIKE '%\pwsh.exe'
OR LOWER("Image") LIKE '%\mshta.exe'
OR LOWER("Image") LIKE '%\rundll32.exe'
OR LOWER("Image") LIKE '%\certutil.exe'
OR LOWER("Image") LIKE '%\bitsadmin.exe'
OR LOWER("Image") LIKE '%\wscript.exe'
OR LOWER("Image") LIKE '%\cscript.exe'
OR LOWER("Image") LIKE '%\regsvr32.exe'
OR LOWER("Image") LIKE '%\msiexec.exe'
OR LOWER("Image") LIKE '%\schtasks.exe'
OR LOWER("Image") LIKE '%\sc.exe'
OR LOWER("Image") LIKE '%\reg.exe'
)
UNION ALL
-- Branch 2: Python/Node C2 callback on non-standard ports
SELECT
DATEFORMAT(devicetime, 'yyyy-MM-dd HH:mm:ss') AS event_time,
'MaliciousLibraryC2Callback' AS detection_branch,
logsourceid,
"username" AS account_name,
"hostname" AS device_name,
QIDNAME(qid) AS event_name,
"sourceip",
UTF8(payload) AS raw_payload
FROM events
WHERE LOGSOURCETYPEID = 12
AND devicetime > (CURRENT_TIMESTAMP - 86400000)
AND eventid = 3 -- Sysmon Network Connect
AND (
LOWER("Image") LIKE '%\python.exe'
OR LOWER("Image") LIKE '%\python3.exe'
OR LOWER("Image") LIKE '%\node.exe'
)
AND destinationport NOT IN (80, 443, 8080, 8443)
AND NOT INCIDR(destinationip, '10.0.0.0/8')
AND NOT INCIDR(destinationip, '172.16.0.0/12')
AND NOT INCIDR(destinationip, '192.168.0.0/16')
AND NOT INCIDR(destinationip, '127.0.0.0/8')
AND NOT (
LOWER("DestinationHostname") LIKE '%pypi.org'
OR LOWER("DestinationHostname") LIKE '%pythonhosted.org'
OR LOWER("DestinationHostname") LIKE '%npmjs.com'
OR LOWER("DestinationHostname") LIKE '%github.com'
OR LOWER("DestinationHostname") LIKE '%githubusercontent.com'
OR LOWER("DestinationHostname") LIKE '%anaconda.com'
OR LOWER("DestinationHostname") LIKE '%yarnpkg.com'
)
UNION ALL
-- Branch 3: Package installer dropping executables in sensitive locations
SELECT
DATEFORMAT(devicetime, 'yyyy-MM-dd HH:mm:ss') AS event_time,
'PackageInstallerDroppedExecutable' AS detection_branch,
logsourceid,
"username" AS account_name,
"hostname" AS device_name,
QIDNAME(qid) AS event_name,
"sourceip",
UTF8(payload) AS raw_payload
FROM events
WHERE LOGSOURCETYPEID = 12
AND devicetime > (CURRENT_TIMESTAMP - 86400000)
AND eventid = 11 -- Sysmon File Create
AND (
LOWER("Image") LIKE '%\python.exe'
OR LOWER("Image") LIKE '%\python3.exe'
OR LOWER("Image") LIKE '%\node.exe'
OR LOWER("Image") LIKE '%\pip.exe'
OR LOWER("Image") LIKE '%\pip3.exe'
)
AND (
LOWER("TargetFilename") LIKE '%.exe'
OR LOWER("TargetFilename") LIKE '%.dll'
OR LOWER("TargetFilename") LIKE '%.bat'
OR LOWER("TargetFilename") LIKE '%.ps1'
OR LOWER("TargetFilename") LIKE '%.vbs'
OR LOWER("TargetFilename") LIKE '%.scr'
)
AND (
LOWER("TargetFilename") LIKE '%\startup\%'
OR LOWER("TargetFilename") LIKE '%appdata\local\temp\%'
OR LOWER("TargetFilename") LIKE '%windows\temp\%'
OR LOWER("TargetFilename") LIKE '%system32\%'
OR LOWER("TargetFilename") LIKE '%syswow64\%'
OR LOWER("TargetFilename") LIKE '%\programdata\%'
)
ORDER BY event_time DESC Three-branch AQL detection for malicious library execution on IBM QRadar using Sysmon event data. Branch 1 identifies package manager parents (pip, npm, node, yarn) spawning Windows living-off-the-land binaries during install-time hooks. Branch 2 catches Python or Node establishing outbound connections on non-HTTP ports to non-trusted public IPs — a pattern consistent with C2 callbacks embedded in malicious library code that executes on import. Branch 3 identifies package runtimes writing executable or script artifacts to persistence-relevant paths (Startup, System32, ProgramData, Temp directories).
Data Sources
Required Tables
False Positives & Tuning
- Native Python extension compilation during legitimate package installation (e.g., numpy, scipy, cryptography) may invoke cmd.exe or MSVC build tools. These will trigger Branch 1. Whitelist by adding known compiler binaries to an exclusion reference set.
- Node.js desktop applications or Electron apps making non-standard port outbound connections to vendor APIs or telemetry services will trigger Branch 2. Suppress by creating a QRadar reference set of approved application process hashes.
- Legitimate Python-based deployment tools (Ansible, SaltStack, Fabric) may drop .ps1 or .bat files into temp directories as part of legitimate automation workflows. Tune by correlating with known service account identities.
- Development workstations running comprehensive npm test suites that invoke powershell.exe for Windows-specific integration tests will generate Branch 1 false positives. Consider excluding devices tagged as dev machines in the asset database.
Other platforms for T1204.005
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 1Malicious Python Package via Local pip install (setup.py subprocess spawn)
Expected signal: Sysmon Event ID 1: Process Create with ParentImage=python.exe (pip runner), Image=cmd.exe, CommandLine containing 'whoami'. DeviceProcessEvents: InitiatingProcessFileName=python.exe with CommandLine containing 'setup.py', FileName=cmd.exe. The process tree root will be pip.exe -> python.exe -> cmd.exe.
- Test 2Malicious NPM Package with Postinstall Hook (Linux/macOS)
Expected signal: Sysmon for Linux or auditd: process creation with parent=node (npm runner), child=sh, CommandLine containing 'id > /tmp/npm_postinstall_test.txt'. If Sysmon for Linux is deployed: EventID=1, ParentImage path contains node, Image=/bin/sh. Linux audit log: execve syscall with parent node process.
- Test 3Python Library C2 Callback Simulation (Non-Standard Port)
Expected signal: Sysmon Event ID 3: Network Connection with Image=python.exe, DestinationIp=127.0.0.1, DestinationPort=4444. DeviceNetworkEvents: InitiatingProcessFileName=python.exe, RemotePort=4444. The connection will fail with ECONNREFUSED but the outbound attempt is still logged.
- Test 4Malicious Python Library Dropping Persistence Script to Startup Folder
Expected signal: Sysmon Event ID 11: File Create with Image=python.exe, TargetFilename=%APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup\df00tech_test_persistence.vbs. DeviceFileEvents: InitiatingProcessFileName=python.exe, FileName=df00tech_test_persistence.vbs, FolderPath contains Startup.
- Test 5Simulated Typosquat Package Python Credential Harvester
Expected signal: Sysmon Event ID 15 (FileCreateStreamHash) or Event ID 11 if file is created. DeviceFileEvents: InitiatingProcessFileName=python.exe accessing FolderPath containing 'Google\Chrome\User Data'. This also fires the hunting query for credential store access.
References (10)
- https://attack.mitre.org/techniques/T1204/005/
- https://securitylabs.datadoghq.com/articles/malicious-pypi-package-targeting-highly-specific-macos-machines/
- https://www.fortinet.com/blog/threat-research/malicious-packages-hiddin-in-npm
- https://www.sentinelone.com/labs/contagious-interview-north-korean-threat-actors-use-clickfix-to-deliver-updated-eavesdropper-malware/
- https://docs.microsoft.com/en-us/microsoft-365/security/defender-endpoint/advanced-hunting-devicenetworkevents-table
- https://docs.microsoft.com/en-us/microsoft-365/security/defender-endpoint/advanced-hunting-devicefileevents-table
- https://github.com/redcanaryco/atomic-red-team/blob/master/atomics/T1204.005/T1204.005.md
- https://osv.dev
- https://pypi.org/project/pip-audit/
- https://docs.npmjs.com/cli/v10/commands/npm-audit
Unlock Pro Content
Get the full detection package for T1204.005 including response playbook, investigation guide, and atomic red team tests.