ARTEX 기능 소개 및 설치 가이드
요약
ARTEX는 자산 관리, 에이전트 운영 및 보안 로그 분석 기능을 통합한 개발 도구입니다. ScopeSentry와 연동하여 회사 자산을 쉽게 동기화하고, LLM을 활용해 탐색 및 분석 작업을 수행할 수 있습니다. Docker 또는 로컬 컴파일 방식으로 설치가 가능하며, 다양한 API 설정을 지원합니다.
핵심 포인트
- ScopeSentry 연동으로 자산 데이터를 원클릭 통합 관리
- LLM(Anthropic/OpenAI) 기반의 에이전트 탐색 및 분석 기능 제공
- Docker Compose 또는 로컬 컴파일 방식으로 설치 가이드 제공
- 다양한 API 설정과 로그 관리를 지원하는 종합 플랫폼
전체 상호작용은 온라인 데모에서 확인 가능합니다.
| 대시보드 (개요 / Token 소모 / 활동 흐름) | 작업 목록 |
|---|---|
| 작업 · 실행 과정 (세션 / 도구 호출) | 탐색 링크 |
|---|---|
| 발견 | 자산 |
|---|---|
| 자산 커버리지 맵 (Force-directed layout · 테스트 완료 강조 · 노드 접기/펼치기) |
|---|---|
|
| 트래픽 기록 | 사람 참여 루프 대화 |
|---|---|
| Agent 관리 | LLM 설정 |
|---|---|
| 차단 승인 | 백엔드 로그 |
|---|---|
전역의 '승인 기록', 작업 내의 '차단 승인' 및 대화 중의 승인 카드는 모두 확장하여 상세 내용을 확인할 수 있습니다. 표시 구조는 AegisHook의 승인 상세 컴포넌트를 참고하며, ARTEX의 컴포넌트와 테마를 사용합니다:
ScopeSentry에서 직접 자산 데이터를 동기화할 수 있어 반복적인 수집이 필요 없습니다:
- '자산 동기화' 페이지에서 ScopeSentry의 주소와 API Key를 입력하여 데이터 소스를 연결합니다. - 프로젝트 또는 작업 차원으로 동기화할 목표 및 자산 유형(도메인 / 서브도메인 / IP / 포트 / 사이트 / 엔드포인트 등)을 선택합니다. - 원클릭으로 가져와 회사 자산 범위로 통합하고, ARTEX의 자산 맵에서 Agent가 탐색하여 사용할 수 있도록 합니다.
데이터베이스 의존성
PostgreSQL;
탐색을 위해서는 LLM(ANTHROPIC_API_KEY 또는 OPENAI_API_KEY)을 설정해야 하며, UI에서도 설정할 수 있습니다.
git clone https://github.com/Autumn-27/ARTEX.git
cd ARTEX
./install.sh
스크립트는 다음 작업을 수행합니다: / 자동으로 Docker를 설치하고 → ① 전체 Docker 또는 ② 로컬 컴파일 실행 중 하나를 선택하게 합니다:
① 전체 Docker: Postgres 비밀번호를 입력합니다 (Enter 키로 임의 생성 가능) → .env 파일 자동 작성 → docker compose up -d.
② 로컬 실행: 데이터베이스를 선택합니다 (기존 연결 / Docker 사용) → config.json 생성 → go 컴파일하여 내장 단일 바이너리를 만들고 → 시작합니다.
설치 후 **http://localhost:8787**에 접속하고 (최초 진입 시 /setup에서 관리자 비밀번호 설정).
git clone https://github.com/Autumn-27/ARTEX.git
cd ARTEX
cp .env.example .env # POSTGRES_PASSWORD, 선택적 ANTHROPIC_API_KEY 입력
...
이미지에는 일반적인 도구(ripgrep/curl/vim/npm/nmap 등)가 포함되어 있습니다. ./skills와 ./data는 바인딩 마운트를 통해 영속화됩니다.
원격 MCP는 시스템 설정에서 http (Streamable HTTP) 또는 sse (구 버전 SSE)를 선택할 수 있습니다.
구 버전 SSE 서비스는 일반적으로 GET /sse로 이벤트 스트림을 생성하고, 서비스가 반환하는 /message?sessionId=...를 통해 JSON-RPC 요청을 받습니다. 설정 시 URL에 /sse를 입력하고, 헤더는 Authorization=Bearer <token>으로 작성합니다.
릴리스(Releases)에서 해당 플랫폼의 zip 파일을 다운로드하여 압축을 풀면 artex + start.sh (Windows의 경우 start.bat) + skills/ + config.example.json이 있습니다:
cp config.example.json config.json # 데이터베이스 연결 정보 입력
./start.sh # → http://localhost:8787
반드시 start.sh 또는 start.bat으로 시작해야 하며, ./artex를 직접 실행해서는 안 됩니다. 이는 데몬 스크립트입니다. 프로그램이 종료되면 종료 코드를 기준으로 재시작 여부를 결정하며, 페이지의 원클릭 업데이트 기능은 이를 통해 이루어집니다. ./artex를 직접 실행하면 업데이트 후에는 다시 시작되지 않습니다. 백그라운드 상주: nohup ./start.sh >artex.log 2>&1 &.
# 1) 프론트엔드 정적 내보내기
cd web && npm ci && npm run build:static && cd ..
# 2) 내장 디렉토리에 복사
...
build.sh
먼저 프론트엔드를 구축하고 임베딩한 후, Go linker를 사용하여 디버깅 정보를 제거하고 배포 파일을 zip으로 압축합니다. Release 모드에서는 기본적으로 Linux amd64/arm64, macOS amd64/arm64 및 Windows amd64의 zip 파일이 생성됩니다:
./build.sh --release
# 산출물: dist/artex-0.3.3-*.zip
UPX는 자체 압축 해제 바이너리(self-extracting binary)일 수 있어 일부 Linux 커널, 가상화 환경 또는 보안 정책과 호환되지 않을 수 있으므로 기본적으로 비활성화됩니다. ARTEX_TARGETS를 사용하여 사용자 정의 목표를 설정할 수 있으며, 목표 실행 환경과의 호환성을 확인한 후에는 --upx를 명시적으로 전달하여 사용할 수 있습니다.
바이너리 크기 추가 축소:
ARTEX_TARGETS=linux/amd64,windows/amd64 ./build.sh --release
./build.sh --target linux/amd64 --upx
데이터만 업데이트하는 방법: Postgres 데이터 볼륨
pgdata, ./data (jwt.key / SQLite 등), ./skills는 모두 보존됩니다. 데이터베이스 마이그레이션은 수동으로 실행할 필요가 없습니다. artex는 시작할 때마다 schema.sql을 **멱등적(idempotent)**으로 재실행합니다 (예: ADD COLUMN/CREATE INDEX IF NOT EXISTS 포함), 즉 '재시작 시 마이그레이션'이 이루어집니다. 업그레이드 전에는 여전히 ./data와 데이터베이스를 백업하는 것이 권장됩니다.
시스템 설정 페이지(사이드바 「시스템 설정」→ /system/settings)의 버전 및 업데이트 카드에서 서버에 로그인할 필요 없이 새 버전을 직접 확인하고 설치할 수 있습니다.
'업데이트'를 누르면 다음 과정이 진행됩니다: 현재 플랫폼의 배포 패키지 다운로드 → Release의 SHA256SUMS와 비교 → -h로 새로운 바이너리 스모크 테스트(smoke test) 실행 → 임시 저장소에 artex.new로 보관 → 프로그램 종료 후, start.sh / start.bat가 재실행되어 교체 작업을 완료합니다. 페이지는 자동으로 새 버전이 온라인 상태가 될 때까지 새로고침됩니다.
실패해도 문제가 남지 않음: 검증 또는 스모크 테스트에 실패하면 임시 파일을 폐기하고 현재 버전을 유지하며, 교체된 새 버전이 연속 3회 시작에 실패할 경우 자동으로 artex.old로 롤백합니다 (실패한 파일은 디버깅을 위해 artex.failed로 보관됩니다). 언제든 롤백 가능: 이전 버전은 artex.old로 유지되며, 카드에는 '이전 버전으로 롤백' 버튼이 있습니다. 주의할 점은 데이터베이스 구조는 롤백되지 않는다는 것입니다. 업데이트 시 실행 중인 작업 중단됨: 업데이트는 곧 재시작을 의미하므로, 여유 시간에 진행해야 합니다. 개발 빌드는 업데이트 기능 없음: 버전 번호가 dev 또는 git describe와 접미사가 붙은 경우 업데이트 기능을 비활성화하여 정식 버전이 로컬 디버깅 바이너리를 덮어쓰는 것을 방지합니다.
Docker 환경에서는 프로그램만 교체하고 이미지는 변경하지 않음: 이미지 내부의 playwright / nmap 같은 도구 체인은 업그레이드에 따라 함께 올라가지 않으며, docker compose up -d로 컨테이너를 재구축하면 이미지 자체에 포함된 버전으로 되돌아갑니다. 만약 이미지까지 함께 업그레이드하려면 docker compose pull artex && docker compose up -d artex를 사용해야 합니다.
- GitHub 접속 시 프록시가 필요한 경우, 같은 페이지에서 **전역 프록시(global proxy)**를 설정하면 업데이트 과정이 이를 따릅니다. 업데이트는 GitHub 도메인에서만 다운로드하며 강제 HTTPS를 사용합니다.
cd ARTEX
./update.sh
스크립트는 먼저 선택적으로 git pull을 실행하여 최신 코드를 가져온 후, ① Docker 업데이트 또는 ② 로컬 컴파일 업데이트(이는 install.sh와 대응됨) 중 하나를 선택하게 합니다:
① Docker: 대상 이미지 태그를 지정할 수 있습니다 (엔터 키를 누르면 .env의 ARTEX_TAG를 사용하며, 기본값은 latest). → docker compose pull → docker compose up -d (새 이미지로 교체하고 재시작하면 자동 마이그레이션됩니다). ② 로컬: 프론트엔드 정적 산출물을 재구축한 후 ./artex를 다시 컴파일합니다 (완료 후 프로세스 재시작 시 적용됨).
cd ARTEX
git pull # compose / 스크립트 업데이트 (선택 사항)
# 버전을 지정하려면: .env에 ARTEX_TAG=v0.2.0 설정; 설정하지 않으면 latest 사용
...
Releases에서 새 버전 zip을 다운로드하여, 기존 프로세스를 중지한 후 artex와 skills/를 덮어쓰고 (사용자의 config.json과 data/는 보존됨), 재시작하면 됩니다:
cp -r <압축 해제 디렉토리>/skills ./ && cp <압축 해제 디렉토리>/artex ./
./start.sh
git pull
cd web && npm ci && npm run build:static && cd ..
cp -r web/out server/webui/dist
...
데이터베이스 (config.json, 또는 환경 변수 ARTEX_PG_DSN으로 덮어쓰기):
{
"database": {
"host": "127.0.0.1", "port": 5432,
...
}
LLM: export ANTHROPIC_API_KEY=sk-...
(또는 OPENAI_API_KEY)로 설정하거나, UI의 'LLM 구성' 페이지에서 입력할 수 있습니다. 선택 사항: ARTEX_LLM_PROVIDER / ARTEX_LLM_MODEL / ARTEX_LLM_BASE_URL / ARTEX_LLM_PROXY.
동시성(Concurrency): 각 작업의 work agent 수는 '시스템 설정'에서 구성합니다 (기본값 3).
자주 사용되는 파라미터: ./start.sh -addr :8787 -proxy :8788
(-addr: 프론트엔드 + API, -proxy: 트래픽 기록 프록시). 시작 스크립트는 이 파라미터를 artex에 그대로 전달합니다.
프론트엔드와 API/SSE는 동일한 백엔드 포트(기본값 :8787)에서 제공되며, 실시간 활동 스트림은 기본적으로 동일 출처(Same Origin) 주소를 사용하므로 NEXT_PUBLIC_SSE_BASE를 설정할 필요가 없습니다. 공용 인터넷에는 443만 열어두고 8787 포트는 내부망에 두면 됩니다.
SSE는 장기 연결(Long Connection) + 지속적인 푸시이므로, 리버스 프록시는 버퍼링을 반드시 비활성화해야 합니다. 그렇지 않으면 브라우저가 연결은 되지만 이벤트를 수신하지 못하는 현상(활동 스트림이 계속 돌아가는 것으로 표시됨)이 발생합니다. Nginx 예시:
server {
listen 443 ssl;
server_name your.domain.com;
...
}
SSE가 페이지와 다른 출처(예: 독립 서브도메인)를 통해 전송되어야 할 때만, 빌드 시점에 NEXT_PUBLIC_SSE_BASE를 설정합니다 (이 변수는 next build 시 정적 패키지에 고정되며, 컨테이너 실행 시에는 무시됩니다).
작업 상세의 '재시험(Retest)' 탭에서는 해당 작업의 취약점 목록을 페이지 단위로 선택하고, 과거 결론 및 증거를 확인하며 수동으로 재시험을 시작할 수 있습니다. 시작 후 현재 탭은 유지되며, 돌아가는 아이콘과 '재시험 중'이 표시됩니다. 수정이 확인되면 취약점 상태가 동기적으로 업데이트됩니다.
취약점 목록의 각 행 작업 영역에서 '재시험'을 클릭하거나, 취약점 상세의 '취약점 재시험' 영역에서 '재시험 시작'을 클릭하고 선택적 수정 버전, 테스트 조건 또는 제한 사항을 입력하면, 시스템은 독립적인 재시험 Agent 세션을 생성하고 현재 페이지를 유지합니다. 목록의 평면 배치(flat), 작업별 그룹화, 자산 뷰 모두 이 진입점을 지원합니다. 재시험 실행 중에는 돌아가는 아이콘과 '재시험 중'이 표시되며, 확인하려면 해당 세션으로 클릭하여 이동해야 하고, 완료되면 '재시험' 상태로 복구됩니다. 재시험은 원본 스캔 작업을 다시 시작할 필요가 없으며, 결론은 '여전히 재현 가능', '수정됨', '확인 불가'로 나뉩니다. 매번의 결론, 증거 및 세션 링크는 취약점 상세에 저장됩니다.
새 버전 백엔드는 최초 실행 시 편집 가능한 '취약점 재시험'(retester) Agent를 기본 제공하며, 이는 Agent 관리에서 프롬프트, LLM, 실행 예산 및 도구를 구성할 수 있습니다. 기본적으로 연결된 LLM을 사용하며, 연결되지 않은 경우 전역 활성화 구성을 사용합니다. 재시험 세션이 성공적으로 완료되고 결론이 '수정됨'인 경우, 시스템은 자동으로 취약점 처리 상태를 '수정됨'으로 변경합니다. 실행 중, 실패, 중지 또는 기타 결론의 경우 원래 상태를 유지합니다. 원본 증거와 보고서는 항상 보존됩니다. 또한 상태 드롭다운 메뉴에서 수동으로 '수정됨'을 선택할 수도 있습니다. 동일한 취약점이 재시험되는 동안 기존 세션을 재사용하며, 중지, 실패 또는 서비스 재시작 후에는 다시 시작할 수 있습니다.
본 버전의 기록은 취약점 상세 및 세션에서 확인할 수 있으며, 아직 취약점 보고서 내보내기나 작업 아카이브 패키지에 포함되지는 않았고, 트래픽 패키지와도 자동으로 연결되지 않습니다. 데모 모드는 명시적으로 표시된 시뮬레이션 기록만 생성하며 실제 목표를 요청하지 않습니다.
./dev.sh # 백엔드(:8787) + 트래픽 프록시(:8788) + 프론트엔드 next dev(:5173) → http://localhost:5173
- 백엔드:
go run ./cmd/artex
(-tags embedui가 없으면 프론트엔드가 내장되지 않음) - 프론트엔드:
cd web && npm run dev
(/api는 백엔드로 리버스 프록시되며, 핫 업데이트 지원) - 테스트:
go test ./... - Mock 미리보기 (백엔드 없음):
cd web && NEXT_PUBLIC_MOCK=1 npm run dev
ARTEX는 LLM 다중 Agent 구동의 자율 침투 시스템입니다: Go 단일 백엔드(Next.js 프론트엔드 내장) + PostgreSQL, agent 능력은 norma SDK에서 제공합니다 (agentcore / tool / permission / harness / memory / transcript) . 핵심은 이중 그래프 아키텍처와 그 주변의 두 가지 자율성 메커니즘입니다: Worker 간 프로세스 레벨 정보 교환과 Planner 다중 라운드 공유 ToDoList 안정 공격 링크.
시스템은 「목표가 무엇인지」와 「어느 정도까지 측정되었는지」를 두 개의 상호 독립적이면서도 앵커(anchor)를 통해 연결된 그래프로 분리합니다:
자산 그래프 (Asset Graph, 전역 공유): 작업 간 동일한 자산의 진실 공급원(Source of Truth)입니다. 노드는 root_domain / subdomain / ip / service / app / endpoint이며, 소속 회사 정보가 포함됩니다.
도메인 → 서브도메인 → 서비스 → 엔드포인트의 부모-자식 관계와 중복 제거 키(key)는 모두 프로그램이 계산하며, agent는 원본 정보만 제출합니다. 탐색 그래프 (Exploration Graph, 작업별 독립): 한 번의 작업에 대한 “사고 및 전진” 과정입니다. 노드는 goal(목표)/ intent(의도)/ fact(사실)/ finding(취약점)/ hint(힌트)이며, spawns / derived_from / yields / proves 등의 엣지(edge)로 연결되어 **혈통 사슬(lineage chain)**을 형성하여 “어떤 방향이 어떤 사실에서 파생되었고, 무엇을 산출했는지”에 답합니다. 두 그래프는 앵커를 통해 연결: exploration_anchors(node_id, asset_id)
의도/사실/취약점을 특정 자산에 고정(anchor)함으로써, “탐색 방향”에서 어떤 자산을 대상으로 했는지 볼 수 있을 뿐만 아니라, “특정 자산”에서 이 작업 내에서 어떤 의도로 테스트했는지, 어떤 사실을 도출했는지를 역추적할 수 있습니다. 이는 자산 테스트 커버리지 및 자산 맵(Asset Map) (범위 내 자산 + 측정 완료 항목 하이라이트)를 지원합니다.
분업:
planner는 탐색 그래프의 상황을 읽고 목표를 판단하며, 미커버된 새로운 방향이 있을 때만 의도를 frontier로 전파합니다. worker는 하나의 의도를 받아 실제 도구를 사용해 실행하고, 새로운 자산/사실/취약점을 두 그래프에 기록한 후 종료됩니다. 자산 그래프는 공유 사실이고, 탐색 그래프는 작업별 진행 사슬입니다.
엔진은 이벤트 기반의 폐쇄 루프(closed loop)입니다: 한 그래프가 변경되면 planner가 깨어나고, planner가 의도를 전파하면 worker가 의도를 받아 실행하고 기록하며, 이 기록은 다음 라운드를 촉발합니다. 이는 목표가 증명될(prove_goal) 때까지 지속됩니다.
한 번의 깊이 있는 탐색 과정에서 많은 가치 있는 관찰(특정 오류 메시지, 특정 응답, 숨겨진 매개변수 등)이 worker의 실행 과정 중에 나타날 수 있지만, 반드시 공식적인 fact로 기록되지는 않습니다. 중복 작업을 방지하고 링크상의 worker가 서로의 어깨 위에 설 수 있도록, worker는 크로스 워크 검색 과정(cross work retrieval process) 능력을 갖추고 있습니다:
search_all_worker_traces(q): 본 작업의 다른 work 실행 과정에서 키워드로 검색합니다 (자신의 의도 단계는 자동 제외). 매칭된 항목은 intent_id를 포함합니다.
list_worker_traces/get_worker_trace(intent_id, step_ids=[…]): 먼저 어떤 work가 실행되었는지 확인한 후, 특정 work의 구체적인 몇 단계를 가져와 상세 정보를 교환합니다.
이렇게 하면 탐색 그래프에 아직 해당 fact가 없더라도, 후속 worker는 타인의 과정에서 얻은 관찰을 재사용할 수 있습니다. 즉, 정보는 worker 간에 “실행 과정”이라는 단위로 흐르지만, 경계는 변하지 않습니다 (각 worker는 여전히 자신이 받은 의도만 수행합니다).
flowchart LR
WA["worker A(意图 #12)"] -->|"每步 activity"| ACT[("探索图 · activity 过程库")]
WB["worker B(意图 #34)"] -->|"每步 activity"| ACT
...
실제 공격 체인은 순차적인 전후 의존성을 가진 다단계 시퀀스입니다 (예: 취약점 주입 지점 발견 → 자격 증명 획득 → 측면 이동 → 권한 상승). 이러한 것들을 한 번에 병렬로 실행하면 혼란만 야기됩니다. 따라서 planner는 **작업별로 보존되며, 호출 간 공유되는 계획 할 일 목록(todolist)**을 보유합니다:
- planner는 이벤트 기반입니다—다이어그램이 변경되면 깨어나지만,
매번의 각성은 새로운 세션입니다; 공유된 todolist 덕분에 하나의 순차적 이용 체인을 한 번 기록하고, 이후 다수의 라운드에 걸쳐 의존성에 따라 단계적으로 의도를 전개합니다. 즉, 전체 체인을 한 라운드에서 미리 펼치지 않습니다.; - 각 라운드에서는 「선행 단계가 완료되었고, 그 의존 fact가 존재하는」 다음 단계를 대상으로만 의도를 전개하며, 진행에 따라 목록을 업데이트합니다 (이미 fact로 충족된 단계는 완료로 표시).
flowchart TB
subgraph TODO["공유 todolist (작업별 보존 · 호출 간 상주)"]
direction LR
...
그리하여 공격 체인은 “이벤트 기반 + 무상태 세션” 환경에서도 안정적으로 진행하고, 중복되지 않으며, 순서가 틀어지지 않습니다—이것이 ARTEX가 다단계 이용 체인을 자율적으로 완료할 수 있는 핵심입니다.
위챗 공식 계정 SecSentry를 스캔하여 팔로우하고, 공식 계정 백그라운드에서 개인 메시지를 보내 그룹에 참여하세요.
본 프로젝트는 GNU Affero General Public License v3.0 (AGPL-3.0) 라이선스로 배포되며, 전체 조항은 저장소 루트 디렉토리의 LICENSE 파일을 참조하십시오.
이는 누구나 본 프로젝트를 자유롭게 사용, 수정 및 배포할 수 있음을 의미하지만, 파생 작품은 반드시 동일하게 AGPL-3.0으로 오픈 소스여야 합니다; 특히, 본 프로젝트를 수정하여 네트워크(예: 온라인 서비스로 배포)를 통해 사용자에게 제공하는 경우에도 해당 완전한 소스 코드를 사용자에게 공개해야 합니다.
⚠️ 중요 공지: 오픈소스 프로토콜 자체는 소프트웨어의 사용 목적을 제한하지 않습니다. 아래의 「사용 제한」 및 「면책 조항」은 저자가 사용자에게 추가로 약속하고 엄중히 밝히는 것이므로, 반드시 준수해 주십시오.
ARTEX는 개인 학습, 코드 연구 및 로컬 기술 검증 목적으로만 사용되어야 하며, 어떠한 온라인 시스템이나 웹사이트에 대한 실제 테스트 용도로는 사용할 수 없습니다.
- 다음 용도로만 사용 가능:
본 프로젝트 소스 코드를 읽고, 배우고, 연구하는 것, 그리고 로컬 격리 환경에서 기술 원리를 검증하는 것; - 개인 학습, 학술 연구, 코드 검토 등 비공격적 목적에 적합합니다.
어떠한 웹사이트, 온라인 서비스 또는 네트워크 시스템에 대한 스캔, 탐지, 이용 또는 공격을 본 도구로 수행하는 것은 엄금됩니다 (권한 여부나 자산 소유 여부를 불문함);
- 본 도구를 실제 침투 테스트, 공방 대항(攻防对抗) 또는 프로덕션 환경에 사용하는 것을 엄금합니다;
- 본 도구를 불법 침입, 데이터 절도, 랜섬웨어, 서비스 거부(DoS) 또는 기타 파괴적이거나 범죄적인 활동에 이용하는 것을 엄금합니다;
- 본 도구를 사용하여 해당 국가/지역의 법률 및 규정을 위반하는 행위를 하는 것을 엄금합니다.
사용자는 자신이 속한 국가/지역의 네트워크 보안, 데이터 보호 및 컴퓨터 범죄 관련 모든 법규를 스스로 준수해야 합니다 (중국 대륙에서는 《사이버보안법》《데이터보안법》《개인정보보호법》 및 관련 사법 해석을 포함하나 이에 국한되지 않습니다). 본 도구 사용으로 인해 발생하는 모든 법적 책임과 결과는 사용자 본인이 부담합니다.
본 프로젝트는
AI 자동 생성 콘텐츠
본 콘텐츠는 GitHub Trending Go (weekly)의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기