이 글 공유하기

보안관제 분석가와 탐지 체계를 운영하시는 분께 드리는 글입니다. 이번에 공개하는 작은 모델은 한 가지 질문에 답합니다. 눈앞의 짧은 기록 구간에 공격의 증거가 실제로 있느냐는 질문입니다.

모델은 서버에서 몇십 초 동안 일어난 일의 기록과 번호 목록을 받습니다. 그리고 판정과 함께 근거로 삼은 기록의 번호를 돌려줍니다. 목록에 없는 번호는 인용하지 못하게 학습했습니다. 다키클라우드는 이 모델을 연구용으로 공개합니다. 자동 차단에 쓰는 모델이 아니라 분석가 옆에서 근거를 짚어 주는 모델입니다.

쉽게 말하면

카드 명세서를 들여다보며 도용 결제를 찾는 일을 떠올려 보시면 됩니다. 명세서에는 줄마다 번호가 붙어 있습니다. 카드사에 신고하려면 “이 줄과 이 줄이 수상합니다”라고 번호로 짚어야 합니다. 명세서에 없는 결제를 지어내서 신고할 수는 없습니다.

평범한 줄 하나만으로 도용이라고 단정해서도 안 됩니다. 동네 편의점 결제 한 건은 그냥 장보기입니다. 반면 새벽에 해외 쇼핑몰 결제가 연달아 찍혔다면 그 줄들이 바로 증거입니다. 가끔은 정말로 어느 쪽인지 알 수 없는 줄도 있습니다.

이번 모델은 이 명세서 판독만 하도록 연습한 모델입니다. 명세서 한 장은 텔레메트리 구간 하나입니다. 줄 번호는 이벤트 ID입니다. 모델은 “증거 있음”, “평범한 활동”, “판단 불가” 가운데 하나를 고르고 근거가 된 줄 번호만 적어 냅니다.

어떤 모델인가

모델 이름은 SOC-IER-4B-v0.1입니다. 입력은 프로세스 실행, DNS, HTTP, 네트워크 흐름 같은 호스트 이벤트입니다. 이벤트마다 [ev_...] 형태의 번호가 붙습니다. 출력은 JSON 객체 하나입니다. 사고 유형, 근거 이벤트 번호 목록, 판정, 60단어 이내의 짧은 이유가 들어갑니다.

판정은 SUPPORTED, INSUFFICIENT, UNKNOWN 세 가지입니다. 사고 유형은 자격 증명 탈취, 데이터 유출, 컨테이너 침해 등 일곱 가지와 none입니다. 예를 들어 고객 DB를 tar로 묶고 처음 보는 도메인을 조회하고 curl로 올려 보내는 구간이 있다고 해 보겠습니다. 이때 모델은 그 세 줄을 근거로 데이터 유출 증거가 있다고 답하도록 배웠습니다.

기반 모델은 Qwen3-4B-Instruct-2507입니다. 여기에 LoRA SFT를 했고 생각 모드는 끄고 학습했습니다. 라이선스는 Apache-2.0입니다. 프롬프트는 영어로만 학습하고 평가했습니다.

무엇으로 배웠나

학습 데이터는 603건입니다. 483건은 사내 사이버 레인지에서 나왔습니다. 레인지는 저희가 직접 꾸린 시험 환경이며 고객 데이터나 운영 데이터는 들어 있지 않습니다. 나머지 120건은 공개 데이터셋 witfoo/precinct6-cybersecurity에서 다시 만든 보조 구간입니다.

정답은 사람이 붙이지 않았습니다. 레인지의 공격 스크립트가 무엇을 언제 했는지 알고 있으니, 판정과 근거 번호는 그 기록에서 나옵니다. 공격 구간마다 같은 호스트의 평범한 구간을 짝으로 두었습니다. 명세서로 치면 도용이 찍힌 달과 평범한 달을 나란히 놓고 배운 셈입니다.

학습은 H100 NVL 한 장에서 약 14분 걸렸습니다. 레시피는 CyberSecQwen-4B 모델 카드에 공개된 것을 따랐고 데이터가 작아 에폭만 10에서 3으로 줄였습니다.

봉인 평가 결과

평가 세트는 모델 선택이 끝난 뒤 한 번만 열었습니다. 독립된 사고 체인 48개, 구간 239개로 이뤄져 있습니다. 학습에 없던 공격 계열에서 나온 체인입니다. 모든 모델을 같은 프롬프트와 같은 파서, 같은 디코딩으로 쟀습니다.

봉인 평가 판정 macro-F1 비교 봉인 평가 판정 macro-F1과 95% 신뢰구간입니다. 수치는 모델 카드에서 그대로 옮겼습니다.

모델 설정 판정 macro-F1 [95% CI] 근거 재현율 근거 정밀도 오탐(False-SUPPORTED) 공격 놓침
SOC-IER-4B-v0.1 LoRA SFT 0.625 [0.604, 0.643] 0.895 0.929 0.064 0.061
Qwen3-4B-Instruct-2507 기본, zero-shot 0.388 [0.345, 0.430] 0.532 0.615 0.688 0.070
Qwen3-8B + LoRA (미공개) 같은 레시피 0.554 [0.524, 0.580] 0.706 0.743 0.088 0.219
Qwen3-8B 기본, zero-shot 0.391 [0.355, 0.428] 0.263 0.347 0.352 0.447
CyberPal2.0-20B 기본, zero-shot 0.385 [0.341, 0.432] 0.565 0.641 0.336 0.465

가장 큰 변화는 오탐입니다. 기본 4B 모델은 평범한 구간의 68.8%를 공격 증거로 불렀는데, 학습 뒤에는 6.4%로 내려갔습니다. 근거를 짚는 능력도 함께 좋아졌습니다. 재현율은 약 53%에서 90%로, 정밀도는 약 62%에서 93%로 올랐습니다. 목록에 없는 번호를 지어낸 경우는 모든 모델에서 0건이었습니다.

판정 macro-F1은 세 판정의 F1을 평균한 값입니다. 뒤에서 말씀드리듯 UNKNOWN은 어느 모델도 맞히지 못했습니다. 그래서 이 지표의 실질 상한은 약 2/3이고 0.63도 이 점을 감안하고 읽어야 합니다.

같은 레시피로 학습한 8B보다 4B가 더 나았다는 점도 눈에 띕니다. 8B는 공격 구간의 21.9%를 놓쳤고 4B는 6.1%만 놓쳤습니다. 다만 이번 실험 하나의 결과이며 그 이유를 따로 분석하지는 않았습니다.

이 비교가 말하지 않는 것

CyberPal2.0-20B는 보안 특화 20B 모델입니다. 저희는 이 모델을 zero-shot으로, 저희 출력 형식에 맞춰, 학습한 적 없는 텔레메트리 구간에 돌렸습니다. 이 표는 CyberPal2.0-20B가 보안 모델로서 약하다는 뜻이 아닙니다. 오히려 그 오탐률 33.6%는 Qwen 기본 모델의 절반 수준입니다.

표가 말하는 것은 더 좁습니다. 과제 예시 603건만으로 4B 모델이 학습 없이 쓴 모델들의 구간(0.39 안팎)을 벗어났고 신뢰구간도 겹치지 않습니다. 이 과제와 이 벤치마크에서만 성립하는 결과라는 점은 분명히 해 둡니다.

병합 가중치를 믿을 수 있는 이유

LoRA를 16비트 가중치에 합치면 모델이 조용히 달라질 수 있습니다. LoRA가 더하는 변화량이 16비트 해상도에 비해 작기 때문입니다. 그래서 병합본과 원래의 기본 모델+어댑터를 같은 309개 구간에서 비교했습니다. 통과 기준 일곱 가지는 결과를 보기 전에 정해 두었습니다.

처음 만든 bf16 병합본은 떨어졌습니다. 사고 유형 일치율이 94.8%로 기준 95%에 조금 못 미쳤습니다. 이 병합본은 공개하지 않았습니다. 두 번째는 fp32에서 합친 뒤 fp16으로 한 번만 바꿔 저장했습니다. 이쪽은 일곱 기준을 모두 통과했습니다.

fp16 병합본은 greedy 디코딩에서 판정이 어댑터와 309개 모두 같았습니다. 사고 유형 일치율은 98.1%, 근거 번호 집합 일치율은 99.7%였습니다. 봉인 평가의 3회 다수결 결과도 어댑터와 똑같았습니다. 어댑터로 잰 수치를 병합 모델의 수치로 싣는 근거가 여기에 있습니다. fp16 가중치를 bf16으로 읽으면 첫 병합본의 손실이 다시 생길 수 있습니다. dtype="auto"로 두시길 권합니다.

직접 실행해 보기

모델은 학습 때와 똑같은 시스템 프롬프트와 입력 형식을 기대합니다. 시스템 프롬프트 전문과 입력 예시는 모델 카드에 있습니다. 형식이 바뀌면 판정 값과 번호 인용 규칙이 흔들릴 수 있습니다.

from transformers import AutoModelForCausalLM, AutoTokenizer

repo = "ThakiCloud/SOC-IER-4B-v0.1"
tok = AutoTokenizer.from_pretrained(repo)
model = AutoModelForCausalLM.from_pretrained(repo, dtype="auto", device_map="auto")

messages = [{"role": "system", "content": SYSTEM_PROMPT},
            {"role": "user", "content": USER_PROMPT}]
enc = tok.apply_chat_template(messages, add_generation_prompt=True,
                              return_tensors="pt", return_dict=True).to(model.device)
out = model.generate(**enc, max_new_tokens=320, do_sample=True,
                     temperature=0.3, top_p=0.95)
print(tok.decode(out[0][enc["input_ids"].shape[1]:], skip_special_tokens=True))

저장소의 inference_example.py는 실행 가능한 전체 예제입니다. 답이 스키마를 지키는지, 후보 목록의 번호만 인용했는지도 검사합니다.

평가는 vLLM의 구조화 출력으로 했습니다. JSON 스키마로 판정과 사고 유형의 값은 묶었지만 근거 번호는 일부러 열어 두었습니다. 그래야 목록 밖 번호를 지어내는지 잴 수 있기 때문입니다. 카드의 수치는 모두 temperature 0.3, top_p 0.95, 최대 320토큰으로 3회 뽑아 다수결한 값입니다.

llm = LLM(model="ThakiCloud/SOC-IER-4B-v0.1", dtype="auto", max_model_len=8192)
sp = SamplingParams(temperature=0.3, top_p=0.95, max_tokens=320,
                    structured_outputs=StructuredOutputsParams(json=SCHEMA))
print(llm.chat([messages], sp)[0].outputs[0].text)

재현하시려면 LoRA 어댑터를 쓰시면 됩니다. 기반 모델의 revision cdbee75f에 PeftModel.from_pretrained(model, "ThakiCloud/SOC-IER-4B-v0.1-LoRA")로 얹습니다. 어댑터 저장소에는 학습 설정과 손실 곡선을 담은 train_report.json과 파일 체크섬도 있습니다.

아직 못 하는 일

UNKNOWN은 한 번도 맞히지 못했습니다. 이 모델뿐 아니라 비교한 모든 모델이 그 판정의 F1이 0이었습니다. 학습 데이터에 그 예시가 9건뿐이었습니다. 명세서로 치면 “모르겠다”고 말해야 할 줄에도 도용이나 정상 가운데 하나를 고릅니다. v0.1에서는 UNKNOWN을 지원하지 않는 판정으로 보셔야 합니다.

오탐 6.4%도 작지 않습니다. 평범한 구간 열여섯 개 가운데 하나꼴로 공격 증거라고 부르는 셈입니다. 관제 현장에서는 분석가의 시간을 잡아먹는 실제 비용이 됩니다. 그래서 다음 버전에서 줄이려는 두 목표 가운데 하나로 잡았습니다.

평가가 같은 레인지 안에서 이뤄졌다는 점도 기억해 주십시오. 공격 계열은 학습과 평가가 다르지만 센서, 호스트, 평범한 배경 활동은 같습니다. 다른 EDR이나 eBPF 스키마, 실제 운영 트래픽에서 통하는지는 확인하지 않았습니다. 평가 구간 하나가 전체의 0.4%이므로 몇 %p 이내의 차이는 해석하기 어렵습니다.

정답이 공격 스크립트에서 나왔다는 점도 한계입니다. 분석가가 보면 개별 구간에서 판정이 다를 수 있습니다. 후보 이벤트 16개 이하, 약 2~3천 토큰 구간에서만 평가했습니다. 더 긴 구간은 시험하지 않았습니다.

어디에 쓰면 되나

첫째 자리는 분석가 보조입니다. 경보가 올라온 구간에서 어느 줄이 공격 가설을 받치는지 먼저 짚어 주면, 분석가는 그 줄부터 확인할 수 있습니다. 최종 판단은 사람이 합니다.

둘째는 섀도 평가입니다. 기존 탐지 파이프라인 옆에 붙여 두고 판정만 기록해 비교하는 방식입니다. 운영 텔레메트리에서 어떻게 동작하는지는 아직 검증되지 않았습니다. 그 검증부터 이 자리에서 해 보시길 권합니다.

자동 차단이나 격리처럼 모델 출력만 보고 대응하는 용도는 권하지 않습니다. 다키클라우드가 만드는 업무 자동화 플랫폼 Paxis는 모든 실행 단계를 정책 게이트와 감사 기록으로 통과시킵니다. 증거를 번호로 짚는 모델은 그런 구조에서 “왜 이 조치를 하려는가”를 기록으로 남기는 재료가 될 수 있습니다. 4B 크기라 폐쇄망 안에서 따로 돌리기도 쉽습니다. 다만 이 모델은 아직 어떤 제품에도 들어가 있지 않습니다. 작은 모델이 정형 업무를 맡는 다른 사례는 KoToolAct-4B 공개 글에서 보실 수 있습니다.

공개한 것

저장소 형식 용도
ThakiCloud/SOC-IER-4B-v0.1 병합 fp16 바로 실행, Transformers와 vLLM용
ThakiCloud/SOC-IER-4B-v0.1-LoRA PEFT 어댑터 재현용, 학습 리포트와 체크섬 포함

학습과 평가 데이터는 공개하지 않습니다. 레인지 텔레메트리에는 저희 시험 환경의 호스트 이름, 주소, 시나리오가 들어 있기 때문입니다. WitFoo에서 만든 보조 구간은 공개 원본에서 다시 만들 수 있습니다.

명세서를 다 읽고 범인을 지목하는 일은 여전히 분석가의 몫입니다. 이 모델은 어느 줄을 먼저 보시면 되는지 번호로 짚어 드리는 데까지만 합니다. 그 번호가 목록 밖으로 나가지 않는다는 점이 이번 공개에서 가장 지키고 싶었던 약속입니다.

측정 출처: SOC-IER-4B-v0.1 모델 카드에 공개된 봉인 평가 결과입니다. vLLM 0.28.0, H100 NVL 한 장(비교용 20B 모델은 H200 NVL)에서 같은 입력으로 쟀습니다.

이 글 공유하기

태그: evidence-reasoning, incident-response, lora, 오픈 웨이트, paxis, qwen3, 보안, slm, soc, soc-ier, telemetry

카테고리:

업데이트: