-
이 실습의 목표는 악성 JavaScript를 “실행”하는 것이 아니라, 네트워크가 끊긴 Podman 샌드박스에서 정적 분석하고 LLM이 만든 가설을 PCAP 증거로 재검증하는 것입니다.
Malware-Traffic-Analysis.net의 2026년 2월 2일 자료는 정상 웹사이트에 삽입된 KongTuke JavaScript가 방문자를 식별하고 가짜 CAPTCHA로 유도한 뒤, ClickFix를 통해 MintsLoader와 GhostWeaver RAT 감염으로 연결된 흔적을 담고 있습니다.
LAB-ONLY malicious JavaScript sample
WARNING: This archive contains the original KongTuke 1d2g.js. Do not open or execute it on Windows, in a browser, or with Node.js. Read README-SAFETY.md first and perform static analysis only in a disposable Podman container with --network=none and --read-only.
Sample SHA-256: fd78199a75a96c6475f7c95400be3bfc3b07651c7de9785a05c293292cdfba54
특히 이 사례는 LLM 실습에 잘 맞습니다. 난독화된 1d2g.js를 LLM에게 주고 구조와 의도를 가설로 만든 뒤, 사람이 원본 코드와 비교하고 Wireshark로 실제 패킷을 확인할 수 있기 때문입니다. 수강생은 코드를 처음부터 직접 작성하지 않고, 이 글의 단계별 프롬프트로 LLM에게 분석 절차와 정적 변환 스크립트를 만들게 합니다.

Podman 격리, LLM 정적 분석, PCAP 교차 검증을 하나의 실습 흐름으로 표현한 이미지
실습하기 전에 바로잡아야 할 사실
공식 페이지는 최종 악성코드를 처음에 Async RAT으로 판단했지만, 후에 GhostWeaver RAT로 정정했습니다. 따라서 이 글의 감염 흐름은 KongTuke → ClickFix → MintsLoader → GhostWeaver RAT로 정리합니다. LLM이 과거 정보나 단서 하나에 끌려 Async RAT으로 답한다면, 그 답변은 오히려 “정정 사항을 확인해야 하는 이유”를 보여 주는 실습 자료가 됩니다.
이 실습에서는 공식 자료 중 다음 두 개만 사용합니다.
자료 용도 주의점 전체 PCAP 압축 DNS·HTTP·TLS·포트 행위 검증 PCAP 내부에 악성 콘텐츠가 있을 수 있음 HTTPS traffic leading to ClickFix page 압축 1d2g.js, js.php 응답 정적 분석 브라우저로 열거나 JavaScript를 실행하지 않음 files from infection 압축은 실행 파일을 포함하므로 이 실습에서 다운로드하지 않습니다. Malware-Traffic-Analysis.net도 압축과 PCAP에 악성 샘플이 있을 수 있으며 Windows 호스트에서 취급할 때 감염 위험이 있다고 경고합니다.
샌드박스는 “권고”가 아니라 실습 조건이다
샘플을 다루는 동안 호스트의 홈 디렉터리, SSH 키, 브라우저 프로필, Podman 소켓을 컨테이너에 마운트하면 안 됩니다. 입력 디렉터리는 읽기 전용, 결과 디렉터리만 쓰기 가능으로 나눕니다. 실행 중에는 네트워크를 완전히 끊고 루트 파일시스템도 읽기 전용으로 두어야 합니다.

그림: LLM에는 정적 텍스트만 전달하고, 최종 판정은 원본과 패킷 증거를 본 사람이 내립니다. Podman run 공식 문서를 바탕으로 재구성
Podman의 --network=none은 컨테이너용 네트워크 네임스페이스만 만들고 인터페이스를 구성하지 않으며, --read-only는 컨테이너 루트 파일시스템 쓰기를 막습니다. 이 두 조건을 생략한 실습은 진행하지 않는 것이 좋습니다.
0단계: LLM에게 격리 실습실을 만들게 하기
먼저 공식 사례 페이지에서 앞서 선정한 두 압축만 kongtuke-lab/input 폴더에 저장합니다. 압축을 호스트에서 풀지 말고 다음 프롬프트를 LLM에 입력합니다.
프롬프트 0 — Podman 샌드박스 설계
너는 악성코드 정적 분석 실습 조리사다. 현재 폴더의 input/ 안에는 Malware-Traffic-Analysis.net 2026-02-02 KongTuke 사례의 PCAP zip과 HTTPS transcript zip만 있다. 다음 조건을 모두 만족하는 Containerfile과 실행 명령을 작성해라. - Debian 12 slim 기반 - p7zip-full, tshark, Python 3, python3-jsbeautifier, ripgrep, jq만 설치 - 이미지 build 때는 샘플을 마운트하지 말 것 - 분석 run은 --network=none, --read-only, --read-only-tmpfs=false를 사용 - /tmp만 noexec,nosuid,nodev tmpfs로 허용 - input은 /input:ro, output은 /output:rw로 분리 - --cap-drop=all, --security-opt=no-new-privileges 사용 - JavaScript, PowerShell, PE 파일은 절대 실행하지 말 것 - 압축 해제는 컨테이너 안에서만 수행 - 해제 전후 SHA-256와 파일 목록을 출력 명령 실행 전에 각 안전 옵션이 무엇을 막는지 한 줄씩 설명해라.LLM이 만든 답안에는 최소한 다음 패턴이 있어야 합니다.
podman run --rm \ --network=none \ --read-only --read-only-tmpfs=false \ --tmpfs /tmp:rw,noexec,nosuid,nodev \ --cap-drop=all \ --security-opt=no-new-privileges \ -v "$PWD/input:/input:ro" \ -v "$PWD/output:/output:rw" \ kongtuke-static-lab:2026.02 ...이미지를 만드는 podman build에는 패키지 설치를 위한 네트워크가 필요합니다. 다만 그 단계에는 샘플을 마운트하지 않습니다. 샘플이 마운트되는 분석 run에서만 네트워크를 끊습니다. Apple Silicon에서 x86 이미지 경고가 나오면 podman build --platform linux/arm64 ...로 아키텍처를 명시합니다.
전체 실습 흐름

그림: 보라색 단계는 LLM이 만드는 가설이고, 초록색 단계는 Wireshark/tshark의 관측 증거입니다. KongTuke 공식 사례와 Wireshark Export 문서를 바탕으로 재구성했습니다.
1단계: PCAP에서 1d2g.js 단서 찾기
이 PCAP은 25,841개 패킷, 약 19MB, 313.955초 분량입니다. 캡처는 2026년 2월 2일 17:49:22 UTC에 시작해 17:54:36 UTC에 끝납니다. 먼저 PCAP을 LLM에 올리지 말고, 다음 프롬프트로 필터와 tshark 명령만 만듭니다.
프롬프트 1 — PCAP 트리아지 명령 생성
이 PCAP은 KongTuke ClickFix 후보 사례다. PCAP 파일을 수정하지 않고 다음 증거를 찾는 tshark 명령을 생성해라. 1. 캡처 시간, 패킷 수, SHA-256 2. DNS 질의 이름 3. TLS ClientHello SNI 4. HTTP 요청의 시간, 호스트, 메서드, URI 5. TCP 79, 3456, 25658 번 포트의 시간순 흐름 조건: - 오프라인 PCAP만 읽어라. - 외부 도메인으로 접속하지 말라. - 출력에서 내부 IP와 피해자 공인 IP는 마스킹하라. - 각 명령 다음에 “이 결과로 알 수 있는 것/알 수 없는 것”을 써라.예상 증거는 처음 방문한 정상 사이트 oceanbistrooumc[.]com과 JavaScript 제공지 soulversr[.]com의 DNS·TLS SNI입니다. 그러나 TLS 패킷에서 1d2g.js 본문까지 바로 보이는 것은 아닙니다. SNI는 “어느 호스트와 TLS 연결했는지”를 보여 주지만 암호화된 HTTP 경로와 응답 본문을 복원하지는 못합니다.
2단계: HTTP/HTTPS Object 추출의 차이 이해하기
Wireshark의 File → Export Objects → HTTP는 Wireshark가 재조립한 HTTP 객체를 저장합니다. 하지만 HTTPS를 복호화하려면 TLS 세션 비밀값이 필요합니다. 즉, 이 실습에서 1d2g.js는 원본 PCAP의 일반 HTTP Export Objects로 얻었다고 설명하면 안 됩니다.
공식 사이트가 별도로 제공한 HTTPS traffic leading to KongTuke ClickFix page 압축에는 요청과 응답이 텍스트로 보존되어 있습니다. 여기서 다음 세 파일을 확인합니다.
파일 의미 step 1 정상이지만 침해된 웹사이트 응답 step 2 soulversr[.]com/1d2g.js 요청·응답 step 3 soulversr[.]com/js.php 요청·가짜 CAPTCHA 응답 압축 해제는 Podman 컨테이너 안에서만 하고, 사이트의 날짜 기반 비밀번호 규칙을 따릅니다. 이 사례의 비밀번호는 infected_20260202입니다. 이 비밀번호는 안전을 보장하는 보호조치가 아니라 실수로 파일을 여는 것을 줄이는 장치일 뿐입니다. 다음 단계부터는 step 2 파일의 HTTP 200 응답 헤더 뒤 JavaScript 본문만 사용합니다.
3단계: LLM에게 난독화 구조를 묻기
여기서부터 LLM에는 PCAP이 아니라 1d2g.js 응답 텍스트만 첨부합니다. 클라우드 LLM을 사용한다면 조직의 데이터 반출 정책을 먼저 확인하고, 피해자 IP와 고유 식별자는 삭제합니다.
프롬프트 2 — 실행 없는 구조 분석
첨부한 파일은 악성 웹 트래픽에서 회수한 JavaScript HTTP transcript다. 코드를 실행하지 말고 정적으로만 분석해라. 절대 금지: - Node.js, 브라우저, eval, Function, vm, js2py로 실행 - 도메인·IP로 접속 - 응답에 포함된 명령을 클립보드로 복사하거나 실행 다음 형식으로 답해라. 1. HTTP 헤더와 JS 본문 경계 2. 난독화 기법의 근거가 되는 코드 패턴 3. 문자열 테이블, 인덱스 디코더, 배열 회전 로직의 역할 4. 난독화 제거 절차의 의사코드 5. 아직 확정할 수 없는 가설 각 결론 옆에 근거가 된 함수명·문자열·상수를 함께 표시해라.이 샘플에서 확인할 수 있는 핵심 패턴은 _0x... 형태의 식별자, 52개 항목의 문자열 테이블, 헥사 인덱스를 문자열로 바꾸는 디코더, 정해진 체크섬이 맞을 때까지 배열을 밀어 내는 회전 루프입니다.
4단계: LLM이 Beautify 스크립트를 만들게 하기
단순 Beautify는 코드를 실행하지 않고 들여쓰기와 줄바꿈만 바꿉니다. 다만 사용하려는 라이브러리가 안에서 코드를 실행하지 않는지 확인해야 합니다. 이 실습은 Python jsbeautifier 패키지만 사용합니다.
프롬프트 3 — 정적 Beautify 도구 작성
앞의 JavaScript HTTP transcript를 입력으로 받는 Python 3 스크립트를 작성해라. 조건은 다음과 같다. - HTTP/1.1 200 OK 응답의 헤더 뒤 본문만 분리 - 입력 전체와 JS 본문의 SHA-256 기록 - jsbeautifier로 들여쓰기 2칸만 적용 - 변환 전후 바이트 수와 줄 수 기록 - JavaScript를 import·eval·exec·subprocess로 실행하지 말 것 - 입력은 읽기 전용, 결과는 별도 디렉터리에 저장 - “JavaScript was never evaluated”를 결과 JSON에 기록 작성한 코드를 먼저 설명하고, Podman --network=none 안에서 실행할 명령까지 제공해라.실측 결과는 다음과 같았습니다.
항목 결과 JS 본문 크기 5,533 bytes Beautify 전 1줄 Beautify 후 133줄 JS 본문 SHA-256 fd78199a75a96c6475f7c95400be3bfc3b07651c7de9785a05c293292cdfba54 문자열 테이블 52개 정상 배열까지의 회전 30회 이 숫자는 LLM의 답을 맹신하는 대신 “우리가 같은 입력과 변환 경계를 봤는지”를 확인하는 체크포인트입니다.
5단계: 문자열과 함수 역할 복원하기
프롬프트 4 — 정적 디코더 생성
Beautify한 JavaScript의 문자열 테이블과 인덱스 디코더를 정적으로 복원하라. 실행기를 사용하지 말고 Python의 ast.literal_eval, 정규표현식, 숫자 연산만 사용해라. 요구 결과: 1. 배열 회전 횟수와 검증한 체크섬 2. 인덱스별 복원 문자열 표 3. 디코더 호출을 문자열 리터럴로 바꾼 새 파일 4. 의미 없는 변수를 역할 기반 이름으로 바꿀 후보 표 5. 원본과 변환본에서 네트워크 URL, 파라미터 수, 분기 조건이 보존되었는지 검사하는 방법 금지: eval, exec, Node.js, 브라우저, 외부 접속, 원본 덮어쓰기. 모든 출력은 새 파일에 저장하고 SHA-256을 남겨라.복원한 의사코드는 아래 정도로 요약됩니다. 이는 실행 가능한 원본을 재현한 것이 아니라 행위를 이해하기 위한 표현입니다.
if 완료 쿠키가 없다: 일정 기간의 완료 쿠키를 설정한다 Cloudflare trace 정보에서 공인 IP와 위치 코드를 얻는다 User-Agent에서 브라우저와 운영체제를 판단한다 현재 URL과 User-Agent를 읽는다 일부 값을 Base64로 인코딩해 js.php 요청을 만든다 응답이 충분히 길면 document.write로 현재 문서에 쓴다이 요약을 원본의 XMLHttpRequest, cdn-cgi/trace, navigator.userAgent, window.location.href, btoa, /js.php, document.write 문자열과 하나씩 맞춰 보면 LLM의 설명이 코드 근거를 가지는지 확인할 수 있습니다.
6단계: Fingerprinting 로직 분석하기
프롬프트 5 — 수집 항목과 목적 분리
복원한 JavaScript에서 환경 식별에 사용되는 값만 찾아 표로 만들어라. 열은 다음과 같다. - 수집 항목 - 코드 출처 - 가공 방식 - js.php 파라미터명 - 가능한 사용 목적 - 확정/추정 공인 IP나 피해자 고유 식별자는 출력하지 말고 <redacted>로 표시해라. “악성코드가 이 값으로 실제로 무엇을 했는지”는 코드만으로 확정하지 말고 후속 PCAP 검증 항목으로 남겨라.수집값 코드 출처 전송 형태 해석 운영체제 platform/User-Agent 패턴 평문 Windows·macOS·iOS·Android·Linux 분류 공인 IP Cloudflare trace의 ip Base64 방문자 식별·위치 추정 가능 유입 URL window.location.href Base64 어느 침해 사이트에서 왔는지 표시 브라우저 User-Agent 문자열 분기 Base64 Edge·Chrome·Firefox 등 분류 User-Agent navigator.userAgent Base64 OS·브라우저 상세 정보 기반 도메인 코드의 base URL Base64 가짜 페이지 생성 정보 국가 코드 Cloudflare trace의 loc Base64 지역별 분기 가능 Base64는 암호화가 아닙니다. 네트워크 로그에서 즉시 읽히지 않게 표현을 바꾸는 수준이므로 복호화한 값을 반드시 원본 생성 코드와 교차 확인합니다.
7단계: js.php 요청 파라미터 분석하기
프롬프트 6 — Base64 파라미터 검증
첨부한 js.php HTTP transcript의 첫 요청줄에서 query string만 분리해라. urllib.parse와 base64 표준 라이브러리만 사용하는 Python 스크립트를 만들어라. 조건: - 네트워크 접속 금지 - ip 값은 복호화하되 출력에는 <public-ip-redacted>로 저장 - refferer 철자는 원본대로 유지 - 파라미터별 원문, 복호화 값, 코드에서 생성한 변수를 표로 정리 - 원본 JavaScript의 URL 조합 순서와 파라미터 순서가 맞는지 검사실제 복호화 결과는 다음과 같습니다.
파라미터 결과 device windows ip <public-ip-redacted> refferer hxxps[:]//oceanbistrooumc[.]com/ browser Edge ua Windows 10, Chrome/Edge 144 계열 User-Agent domain hxxps[:]//soulversr[.]com loc US is_ajax 1 여기서 코드 가설과 패킷 관측이 첫 번째로 만납니다. 코드가 soulversr[.]com/js.php를 만든다는 점, 공식 HTTPS 텍스트에 같은 요청이 남아 있다는 점, 해당 호스트의 TLS SNI가 PCAP에 존재한다는 점이 연결됩니다.
8단계: ClickFix에서 GhostWeaver까지 PCAP로 검증하기
js.php 응답은 사용자에게 “사람임을 확인하라”는 가짜 CAPTCHA를 보여 주고, Windows 실행 창을 열어 클립보드의 내용을 붙여 넣고 실행하도록 유도합니다. 응답 소스에는 클립보드에 실행 명령을 심는 로직이 있습니다.
이 글에는 해당 명령 전문을 싣지 않습니다. 수강생도 복사하거나 Windows에서 실행하지 않습니다. 대신 후속 패킷을 시간순으로 보며 클립보드 명령이 실행된 뒤의 효과만 검증합니다.
프롬프트 7 — 코드 가설을 PCAP 필터로 바꾸기
정적 코드 분석 결과는 아래와 같다. - 가짜 CAPTCHA가 Windows 실행 창과 클립보드 붙여넣기를 유도한다. - 응답에 클립보드 명령 생성 로직이 있다. - 정확한 명령 전문은 보고서에 싣지 않는다. 이 가설을 검증하기 위한 Wireshark display filter와 tshark 명령을 만들어라. 검증 대상은 다음과 같다. 1. Finger 프로토콜 TCP 79 2. TCP 3456의 HTTP GET /o, POST /m 3. 후속 .top 도메인의 HTTP 요청 4. TCP 25658의 TLSv1 세션 5. api.ipify.org, checkip.dyndns.org, ipinfo.io 접속 각 행을 시간순 표로 만들고, “코드로 예상한 것”과 “PCAP에서 관측한 것”을 별도 열로 두어라. IOC는 보고서에서 도메인의 마침표를 [.] 형태로 비활성화해라.Wireshark에서는 아래 필터를 순서대로 적용하면 됩니다.
dns.qry.name tls.handshake.extensions_server_name http.request tcp.port == 79 || tcp.port == 3456 || tcp.port == 25658관측한 핵심 시간선은 다음과 같습니다. 모든 IOC는 비활성화했습니다.
UTC 시각 PCAP 관측 해석 17:50:04 144.31.238[.]37:79 Finger 질의·응답 ClickFix 후 첫 단계 통신 17:50:04 85.137.253[.]64:3456 GET /o 후속 콘텐츠 가져오기 17:50:10 같은 호스트에 POST /m 후속 요청 전송 17:50:11 sbwur1[.]top GET /1.php?... MintsLoader 트래픽 17:50:13 gecdfcjcbcmmakk[.]top GET /9at1biglx5htr.php?... MintsLoader 후속 트래픽 17:50:22 173.232.146[.]62:25658 TLSv1 ClientHello GhostWeaver RAT 통신 시작 17:50:23 이후 api.ipify[.]org HTTPS 공인 IP 확인 17:51:16 checkip.dyndns[.]org, ipinfo[.]io HTTP IP·지역 정보 확인 이제 LLM이 설명한 행위와 PCAP의 실제 패킷이 만납니다. JavaScript 정적 분석은 사용자 식별과 가짜 CAPTCHA 생성까지를 보여 주고, PCAP은 클립보드 명령 실행 후 Finger·HTTP·MintsLoader·GhostWeaver 통신이 실제로 이어졌음을 보여 줍니다.
최종 프롬프트: LLM 분석가를 다시 검증하기
마지막 프롬프트는 요약을 시키는 것이 아니라 틀릴 수 있는 부분을 스스로 찾게 하는 역할을 합니다.
네가 앞서 만든 KongTuke 분석 보고서를 적대적으로 검토해라. 각 주장을 다음 세 등급으로 분류해라. - A: 원본 JavaScript와 PCAP 둘 다에서 확인 - B: 둘 중 하나에서만 확인 - C: 외부 자료 또는 추정에만 의존 특히 다음을 점검해라. 1. `1d2g.js`를 원본 PCAP의 HTTP Export Objects로 추출했다고 잘못 설명했는가? 2. Base64를 암호화라고 잘못 표현했는가? 3. 코드를 실행하지 않고도 알 수 없는 행위를 확정했는가? 4. 최종 악성코드를 Async RAT으로 쓰지 않았는가? 5. 정확한 ClickFix 명령을 불필요하게 보고서에 노출했는가? 6. IOC가 모두 비활성화되었는가? 틀린 주장은 근거와 함께 수정하고, 증거가 없는 주장은 삭제해라.이 실습에서 얻어야 할 분석 습관
LLM은 난독화 코드에서 반복 패턴을 찾고, 변수에 이름을 붙이고, 분석 스크립트를 만드는 데 효과적입니다. 하지만 LLM이 작성한 매끄러운 설명이 증거는 아닙니다. 코드에서 발견한 URL 조합 로직, 공식 HTTPS 텍스트의 실제 요청, PCAP의 DNS·SNI·HTTP·TLS 패킷이 같은 이야기를 할 때 비로소 결론을 내릴 수 있습니다.
이 사례의 핵심은 “AI로 난독화를 풀었다”가 아닙니다. 격리된 정적 분석으로 가설을 만들고, 사람이 원본을 비교하며, Wireshark로 실제 네트워크 행위를 검증했다는 것입니다. 이 순서를 지키면 LLM은 분석가를 대체하는 답안 생성기가 아니라, 분석 속도를 높이는 가설 생성기와 검증 보조 도구가 됩니다.
참고 자료
'일반IT > IT보안' 카테고리의 다른 글
| Claude Code를 보안 코파일럿으로 만드는 19개 Skill — Claude-Code-CyberSecurity-Skill 구조와 안전한 실습 (0) | 2026.08.08 |
|---|---|
| [보안 프롬프트 설계와 작성 실무 5] 악성코드 스크립트 난독화 정적 분석하기 (0) | 2026.08.07 |
| 주요정보통신기반시설 Linux 진단 스크립트 만들기: 계획부터 실행·점검·보완까지 (0) | 2026.08.07 |
| [보안 프롬프트 설계와 작성 실무 3] Agent Skill 실제 구성 살펴보기 (0) | 2026.08.07 |
| [보안 프롬프트 설계와 작성 실무 2] skill-creator로 보안 리뷰 스킬 만들기 (0) | 2026.08.07 |