AgentStack
SKILL verified MIT Self-run

Enum Network

skill-thapr0digy-skills-enum-network · by thapr0digy

Network service security assessment — service configuration analysis, protocol security validation, and infrastructure compliance evaluation (SMB, LDAP/AD, SNMP, DNS, RDP/SSH/WinRM, SMTP, FTP, databases, IPMI). Invoke via /enum-network [target].

No reviews yet
0 installs
16 views
0.0% view→install

Install

$ agentstack add skill-thapr0digy-skills-enum-network

✓ 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 No
  • Filesystem access Used
  • 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.

Are you the author of Enum Network? 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/activity-log.md @pentest-core/skills/shared/remote-exec.md

/enum-network — Network Service Security Assessment

You are conducting systematic security assessment of network services discovered during infrastructure analysis. You analyze service configurations, validate security controls, and assess compliance with security standards. Each service type follows established security assessment methodologies to identify misconfigurations, security gaps, and compliance issues.


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

  • IP / hostname / CIDR — e.g., 10.0.0.1, dc01.acme.local, 10.0.0.0/24
  • No argument — fall back to most recent active recon output, filtering for non-web services
ARG="${1:-}"

if [ -n "$ARG" ]; then
  NETWORK_TARGETS=("$ARG")
elif ls "${OUTPUT_DIR}/recon/active-"*.json > /dev/null 2>&1; then
  RECON_FILE=$(ls -t "${OUTPUT_DIR}/recon/active-"*.json | head -1)
  echo "No target specified — reading network services from $RECON_FILE"
  # Extract hosts with non-web, non-other service ports from the most recent active recon output
  NETWORK_TARGETS_JSON=$(jq '[.hosts[] | {ip, hostnames, ports: [.ports[] | select(.category != "web" and .category != "other")]} | select(.ports | length > 0)]' "$RECON_FILE" 2>/dev/null)
  if [ -z "$NETWORK_TARGETS_JSON" ] || [ "$NETWORK_TARGETS_JSON" = "[]" ]; then
    echo "No network services found in $RECON_FILE. Provide a target: /enum-network " >&2
    exit 1
  fi
  # Build target list from recon data
  mapfile -t NETWORK_TARGETS &2
  echo "Provide a target: /enum-network " >&2
  exit 1
fi

If no recon data is available and no target was provided, ask the user:

> No active recon data found. Please provide a target: /enum-network 10.0.0.1

Group by service category

When reading from recon data, group the discovered ports by service category to drive per-service enumeration steps:

# Build a per-host service map from recon data
# Keys: smb, ldap, snmp, dns, rdp, ssh, winrm, smtp, ftp, mysql, mssql, postgresql, redis, mongodb, ipmi
if [ -n "${NETWORK_TARGETS_JSON:-}" ]; then
  SERVICE_MAP=$(echo "$NETWORK_TARGETS_JSON" | jq '
    [.[] | {
      ip,
      hostnames,
      services: (.ports | group_by(.service) | map({(.[0].service): map(.port)}) | add)
    }]
  ')
fi

Scope validation

For each target in NETWORK_TARGETS, validate against scope before proceeding. Check against scope.out_of_scope (hard block) and scope.in_scope (warn if unlisted). Validate testing window. Log every check with action: "scope_check".

for TARGET_IP in "${NETWORK_TARGETS[@]}"; do
  OUT_OF_SCOPE=$(jq -r '.scope.out_of_scope[]' "$ENGAGEMENT_JSON" 2>/dev/null)
  # Match target IP against out_of_scope entries — block on match
  # ... (apply scope-validator.md logic in full) ...

  TESTING_START=$(jq -r '.testing_window.start // empty' "$ENGAGEMENT_JSON" 2>/dev/null)
  TESTING_END=$(jq -r '.testing_window.end // empty' "$ENGAGEMENT_JSON" 2>/dev/null)
  NOW_EPOCH=$(date +%s)
  # Block if outside testing window when window is defined
  # ... (apply scope-validator.md testing window logic) ...

  jq -nc \
    --arg ts "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \
    --arg security assessor "$ASSESSOR" \
    --arg action "scope_check" \
    --arg target "$TARGET_IP" \
    --arg status "completed" \
    --arg result "in_scope" \
    '{ts:$ts, security assessor:$security assessor, action:$action, target:$target, status:$status, result:$result}' \
    >> "${OUTPUT_DIR}/activity.log"
done

Target selection

Present the validated target list and discovered services to the user:

> Network targets identified: > 1. 10.0.0.1 — SMB (445), LDAP (389), DNS (53) > 2. 10.0.0.5 — SMB (445), WinRM (5985) > 3. 10.0.0.10 — MySQL (3306), SSH (22) > > Enumerate which targets? (comma-separated numbers or "all")

Wait for user selection before proceeding.

mkdir -p "${OUTPUT_DIR}/enum"
mkdir -p "${OUTPUT_DIR}/findings"
ENUM_DIR="${OUTPUT_DIR}/enum"
FINDINGS_DIR="${OUTPUT_DIR}/findings"
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 an optional tool is missing — skip that step, note the gap, and continue. Log every check with action: "tool_check".

| Tool | Required | Steps | |---|---|---| | crackmapexec | Required | 4, 5, 8, 11 — SMB/LDAP/WinRM/DB enumeration | | smbclient | Required | 4 — SMB share listing | | Network Discovery | Required | 4, 6, 7, 8, 9, 10, 11, 12 — Security analysis modules across all services | | kerbrute | Optional | 5 — Kerberos user enumeration | | bloodhound-python | Optional | 5 — BloodHound AD collection | | onesixtyone | Optional | 6 — SNMP community brute-force | | snmpwalk | Optional | 6 — SNMP MIB walking | | smtp-user-enum | Optional | 9 — SMTP user enumeration | | ipmitool | Optional | 12 — IPMI hash dumping |

If all three required tools (crackmapexec, smbclient, and the network discovery tool) are missing, abort:

> Required tools crackmapexec, smbclient, and network discovery tool are not available. Install them and retry.

declare -A TOOL_AVAILABLE

for TOOL in crackmapexec smbclient nmap kerbrute bloodhound-python onesixtyone snmpwalk smtp-user-enum ipmitool; do
  if which "$TOOL" > /dev/null 2>&1; then
    TOOL_AVAILABLE[$TOOL]=true
    STATUS="available"
  else
    TOOL_AVAILABLE[$TOOL]=false
    STATUS="not found"
  fi
  jq -nc \
    --arg ts "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \
    --arg security assessor "$ASSESSOR" \
    --arg action "tool_check" \
    --arg command "TOOL_AVAILABLE[$TOOL]=false" \
    --arg status "completed" \
    --arg result "$STATUS" \
    '{ts:$ts, security assessor:$security assessor, action:$action, command:$command, status:$status, result:$result}' \
    >> "${OUTPUT_DIR}/activity.log"
done

REQUIRED_MISSING=0
for TOOL in crackmapexec smbclient nmap; do
  [ "${TOOL_AVAILABLE[$TOOL]}" = "false" ] && REQUIRED_MISSING=$((REQUIRED_MISSING + 1))
done

if [ "$REQUIRED_MISSING" -eq 3 ]; then
  echo "Required tools crackmapexec, smbclient, and network discovery tool are not available. Install them and retry." >&2
  exit 1
fi

Step 4: SMB Enumeration (Port 445/139)

Skip this step for any host without port 445 or 139 open. For each SMB host:

Null session and share enumeration

for TARGET_IP in "${SMB_HOSTS[@]}"; do
  TARGET_SLUG=$(echo "$TARGET_IP" | tr '.' '_')

  # Null session share listing via crackmapexec
  CME_SHARES_OUT="${ENUM_DIR}/cme-smb-shares-${TARGET_SLUG}-${ASSESSOR}-$(date +%s).txt"
  CMD="crackmapexec smb ${TARGET_IP} -u '' -p '' --shares"
  jq -nc \
    --arg ts "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \
    --arg security assessor "$ASSESSOR" \
    --arg action "enum" \
    --arg target "$TARGET_IP" \
    --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 | tee "$CME_SHARES_OUT"
  jq -nc \
    --arg ts "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \
    --arg security assessor "$ASSESSOR" \
    --arg action "enum" \
    --arg target "$TARGET_IP" \
    --arg command "$CMD | tee \"$CME_SHARES_OUT\"" \
    --arg status "$([ $? -eq 0 ] && echo completed || echo failed)" \
    --arg output_file "$CME_SHARES_OUT" \
    '{ts:$ts, security assessor:$security assessor, action:$action, target:$target, command:$command, status:$status, output_file:$output_file}' \
    >> "${OUTPUT_DIR}/activity.log"

  # Null session share listing via smbclient
  SMB_LIST_OUT="${ENUM_DIR}/smbclient-list-${TARGET_SLUG}-${ASSESSOR}-$(date +%s).txt"
  smbclient -L "//${TARGET_IP}" -N 2>&1 | tee "$SMB_LIST_OUT"

Signing check and relay list generation

  CME_SIGNING_OUT="${ENUM_DIR}/cme-smb-signing-${TARGET_SLUG}-${ASSESSOR}-$(date +%s).txt"
  RELAY_LIST="${ENUM_DIR}/smb-relay-candidates-${ASSESSOR}-$(date +%s).txt"
  crackmapexec smb "${TARGET_IP}" --gen-relay-list "$RELAY_LIST" 2>&1 | tee "$CME_SIGNING_OUT"

User and RID enumeration

  CME_USERS_OUT="${ENUM_DIR}/cme-smb-users-${TARGET_SLUG}-${ASSESSOR}-$(date +%s).txt"
  crackmapexec smb "${TARGET_IP}" -u '' -p '' --users --rid-brute 2>&1 | tee "$CME_USERS_OUT"

NSE scripts

  NSE_SMB_OUT="${ENUM_DIR}/smb-security-${TARGET_SLUG}-${ASSESSOR}-$(date +%s).xml"
  CMD="nmap -p 445 --script smb-enum-shares,smb-enum-users,smb-os-discovery,smb-security-mode -oX ${NSE_SMB_OUT} ${TARGET_IP}"
  jq -nc \
    --arg ts "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \
    --arg security assessor "$ASSESSOR" \
    --arg action "enum" \
    --arg target "$TARGET_IP" \
    --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 "enum" \
    --arg target "$TARGET_IP" \
    --arg command "$CMD" \
    --arg status "$([ $? -eq 0 ] && echo completed || echo failed)" \
    --arg output_file "$NSE_SMB_OUT" \
    '{ts:$ts, security assessor:$security assessor, action:$action, target:$target, command:$command, status:$status, output_file:$output_file}' \
    >> "${OUTPUT_DIR}/activity.log"
done

SMB findings to flag

  • Null session access — anonymous login accepted (medium/high depending on shares readable)
  • Anonymous share access — readable shares with no credentials (high if sensitive data present)
  • SMB signing disabled — relay attacks possible (medium; high if combined with null sessions)
  • Guest access enabled — guest account active on the host (medium)

Write a finding for each confirmed condition using the standard finding schema (see Step 13).


Step 5: LDAP/AD Enumeration (Port 389/636)

Skip this step for any host without port 389 or 636 open.

Anonymous bind check

for TARGET_IP in "${LDAP_HOSTS[@]}"; do
  TARGET_SLUG=$(echo "$TARGET_IP" | tr '.' '_')

  # Probe for namingContexts via anonymous bind
  LDAP_NC_OUT="${ENUM_DIR}/ldap-namingcontexts-${TARGET_SLUG}-${ASSESSOR}-$(date +%s).txt"
  CMD="ldapsearch -x -H ldap://${TARGET_IP} -b '' -s base namingContexts"
  jq -nc \
    --arg ts "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \
    --arg security assessor "$ASSESSOR" \
    --arg action "enum" \
    --arg target "$TARGET_IP" \
    --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 2>&1 | tee "$LDAP_NC_OUT"
  jq -nc \
    --arg ts "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \
    --arg security assessor "$ASSESSOR" \
    --arg action "enum" \
    --arg target "$TARGET_IP" \
    --arg command "$CMD 2>&1 | tee \"$LDAP_NC_OUT\"" \
    --arg status "$([ $? -eq 0 ] && echo completed || echo failed)" \
    --arg output_file "$LDAP_NC_OUT" \
    '{ts:$ts, security assessor:$security assessor, action:$action, target:$target, command:$command, status:$status, output_file:$output_file}' \
    >> "${OUTPUT_DIR}/activity.log"

  # Extract base DN from namingContexts output
  BASE_DN=$(grep -i 'namingContexts:' "$LDAP_NC_OUT" | head -1 | awk '{print $2}')

  if [ -n "$BASE_DN" ]; then
    # Retrieve domain object anonymously
    LDAP_DOMAIN_OUT="${ENUM_DIR}/ldap-domain-${TARGET_SLUG}-${ASSESSOR}-$(date +%s).txt"
    ldapsearch -x -H "ldap://${TARGET_IP}" -b "$BASE_DN" "(objectClass=domain)" 2>&1 | tee "$LDAP_DOMAIN_OUT"
    ANON_BIND_SUCCESS=true
  else
    ANON_BIND_SUCCESS=false
  fi

Authenticated enumeration

If credentials are available (check $LDAP_USER / $LDAP_PASS or $DOMAIN_USER / $DOMAIN_PASS):

  if [ -n "${DOMAIN_USER:-}" ] && [ -n "${DOMAIN_PASS:-}" ] && [ -n "${BASE_DN:-}" ]; then
    # Users with crackmapexec
    crackmapexec ldap "${TARGET_IP}" -u "$DOMAIN_USER" -p "$DOMAIN_PASS" --users \
      2>&1 | tee "${ENUM_DIR}/cme-ldap-users-${TARGET_SLUG}-${ASSESSOR}-$(date +%s).txt"

    # Groups
    crackmapexec ldap "${TARGET_IP}" -u "$DOMAIN_USER" -p "$DOMAIN_PASS" --groups \
      2>&1 | tee "${ENUM_DIR}/cme-ldap-groups-${TARGET_SLUG}-${ASSESSOR}-$(date +%s).txt"

    # Kerberoastable accounts
    crackmapexec ldap "${TARGET_IP}" -u "$DOMAIN_USER" -p "$DOMAIN_PASS" --kerberoasting \
      "${ENUM_DIR}/kerberoast-hashes-${TARGET_SLUG}-${ASSESSOR}-$(date +%s).txt"

    # AS-REP roastable accounts (no pre-auth required)
    crackmapexec ldap "${TARGET_IP}" -u "$DOMAIN_USER" -p "$DOMAIN_PASS" --asreproast \
      "${ENUM_DIR}/asrep-hashes-${TARGET_SLUG}-${ASSESSOR}-$(date +%s).txt"
  fi

BloodHound collection (async)

If bloodhound-python is available and domain credentials exist, dispatch collection asynchronously via the remote-exec pattern:

  if [ "${TOOL_AVAILABLE[bloodhound-python]}" = "true" ] && [ -n "${DOMAIN_USER:-}" ]; then
    # Resolve remote host connection config
    HOST_NAME="${HOST_NAME:-kali-aws}"
    METHOD=$(jq -r --arg h "$HOST_NAME" '.remote_hosts[$h].method' "$ENGAGEMENT_JSON")
    WORK_DIR=$(jq -r --arg h "$HOST_NAME" '.remote_hosts[$h].work_dir' "$ENGAGEMENT_JSON")
    SSH_HOST=$(jq -r --arg h "$HOST_NAME" '.remote_hosts[$h].host // empty' "$ENGAGEMENT_JSON")
    SSH_KEY=$(jq -r --arg h "$HOST_NAME" '.remote_hosts[$h].key // empty' "$ENGAGEMENT_JSON")
    SSH_USER=$(jq -r --arg h "$HOST_NAME" '.remote_hosts[$h].user // "kali"' "$ENGAGEMENT_JSON")

    SESSION_NAME="${ENGAGEMENT_ID}-bloodhound-$(date +%s)"
    BH_OUTPUT_DIR="${WORK_DIR}/bloodhound-${ASSESSOR}"
    REMOTE_OUTPUT="${WORK_DIR}/${SESSION_NAME}.log"

    BH_CMD="mkdir -p ${BH_OUTPUT_DIR} && bloodhound-python -d ${DOMAIN} -u ${DOMAIN_USER} -p ${DOMAIN_PASS} -c All -ns ${TARGET_IP} --zip -o ${BH_OUTPUT_DIR}"

    if [ "$METHOD" = "local" ] || [ "$HOST_NAME" = "local" ]; then
      tmux new-session -d -s "$SESSION_NAME" "bash -c '${BH_CMD} > ${REMOTE_OUTPUT} 2>&1'"
    else
      ssh -i "$SSH_KEY" -o StrictHostKeyChecking=no "${SSH_USER}@${SSH_HOST}" \
        "tmux new-session -d -s '${SESSION_NAME}' '${BH_CMD} > ${REMOTE_OUTPUT} 2>&1'"
    fi

    jq -nc \
      --arg ts "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \
      --arg security assessor "$ASSESSOR" \
      --arg action "enum" \
      --arg target "$TARGET_IP" \
      --arg command "$BH_CMD" \
      --arg status "dispatched" \
      --arg session "$SESSION_NAME" \
      --arg remote_host "$HOST_NAME" \
      --arg output_path "$REMOTE_OUTPUT" \
      '{ts:$ts, security assessor:$security assessor, action:$action, target:$target, command:$command, stat

…

## Source & license

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

- **Author:** [thapr0digy](https://github.com/thapr0digy)
- **Source:** [thapr0digy/skills](https://github.com/thapr0digy/skills)
- **License:** MIT

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.