security
CHAPTER 69 / 84
읽기 약 2분
FUNCTION
서비스 감지: 무엇이 실행 중인가
핵심 개념
배너 그래빙(Banner Grabbing)과 python-nmap으로 열린 포트의 서비스를 식별한다.
본문
배너 그래빙 — 서비스가 자기 정보를 흘림
# ⚠️ 이 코드는 허가된 환경에서만 사용하세요.
import socket
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))
# 1) 일부 서비스(SSH/SMTP)는 연결만으로 배너 전송
try:
data = s.recv(1024)
if data:
return data.decode('utf-8', errors='replace').strip()
except socket.timeout:
pass
# 2) HTTP 서비스 — HEAD 요청으로 헤더 수집
if port in (80, 8080, 8443, 443):
s.send(b'HEAD / HTTP/1.0\r\nHost: ' + host.encode() + b'\r\n\r\n')
data = s.recv(4096)
return data.decode('utf-8', errors='replace').strip()
return ''
except (socket.timeout, ConnectionRefusedError, OSError) as e:
return f'error: {e}'
finally:
s.close()
# 결과 예시
"""
SSH: SSH-2.0-OpenSSH_8.4p1 Debian-5
SMTP: 220 mail.example.com ESMTP Postfix (Ubuntu)
HTTP: HTTP/1.1 200 OK\r\nServer: nginx/1.18.0 (Ubuntu)\r\n...
"""서비스 식별 패턴
import re
SERVICE_PATTERNS = {
'SSH': re.compile(r'^SSH-(\d+\.\d+)-(.+?)(\s|$)'),
'SMTP': re.compile(r'^220.*ESMTP'),
'HTTP': re.compile(r'HTTP/\d\.\d (\d{3})'),
'FTP': re.compile(r'^220.*FTP'),
'MySQL': re.compile(r'\x00\x00\x00\x0a(\d+\.\d+)'),
'Redis': re.compile(r'-NOAUTH'),
'Docker': re.compile(r'docker'),
}
def identify_service(banner: str) -> dict:
"""배너에서 서비스 종류와 버전 추출."""
for service, pattern in SERVICE_PATTERNS.items():
m = pattern.search(banner)
if m:
return {
'service': service,
'version': m.group(1) if m.groups() else 'unknown',
'raw_banner': banner[:200],
}
return {'service': 'unknown', 'raw_banner': banner[:200]}python-nmap 활용 — 더 강력한 식별
# pip install python-nmap
# ⚠️ 이 코드는 허가된 환경에서만 사용하세요.
import nmap
def nmap_service_scan(host: str, ports: str = '1-1024') -> dict:
"""nmap의 -sV 옵션을 Python에서 호출."""
nm = nmap.PortScanner()
# -sV: 서비스/버전 감지, -T4: 빠른 속도
nm.scan(host, ports, arguments='-sV -T4')
result = {}
for h in nm.all_hosts():
result[h] = {
'state': nm[h].state(),
'services': [],
}
for proto in nm[h].all_protocols():
for port in nm[h][proto].keys():
info = nm[h][proto][port]
result[h]['services'].append({
'port': port,
'protocol': proto,
'state': info['state'],
'service': info.get('name', 'unknown'),
'product': info.get('product', ''),
'version': info.get('version', ''),
})
return result
# print(nmap_service_scan('127.0.0.1'))실습: 열린 포트 → 서비스 식별 → 버전 확인
# ⚠️ 이 코드는 허가된 환경에서만 사용하세요.
def fingerprint_host(host: str, ports: list[int]) -> dict:
"""포트별 서비스/버전 식별."""
findings = []
for port in ports:
banner = grab_banner(host, port, 3.0)
if banner and not banner.startswith('error'):
service_info = identify_service(banner)
findings.append({
'port': port,
**service_info,
})
return {'host': host, 'findings': findings}
# CVE 매핑 — 알려진 취약점이 있는 버전 확인
KNOWN_VULNS = {
'OpenSSH_7.': ['CVE-2018-15473 (사용자 열거)'],
'nginx/1.16.': ['CVE-2019-9511 (HTTP/2 DoS)'],
'Apache/2.4.49': ['CVE-2021-41773 (경로 탐색)'],
}
def check_known_vulns(banner: str) -> list[str]:
"""배너에서 알려진 취약점 매칭."""
vulns = []
for pattern, cves in KNOWN_VULNS.items():
if pattern in banner:
vulns.extend(cves)
return vulns⚠️ 보안 관점
- 배너 그래빙은 **수동(passive)**으로 분류되지만 일부 IDS가 감지
- 운영 서비스는 배너에서 버전을 숨겨야 함:
- nginx:
server_tokens off; - Apache:
ServerTokens Prod - SSH:
DebianBanner no(sshd_config)
- nginx:
- CVE 매핑은 참고용 — 실제 취약 여부는 보안 패치 적용 여부에 따라 다름
AI 프롬프트
🤖 AI에게 잘 물어보는 법 — 모델·전략별 프롬프트
Claude
무료: Sonnet 4.6 / Pro $20/mo: Opus 4.6
내 배너 그래빙 코드의 서비스 식별 정확도와 timeout 처리를 분석하고 false positive를 줄이는 패턴을 보강해줘.
ChatGPT
무료: GPT-5.5 / Plus $20/mo: GPT-5.5 Pro
배너 그래빙으로 식별 가능한 서비스 Top 20과 각각의 default 응답 패턴을 복사 가능한 정규식으로 정리해줘.
Gemini
무료: 2.5 Flash / Pro $19.99/mo: 3.1 Pro
내 호스트 핑거프린팅 결과 로그를 분석해서 CVE 매핑·취약 버전·우선순위 패치 항목을 종합 리포트로 만들어줘.
Grok
무료: Grok 4.1 / SuperGrok $30/mo
2026년 서비스 감지 트렌드 — Nmap NSE vs Masscan + Banner-grab vs ML 기반 핑거프린팅 실무 활용도를 솔직히 알려줘.
⭐ 이것만 기억하세요
서비스 감지: 무엇이 실행 중인가는 이 3가지만 확실히 잡으세요
1.배너 그래빙 + 정규식 패턴 매칭으로 서비스 종류와 버전을 80~90% 식별할 수 있다
2.python-nmap을 쓰면 nmap의 -sV(서비스 버전 감지) 결과를 Python에서 직접 활용할 수 있다
3.다음 챕터에서 ICMP/DNS/traceroute로 네트워크 응답을 분석하는 기법을 배운다
공유하기
진행도 69 / 84