mcpField
P
port-service-discovery

port-service-discovery

github.com/uphiago安全1.3k40 次安装8 周前更新
代码仓库

关于 port-service-discovery

面向安全评估的技能,使用 Nmap 对 Web 应用周边服务进行范围限定的发现。它指导操作人员扫描端口、验证服务、检查暴露情况并记录发现。

主要功能

  1. 01范围限定的 Nmap 端口扫描
  2. 02服务版本检测
  3. 03检查关键服务暴露
  4. 04防火墙与 WAF 指纹识别
  5. 05发现结果验证指南

适用场景

  1. 01Web 侦察后检查基础设施
  2. 02检查预发布主机的后端端口
  3. 03验证暴露的数据库或管理服务

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/uphiago/recon-skills --skill port-service-discovery

安装后在 Claude Code 中输入/port-service-discovery确认已加载。

详细介绍

端口与服务发现技能

使用范围限定的 Nmap 发现与 Web 应用相邻的服务,包括数据库、远程管理、邮件、缓存以及非标准 API 端口。开放端口只是一项观察结果;服务身份和未经授权的访问需要分别验证。

适用场景

  • 对高价值目标运行 deep-invade 第 6 阶段。
  • 表层侦察未发现可利用的 Web 漏洞后,转而检查基础设施。
  • 目标是 SaaS,且后端 API 使用非标准端口时。
  • 发现暂存子域名后,检查数据库/管理端口。

前置条件

  • 执行环境中有 nmap。
  • 目标域名或 IP 地址。
  • 进行全端口扫描时需要耐心(扫描全部 65535 个端口可能需要 10–60 分钟)。

运行方法

# Fast top-100 port scan (30 seconds)
nmap -F --open -T4 TARGET -oN nmap_fast.txt

# Top 1000 ports (2-3 minutes)
nmap --top-ports 1000 --open -T4 TARGET -oN nmap_1000.txt

# Service version detection on open ports
nmap -sV -p $(grep 'open' nmap_fast.txt | cut -d/ -f1 | tr '\n' ',') TARGET

# Firewall bypass: fragment packets
nmap -f -F TARGET

快速参考

端口服务发现项严重程度
3306MySQL严重(若对互联网开放)
27017MongoDB严重(若无身份验证)
6379Redis严重(若无身份验证)
5432PostgreSQL高
1433MS SQL Server高
21FTP高(是否允许匿名登录?)
22SSH信息(检查是否存在弱身份验证)
8080/8081/8082/8084内部 API高(后端服务暴露)
9200Elasticsearch高(数据暴露)
25/587SMTP中(是否为开放中继?)
110/143/993POP3/IMAP信息
8443HTTPS 替代端口(管理面板)中
9090Prometheus/Cockpit中
3000Grafana/Node.js 开发服务中

操作步骤

步骤 1 — 快速扫描排名前 100 的端口
TARGET="$1"
OUTDIR="$OUTDIR/ports"
mkdir -p "$OUTDIR"

echo "[*] Fast scan (top 100 ports) on $TARGET..."
nmap -F --open -T4 --max-retries 1 --host-timeout 60s "$TARGET" -oN "$OUTDIR/${TARGET}_fast.nmap" 2>/dev/null

echo "[*] Open ports:"
grep 'open' "$OUTDIR/${TARGET}_fast.nmap" || echo "  None found"
步骤 2 — 服务版本检测
TARGET="$1"
OUTDIR="$OUTDIR/ports"

# Get comma-separated list of open ports
OPEN_PORTS=$(grep '^[0-9]' "$OUTDIR/${TARGET}_fast.nmap" | awk -F/ '{print $1}' | tr '\n' ',' | sed 's/,$//')

if [[ -n "$OPEN_PORTS" ]]; then
  echo "[*] Service detection on ports: $OPEN_PORTS"
  nmap -sV --version-intensity 5 -p "$OPEN_PORTS" "$TARGET" -oN "$OUTDIR/${TARGET}_services.nmap" 2>/dev/null

  echo "[*] Services:"
  grep 'open' "$OUTDIR/${TARGET}_services.nmap"
else
  echo "[-] No open ports found"
fi
步骤 3 — 关键暴露检查
TARGET="$1"
OUTDIR="$OUTDIR/ports"

echo "[*] Critical exposure assessment:"

# MySQL (3306)
if grep -q '3306.*open' "$OUTDIR/${TARGET}_fast.nmap" 2>/dev/null; then
  echo ""
  echo "[CRITICAL] MySQL 3306 OPEN — attempting banner grab..."
  # Try to get MySQL version
  mysql_info=$(timeout 5 nc -w 3 "$TARGET" 3306 </dev/null 2>/dev/null | head -1)
  [[ -n "$mysql_info" ]] && echo "  Banner: $mysql_info"

  # Test for no-auth MySQL
  echo "  Testing anonymous access..."
  # This typically requires mysql client; note methodology
  echo "  Manual check: mysql -h $TARGET -u root --skip-ssl"
  echo "  Manual check: mysql -h $TARGET -u admin --skip-ssl"
fi

# MongoDB (27017)
if grep -q '27017.*open' "$OUTDIR/${TARGET}_fast.nmap" 2>/dev/null; then
  echo ""
  echo "[CRITICAL] MongoDB 27017 OPEN"
  echo "  Manual check: mongosh mongodb://$TARGET:27017"
fi

# Redis (6379)
if grep -q '6379.*open' "$OUTDIR/${TARGET}_fast.nmap" 2>/dev/null; then
  echo ""
  echo "[HIGH] Redis 6379 OPEN — testing no-auth access..."
  redis_test=$(timeout 5 bash -c "echo -e 'PING\r\nINFO\r\n' | nc -w 3 '$TARGET' 6379 2>/dev/null")
  if echo "$redis_test" | grep -q "PONG"; then
    echo "  [CRITICAL] Redis NO AUTH — full access!"
    echo "  Response: $(echo "$redis_test" | head -5)"
  else
    echo "  Redis requires auth (or connection failed)"
  fi
fi

# Internal API ports (8080-8089)
for port in 8080 8081 8082 8084 8088 8443 3000 5000 9000 9090; do
  if grep -q "${port}.*open" "$OUTDIR/${TARGET}_fast.nmap" 2>/dev/null; then
    echo ""
    echo "[HIGH] Port $port OPEN — probing HTTP..."
    http_code=$(curl -sk -o /dev/null -w "%{http_code}" --max-time 5 --connect-timeout 5 "http://$TARGET:$port/" 2>/dev/null)

    if [[ "$http_code" != "000" ]]; then
      echo "  HTTP $http_code on port $port"
      title=$(curl -sk --max-time 5 --connect-timeout 5 "http://$TARGET:$port/" 2>/dev/null | grep -Eo '<title>\K[^<]+')
      [[ -n "$title" ]] && echo "  Title: $title"

      # Check for Swagger/API docs
      for api_path in "swagger.json" "api-docs" "swagger-ui.html" "graphql" "actuator/health"; do
        api_code=$(curl -sk -o /dev/null -w "%{http_code}" --max-time 5 --connect-timeout 5 "http://$TARGET:$port/$api_path")
        [[ "$api_code" == "200" ]] && echo "  [API] http://$TARGET:$port/$api_path (HTTP 200)"
        sleep 0.2
      done
    fi
  fi
done

# FTP (21) — check for anonymous login
if grep -q '21.*open' "$OUTDIR/${TARGET}_fast.nmap" 2>/dev/null; then
  echo ""
  echo "[HIGH] FTP 21 OPEN — testing anonymous login..."
  anon_test=$(timeout 10 bash -c "echo -e 'anonymous\nanonymous\n' | nc -w 3 '$TARGET' 21 2>/dev/null")
  if echo "$anon_test" | grep -qi "230"; then
    echo "  [CRITICAL] Anonymous FTP login successful!"
  elif echo "$anon_test" | grep -qi "530\|331"; then
    echo "  Anonymous FTP: requires auth"
  fi
fi

# SSH (22) — check for weak ciphers
if grep -q '22.*open' "$OUTDIR/${TARGET}_fast.nmap" 2>/dev/null; then
  echo ""
  echo "[INFO] SSH 22 OPEN"
  ssh_banner=$(timeout 5 nc -w 3 "$TARGET" 22 </dev/null 2>/dev/null | head -1)
  [[ -n "$ssh_banner" ]] && echo "  Banner: $ssh_banner"
fi
步骤 4 — 扩展端口范围(快速扫描未发现端口时)
TARGET="$1"
OUTDIR="$OUTDIR/ports"

# If no ports found in top-100, expand to top-1000
if ! grep -q 'open' "$OUTDIR/${TARGET}_fast.nmap" 2>/dev/null; then
  echo "[*] No ports in top-100, scanning top-1000..."
  nmap --top-ports 1000 --open -T4 --max-retries 1 --host-timeout 120s "$TARGET" -oN "$OUTDIR/${TARGET}_1000.nmap" 2>/dev/null

  OPEN=$(grep 'open' "$OUTDIR/${TARGET}_1000.nmap")
  if [[ -z "$OPEN" ]]; then
    # Try SYN scan with fragmentation for firewall evasion
    echo "[*] Still nothing — trying fragmented SYN scan..."
    nmap -f -sS -F --open -T4 "$TARGET" -oN "$OUTDIR/${TARGET}_frag.nmap" 2>/dev/null
  fi
fi
步骤 5 — 防火墙/WAF 指纹识别
TARGET="$1"

echo "[*] WAF/CDN detection:"

# Check for Cloudflare
cf_header=$(curl -skI --max-time 5 --connect-timeout 5 "https://$TARGET/" 2>/dev/null | grep -i "cf-ray\|cloudflare")
[[ -n "$cf_header" ]] && echo "  Cloudflare detected"

# Check for AWS CloudFront
cf_header=$(curl -skI --max-time 5 --connect-timeout 5 "https://$TARGET/" 2>/dev/null | grep -i "x-amz-cf\|cloudfront")
[[ -n "$cf_header" ]] && echo "  AWS CloudFront detected"

# Check origin IP (bypass CDN)
echo "[*] Historical DNS records for origin IP discovery:"
# SecurityTrails, DNSDumpster, etc. — use HTTP fetch for these
echo "  Manual: securitytrails.com/domain/$TARGET/dns/a"
echo "  Manual: dnsdumpster.com"

# Try direct IP connection (if known)
# curl -sk --resolve "$TARGET:443:ORIGIN_IP" "https://$TARGET/"

注意事项

  • nmap SYN 扫描需要原始套接字权限。 如果执行环境不授予此权限,请使用 -sT(TCP 连接扫描)。
  • 端口扫描可能受到速率限制。 某些提供商(AWS、Cloudflare)会限制或阻止端口扫描。对敏感目标使用 -T2(较温和的扫描速度)和 --max-retries 1。
  • MySQL/MongoDB 可能无法通过横幅抓取识别。 某些数据库需要进行 TLS 协商(MySQL 8.0+ 默认使用 caching_sha2_password)。横幅可能为空。
  • 内部 API 端口可能超时。 某些服务只响应特定的 Host 标头或有效的 HTTP 请求。使用 curl 并尝试不同的 Host 标头。

验证

  • 必须使用服务版本检测(nmap -sV)确认每个开放端口。
  • 必须通过实际连接尝试测试 MySQL 访问,而不能只确认端口开放。
  • 无身份验证的 Redis 必须对 PING 命令返回 PONG。
  • FTP 匿名登录必须返回代码 230(登录成功)。
  • 必须记录所有发现项的准确端口、服务、版本和访问级别。

评论

支持 Markdown