h0neytr4p

command module
v0.0.0-...-ff6a5e1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 12, 2026 License: Apache-2.0 Imports: 7 Imported by: 0

README

h0neytr4p

h0neytr4p is a lightweight HTTP/HTTPS honeypot for detecting web scanners, recon attempts, exploit probes, and known attack paths without running the real vulnerable applications behind those paths.

This fork is adjusted for T-Pot style deployments and focuses on:

  • Docker and Docker Compose support.
  • JSON logging to a single logfile.
  • Enriched request metadata such as headers, cookies, source IP, destination port, user agent details, and trap metadata.
  • HTTP and HTTPS trap handling on container ports 80 and 443.
  • Payload capture for JSON, form, text, and multipart requests.
  • T-Pot-compatible runtime permissions for log and payload artifacts.

Original h0neytr4p work: pbssubhash/h0neytr4p

How It Works

A trap is a JSON rule that describes:

  • which request should match, for example GET /jenkins;
  • optional headers or parameters that must match;
  • which response should be returned;
  • which trap name, references, and risk metadata should be written to the log.

At startup, h0neytr4p loads all *.json files below traps/. When a request matches a trap, h0neytr4p writes a JSON log entry and returns the configured response. For POST/PUT/DELETE requests, h0neytr4p can also capture request payloads and uploaded files.

Trap definitions live in:

traps/

Response assets referenced by traps live in:

traps/assets/

For trap authoring details, see docs/Creating-Traps.md.

Requirements

For Docker deployments:

  • Docker
  • Docker Compose plugin

For local Go development:

  • Go 1.26 or newer

The Docker build uses:

golang:1.26.4-alpine3.23

Quick Start With Docker

Clone and start the honeypot:

git clone https://github.com/t3chn0m4g3/h0neytr4p
cd h0neytr4p
mkdir -p log payloads
docker compose build
docker compose up

The default docker-compose.yml exposes:

Host port Container port Purpose
80 80 HTTP
443 443 HTTPS
2087 443 WHM-style HTTPS alias for cPanel/WHM probes
8080 80 Alternative HTTP
8443 443 Alternative HTTPS
10443 443 Alternative HTTPS

The container itself only runs HTTP on 80 and HTTPS on 443. Additional host ports such as 2087, 8443, and 10443 are host-side aliases that forward to the HTTPS listener.

The default container command is:

./h0neytr4p \
  -cert=app.crt \
  -key=app.key \
  -log=log/log.json \
  -catchall=false \
  -payload=/opt/h0neytr4p/payloads/ \
  -wildcard=true \
  -traps=traps/

The image generates a self-signed certificate during build. Use curl -k or your browser's certificate exception flow when testing HTTPS locally.

Runtime Paths

The compose file bind-mounts:

Host path Container path Description
./log/ /opt/h0neytr4p/log/ JSON log output
./payloads/ /opt/h0neytr4p/payloads/ Captured upload payloads

Logs are written as JSON lines to:

log/log.json

Captured uploaded files are written to:

payloads/<md5>

The filename is the MD5 hash of the captured file content. Runtime directories and files are chmodded to 0775 so group-based T-Pot processing can read and write them.

Command-Line Flags

Flag Default in binary Default in Docker image Description
-traps Default traps/ Directory containing trap JSON files
-log Default log/log.json JSON-lines logfile path
-payload Default /opt/h0neytr4p/payloads/ Directory for captured files
-cert Default app.crt TLS certificate file
-key Default app.key TLS key file
-catchall true false Capture payloads for all requests, not only known trap method/path combinations
-wildcard false true Load all traps on ports 80 and 443
-verbose true true Print log summaries to stdout

With -wildcard=true, every trap is loaded on both port 80 and port 443, regardless of the port defined in the trap file. With -wildcard=false, traps are loaded only on their configured BasicInfo.Port.

The Docker image uses -wildcard=true by default, so all bundled traps are available through the container's 80 and 443 listeners. Host-side aliases in docker-compose.yml, such as 2087:443, do not create additional listeners inside h0neytr4p.

With -catchall=false, payloads are captured only if the request method and path match at least one configured trap. With -catchall=true, payloads are captured even for unmatched requests.

Logs

Each request produces one JSON object per line. A trapped request includes fields such as:

{
  "timestamp": "2026-06-08T11:31:09Z",
  "src_ip": "172.17.0.1",
  "dest_port": "8443",
  "request_method": "POST",
  "protocol": "https",
  "hostname": "127.0.0.1",
  "request_uri": "/vpns/portal/scripts/newbm.pl",
  "trapped": "true",
  "trapped_for": "CVE-2019-19781",
  "payload_hash_md5": "ba0116a9f1982d6790528a5992c0fe90",
  "payload_filename": "/opt/h0neytr4p/payloads/ba0116a9f1982d6790528a5992c0fe90"
}

Additional fields are added for request headers, cookies, user-agent details, trap references, and risk rating when available.

Payload Capture

Payload capture currently handles:

  • application/json
  • application/x-www-form-urlencoded
  • text/plain
  • multipart/form-data

Size limits:

Payload type Limit
Multipart 101 KiB
JSON, form, text, other body types 11 KiB

If a multipart request contains a file, the file is saved under its MD5 hash in the payload directory and the log entry includes:

  • payload_hash_md5
  • payload_filename
  • payload_mime_type
  • payload_parameter for non-file multipart fields

Creating Or Updating Traps

Minimal trap example:

{
  "BasicInfo": {
    "Name": "jenkins_home",
    "Port": "443",
    "Protocol": "HTTP",
    "MitreAttackTags": "",
    "References": "",
    "RiskRating": "Critical",
    "Description": "Detect Jenkins home path probes"
  },
  "Behaviour": [
    {
      "Request": {
        "Url": "/jenkins*",
        "Method": "GET",
        "Proto": "",
        "Headers": {},
        "Params": {}
      },
      "Response": {
        "StatusCode": 302,
        "Body": "traps/assets/jenkins/default.html",
        "Headers": {},
        "Type": "file"
      },
      "trap": "true"
    }
  ]
}

Notes:

  • Request.Url, Request.Proto, Request.Headers, and Request.Params support glob-style * matching.
  • Request.Proto is optional. Leave it empty or omit it to match any HTTP version, or use values such as HTTP/2* for HTTP/2-specific traps.
  • Request.Headers also supports the virtual key Authorization-Basic-Decoded for matching decoded HTTP Basic auth content without writing decoded credentials to the log.
  • Use {} for empty headers or parameters.
  • Response.Type can be file or string.
  • For file responses, Response.Body is a path relative to the working directory.
  • Restart h0neytr4p after adding or changing trap files.

More detail is available in docs/Creating-Traps.md.

Tests

Go Unit Tests

The Go tests in pkg/ exercise the trap parser and request handler without opening real network listeners.

Run them with a local Go toolchain:

go test ./pkg

Or run them through the same Go Docker image used by the build:

docker run --rm -v "$PWD:/src" -w /src golang:1.26.4-alpine3.23 go test ./pkg

The handler tests cover:

  • text/plain payload capture and matching against trap parameters.
  • JSON payload capture and matching against top-level JSON fields.
  • HTTP protocol matching via Request.Proto, including HTTP/2-specific traps.
  • Decoded HTTP Basic auth matching through Authorization-Basic-Decoded without logging the decoded value.
  • WebDAV COPY/MOVE trap matching for CVE-2026-27654, including rejection when the required Destination header is missing.
  • Method-aware payload preselection, so wildcard traps such as COPY /* do not capture payloads from unrelated methods.
  • Multipart upload capture, MD5-based payload file naming, payload parameter logging, and T-Pot-compatible payload file permissions.

The parser test verifies that invalid trap JSON returns an error instead of terminating the process.

Payload Smoke Test

tests/test-cve-2019-19781-payload.sh sends a multipart upload to the CVE-2019-19781 trap:

POST /vpns/portal/scripts/newbm.pl

With the default docker-compose.yml port mapping, start h0neytr4p and run:

tests/test-cve-2019-19781-payload.sh

The script verifies that:

  • The trap responds with HTTP 200.
  • The uploaded file is written to the payload directory under its MD5 hash.
  • The payload file mode matches the runtime mode (0775).
  • The JSON log contains a matching trapped=true entry for CVE-2019-19781.

Useful overrides:

BASE_URL=https://127.0.0.1:8443 \
LOG_FILE=/path/to/log/log.json \
PAYLOAD_DIR=/path/to/payloads \
CONTAINER_NAME=h0neytr4p \
tests/test-cve-2019-19781-payload.sh

If the host-side log/ or payloads/ paths are not readable because of ownership or group permissions, the script falls back to docker cp from CONTAINER_NAME.

WebDAV CVE Smoke Test

tests/test-cve-2026-27654-webdav.sh sends WebDAV-style requests to the NGINX CVE-2026-27654 trap:

COPY /dav/<run-id>/source.txt?h0neytr4p_test=<run-id>
Destination: https://127.0.0.1:8443/dav/<run-id>/target.txt

MOVE /webdav/<run-id>/source.txt?h0neytr4p_test=<run-id>
Destination: https://127.0.0.1:8443/webdav/<run-id>/target.txt

With the default docker-compose.yml port mapping, run it against a TLS-enabled h0neytr4p instance:

tests/test-cve-2026-27654-webdav.sh

The script verifies that:

  • COPY with Destination responds with HTTP 201 and logs trapped_for=CVE-2026-27654.
  • MOVE with Destination responds with HTTP 201 and logs trapped_for=CVE-2026-27654.
  • COPY without Destination is logged as trapped=false.
Decoded Basic Auth Smoke Test

tests/test-cve-2026-41940-basic-decoded.sh verifies the Authorization-Basic-Decoded matcher used by the cPanel/WHM CVE-2026-41940 trap:

POST /login/?login_only=1&h0neytr4p_test=<run-id>
Authorization: Basic <synthetic-base64-marker>
Cookie: whostmgrsession=<run-id>

With the default docker-compose.yml port mapping, run it against the WHM-style host port 2087, which forwards to the container's HTTPS listener on 443:

tests/test-cve-2026-41940-basic-decoded.sh

The script verifies that:

  • A synthetic decoded Basic Auth marker triggers CVE-2026-41940.
  • A normal admin:admin Basic Auth request with the same path and cookie shape does not trigger the trap.
  • The decoded marker is not written as plaintext into the JSON log entry.

Development Checks

Recommended checks before committing:

go test ./...
go vet ./...
go run golang.org/x/vuln/cmd/govulncheck@latest ./...
find traps -name '*.json' -exec jq empty {} \;
docker compose config
docker build --progress=plain -t h0neytr4p:dev .

If Go is not installed locally, run Go commands through the Go Docker image:

docker run --rm -v "$PWD:/src" -w /src golang:1.26.4-alpine3.23 go test ./...

Troubleshooting

Port already in use

If 80, 443, or the alternate ports are already in use, change the host-side port in docker-compose.yml, for example:

ports:
  - "8080:80"
  - "8443:443"

Then test with:

BASE_URL=http://127.0.0.1:8080 tests/test-cve-2019-19781-payload.sh
Payload file not visible on the host

Check that the compose volume points to the directory you are inspecting:

volumes:
  - ./payloads/:/opt/h0neytr4p/payloads/

If ownership or group permissions prevent direct host access, use the smoke test's CONTAINER_NAME fallback or inspect from inside the container.

HTTPS certificate warning

The Docker image uses a self-signed certificate generated at build time. This is expected for local testing. Use curl -k or provide your own -cert and -key files.

Credits

This fork is adjusted for T-Pot by t3chn0m4g3.

Original h0neytr4p:

Documentation

The Go Gopher

There is no documentation for this package.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL