AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

Recon Active

skill-thapr0digy-skills-recon-active · by thapr0digy

Authorized asset discovery — network service enumeration, technology fingerprinting, security configuration analysis, and infrastructure mapping. Invoke via /recon-active [target].

— No reviews yet
0 installs
31 views
0.0% view→install

Install

$ agentstack add skill-thapr0digy-skills-recon-active

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • ✓ Prompt-injection patterns
  • ✓ Secret / credential exfiltration
  • ✓ Dangerous shell & filesystem operations
  • ✓ Untrusted network calls
  • ✓ Known-malicious package signatures

What it can access

  • ● Network access Used
  • ✓ Filesystem access No
  • ✓ Shell / process execution No
  • ✓ Environment & secrets No
  • ✓ Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-thapr0digy-skills-recon-active)

Reliability & compatibility

✓ Security review passed
0 installs to date
— no reviews yet
○ 4mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Recon Active? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

@pentest-core/skills/shared/engagement-resolver.md @pentest-core/skills/shared/scope-validator.md @pentest-core/skills/shared/remote-exec.md @pentest-core/skills/shared/activity-log.md

/recon-active — Authorized Asset Discovery

You are performing authorized asset discovery and security assessment on approved infrastructure. You conduct network service enumeration and security configuration analysis to build comprehensive asset profiles: service inventory, technology stack, security configurations, and compliance status. Every target must pass scope validation before assessment begins.


Step 1: Resolve Active Engagement

Run the engagement resolver block verbatim before any other logic.

# --- Engagement Resolver ---
ENGAGEMENT_JSON=$(cat ~/.pentest/active-engagement 2>/dev/null)

if [ -z "$ENGAGEMENT_JSON" ]; then
  echo "No active engagement found. Run /pentest-init or /pentest-switch." >&2
  exit 1
fi

if [ ! -f "$ENGAGEMENT_JSON" ]; then
  echo "Active engagement path '$ENGAGEMENT_JSON' does not exist. Run /pentest-switch." >&2
  exit 1
fi

ENGAGEMENT_ID=$(jq -r '.engagement_id' "$ENGAGEMENT_JSON")
OUTPUT_DIR=$(jq -r '.output_dir' "$ENGAGEMENT_JSON")
ASSESSOR=$(whoami)

ASSESSOR_MATCH=$(jq -r --arg h "$ASSESSOR" '.security assessors[] | select(.handle == $h) | .handle' "$ENGAGEMENT_JSON")
if [ -z "$ASSESSOR_MATCH" ]; then
  echo "Operator '$ASSESSOR' is not registered on this engagement." >&2
  exit 1
fi
# --- End Engagement Resolver ---

After this block, $ENGAGEMENT_ID, $OUTPUT_DIR, and $ASSESSOR are guaranteed set and valid. If the resolver fails for any reason, stop and tell the user to run /pentest-init.


Step 2: Parse Arguments and Determine Targets

Accepted input formats

  • IP address — e.g., 10.0.0.1
  • CIDR range — e.g., 10.0.0.0/24
  • Domain — e.g., app.acme.com
  • File path — e.g., @/path/to/hosts.txt — one target per line
ARG="${1:-}"   # first argument passed to the skill

if [ -n "$ARG" ]; then
  TARGET="$ARG"
elif ls "${OUTPUT_DIR}/recon/passive-"*.json > /dev/null 2>&1; then
  # Fall back to most recent passive recon output — extract discovered hosts
  PASSIVE_FILE=$(ls -t "${OUTPUT_DIR}/recon/passive-"*.json | head -1)
  echo "No target specified — using discovered hosts from $PASSIVE_FILE"
  TARGET="$(jq -r '.sections.resolved_hosts // empty' "$PASSIVE_FILE" 2>/dev/null)"
  # If the passive file has a resolved hosts file reference, use scope.in_scope as fallback
  if [ -z "$TARGET" ]; then
    TARGET=$(jq -r '.scope.in_scope[]' "$ENGAGEMENT_JSON" 2>/dev/null | head -20 | tr '\n' ',')
  fi
else
  # No arg and no passive recon — fall back to scope
  TARGET=$(jq -r '.scope.in_scope[]' "$ENGAGEMENT_JSON" 2>/dev/null | tr '\n' '\n')
  if [ -z "$TARGET" ]; then
    echo "No target provided and no in-scope entries found. Provide a target: /recon-active " >&2
    exit 1
  fi
fi

If the argument begins with @, treat the remainder as a file path and read targets from it:

if echo "$ARG" | grep -q '^@'; then
  HOSTS_FILE="${ARG#@}"
  if [ ! -f "$HOSTS_FILE" ]; then
    echo "Hosts file not found: $HOSTS_FILE" >&2
    exit 1
  fi
  TARGET="$HOSTS_FILE"
  TARGET_IS_FILE=true
fi

Determine remote host

# Check if the engagement has a configured default remote host
DEFAULT_HOST=$(jq -r '.remote_hosts | keys[0] // "local"' "$ENGAGEMENT_JSON" 2>/dev/null)
HOST_NAME="${HOST_NAME:-${DEFAULT_HOST:-local}}"

If $HOST_NAME resolves to local (no remote hosts configured), all commands execute in the current shell.

Full scope validation

For each target, run complete scope validation per scope-validator.md. For active recon, perform all checks including the testing window check — active scans generate traffic and must respect testing windows.

# Normalize target
TARGET_ORIG="$TARGET"

if echo "$TARGET" | grep -qE '^https?://'; then
  TARGET_HOST=$(python3 -c "from urllib.parse import urlparse; print(urlparse('$TARGET').hostname)")
else
  TARGET_HOST="$TARGET"
fi

# Resolve hostname to IPs (skip for CIDRs and bare IPs, and for files)
if [ "${TARGET_IS_FILE:-false}" = "false" ]; then
  if echo "$TARGET_HOST" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+(\/[0-9]+)?$'; then
    TARGET_IPS="$TARGET_HOST"
  else
    TARGET_IPS=$(dig +short "$TARGET_HOST" | grep -E '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$')
  fi
fi

# Check out-of-scope (hard block)
OUT_OF_SCOPE=$(jq -r '.scope.out_of_scope[]' "$ENGAGEMENT_JSON" 2>/dev/null)

# Check in-scope (confirm or warn if unlisted)
IN_SCOPE=$(jq -r '.scope.in_scope[]' "$ENGAGEMENT_JSON" 2>/dev/null)

# Check testing window
WINDOWS=$(jq -c '.roe.testing_windows' "$ENGAGEMENT_JSON" 2>/dev/null)
TIMEZONE=$(jq -r '.roe.timezone // "UTC"' "$ENGAGEMENT_JSON" 2>/dev/null)

Apply all matching rules from scope-validator.md. Log every scope check outcome to ${OUTPUT_DIR}/activity.log using action: "scope_check".

When processing multiple targets (CIDR or file), validate each target individually before running any scan against it. Do not batch-validate.

Create output directories:

mkdir -p "${OUTPUT_DIR}/recon"
mkdir -p "${OUTPUT_DIR}/evidence/screenshots"
RECON_DIR="${OUTPUT_DIR}/recon"
TIMESTAMP=$(date -u +"%Y%m%dT%H%M%SZ")

Step 3: Check Tool Availability

Check each tool with which 2>/dev/null. Do not abort if a tool is missing — skip that step, note the gap in output, and continue. Log every check.

| Tool | Steps | Priority | |---|---|---| | naabu | 4 — Port Scanning | Required (one of naabu/service discovery) | | Network Discovery | 5 — Service Fingerprinting | Required (one of naabu/service discovery) | | httpx | 6 — HTTP Probing | Recommended | | whatweb | 7 — Web Technology Detection | Optional | | wafw00f | 8 — WAF Detection | Optional | | gowitness | 9 — Web Screenshots | Recommended — always run when web services found | | tlsx | 10 — SSL/TLS Scanning | Recommended — always run when web services found |

declare -A TOOL_AVAILABLE

for TOOL in naabu nmap httpx whatweb wafw00f gowitness tlsx; do
  if which "$TOOL" > /dev/null 2>&1; then
    TOOL_AVAILABLE[$TOOL]=true
    jq -nc \
      --arg ts "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \
      --arg security assessor "$ASSESSOR" \
      --arg action "tool_check" \
      --arg command "which $TOOL" \
      --arg status "completed" \
      --arg result "available" \
      '{ts:$ts, security assessor:$security assessor, action:$action, command:$command, status:$status, result:$result}' \
      >> "${OUTPUT_DIR}/activity.log"
  else
    TOOL_AVAILABLE[$TOOL]=false
    jq -nc \
      --arg ts "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \
      --arg security assessor "$ASSESSOR" \
      --arg action "tool_check" \
      --arg command "which $TOOL" \
      --arg status "skipped" \
      --arg result "not found" \
      '{ts:$ts, security assessor:$security assessor, action:$action, command:$command, status:$status, result:$result}' \
      >> "${OUTPUT_DIR}/activity.log"
  fi
done

If naabu and the network service discovery tool are both missing, abort — the skill cannot perform meaningful port scanning without at least one of them.


Step 4: Port Scanning with naabu (Two-Phase)

Skip this step if naabu is not available and note the gap. If skipped, proceed directly to Step 5 (nmap will perform its own two-phase port discovery).

Always run both phases automatically:

  • Phase 1 (Quick) — top 1000 ports, synchronous. Results feed immediately into Steps 5–11 so useful work starts right away.
  • Phase 2 (Full) — all 65535 ports, asynchronous in tmux. Catches services on non-standard ports (backdoors, debug interfaces, custom apps).

Phase 1: Quick scan (synchronous)

NAABU_OUT="${RECON_DIR}/naabu-${ASSESSOR}-$(date +%s).txt"
CMD="naabu -host ${TARGET} -top-ports 1000 -silent -o ${NAABU_OUT}"

jq -nc \
  --arg ts "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \
  --arg security assessor "$ASSESSOR" \
  --arg action "scan" \
  --arg target "$TARGET" \
  --arg command "$CMD" \
  --arg status "dispatched" \
  '{ts:$ts, security assessor:$security assessor, action:$action, target:$target,
    command:$command, status:$status}' \
  >> "${OUTPUT_DIR}/activity.log"

$CMD

jq -nc \
  --arg ts "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \
  --arg security assessor "$ASSESSOR" \
  --arg action "scan" \
  --arg target "$TARGET" \
  --arg command "$CMD" \
  --arg status "$([ $? -eq 0 ] && echo completed || echo failed)" \
  --arg output_file "$NAABU_OUT" \
  '{ts:$ts, security assessor:$security assessor, action:$action, target:$target,
    command:$command, status:$status, output_file:$output_file}' \
  >> "${OUTPUT_DIR}/activity.log"

Phase 2: Full scan (asynchronous — tmux)

Always launch Phase 2 immediately after Phase 1 completes. This runs in the background while Steps 5–11 proceed using Phase 1 results.

NAABU_FULL_OUT="${RECON_DIR}/naabu-full-${ASSESSOR}-$(date +%s).txt"
CMD="naabu -host ${TARGET} -p - -silent -o ${NAABU_FULL_OUT}"

SESSION_NAME="${ENGAGEMENT_ID}-naabu-full-$(date +%s)"

# Dispatch per remote-exec.md — SSH, SSM, or local depending on $HOST_NAME
# For local execution:
tmux new-session -d -s "$SESSION_NAME" "$CMD > /dev/null 2>&1"

jq -nc \
  --arg ts "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \
  --arg security assessor "$ASSESSOR" \
  --arg action "scan" \
  --arg target "$TARGET" \
  --arg command "$CMD" \
  --arg status "dispatched" \
  --arg session "$SESSION_NAME" \
  --arg remote_host "$HOST_NAME" \
  --arg phase "full" \
  '{ts:$ts, security assessor:$security assessor, action:$action, target:$target,
    command:$command, status:$status,
    session:$session, remote_host:$remote_host, phase:$phase}' \
  >> "${OUTPUT_DIR}/activity.log"

Tell the user:

> Full port scan (Phase 2) dispatched in tmux session $SESSION_NAME. Output: $NAABU_FULL_OUT > This will take 10–30+ minutes. Steps 5–11 are proceeding now using Phase 1 (top 1000) results. Check progress with: tmux attach -t $SESSION_NAME

Parse the Phase 1 naabu output to extract open ports:

# Output format: "host:port" per line
OPEN_PORTS=$(awk -F: '{print $2}' "$NAABU_OUT" 2>/dev/null | sort -un | tr '\n' ',' | sed 's/,$//')

Step 5: Deep Service Fingerprinting with Network Discovery Tool (Two-Phase when naabu was skipped)

Skip this step if the network service discovery tool is not available and note the gap.

If naabu ran (Step 4): Use $OPEN_PORTS from naabu Phase 1. The full-port coverage is already handled by naabu Phase 2 running async.

If naabu was skipped: the network service discovery tool performs its own two-phase scan:

  • Phase 1 — top 1000 ports, synchronous with -sV -sC -O — feeds immediately into Steps 6–11
  • Phase 2 — remaining ports 1001–65535, asynchronous in tmux with -sV -sC -O

Single host — Phase 1 (synchronous)

SERVICE_DISC_OUT="${RECON_DIR}/service-discovery-${ASSESSOR}-$(date +%s).xml"

if [ -n "${OPEN_PORTS:-}" ]; then
  PORT_FLAG="-p ${OPEN_PORTS}"
  NAABU_PROVIDED_PORTS=true
else
  PORT_FLAG="--top-ports 1000"
  NAABU_PROVIDED_PORTS=false
fi

CMD="nmap -sV -sC -O ${PORT_FLAG} -oX ${SERVICE_DISC_OUT} ${TARGET}"

jq -nc \
  --arg ts "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \
  --arg security assessor "$ASSESSOR" \
  --arg action "scan" \
  --arg target "$TARGET" \
  --arg command "$CMD" \
  --arg status "dispatched" \
  --arg phase "quick" \
  '{ts:$ts, security assessor:$security assessor, action:$action, target:$target,
    command:$command, status:$status, phase:$phase}' \
  >> "${OUTPUT_DIR}/activity.log"

$CMD

jq -nc \
  --arg ts "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \
  --arg security assessor "$ASSESSOR" \
  --arg action "scan" \
  --arg target "$TARGET" \
  --arg command "$CMD" \
  --arg status "$([ $? -eq 0 ] && echo completed || echo failed)" \
  --arg output_file "$SERVICE_DISC_OUT" \
  --arg phase "quick" \
  '{ts:$ts, security assessor:$security assessor, action:$action, target:$target,
    command:$command, status:$status, output_file:$output_file, phase:$phase}' \
  >> "${OUTPUT_DIR}/activity.log"

Single host — Phase 2 (asynchronous, only when naabu was skipped)

If naabu already launched a full-port scan (Step 4 Phase 2), skip this — naabu covers the remaining ports. Only launch service discovery Phase 2 when the network discovery tool is acting as the sole port scanner.

if [ "${NAABU_PROVIDED_PORTS:-false}" = "false" ]; then
  SERVICE_DISC_FULL_OUT="${RECON_DIR}/service-discovery-full-${ASSESSOR}-$(date +%s).xml"
  SERVICE_DISC_FULL_SESSION="${ENGAGEMENT_ID}-service-discovery-full-$(date +%s)"
  CMD_FULL="nmap -sV -sC -O -p 1001-65535 -oX ${SERVICE_DISC_FULL_OUT} ${TARGET}"

  tmux new-session -d -s "$SERVICE_DISC_FULL_SESSION" "$CMD_FULL"

  jq -nc \
    --arg ts "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \
    --arg security assessor "$ASSESSOR" \
    --arg action "scan" \
    --arg target "$TARGET" \
    --arg command "$CMD_FULL" \
    --arg status "dispatched" \
    --arg session "$SERVICE_DISC_FULL_SESSION" \
    --arg remote_host "$HOST_NAME" \
    --arg phase "full" \
    '{ts:$ts, security assessor:$security assessor, action:$action, target:$target,
      command:$command, status:$status,
      session:$session, remote_host:$remote_host, phase:$phase}' \
    >> "${OUTPUT_DIR}/activity.log"

  echo "Service discovery full-port scan (Phase 2: ports 1001-65535) dispatched in tmux session $SERVICE_DISC_FULL_SESSION"
  echo "Output: $SERVICE_DISC_FULL_OUT — check progress: tmux attach -t $SERVICE_DISC_FULL_SESSION"
fi

IP range or CIDR (asynchronous — tmux)

For ranges with more than one host, dispatch both phases asynchronously per remote-exec.md:

SESSION_NAME="${ENGAGEMENT_ID}-service-discovery-$(date +%s)"
SERVICE_DISC_OUT="${RECON_DIR}/service-discovery-${ASSESSOR}-$(date +%s).xml"
CMD="nmap -sV -sC -O --top-ports 1000 -oX ${SERVICE_DISC_OUT} ${TARGET}"

# Phase 1: top 1000 ports
tmux new-session -d -s "$SESSION_NAME" "$CMD"

jq -nc \
  --arg ts "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \
  --arg security assessor "$ASSESSOR" \
  --arg action "scan" \
  --arg target "$TARGET" \
  --arg command "$CMD" \
  --arg status "dispatched" \
  --arg session "$SESSION_NAME" \
  --arg remote_host "$HOST_NAME" \
  --arg phase "quick" \
  '{ts:$ts, security assessor:$security assessor, action:$action, target:$target,
    command:$command, status:$status,
    session:$session, remote_host:$remote_host, phase:$phase}' \
  >> "${OUTPUT_DIR}/activity.log"

# Phase 2: remaining ports 1001-65535
if [ "${NAABU_PROVIDED_PORTS:-false}" = "false" ]; then
  SESSION_NAME_FULL="${ENGAGEMENT_ID}-service-discovery-full-$(date +%s)"
  SERVICE_DISC_FULL_OUT="${RECON_DIR}/service-discovery-full-${ASSESSOR}-$(date +%s).xml"
  CMD_FULL="nmap -sV -sC -O -p 1001-65535 -oX ${SERVICE_DISC_FULL_OUT} ${TARGET}"

  tmux new-session -d -s "$SESSION_NAME_FULL" "$CMD_FULL"

  jq -nc \
    --arg ts "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \
    --arg security assessor "$ASSESSOR" \
    --arg action "scan" \
    --arg target "$TARGET" \
    --arg command "$CMD_FULL" \
    --arg status "dispatched" \
    --arg session "$SESSION_NAME_FULL" \
    --arg remote_host "$HOST_NAME" \
    --arg phase "full" \
    '{ts:$ts, security assessor:$security assessor, action:$action, target:$target,
      command:$command, status:$status,
      session:$session, remote_host:$remote_host, phase:$phase}' \
    >> "${OUTPUT_DIR}/activity.log"
fi

Parse network service discovery XML output to extract service and version data for host profile construction in Step 12.


Step 6: HTTP Probing with httpx

Skip this step if httpx is not available. HTTP probing identifies live web services, collects status codes, titles, and technology fingerprints.

Build a hosts file from naabu/service discovery results — include only hosts with open web ports (80, 443, 8080, 8443, 8000, 8888, 9000, 9443, and any other high por

…

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.