
대규모 포트 탐색, 호스트 탐색, 배너 그래빙, 그리고 내부 또는 외부 네트워크 전반에 걸친 NSE 기반 취약점 스캐닝을 위한 masscan 및 nmap의 Python 래퍼입니다.
이 스크립트는 masscan과 nmap의 래퍼입니다. nmap은 호스트 탐색과 (규모가 작은 스캔의 경우) 포트 탐색, 서비스 배너 수집, NSE 스크립트를 처리합니다. Masscan은 원시 속도가 중요한 대규모 포트 탐색에 사용됩니다. 선호하는 패키지 관리자나 소스에서 둘 다 설치하세요.
Python 3.8+가 필요합니다 (pyproject.toml의 requires-python; CI 최소 버전은 3.8).
SpooNMAP은 체크아웃에서 바로 실행할 수 있으며 — 별도의 설치 단계가 필요 없습니다. 아래 "사용법"을 참고하세요 — 또는 uv를 사용하여 독립 실행형 명령으로 설치할 수 있습니다:
uv tool install git+https://github.com/trustedsec/spoonmap
이렇게 하면 spoonmap 실행 파일이 PATH에 추가되므로, 저장소를 복제하고 ./spoonmap.py를 실행하는 대신 어느 디렉터리에서든 spoonmap으로 호출할 수 있습니다. PyPI 패키지는 없습니다 — 이 프로젝트는 pypi.org에 게시된 적이 없으며, 위 명령은 대신 git 저장소에서 직접 설치합니다. 위에 나온 전체 git+https://... 형식을 사용하고, uv tool install spoonmap만 단독으로 사용하지 마십시오. PyPI에서 그 이름이 현재 또는 미래에 무엇을 가리키든, 그것은 이 프로젝트가 아닙니다.
최신 커밋으로 업데이트하려면:
uv tool upgrade spoonmap
이 방식으로 설치해도 SpooNMAP이 자체 완결형 스캐너가 되지는 않습니다:
masscan과 nmap은 여전히 독립적으로 설치해야 하는 별도의 시스템 도구입니다
(위의 "Dependencies" 참조). 체크아웃에서 실행할 때와 정확히 마찬가지입니다 —
uv tool install은 SpooNMAP 자체의 Python 코드와 번들된 NSE 스크립트만
패키징할 뿐, 셸을 통해 호출하는 외부 바이너리는 패키징하지 않습니다.
이 방식으로 설치하기 전에 알아둘 만한 한 가지: 설치된 spoonmap의 Python
모듈은 uv가 관리형 도구 환경을 둔 위치에 존재합니다 — 설정 파일이나 스캔
출력을 찾으려고 생각할 만한 디렉터리가 아닙니다. 바로 이것이 아래 "Where Files
Live" 섹션이 다루는 시나리오입니다 — 현재 디렉터리를 기준으로 무엇이 해석되는지,
그리고 그 이유는 해당 섹션을 읽어보세요. uv tool install로 설치해도 규칙은
바뀌지 않습니다. 다만 그 규칙이 중요해질 뿐입니다. 습관적으로 설정이나 출력
경로가 기댈 체크아웃 디렉터리가 더 이상 남아 있지 않기 때문입니다.
스크립트를 실행하기만 하면 필요한 모든 옵션을 묻는 프롬프트가 표시됩니다.
config.json, 대상/제외 파일, 스캔 출력은 모두 명령을 실행한 디렉터리를 기준으로
해석됩니다 — 출력이 예상한 위치에 없다면 아래 "Where Files Live"를 참조하세요.
특히 SpooNMAP을 자체 디렉터리 밖에서 경로로 호출하는 데 익숙한 경우라면 더욱
그렇습니다.
uv를 사용한다면 별도의 가상 환경 없이 실행할 수 있습니다:
uv run spoonmap.py
스크립트가 실행 가능한 경우 직접 호출하세요:
# ./spoonmap.py
________ _____ _______ _________________
__ ___/______________________ | / /__ |/ /__ |__ __ \
_____ \___ __ \ __ \ __ \_ |/ /__ /|_/ /__ /| |_ /_/ /
____/ /__ /_/ / /_/ / /_/ / /| / _ / / / _ ___ | ____/
/____/ _ .___/\____/\____//_/ |_/ /_/ /_/ /_/ |_/_/
/_/
Service Categories (comma-separated numbers, default: All)
(1) Web [80, 443, 7001, 7002, 8000, 8080, 8081, 8443, 8888, 9090, 10443]
(2) Database [1433, U:1434, 1521, 3306, 5432, 6379, 9200, 27017]
(3) Remote Management [22, 23, 3389, 5900, 5901, 6129, 1723, 5985, 5986]
(4) Email [25, 110, 143, 465, 587, 993, 995]
(5) LDAP [389, 636]
(6) Network Infrastructure [53, 179, U:500, U:161, U:623, U:631, U:1194, 1194]
(7) File Transfer [21, 111]
(8) SMB [445, 135, 139, U:137]
(9) Specialized [1090, 3300, 4786, 6970, 2375, 4243, 9100, 8530, 8531]
(10) Containers & Debuggers [2377, 10250, 8001, 9229, 2345, 5005, 61616, 8009, 6000]
(11) Local LLM [11434, 1234, 7860, 5000, 5001, 1337, 3000, 8000, 8080]
(12) Full Port Scan [1-65535, TCP only — no UDP]
(c) Custom Port Scan [enter your own comma-separated ports]
(The Full Port Scan number increments automatically with the number of categories.)
**Full Port Scan is TCP only.** It sweeps TCP 1-65535 and runs no UDP discovery at
all, so every `U:` port listed in the categories above — SNMP (U:161), IKE (U:500),
IPMI (U:623), IPP (U:631), OpenVPN (U:1194), NetBIOS (U:137), SQL Browser (U:1434) —
is skipped, along with the NSE scripts and findings that depend on them. It is
*wider* than All on TCP and *narrower* on UDP. For both, run All and Full as two
passes, or use the Custom option with the UDP ports appended
(e.g. `1-65535,U:161,U:500,U:623`).
Which categories would you like to scan (e.g. 1,3 — default: All)?
Would you like to enumerate service banners for any identified services (default: Yes)?
Would you like to run NSE security scripts on identified services (default: No)?
Target Scan
(1) External
(2) Internal
Is this an internal or external scan (default: External)?
How fast would you like to scan (default: 20000 packets/second)?
Please enter the full path for the file containing target hosts (default: /opt/spoonmap/ranges.txt):
Would you like to exclude any hosts? (default: No)
Run host discovery before port scanning (default: Yes)?
Tune advanced settings (nmap threads, masscan batch size, nmap work-unit threshold)? (default: No)
config.json.sample을 기반으로 config.json 파일을 생성하여 모든 프롬프트를 건너뛸 수도 있습니다:
{
"scan_categories": ["Web", "Database", "Remote Management"],
"banner_scan": "True",
"script_scan": "False",
"host_discovery": "True",
"target_scan": "Internal",
"max_rate": "2000",
"target_file": "ranges.txt",
"output_path": "./",
"exclusions_file": "exclusions.txt",
"nmap_threads": 5,
"masscan_batch_size": 5,
"nmap_threshold": 5000000
}
모든 카테고리를 스캔하려면 "scan_categories": "All"로 설정하세요.
65535개의 모든 TCP 포트를 스캔하려면 "scan_categories": "Full"로 설정하세요 — 이는 TCP 전용이며 UDP 탐색을 수행하지 않는다는 점에 유의하세요.
완전히 사용자 지정한 포트 목록을 사용하려면 scan_categories를 생략하고 대신 "dest_ports": ["80","443","U:53"]을 사용하세요.
UDP 포트는 U: 접두사로 지정합니다(예: "U:53").
대화형 프롬프트에 응답하면 선택한 옵션이 스캔 시작 전에 config.json에 기록됩니다. 생성된 파일은 config.json.sample과 동일한 방식으로 각 편집 가능한 필드를 문서화하며, __generated_by_prompts__ 마커 키를 포함합니다. 즉, 중단된 대화형 스캔은 설정 기반 스캔과 동일한 방식으로 재개할 수 있습니다 — --resume으로 다시 실행하기만 하면 모든 프롬프트가 건너뛰어집니다.
output_path에서 이전 스캔의 출력이 감지되면, 도구는 세 가지 선택지를 제공합니다: [d]elete(이전 출력을 제거하고 새로 시작), [a]ppend(이전 출력을 유지하되 모든 단계를 다시 실행), 또는 [r]esume(이전 출력을 유지하고 이미 완료된 작업을 건너뜀, 정확히 --resume 플래그와 동일).
재실행 시 옵션 변경. [d]elete 또는 [a]ppend를 선택하면 저장된 config.json 값이 기본값으로 미리 채워진 상태로 모든 옵션을 다시 묻습니다 — 따라서 프롬프트에서 Enter를 눌러 진행하면 이전 스캔이 재현되며, 관심 있는 포트, 속도 또는 대상만 변경할 수 있습니다. [r]esume은 동일한 스캔을 계속하는 것이므로 프롬프트를 건너뜁니다. 재프롬프트는 도구가 생성한 config.json(__generated_by_prompts__를 포함하는 파일)에만 적용됩니다. 직접 작성한 설정 파일은 위에서 설명한 모든 프롬프트를 엄격히 건너뛰는 동작을 유지합니다. 옵트아웃하려면 해당 키를 제거하거나, 처음부터 시작하려면 config.json을 완전히 삭제하세요.
프롬프트에 다시 응답하면 config.json을 덮어쓰는 것이 아니라 병합하여 다시 작성합니다: 파일에 직접 추가한 모든 키는 보존됩니다.
대상 파일을 편집하지 않고 단일 주소(또는 짧은 목록)를 스캔하려면 --target을 사용하세요:
./spoonmap.py --target 10.0.0.5
./spoonmap.py --target 10.0.0.0/24
./spoonmap.py --target 10.0.0.5,10.0.1.0/24,10.0.2.1-10.0.2.9
이 값은 대상 파일의 한 줄이 허용하는 모든 형식을 받아들입니다 — 단일 IP, CIDR, A-B 범위, 또는 address netmask — 쉼표로 구분됩니다. 이 값은 스캔이 시작되기 전에 검증됩니다. 형식이 잘못되었거나 IPv6 주소인 경우, 빈 대상 집합에 대해 문제없이 실행되는 대신 문제가 되는 항목의 이름을 명시하며 0이 아닌 종료 코드로 중단됩니다.
--target은 config.json의 target_file과 대화형 프롬프트 모두보다 우선하므로, 그 외에는 완전히 비대화형으로 실행되는 경우에도 작동합니다. 주소는 output_path의 cli_targets.txt에 기록됩니다. ranges.txt는 절대 수정되지 않으므로 참여 범위 파일이 그대로 유지되며, 각 실행이 실제로 무엇을 대상으로 했는지에 대한 기록이 디스크에 남습니다.
--target=10.0.0.5(플래그와 값 사이에 =를 넣는 형식)도 이제 --target 10.0.0.5와 마찬가지로 작동합니다 — --cleanup=/path/to/output도 마찬가지입니다. 이 도구가 argparse로 전환되기 전에는 --flag=value 형식이 수작업으로 작성된 '--flag' in sys.argv 검사 어디에도 걸리지 않았기 때문에, --target=10.0.0.5는 완전히 조용히 무시되었고 스캔은 실제로 요청한 주소 대신 ranges.txt를 대상으로 실행되었습니다 — 이는 예전 버그가 단순히 플래그를 무시한 것이 아니라 조용히 범위를 바꿔버린 유일한 사례입니다.
프롬프트 없이 중단된 스캔을 재개하려면 --resume 플래그를 사용하십시오: