Skip to content

ruzickap/malware-cryptominer-container

Repository files navigation

Container image with malware and crypto miner for testing purposes

Artifact Hub Container build Docker Image Size (latest semver) GitHub release (latest SemVer)

Ransomware Malware Threat Actor

I decided to build minimal nginx based container image which contains malware / ransomware / crypto miner / ...

Security tools should be able to scan the image and discover harmful files.

Running/starting the container image do not "activate" / "execute" the malware.

The malware files inside container image were downloaded from:

The malware/crypto miner files are located in the /usr/share/nginx/html directory:

/usr/share/nginx/html
├── eicar
│   ├── eicar.com                        [EICAR virus test files]
│   ├── eicar.com.txt                    [EICAR virus test files]
│   └── eicarcom2.zip                    [Zip archive data, at least v1.0 to extract]
├── malware
│   ├── ILOVEYOU.vbs                     [C source, ASCII text]
│   ├── Invoke-ConPtyShell.ps1           [ASCII text, with very long lines (361)]
│   ├── L0Lz.bat                         [DOS batch file, ASCII text]
│   ├── Linux.Trojan.Multiverze.elf.x86  [ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), statically linked, with debug_info, not stripped]
│   ├── MadMan.exe                       [MS-DOS executable, MZ for MS-DOS]
│   ├── Melissa.doc                      [Composite Document File V2 Document, Little Endian, Os: Windows, Version 4.10, Code page: 1252, Title: Password List for March 26th 1999, Subject: Adult Website Passwords, Author: John Holmes, Keywords: 73 sites in this list, Comments: Password List for March 26th 1999, Template: Normal.dot, Last Saved By: Him, Revision Number: 2, Name of Creating Application: Microsoft Word 8.0, Create Time/Date: Fri Mar 26 11:39:00 1999, Last Saved Time/Date: Fri Mar 26 11:39:00 1999, Number of Pages: 2, Number of Words: 745, Number of Characters: 4249, Security: 0]
│   ├── Py.Trojan.NecroBot.py            [Python script, ASCII text executable, with very long lines (4330), with CRLF line terminators]
│   ├── Trojan.Java.Fractureiser.MTB.jar [Java archive data (JAR)]
│   ├── TrojanSpy.MacOS.XCSSET.A.bin     [Mach-O 64-bit x86_64 executable, flags:<NOUNDEFS|DYLDLINK|TWOLEVEL|PIE>]
│   ├── Txt.Malware.Sustes.sh            [Bourne-Again shell script, ASCII text executable]
│   ├── Unix.Downloader.Rocke.sh         [POSIX shell script, ASCII text executable]
│   ├── Unix.Malware.Kaiji.elf.arm       [ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), statically linked, Go, stripped]
│   ├── Unix.Trojan.Mirai.elf.m68k       [ELF 32-bit MSB executable, Motorola m68k, 68020, version 1 (SYSV), statically linked, stripped]
│   ├── Unix.Trojan.Mirai.elf.mips       [ELF 32-bit MSB executable, MIPS, MIPS-I version 1 (SYSV), statically linked, not stripped]
│   ├── Unix.Trojan.Mirai.elf.ppc        [ELF 32-bit MSB executable, PowerPC or cisco 4500, version 1 (SYSV), statically linked, not stripped]
│   ├── Unix.Trojan.Mirai.elf.sparc      [ELF 32-bit MSB executable, SPARC, version 1 (SYSV), statically linked, not stripped]
│   ├── Unix.Trojan.Mirai.elf.x86_64     [ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, stripped]
│   ├── Unix.Trojan.Spike.elf.arm        [ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), statically linked, for GNU/Linux 2.6.16, with debug_info, not stripped]
│   ├── Walker.com                       [DOS executable (COM), start instruction 0xe9cd04e8 5400e871]
│   ├── WannaCry.exe                     [PE32 executable (GUI) Intel 80386, for MS Windows, 4 sections]
│   ├── Win.Trojan.Perl.perl             [Perl script text executable]
│   └── Zloader.xlsm                     [Microsoft Excel 2007+]
└── xmrig
    ├── my-xmrig                         [ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, stripped]
    ├── xmrig                            [ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, stripped]
    └── xmrig-linux-static-x64.tar.gz    [gzip compressed data, from Unix, original size modulo 2^32 8291840]

List of malware/ransomware/crypto miner files:

Deployment of the vulnerable image

There are several ways how to run the "malware container image" and there are few of them.

Note: Running the container image is not harmful for the host system.

CloudFormation - EC2 instance

Run the EC2 instance with docker and the quay.io/petr_ruzicka/malware-cryptominer-container container with SSM enabled (only console access):

export AWS_DEFAULT_REGION="eu-central-1"

aws cloudformation deploy --capabilities CAPABILITY_IAM \
  --stack-name "${USER}-malware-cryptominer-container-ec2" \
  --parameter-overrides "ContainerImage=quay.io/petr_ruzicka/malware-cryptominer-container:3" \
  --template-file EC2InstanceWithDockerSample.yaml \
  --tags "Name=${USER}-malware-cryptominer-container-ec2"

# aws cloudformation delete-stack --stack-name ${USER}-malware-cryptominer-container-ec2

Amazon ECS

Copilot example:

export AWS_DEFAULT_REGION="eu-central-1"

copilot init --app "${USER}-malware-cryptominer-app" --name "${USER}-malware-cryptominer" \
  --image quay.io/petr_ruzicka/malware-cryptominer-container:3 \
  --type 'Load Balanced Web Service' --port 8080 --deploy

# copilot app delete --name "${USER}-malware-cryptominer-app"

Amazon EKS

Run simple Amazon EKS cluster with "malware pod":

export AWS_DEFAULT_REGION="eu-central-1"
export CLUSTER_NAME="${USER}-malware-cryptominer-eks"
export KUBECONFIG="/tmp/kubeconfig-${CLUSTER_NAME}.conf"

eksctl create cluster --name "${CLUSTER_NAME}" --instance-types t3a.small --kubeconfig "${KUBECONFIG}"
kubectl run malware-cryptominer --image=quay.io/petr_ruzicka/malware-cryptominer-container:3

# eksctl delete cluster --name "${CLUSTER_NAME}"

Scanner tests

Details from various scanner tests (Aqua, Trivy, Prisma Cloud, Wiz.io, Grype, Snyk) can be found in Scanner tests

Verify image integrity

CONTAINER_REGISTRY_IMAGE_NAME="quay.io/petr_ruzicka/malware-cryptominer-container"
CONTAINER_IMAGE_TAG="3"
CONTAINER_IMAGE_DIGEST=$(regctl image digest "${CONTAINER_REGISTRY_IMAGE_NAME}:${CONTAINER_IMAGE_TAG}")
CONTAINER_REGISTRY_IMAGE="${CONTAINER_REGISTRY_IMAGE_NAME}@${CONTAINER_IMAGE_DIGEST}"
COSIGN_CERTIFICATE_IDENTITY_REGEXP="https://github.com/ruzickap/malware-cryptominer-container/.github/workflows"
COSIGN_CERTIFICATE_OIDC_ISSUER="https://token.actions.githubusercontent.com"
COSIGN_ATTESTATION_TYPE="https://cyclonedx.org/bom"
CONTAINER_IMAGE_PLATFORMS="linux/amd64,linux/arm64"

# Verify the manifest list is signed
cosign verify \
  --certificate-identity-regexp="${COSIGN_CERTIFICATE_IDENTITY_REGEXP}" \
  --certificate-oidc-issuer="${COSIGN_CERTIFICATE_OIDC_ISSUER}" \
  "${CONTAINER_REGISTRY_IMAGE}" | jq --color-output

# Verify if every platfrom image manifest is signed
while read -r MANIFEST_DIGESTS; do
  cosign verify \
    --certificate-identity-regexp="${COSIGN_CERTIFICATE_IDENTITY_REGEXP}" \
    --certificate-oidc-issuer="${COSIGN_CERTIFICATE_OIDC_ISSUER}" \
    "${CONTAINER_REGISTRY_IMAGE_NAME}@${MANIFEST_DIGESTS}" | jq --color-output
done <<< "$(regctl manifest get "${CONTAINER_REGISTRY_IMAGE}" --format '{{jsonPretty .}}' | jq -r '.manifests[].digest')"

cosign verify-attestation --type="${COSIGN_ATTESTATION_TYPE}" \
  --certificate-oidc-issuer="${COSIGN_CERTIFICATE_OIDC_ISSUER}" \
  --certificate-identity-regexp="${COSIGN_CERTIFICATE_IDENTITY_REGEXP}" \
  "${CONTAINER_REGISTRY_IMAGE}" | jq --color-output '.payload |= .[:2000] + "...<rest_is_removed>..."' --color-output

cosign verify-attestation --type="${COSIGN_ATTESTATION_TYPE}" \
  --certificate-oidc-issuer="${COSIGN_CERTIFICATE_OIDC_ISSUER}" \
  --certificate-identity-regexp="${COSIGN_CERTIFICATE_IDENTITY_REGEXP}" \
  "${CONTAINER_REGISTRY_IMAGE}" | jq '.payload | @base64d | fromjson | .predicate' | grype

for PLATFORM in ${CONTAINER_IMAGE_PLATFORMS//,/ }; do
  cosign download attestation --platform="${PLATFORM}" --predicate-type="${COSIGN_ATTESTATION_TYPE}" \
    "${CONTAINER_REGISTRY_IMAGE}" | jq -r .payload | base64 -d | jq .predicate | grype --add-cpes-if-none
done

cosign verify-attestation --type="slsaprovenance" \
  --certificate-oidc-issuer="${COSIGN_CERTIFICATE_OIDC_ISSUER}" \
  --certificate-identity-regexp='^https://github.com/slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@refs/tags/v[0-9]+.[0-9]+.[0-9]+$' \
  "${CONTAINER_REGISTRY_IMAGE}" | jq --color-output

slsa-verifier verify-image --print-provenance --source-uri "github.com/ruzickap/malware-cryptominer-container" \
  "${CONTAINER_REGISTRY_IMAGE}" | jq --color-output

cosign tree "${CONTAINER_REGISTRY_IMAGE}"

Local tests

Container build:

docker build . -t malware-cryptominer-container

Run container and download the malware file:

docker run -it --rm -p 8080:8080 malware-cryptominer-container

curl http://localhost:8080/eicar/

Debug container:

docker run -it --rm --entrypoint=/bin/sh --user root malware-cryptominer-container

Run in Kubernetes:

kubectl run malware-cryptominer --image=quay.io/petr_ruzicka/malware-cryptominer-container:3