security
CHAPTER 72 / 84
읽기 약 2분
FUNCTION
종합: 네트워크 정찰 도구
핵심 개념
모듈 3 통합 프로젝트 — DNS + 포트 스캔 + 서비스 감지를 결합한 CLI 도구.
본문
통합 도구: netrecon
$ python netrecon.py --target localhost --ports 1-1024 --output report.json
🎯 대상: localhost (127.0.0.1)
📡 DNS: A=[127.0.0.1] · MX=[]
📊 포트 스캔: 1-1024 (1024개)
✅ 열린 포트: 5
22/tcp SSH OpenSSH_8.4p1
80/tcp HTTP nginx/1.18.0
443/tcp HTTPS nginx/1.18.0
3000/tcp Unknown Node.js
5432/tcp PostgreSQL 13.x
📁 저장: report.json전체 구현
# netrecon.py — 네트워크 정찰 통합 도구
# ⚠️ 이 코드는 허가된 환경에서만 사용하세요.
import argparse
import json
import logging
import socket
import ipaddress
import sys
from concurrent.futures import ThreadPoolExecutor, as_completed
import dns.resolver
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s [%(levelname)s] %(message)s',
)
log = logging.getLogger('netrecon')
WELL_KNOWN = {
21: 'FTP', 22: 'SSH', 23: 'Telnet', 25: 'SMTP', 53: 'DNS',
80: 'HTTP', 110: 'POP3', 143: 'IMAP', 443: 'HTTPS',
3306: 'MySQL', 5432: 'PostgreSQL', 6379: 'Redis',
8080: 'HTTP-Alt', 8443: 'HTTPS-Alt', 27017: 'MongoDB',
}
def resolve_target(target: str) -> tuple[str, str]:
"""도메인 또는 IP를 받아 (ip, hostname) 반환."""
try:
ip = socket.gethostbyname(target)
except socket.gaierror:
raise SystemExit(f'❌ DNS 해석 실패: {target}')
addr = ipaddress.ip_address(ip)
if not (addr.is_private or addr.is_loopback):
raise SystemExit(f'❌ 공용 IP 스캔 금지 (허가된 환경만): {ip}')
try:
hostname = socket.gethostbyaddr(ip)[0]
except socket.herror:
hostname = target
return ip, hostname
def dns_records(domain: str) -> dict:
"""주요 DNS 레코드 수집."""
records = {}
for rtype in ['A', 'AAAA', 'MX', 'NS', 'TXT', 'CNAME']:
try:
answers = dns.resolver.resolve(domain, rtype, lifetime=5)
records[rtype] = [str(r) for r in answers]
except (dns.resolver.NoAnswer, dns.resolver.NXDOMAIN, dns.exception.Timeout):
records[rtype] = []
return records
def scan_port(host: str, port: int, timeout: float = 1.0) -> tuple[int, bool]:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(timeout)
try:
return port, s.connect_ex((host, port)) == 0
except (socket.timeout, OSError):
return port, False
finally:
s.close()
def grab_banner(host: str, port: int, timeout: float = 3.0) -> str:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(timeout)
try:
s.connect((host, port))
try:
data = s.recv(1024)
if data:
return data.decode('utf-8', errors='replace').strip()[:200]
except socket.timeout:
pass
if port in (80, 8080, 8443, 443):
s.send(b'HEAD / HTTP/1.0\r\nHost: ' + host.encode() + b'\r\n\r\n')
return s.recv(2048).decode('utf-8', errors='replace').strip()[:300]
return ''
except (socket.timeout, ConnectionRefusedError, OSError):
return ''
finally:
s.close()
def parse_port_range(spec: str) -> list[int]:
"""1-1024 또는 22,80,443 형식 파싱."""
result = set()
for part in spec.split(','):
if '-' in part:
start, end = part.split('-')
result.update(range(int(start), int(end) + 1))
else:
result.add(int(part))
return sorted(result)
def reconnaissance(target: str, ports_spec: str, workers: int = 100) -> dict:
"""통합 정찰 흐름."""
ip, hostname = resolve_target(target)
# 1. DNS
log.info(f'DNS 조회: {target}')
dns_data = dns_records(target) if target != ip else {}
# 2. 포트 스캔
ports = parse_port_range(ports_spec)
log.info(f'포트 스캔: {len(ports)}개')
open_ports = []
with ThreadPoolExecutor(max_workers=workers) as ex:
futures = {ex.submit(scan_port, ip, p, 1.0): p for p in ports}
for fut in as_completed(futures):
port, is_open = fut.result()
if is_open:
open_ports.append(port)
open_ports.sort()
log.info(f'열린 포트: {len(open_ports)}')
# 3. 서비스 감지 (병렬)
services = []
with ThreadPoolExecutor(max_workers=20) as ex:
futures = {ex.submit(grab_banner, ip, p, 3.0): p for p in open_ports}
for fut in as_completed(futures):
port = futures[fut]
banner = fut.result()
services.append({
'port': port,
'service': WELL_KNOWN.get(port, 'Unknown'),
'banner': banner.split('\n')[0] if banner else '',
})
services.sort(key=lambda x: x['port'])
return {
'target': target,
'resolved': {'ip': ip, 'hostname': hostname},
'dns': dns_data,
'open_ports': open_ports,
'services': services,
}
def print_report(report: dict) -> None:
print(f'\n🎯 대상: {report["target"]} ({report["resolved"]["ip"]})')
print(f' 호스트명: {report["resolved"]["hostname"]}')
if report['dns']:
print('\n📡 DNS:')
for rtype, records in report['dns'].items():
if records:
print(f' {rtype}: {records[:3]}')
print(f'\n📊 열린 포트: {len(report["open_ports"])}')
for svc in report['services']:
banner_preview = svc['banner'][:60] if svc['banner'] else '-'
print(f' {svc["port"]:5d}/tcp {svc["service"]:10s} {banner_preview}')
def main():
parser = argparse.ArgumentParser(description='네트워크 정찰 통합 도구')
parser.add_argument('--target', '-t', required=True)
parser.add_argument('--ports', '-p', default='1-1024')
parser.add_argument('--workers', '-w', type=int, default=100)
parser.add_argument('--output', '-o', help='JSON 저장 경로')
parser.add_argument('--json', '-j', action='store_true', help='JSON 출력')
parser.add_argument('--verbose', '-v', action='store_true')
args = parser.parse_args()
if args.verbose:
log.setLevel(logging.DEBUG)
report = reconnaissance(args.target, args.ports, args.workers)
if args.json:
out = json.dumps(report, indent=2, ensure_ascii=False)
print(out)
if args.output:
with open(args.output, 'w', encoding='utf-8') as f:
f.write(out)
else:
print_report(report)
if args.output:
with open(args.output, 'w', encoding='utf-8') as f:
json.dump(report, f, indent=2, ensure_ascii=False)
print(f'\n📁 저장: {args.output}')
sys.exit(0 if report['open_ports'] else 1)
if __name__ == '__main__':
main()사용 예시
# 로컬 서버 정찰
python netrecon.py --target localhost --ports 1-1024
# 사내망 서버
python netrecon.py --target 192.168.1.100 --ports 22,80,443,3306,5432 --output server_audit.json
# JSON 출력 (CI/CD 통합)
python netrecon.py --target localhost --json | jq '.services'확장 아이디어
- 서브넷 sweep + 각 호스트 정찰 (
--cidr 192.168.1.0/24) - CVE 매핑 (배너 → 알려진 취약점)
- HTML 리포트 (matplotlib 그래프 첨부)
- Slack/Discord 알림 (열린 포트 변화 감지)
🎯 다음 모듈 (4): 로그 분석
지금까지는 외부에서 시스템을 탐색했습니다. 다음 모듈에서는 내부 로그를 분석해 공격 흔적을 찾는 기법을 배웁니다.
AI 프롬프트
🤖 AI에게 잘 물어보는 법 — 모델·전략별 프롬프트
Claude
무료: Sonnet 4.6 / Pro $20/mo: Opus 4.6
내 netrecon 도구의 예외 처리·확장성·CI/CD 호환성을 코드 리뷰하고 프로덕션 수준으로 리팩토링해줘.
ChatGPT
무료: GPT-5.5 / Plus $20/mo: GPT-5.5 Pro
argparse + concurrent.futures + dnspython 패턴을 다른 보안 도구(SSL 점검/JWT 분석/로그 파서) 동일 구조로 재사용하는 템플릿을 보여줘.
Gemini
무료: 2.5 Flash / Pro $19.99/mo: 3.1 Pro
내 정찰 결과 데이터(JSON)를 분석해서 CVE 매핑·우선순위 패치·사내 보안 리포트를 경영진 보고용으로 만들어줘.
Grok
무료: Grok 4.1 / SuperGrok $30/mo
2026년 네트워크 정찰 자동화 트렌드 — 자체 Python 도구 vs SecurityTrails/Shodan API 비용 대비 효과를 솔직히 알려줘.
⭐ 이것만 기억하세요
종합: 네트워크 정찰 도구는 이 3가지만 확실히 잡으세요
1.모듈 3에서 배운 DNS·포트·서비스 기법을 통합해 실용적인 정찰 도구를 완성했다
2.argparse + JSON 리포트 + exit code 패턴으로 CI/CD 통합 가능한 보안 도구가 된다
3.다음 모듈 4에서 로그 분석 — 외부 탐색에서 내부 흔적 찾기로 시야를 옮긴다
공유하기
진행도 72 / 84