수리카타 발표.html
59.99 KB · text/html · 업로드 2026-07-08 17:11
<!doctype html>
<html lang="ko">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Suricata 학습용 자료 | 학습용 자료</title>
<style>
*{box-sizing:border-box;margin:0;padding:0}
:root{
--bg:#fff8ea;--paper:#fffdf7;--card:#fff;--ink:#1f2d27;--muted:#66736b;
--line:#eadfca;--green:#2f8f62;--green2:#1f6c4b;--softgreen:#e7f5eb;
--yellow:#fff4c7;--blue:#eaf3ff;--orange:#f29d52;--red:#fff0ed;
--shadow:0 16px 42px rgba(60,45,20,.10);--shadow2:0 8px 20px rgba(60,45,20,.07);
}
body{
font-family:-apple-system,BlinkMacSystemFont,"Segoe UI","Noto Sans KR",sans-serif;
background:
radial-gradient(circle at 8% 4%,rgba(255,223,132,.55),transparent 28%),
radial-gradient(circle at 92% 6%,rgba(93,194,132,.23),transparent 25%),
linear-gradient(180deg,#fff4d8 0%,var(--bg) 28%,var(--paper) 100%);
color:var(--ink);line-height:1.7;font-size:15px;word-break:keep-all;
}
a{text-decoration:none;color:inherit} button{font-family:inherit}
.wrap{max-width:1230px;margin:0 auto;padding:22px}
.header{
background:linear-gradient(135deg,rgba(255,255,255,.94),rgba(255,252,244,.97));
border:1px solid var(--line);border-radius:28px;padding:34px;box-shadow:var(--shadow);
position:relative;overflow:hidden;
}
.header:after{content:"";position:absolute;right:-70px;bottom:-90px;width:260px;height:260px;border-radius:50%;background:rgba(47,143,98,.08)}
.kicker{display:inline-flex;align-items:center;gap:8px;background:var(--softgreen);color:var(--green2);padding:7px 13px;border-radius:999px;font-weight:800;font-size:13px}
.header h1{font-size:clamp(30px,4.7vw,58px);line-height:1.1;letter-spacing:-.055em;margin:15px 0 12px}
.header p{max-width:880px;color:#435149;font-size:17px}
.actions{display:flex;gap:10px;flex-wrap:wrap;margin-top:22px}
.btn{border:1px solid var(--line);background:#fff;color:var(--ink);padding:11px 16px;border-radius:14px;cursor:pointer;font-weight:800;box-shadow:0 7px 16px rgba(60,45,20,.06);transition:.15s}
.btn:hover{transform:translateY(-1px);border-color:#cbbda2}.btn.primary{background:var(--green);border-color:var(--green);color:#fff}
.top-tabs{position:sticky;top:0;z-index:20;margin:18px 0 0;display:flex;gap:8px;overflow-x:auto;background:rgba(255,248,234,.88);backdrop-filter:blur(12px);border:1px solid rgba(234,223,202,.8);border-radius:22px;padding:10px;box-shadow:var(--shadow2)}
.tab{flex:0 0 auto;border:none;cursor:pointer;padding:10px 15px;border-radius:14px;background:transparent;color:#536159;font-weight:800;transition:.15s}.tab:hover{background:#fff}.tab.on{background:var(--green);color:#fff;box-shadow:0 8px 18px rgba(47,143,98,.22)}
.page{display:none;margin-top:18px}.page.on{display:block}
.panel{background:rgba(255,255,255,.82);border:1px solid var(--line);border-radius:26px;box-shadow:var(--shadow2);padding:26px;margin-bottom:16px}
.panel h2{font-size:clamp(24px,3.2vw,38px);letter-spacing:-.045em;line-height:1.16;margin:8px 0}.panel h3{font-size:20px;margin-bottom:10px;letter-spacing:-.02em}.panel h4{font-size:15px;margin:8px 0;color:var(--green2)}
.lead{color:#526057;font-size:16px;max-width:920px}.grid{display:grid;gap:14px}.g2{grid-template-columns:repeat(2,minmax(0,1fr))}.g3{grid-template-columns:repeat(3,minmax(0,1fr))}.g4{grid-template-columns:repeat(4,minmax(0,1fr))}
.card{background:#fff;border:1px solid var(--line);border-radius:20px;padding:18px;box-shadow:0 8px 18px rgba(60,45,20,.05)}.card.green{background:var(--softgreen);border-color:#cce9d4}.card.yellow{background:#fff7dc;border-color:#ead796}.card.blue{background:var(--blue);border-color:#d8e7f7}.card.red{background:var(--red);border-color:#f3d2ca}.card p{color:#4d5b53}.why{border-left:6px solid var(--green)}
.chips{display:flex;flex-wrap:wrap;gap:7px;margin-top:12px}.chip{display:inline-flex;padding:6px 10px;border-radius:999px;background:#f5efe1;border:1px solid #ece0ca;color:#4b5b52;font-size:12px;font-weight:800;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}.chip.hot{background:var(--green);color:white;border-color:var(--green)}
.code{background:#23322b;color:#eef8ef;border-radius:16px;padding:16px;overflow:auto;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:13px;white-space:pre;line-height:1.65;margin-top:10px}
.subtabs{display:flex;gap:8px;flex-wrap:wrap;margin:16px 0}.subtab{border:1.5px solid var(--line);background:#fff;color:#526057;cursor:pointer;border-radius:12px;padding:9px 13px;font-size:14px;font-weight:800}.subtab.on{background:var(--green);border-color:var(--green);color:#fff}
.subpage{display:none}.subpage.on{display:block}
.accordion{display:grid;gap:10px}.acc{background:#fff;border:1px solid var(--line);border-radius:18px;overflow:hidden}.acc-head{display:flex;align-items:center;gap:12px;cursor:pointer;padding:15px 17px;user-select:none}.acc-head:hover{background:#fffaf0}.acc-num{width:34px;height:34px;border-radius:12px;display:grid;place-items:center;background:var(--softgreen);color:var(--green2);font-weight:900;flex:0 0 auto}.acc-title{font-weight:900}.acc-sum{font-size:13px;color:var(--muted);margin-top:2px}.acc-toggle{margin-left:auto;color:#aaa;font-weight:900}.acc-body{display:none;padding:0 17px 17px;border-top:1px solid #f0eadf}.acc.open .acc-body{display:block}.acc.open .acc-toggle{transform:rotate(180deg)}
.table{width:100%;border-collapse:separate;border-spacing:0;border:1px solid var(--line);border-radius:18px;overflow:hidden;background:#fff;font-size:14px}.table th,.table td{padding:11px 12px;border-bottom:1px solid var(--line);vertical-align:top}.table th{background:#fff6d9;text-align:left;font-weight:900}.table tr:last-child td{border-bottom:none}
.flowbar{display:grid;grid-template-columns:repeat(var(--n),minmax(120px,1fr));gap:8px;overflow-x:auto;padding:6px 2px 12px}.fstep{cursor:pointer;background:#fff;border:1.5px solid var(--line);border-radius:16px;min-height:76px;padding:12px 10px;display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;font-weight:900;color:#496057;transition:.15s}.fstep small{display:block;color:var(--muted);font-weight:700;font-size:11px;margin-top:3px}.fstep.on{background:var(--green);border-color:var(--green);color:#fff;box-shadow:0 10px 20px rgba(47,143,98,.22)}.fstep.on small{color:#e9fff1}
.stepview{margin-top:14px;display:grid;grid-template-columns:285px minmax(0,1fr);gap:14px;align-items:stretch}.step-index{background:linear-gradient(135deg,var(--softgreen),#fff);border:1px solid #cfe8d6;border-radius:22px;padding:20px;display:flex;flex-direction:column;justify-content:space-between}.big-num{font-size:54px;font-weight:900;letter-spacing:-.06em;color:var(--green2);line-height:1}.step-title{font-size:22px;font-weight:900;margin-top:8px}.step-desc{color:#4d5b53;white-space:pre-line}.navrow{display:flex;justify-content:space-between;gap:10px;margin-top:14px}.navrow .btn{box-shadow:none}.step-tags{display:flex;gap:7px;flex-wrap:wrap;margin-top:12px}.note{padding:14px 16px;border-radius:16px;background:#fff6d9;border:1px solid #ead796;color:#7a5318;font-weight:800;margin-top:12px}
.term-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(210px,1fr));gap:10px;margin-top:12px}.term{background:#fff;border:1px solid var(--line);border-radius:14px;padding:12px}.term b{display:block;margin-bottom:3px;color:var(--green2)}
.mini-title{font-weight:900;color:var(--green2);margin-bottom:6px}.footer{text-align:center;color:var(--muted);font-size:13px;padding:24px 0}
@media(max-width:850px){.wrap{padding:12px}.g2,.g3,.g4{grid-template-columns:1fr}.stepview{grid-template-columns:1fr}.header,.panel{padding:20px;border-radius:22px}.top-tabs{position:relative}}
@media print{.top-tabs,.actions,.navrow{display:none}body{background:#fff}.page{display:block}.panel,.header{box-shadow:none;break-inside:avoid}}
</style>
</head>
<body>
<div class="wrap">
<header class="header">
<span class="kicker">Suricata 학습용 자료</span>
<h1>패킷이 들어오는 순간부터<br>IDS 로그 분석까지</h1>
<p>Suricata의 개념, 설치, 설정, Snort 비교, 패킷 처리 구조, Suricata 내부 파이프라인, 룰셋 호환 실습을 순서대로 학습한다.</p>
<div class="actions">
<button class="btn primary" onclick="showPage('intro')">학습 시작</button>
<button class="btn" onclick="showPage('cpu')">5.0 CPU</button>
<button class="btn" onclick="showPage('network')">패킷 수신 경로</button>
<button class="btn" onclick="showPage('pipeline')">Suricata 파이프라인</button>
</div>
</header>
<nav class="top-tabs">
<button class="tab on" data-page="intro" onclick="showPage('intro')">1. 개념</button>
<button class="tab" data-page="install" onclick="showPage('install')">2. 설치</button>
<button class="tab" data-page="config" onclick="showPage('config')">3. 설정</button>
<button class="tab" data-page="compare" onclick="showPage('compare')">4. 비교</button>
<button class="tab" data-page="cpu" onclick="showPage('cpu')">5.0 CPU·스레드</button>
<button class="tab" data-page="network" onclick="showPage('network')">5.1 패킷 수신 경로</button>
<button class="tab" data-page="pipeline" onclick="showPage('pipeline')">5.2 Suricata 파이프라인</button>
<button class="tab" data-page="lab" onclick="showPage('lab')">6. 실습</button>
<button class="tab" data-page="conclusion" onclick="showPage('conclusion')">7. 결론</button>
</nav>
<section class="page on" id="page-intro">
<div class="panel">
<span class="kicker">Chapter 1</span>
<h2>Suricata란?</h2>
<p class="lead">Suricata는 오픈소스 기반 IDS/IPS 엔진이다. 네트워크 트래픽을 분석하여 공격 패턴을 탐지하고, 탐지 결과와 메타데이터를 로그로 남긴다. Snort 룰셋 호환성이 높고 EVE JSON 형식으로 다양한 네트워크 메타데이터를 출력할 수 있다.</p>
<div class="grid g3" style="margin-top:16px">
<div class="card why"><h3>이 챕터가 중요한 이유</h3><p>보안 관제와 솔루션 직무에서는 IDS, IPS, NSM, SIEM의 차이를 설명할 수 있어야 한다. Suricata는 단순 탐지 센서에서 로그 분석·SIEM 연동까지 연결되는 도구다.</p></div>
<div class="card green"><h3>IDS / IPS</h3><p>IDS는 네트워크 트래픽을 분석해 공격 패턴을 탐지하고 Alert를 남긴다. IPS는 inline 구조에서 차단까지 수행할 수 있다.</p></div>
<div class="card yellow"><h3>NSM</h3><p>Network Security Monitoring. 단순히 공격 탐지로 끝나지 않고 누가 누구와 통신했는지, 어떤 프로토콜과 요청이 있었는지까지 관찰한다.</p></div>
</div>
</div>
<div class="panel">
<h2>Snort / Suricata, NSM, SIEM 관계</h2>
<div class="flowbar" style="--n:6">
<div class="fstep">네트워크 트래픽</div>
<div class="fstep">Snort / Suricata<br><small>IDS 센서</small></div>
<div class="fstep">Alert / JSON / Flow / PCAP</div>
<div class="fstep">Filebeat / Logstash / rsyslog / Agent</div>
<div class="fstep">SIEM</div>
<div class="fstep">대시보드 / 검색 / 상관분석 / 경보</div>
</div>
<div class="grid g2" style="margin-top:14px">
<div class="card"><h3>SIEM이 하는 일</h3><p>웹서버 접속 로그, IDS 탐지 로그, 방화벽 차단 로그, 서버 로그인 실패 로그를 따로 보지 않고 하나의 공격 흐름으로 분석한다.</p></div>
<div class="card green"><h3>Suricata가 NSM에 유리한 이유</h3><p>Flow, HTTP, DNS, TLS 같은 메타데이터를 남길 수 있기 때문에 단순 alert보다 풍부한 분석이 가능하다.</p></div>
</div>
<div class="chips"><span class="chip hot">IDS</span><span class="chip hot">NSM</span><span class="chip hot">SIEM</span><span class="chip">EVE JSON</span><span class="chip">Flow</span><span class="chip">Metadata</span></div>
</div>
</section>
<section class="page" id="page-install">
<div class="panel">
<span class="kicker">Chapter 2</span>
<h2>Suricata 설치</h2>
<p class="lead">설치는 단순히 프로그램을 깔아보는 단계가 아니다. 어떤 라이브러리를 포함해서 빌드했는지에 따라 AF_PACKET, NFQUEUE, DPDK, Lua, Hyperscan 같은 기능 사용 가능 여부가 달라진다.</p>
<div class="grid g2" style="margin-top:16px">
<div class="card why"><h3>이 챕터가 중요한 이유</h3><p>보안 직무에서는 실행만 할 줄 아는 것보다 의존성, 빌드 옵션, 실행 경로, 설정 파일 위치를 이해하는 것이 중요하다. 설치 과정 자체가 기능 지원 여부를 확인하는 과정이다.</p></div>
<div class="card green"><h3>진행 순서</h3><p>버전·다운로드 → 저장소 활성화 → 종속성 패키지 → 빌드·설치 → 설치 확인 → 패키지 역할 순서로 진행한다.</p></div>
</div>
<div class="subtabs">
<button class="subtab on" data-sub="install-1" onclick="showSub('install','install-1')">1. 버전·다운로드</button>
<button class="subtab" data-sub="install-2" onclick="showSub('install','install-2')">2. 저장소 활성화</button>
<button class="subtab" data-sub="install-3" onclick="showSub('install','install-3')">3. 종속성 패키지</button>
<button class="subtab" data-sub="install-4" onclick="showSub('install','install-4')">4. 빌드·설치</button>
<button class="subtab" data-sub="install-5" onclick="showSub('install','install-5')">5. 설치 확인</button>
<button class="subtab" data-sub="install-6" onclick="showSub('install','install-6')">6. 패키지 역할</button>
</div>
<div class="subpage on" id="install-1">
<div class="card">
<h3>1. 버전 선택과 다운로드</h3>
<p>실습에서는 Suricata 7.0.11을 기준으로 진행한다. 최신 버전이 별도로 있더라도 실습 환경이나 pfSense 기준에 맞춰 버전을 고정할 수 있다.</p>
<pre class="code">mkdir /usr/local/src/suricata
cd /usr/local/src/suricata
wget https://www.openinfosecfoundation.org/download/suricata-7.0.11.tar.gz
ls</pre>
</div>
</div>
<div class="subpage" id="install-2">
<div class="card">
<h3>2. 추가 패키지 저장소 활성화</h3>
<pre class="code">dnf -y update
dnf -y install epel-release dnf-plugins-core # 추가 패키지 저장소 install
dnf config-manager --set-enable crb # 추가 패키지 저장소 활성화</pre>
<div class="term-grid">
<div class="term"><b>epel-release</b>Rocky/RHEL 기본 저장소에 없는 추가 패키지를 설치하기 위한 EPEL 저장소 패키지.</div>
<div class="term"><b>dnf-plugins-core</b>dnf config-manager 같은 DNF 확장 명령을 사용하기 위한 플러그인 패키지.</div>
<div class="term"><b>CRB</b>일부 개발 라이브러리와 빌드 의존성을 확보하기 위해 활성화한다.</div>
</div>
</div>
</div>
<div class="subpage" id="install-3">
<div class="card">
<h3>3. 종속성 패키지 설치</h3>
<p>빌드 도구, Rust, Python, JSON/YAML/PCAP/정규표현식/패턴매칭 라이브러리, 패킷 분석 도구를 설치한다.</p>
<pre class="code">sudo dnf install -y wget tar gzip file git vim
sudo dnf install -y make autoconf automake libtool pkgconf-pkg-config gcc gcc-c++
sudo dnf install -y rustc cargo cbindgen
sudo dnf install -y python3 python3-pyyaml
sudo dnf install -y jansson-devel libpcap-devel libyaml-devel pcre2-devel zlib-devel hyperscan-devel
sudo dnf install -y libcap-ng-devel file-devel lz4-devel libnet-devel systemd-devel
sudo dnf install -y tcpdump wireshark-cli
# 추후 필요시 설치
# sudo dnf install -y libnetfilter_queue-devel libnfnetlink-devel libnetfilter_log-devel libmnl-devel</pre>
</div>
</div>
<div class="subpage" id="install-4">
<div class="grid g2">
<div class="card">
<h3>4. 설치 파일 빌드</h3>
<pre class="code">tar xzvf suricata-7.0.11.tar.gz
cd suricata-7.0.11
./configure \
--prefix=/usr/ \
--sysconfdir=/etc/ \
--localstatedir=/var/
make
make install
echo $?
make install-conf
make install-rules
make install-full
sudo suricata-update</pre>
</div>
<div class="card yellow">
<h3>빌드 과정 의미</h3>
<div class="term-grid">
<div class="term"><b>tar xzvf</b>소스 압축파일을 해제한다. x는 extract, v는 verbose, f는 file, z는 gzip 처리다.</div>
<div class="term"><b>configure</b>시스템 라이브러리와 설치 경로를 확인한다.</div>
<div class="term"><b>--prefix=/usr/</b>실행 파일이 /usr/bin 아래에 설치되어 환경변수 추가 없이 실행할 수 있다.</div>
<div class="term"><b>make</b>소스코드를 컴파일하고 여러 파일과 라이브러리를 링크한다.</div>
<div class="term"><b>install-conf</b>suricata.yaml과 필요한 디렉터리를 설치한다.</div>
<div class="term"><b>suricata-update</b>탐지 룰을 내려받고 정리해 적용 가능한 룰 파일로 합친다.</div>
</div>
</div>
</div>
</div>
<div class="subpage" id="install-5">
<div class="card">
<h3>5. 설치 확인</h3>
<pre class="code">suricata --build-info</pre>
<table class="table" style="margin-top:12px">
<tr><th>기능</th><th>확인 의미</th></tr>
<tr><td>AF_PACKET support</td><td>Linux 기본 고성능 패킷 캡처 방식. NIDS 실습 핵심.</td></tr>
<tr><td>AF_XDP / XDP / eBPF</td><td>XDP 기반 고성능 userspace 캡처와 커널 내부 필터링·추적 기능.</td></tr>
<tr><td>DPDK</td><td>커널 우회 고성능 패킷 처리. 전용 NIC와 hugepage 필요.</td></tr>
<tr><td>PF_RING</td><td>ntop PF_RING 기반 고성능 패킷 캡처 프레임워크.</td></tr>
<tr><td>NFQueue / NFLOG</td><td>Netfilter 큐 기반 IPS/inline 확장 또는 로그 패킷 수집 기능.</td></tr>
<tr><td>Libmagic / liblz4 / LUA / GeoIP2</td><td>파일 타입 식별, 압축 PCAP, Lua 룰, IP 국가/위치 매칭 고도화.</td></tr>
</table>
</div>
</div>
<div class="subpage" id="install-6">
<div class="card">
<h3>6. 패키지 역할 요약</h3>
<table class="table">
<tr><th>분류</th><th>패키지</th><th>역할</th></tr>
<tr><td>다운로드/압축</td><td>wget, tar, gzip, file, git</td><td>소스 압축파일 다운로드, 압축 해제, 파일 형식 확인, Git 저장소 사용.</td></tr>
<tr><td>빌드</td><td>make, autoconf, automake, libtool, pkgconf, gcc, gcc-c++</td><td>configure 스크립트, Makefile, 컴파일, 링크에 필요.</td></tr>
<tr><td>Rust</td><td>rustc, cargo, cbindgen</td><td>Suricata 7.x의 Rust 기반 모듈 빌드와 C 엔진 연결.</td></tr>
<tr><td>설정/로그</td><td>python3, python3-pyyaml, jansson-devel, libyaml-devel</td><td>suricata-update 실행, YAML 설정 해석, eve.json 출력.</td></tr>
<tr><td>탐지 성능</td><td>pcre2-devel, hyperscan-devel</td><td>pcre 옵션 처리와 고속 패턴 매칭 성능 향상.</td></tr>
<tr><td>패킷/분석</td><td>libpcap-devel, tcpdump, wireshark-cli</td><td>NIC 캡처, PCAP 처리, CLI 기반 패킷 분석.</td></tr>
<tr><td>확장 기능</td><td>libnetfilter_queue, libnfnetlink, libnetfilter_log, libmnl</td><td>NFQUEUE/NFLOG 기반 IPS/Netfilter 연동에 필요할 수 있음.</td></tr>
</table>
</div>
</div>
</div>
</section>
<section class="page" id="page-config">
<div class="panel">
<span class="kicker">Chapter 3</span>
<h2>Suricata 설정</h2>
<p class="lead">설정은 Suricata를 실제 환경에 맞게 운영하기 위한 기본 운영 능력이다. 탐지가 안 되거나 로그가 안 남을 때 원인을 찾으려면 이 구간을 이해해야 한다.</p>
<div class="accordion" style="margin-top:16px">
<div class="acc open">
<div class="acc-head" onclick="toggleAcc(this)"><div class="acc-num">1</div><div><div class="acc-title">자기 IP 확인과 HOME_NET 수정</div><div class="acc-sum">보호 대상 네트워크 지정</div></div><div class="acc-toggle">▼</div></div>
<div class="acc-body">
<pre class="code">ip addr
ip route
# 자기 OS의 IP 주소 확인 후 suricata.yaml 수정
vim /etc/suricata/suricata.yaml
# 예시: 자기 OS IP가 172.16.14.98이면
HOME_NET: "[172.16.14.98]"
# 또는 실습 표기용
HOME_NET: "[각자_자기_OS_IP]"</pre>
<p>HOME_NET은 Suricata가 보호 대상으로 보는 주소다. 실습에서는 강의실 공통 대역을 고정으로 쓰지 않고, 각 사용자가 자기 OS의 IP 주소를 확인해서 입력한다.</p>
</div>
</div>
<div class="acc">
<div class="acc-head" onclick="toggleAcc(this)"><div class="acc-num">2</div><div><div class="acc-title">캡처 인터페이스와 로그 위치</div><div class="acc-sum">af-packet, default-log-dir</div></div><div class="acc-toggle">▼</div></div>
<div class="acc-body">
<pre class="code"># suricata.yaml
af-packet:
- interface: ens160
default-log-dir: /var/log/suricata/</pre>
<p>인터페이스 이름이 틀리면 패킷을 받지 못한다. 브릿지 모드에서 실제 트래픽이 들어오는 NIC 이름을 확인해야 한다.</p>
</div>
</div>
<div class="acc">
<div class="acc-head" onclick="toggleAcc(this)"><div class="acc-num">3</div><div><div class="acc-title">룰 파일 경로 설정</div><div class="acc-sum">suricata.rules 대신 local.rules 사용</div></div><div class="acc-toggle">▼</div></div>
<div class="acc-body">
<pre class="code">default-rule-path: /var/lib/suricata/rules
rule-files:
# - suricata.rules
- local.rules</pre>
<p>실습에서는 공식 룰셋을 주석 처리하고 local.rules만 로드하면 확인이 쉽다.</p>
</div>
</div>
<div class="acc">
<div class="acc-head" onclick="toggleAcc(this)"><div class="acc-num">4</div><div><div class="acc-title">host-os-policy</div><div class="acc-sum">OS별 fragment 재조립 정책</div></div><div class="acc-toggle">▼</div></div>
<div class="acc-body">
<p>OS마다 조각화된 패킷이 겹칠 때 앞 패킷을 우선할지, 뒤 패킷을 우선할지 처리 방식이 다를 수 있다. 감시 대상이 Linux라면 Linux 정책으로 맞춘다.</p>
<pre class="code">host-os-policy:
windows: []
linux: [0.0.0.0/0]</pre>
</div>
</div>
<div class="acc">
<div class="acc-head" onclick="toggleAcc(this)"><div class="acc-num">5</div><div><div class="acc-title">eve-log 프로토콜 조정</div><div class="acc-sum">로그량·저장공간·성능 관리</div></div><div class="acc-toggle">▼</div></div>
<div class="acc-body">
<p>eve.json은 네트워크 패킷을 종합적으로 로그에 남기므로 로그가 빠르게 쌓인다. 실습에서는 필요한 프로토콜만 켜서 분석 대상이 흐려지지 않게 한다.</p>
<pre class="code"># 설정 파일 백업
cp /etc/suricata/suricata.yaml /etc/suricata/suricata.yaml.bak
# 실습 상황에서 필요 없는 프로토콜 로그는 주석 처리 가능
# dns, tls, files, smtp, ftp, rdp, nfs, smb, tftp, ike,
# dcerpc, krb5, bittorrent-dht, snmp, rfb, sip, quic,
# dhcp, ssh, mqtt, http2, stats 등</pre>
</div>
</div>
<div class="acc">
<div class="acc-head" onclick="toggleAcc(this)"><div class="acc-num">6</div><div><div class="acc-title">pcap-log와 문법 검사</div><div class="acc-sum">원본 패킷 저장과 실행 전 검증</div></div><div class="acc-toggle">▼</div></div>
<div class="acc-body">
<pre class="code">pcap-log:
enabled: yes
sudo suricata -T -c /etc/suricata/suricata.yaml -v</pre>
<p>PCAP 로그는 Wireshark로 실제 패킷을 확인할 수 있는 증적 자료다. 실행 전에 -T로 설정과 룰 문법을 먼저 검사한다.</p>
</div>
</div>
<div class="acc">
<div class="acc-head" onclick="toggleAcc(this)"><div class="acc-num">7</div><div><div class="acc-title">local.rules 생성과 실행</div><div class="acc-sum">사용자 룰 작성과 Suricata 실행</div></div><div class="acc-toggle">▼</div></div>
<div class="acc-body">
<pre class="code">echo "" > /var/lib/suricata/rules/local.rules
ln -s /var/lib/suricata/rules /etc/suricata/rules
vim /etc/suricata/rules/local.rules
alert http any any -> $HOME_NET 80 (msg:"DVWA server movement detected!!"; sid:2000001;rev:1;)
suricata -c /etc/suricata/suricata.yaml -i 인터페이스 -l /var/log/suricata/</pre>
</div>
</div>
<div class="acc">
<div class="acc-head" onclick="toggleAcc(this)"><div class="acc-num">8</div><div><div class="acc-title">서비스 등록</div><div class="acc-sum">systemd로 운영</div></div><div class="acc-toggle">▼</div></div>
<div class="acc-body">
<pre class="code">which suricata
# /usr/bin/suricata
vim /etc/systemd/system/suricata.service
[Unit]
Description=Suricata IDS Service
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
ExecStart=/usr/bin/suricata -c /etc/suricata/suricata.yaml -i ens160
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable suricata
sudo systemctl start suricata
sudo systemctl status suricata
sudo journalctl -u suricata -f
tail -f /var/log/suricata/eve.json
tail -f /var/log/suricata/fast.log</pre>
</div>
</div>
</div>
<div class="chips"><span class="chip hot">suricata.yaml</span><span class="chip">HOME_NET</span><span class="chip">af-packet</span><span class="chip">local.rules</span><span class="chip">eve.json</span><span class="chip">fast.log</span><span class="chip">pcap-log</span><span class="chip">systemd</span></div>
</div>
</section>
<section class="page" id="page-compare">
<div class="panel">
<span class="kicker">Chapter 4</span>
<h2>Snort와 Suricata</h2>
<p class="lead">둘 다 IDS/IPS 엔진이지만 학습 포인트가 다르다. Snort는 룰 기반 탐지 원리를 보기 좋고, Suricata는 멀티스레드 처리와 EVE JSON 메타데이터 기반 분석에 강점이 있다.</p>
<table class="table" style="margin-top:16px">
<tr><th>구분</th><th>Snort</th><th>Suricata</th></tr>
<tr><td>주요 목적</td><td>룰 기반 IDS/IPS 탐지</td><td>IDS/IPS + NSM 메타데이터 수집</td></tr>
<tr><td>처리 구조</td><td>단일 스레드 중심</td><td>멀티스레드 기반 고성능 처리</td></tr>
<tr><td>대표 로그</td><td>alert_fast.txt, alert_json 등</td><td>eve.json, fast.log</td></tr>
<tr><td>로그 특징</td><td>Alert 중심</td><td>Alert + HTTP/DNS/TLS/Flow/File 로그</td></tr>
<tr><td>SIEM 연동</td><td>가능</td><td>JSON 기반 연동에 유리</td></tr>
<tr><td>장점</td><td>룰 작성·탐지 원리 학습에 적합</td><td>관제·분석·대용량 트래픽 처리에 적합</td></tr>
<tr><td>설정 파일</td><td>snort.lua</td><td>suricata.yaml</td></tr>
</table>
<div class="grid g3" style="margin-top:16px">
<div class="card green"><h3>멀티스레드 기반 처리</h3><p>Suricata는 runmode를 통해 workers, autofp, single 방식을 사용할 수 있다. 대용량 트래픽 처리에서 병렬 처리 개념과 연결된다.</p></div>
<div class="card yellow"><h3>Snort 룰셋 호환</h3><p>Snort에서 작성한 룰셋은 일부 옵션을 제외하면 Suricata에서 호환된다. 같은 룰로 두 엔진의 로그 차이를 비교할 수 있다.</p></div>
<div class="card blue"><h3>EVE JSON</h3><p>alert뿐 아니라 flow, http, dns, tls, file 정보를 함께 남기므로 SIEM 연동과 상관분석에 유리하다.</p></div>
</div>
</div>
</section>
<section class="page" id="page-cpu">
<div class="panel">
<span class="kicker">Chapter 5.0</span>
<h2>프로그램, 프로세스, CPU, 멀티스레드</h2>
<p class="lead">Suricata의 멀티스레드 구조를 이해하려면 프로그램, 프로세스, CPU, 스레드의 차이를 먼저 이해해야 한다. 이 챕터는 패킷 처리 성능 설명으로 넘어가기 위한 기초다.</p>
<div class="grid g2" style="margin-top:16px">
<div class="card why"><h3>이 챕터가 중요한 이유</h3><p>Suricata는 하나의 프로그램이지만 실행되면 프로세스가 되고, 그 안에서 여러 스레드가 패킷 수신·분석·탐지·로그 처리를 나누어 수행한다. 이걸 설명할 수 있어야 workers, CPU core, RSS 흐름까지 자연스럽게 이어진다.</p></div>
<div class="card green"><h3>학습 핵심</h3><p>프로그램은 실행 전 파일, 프로세스는 메모리에 올라간 실행 단위, CPU는 명령어 처리 장치, 스레드는 프로세스 안의 실제 실행 흐름이다.</p></div>
</div>
</div>
<div class="panel">
<h2>기본 정의</h2>
<div class="grid g4">
<div class="card"><h3>프로그램</h3><p>저장장치에 저장되어 있는 실행 가능한 코드와 파일의 묶음. 실행되기 전 상태다.</p></div>
<div class="card"><h3>프로세스</h3><p>프로그램이 실행되어 메모리에 올라간 상태. 운영체제가 관리하는 실행 중인 프로그램 단위다.</p></div>
<div class="card"><h3>CPU</h3><p>실제 명령어를 계산하고 실행하는 장치. 프로세스 안의 스레드를 CPU 코어가 실행한다.</p></div>
<div class="card"><h3>스레드</h3><p>프로세스의 실제 실행 흐름. CPU가 실행하는 기본 단위다.</p></div>
</div>
<div class="grid g2" style="margin-top:14px">
<div class="card yellow"><h3>CPU 특징</h3><p>대부분의 프로세스는 CPU가 처리한다. 실제 작업 처리는 코어별로 담당한다. 한 순간에 하나의 CPU 코어는 하나의 스레드만 실행할 수 있다.</p></div>
<div class="card blue"><h3>프로세스 특징</h3><p>프로세스는 자기만의 메모리 공간을 가진다. 따라서 서로 다른 프로세스는 기본적으로 메모리를 직접 공유하지 않는다.</p></div>
</div>
</div>
<div class="panel">
<h2>멀티스레드가 필요한 이유</h2>
<div class="grid g2">
<div class="card">
<h3>비유: 요리</h3>
<p>레시피는 프로그램, 요리사가 레시피를 꺼내 요리를 시작하면 프로세스가 된다. 라면처럼 순서대로만 진행되는 작업은 하나의 흐름, 즉 하나의 스레드로 볼 수 있다.</p>
</div>
<div class="card green">
<h3>동시성 / 병렬</h3>
<p>볶음밥을 만들 때 밥을 짓는 동안 재료 손질을 같이 하면 전체 시간이 줄어든다. 프로세스 내에서 여러 실행 흐름을 나누면 CPU 코어 여러 개를 활용하거나 하나의 코어에서 번갈아 실행할 수 있다.</p>
</div>
</div>
<div class="note">멀티프로세싱은 프로세스마다 독립된 메모리 공간을 가지므로 비효율이 있을 수 있다. 그래서 하나의 프로세스 안에서 여러 실행 흐름을 나누는 스레드가 중요해진다.</div>
</div>
<div class="panel">
<h2>실습 명령어</h2>
<div class="grid g2">
<div class="card">
<h3>Suricata 프로세스와 스레드 확인</h3>
<pre class="code">suricata -i ens160 -c /etc/suricata/suricata.yaml -l /var/log/suricata/ &
ps
ps -lf
# l = 스레드 관련 정보
# f = 자세하게
ps -Lf -p <수리카타 PID>
# 하나의 Suricata 프로세스 안에서 여러 스레드 동작 확인</pre>
</div>
<div class="card">
<h3>CPU 정보 확인</h3>
<pre class="code">nproc
lscpu</pre>
<div class="term-grid">
<div class="term"><b>CPU(s)</b>논리 CPU 개수.</div>
<div class="term"><b>On-line CPU(s) list</b>사용 가능한 CPU 번호.</div>
<div class="term"><b>Thread(s) per core</b>코어당 스레드 개수.</div>
<div class="term"><b>Core(s) per socket</b>CPU 소켓 하나당 코어 수.</div>
<div class="term"><b>Socket(s)</b>인식된 CPU 소켓 수.</div>
<div class="term"><b>Virtualization type</b>가상화 환경 정보.</div>
</div>
</div>
</div>
<div class="card green" style="margin-top:14px">
<h3>Suricata와 연결</h3>
<p>CPU 코어가 4개이고 Suricata가 여러 스레드를 사용한다면 운영체제는 각 스레드를 여러 코어에 나누어 실행할 수 있다.</p>
<pre class="code">CPU Core 1 → Thread 1
CPU Core 2 → Thread 2
CPU Core 3 → Thread 3
CPU Core 4 → Thread 4</pre>
</div>
</div>
</section>
<section class="page" id="page-network">
<div class="panel">
<span class="kicker">Chapter 5.1</span>
<h2>네트워크 패킷 수신 경로</h2>
<p class="lead">패킷은 애플리케이션으로 바로 들어오지 않는다. NIC, RX Queue/RX Ring, Driver, skb, Kernel Network Stack, Socket Buffer를 거쳐 사용자 공간 프로그램이 읽을 수 있는 형태가 된다.</p>
<div id="netFlow" class="flowbar" style="--n:9"></div>
<div class="stepview">
<div class="step-index">
<div>
<div class="big-num" id="netNum">01</div>
<div class="step-title" id="netTitle"></div>
</div>
<div class="step-tags" id="netTags"></div>
</div>
<div class="card">
<h3 id="netSub"></h3>
<p class="step-desc" id="netDesc"></p>
<pre class="code" id="netCode" style="display:none"></pre>
<div class="note" id="netNote"></div>
<div class="navrow">
<button class="btn" onclick="moveStep('net',-1)">← 이전 단계</button>
<button class="btn primary" onclick="moveStep('net',1)">다음 단계 →</button>
</div>
</div>
</div>
</div>
<div class="panel">
<h2>캡처 방식은 어디서 패킷을 보는가?</h2>
<div class="grid g2">
<div class="card"><h3>DPDK</h3><p>NIC를 커널에서 거의 떼어내고 사용자 공간 프로그램이 NIC 큐를 직접 읽는다. 커널 네트워크 스택을 우회하는 가장 앞단에 가깝다.</p></div>
<div class="card"><h3>XDP</h3><p>드라이버 단계, skb 생성 전의 이른 지점에서 패킷을 처리한다. 커널 안이지만 매우 앞단이다.</p></div>
<div class="card"><h3>netmap / PF_RING</h3><p>NIC RX/TX Ring에 가까운 지점을 사용자 공간에 매핑하거나 일반 캡처보다 NIC/Ring에 더 가까운 쪽에서 고속 캡처를 지원한다.</p></div>
<div class="card green"><h3>AF_PACKET / libpcap</h3><p>AF_PACKET은 skb 생성 후 커널 네트워크 스택 쪽에서 packet socket으로 패킷을 받는다. libpcap은 보통 AF_PACKET 같은 OS 캡처 인터페이스 위에서 패킷을 읽는다.</p></div>
</div>
<div class="chips"><span class="chip">DPDK</span><span class="chip">XDP</span><span class="chip">netmap</span><span class="chip">PF_RING</span><span class="chip hot">AF_PACKET</span><span class="chip">libpcap</span><span class="chip">tcpdump</span><span class="chip">Wireshark</span></div>
</div>
</section>
<section class="page" id="page-pipeline">
<div class="panel">
<span class="kicker">Chapter 5.2</span>
<h2>Suricata 패킷 처리 파이프라인</h2>
<p class="lead">Suricata는 패킷 하나를 바로 룰과 비교하지 않는다. 캡처·디코딩·재조립·플로우 추적·애플리케이션 분석·탐지·로그화의 파이프라인으로 처리한다.</p>
<div id="surFlow" class="flowbar" style="--n:8"></div>
<div class="stepview">
<div class="step-index">
<div>
<div class="big-num" id="surNum">01</div>
<div class="step-title" id="surTitle"></div>
</div>
<div class="step-tags" id="surTags"></div>
</div>
<div class="card">
<h3 id="surSub"></h3>
<p class="step-desc" id="surDesc"></p>
<pre class="code" id="surCode" style="display:none"></pre>
<div class="note" id="surNote"></div>
<div class="navrow">
<button class="btn" onclick="moveStep('sur',-1)">← 이전 단계</button>
<button class="btn primary" onclick="moveStep('sur',1)">다음 단계 →</button>
</div>
</div>
</div>
</div>
<div class="panel">
<h2>관련 suricata.yaml 내부 설정</h2>
<div class="accordion">
<div class="acc open"><div class="acc-head" onclick="toggleAcc(this)"><div class="acc-num">T</div><div><div class="acc-title">threading</div><div class="acc-sum">CPU affinity, worker-cpu-set, detect-thread-ratio</div></div><div class="acc-toggle">▼</div></div><div class="acc-body"><pre class="code">threading:
set-cpu-affinity: no
cpu-affinity:
- management-cpu-set:
cpu: [ 0 ]
- receive-cpu-set:
cpu: [ 0 ]
- worker-cpu-set:
cpu: [ "all" ]
mode: "exclusive"
detect-thread-ratio: 1.0</pre><p>detect-thread-ratio: 1.0은 탐지된 CPU 수 1개당 탐지 스레드 1개를 배정한다는 의미로 설명할 수 있다.</p></div></div>
<div class="acc"><div class="acc-head" onclick="toggleAcc(this)"><div class="acc-num">S</div><div><div class="acc-title">security</div><div class="acc-sum">limit-noproc, landlock, lua</div></div><div class="acc-toggle">▼</div></div><div class="acc-body"><pre class="code">security:
limit-noproc: true
landlock:
enabled: no
directories:
read:
- /usr/
- /etc/
- /etc/suricata/
lua:
#allow-rules: false</pre><p>limit-noproc는 새 프로세스 생성을 제한한다. Landlock이 켜져 있으면 지정된 디렉터리 중심으로 접근이 제한된다.</p></div></div>
<div class="acc"><div class="acc-head" onclick="toggleAcc(this)"><div class="acc-num">R</div><div><div class="acc-title">runmode</div><div class="acc-sum">single, workers, autofp</div></div><div class="acc-toggle">▼</div></div><div class="acc-body"><pre class="code"># Runmode the engine should use.
# Default depends on selected capture method.
# 'workers' generally gives best performance.
#runmode: autofp</pre><p>single은 단순 구조, workers는 일반적으로 성능에 유리한 구조, autofp는 flow pinning을 활용하는 구조로 설명할 수 있다.</p></div></div>
<div class="acc"><div class="acc-head" onclick="toggleAcc(this)"><div class="acc-num">D</div><div><div class="acc-title">defrag</div><div class="acc-sum">IP 계층 조각화 패킷 재조립</div></div><div class="acc-toggle">▼</div></div><div class="acc-body"><pre class="code">defrag:
memcap: 32mb
hash-size: 65536
trackers: 65535
max-frags: 65535
prealloc: yes
timeout: 60</pre><p>TCP는 자체적으로 세그먼트 단위로 나뉘지만, UDP는 데이터그램 단위로 전송되므로 IP 계층 조각화가 발생할 수 있다.</p></div></div>
<div class="acc"><div class="acc-head" onclick="toggleAcc(this)"><div class="acc-num">F</div><div><div class="acc-title">flow</div><div class="acc-sum">5-tuple 기반 통신 흐름 추적</div></div><div class="acc-toggle">▼</div></div><div class="acc-body"><pre class="code">flow:
memcap: 128mb
hash-size: 65536
prealloc: 10000
vlan:
use-for-tracking: true
livedev:
use-for-tracking: true</pre></div></div>
<div class="acc"><div class="acc-head" onclick="toggleAcc(this)"><div class="acc-num">ST</div><div><div class="acc-title">stream</div><div class="acc-sum">TCP 상태 추적과 payload 재조립</div></div><div class="acc-toggle">▼</div></div><div class="acc-body"><pre class="code">stream:
memcap: 64mb
checksum-validation: yes
#midstream: false
reassembly:
memcap: 256mb
depth: 1mb
#raw: yes
#segment-prealloc: 2048
#check-overlap-different-data: true</pre><p>depth가 1mb이면 TCP payload가 1mb를 넘어간 이후는 재조립하지 않는다. 공격 문자열이 그 뒤에 있으면 재조립 기반 탐지가 어려울 수 있다.</p></div></div>
<div class="acc"><div class="acc-head" onclick="toggleAcc(this)"><div class="acc-num">P</div><div><div class="acc-title">decoder / detect / profiling</div><div class="acc-sum">터널 해석, 룰 검사, 성능 분석</div></div><div class="acc-toggle">▼</div></div><div class="acc-body"><pre class="code">decoder:
teredo:
enabled: true
vxlan:
enabled: true
geneve:
enabled: true
detect:
profile: medium
prefilter:
default: mpm
profiling:
# rule, keyword, packet profiling</pre><p>decoder는 Teredo, VXLAN, Geneve 같은 캡슐화 패킷의 내부 패킷까지 해석한다. detect는 prefilter와 mpm으로 후보 룰을 좁혀 자원 소모를 줄인다.</p></div></div>
</div>
</div>
</section>
<section class="page" id="page-lab">
<div class="panel">
<span class="kicker">Chapter 6</span>
<h2>Snort 룰셋 호환 실습</h2>
<p class="lead">Suricata에서 Snort 룰셋을 사용할 수 있다는 것을 확인하고, Snort의 alert_json과 Suricata의 eve.json을 비교한다. 실습 명령어는 빠짐없이 순서대로 정리했다.</p>
<div class="subtabs">
<button class="subtab on" data-sub="lab-1" onclick="showSub('lab','lab-1')">1. Snort 환경 통일</button>
<button class="subtab" data-sub="lab-2" onclick="showSub('lab','lab-2')">2. Snort 로그 설정</button>
<button class="subtab" data-sub="lab-3" onclick="showSub('lab','lab-3')">3. 룰 작성</button>
<button class="subtab" data-sub="lab-4" onclick="showSub('lab','lab-4')">4. 캡처 실행</button>
<button class="subtab" data-sub="lab-5" onclick="showSub('lab','lab-5')">5. Suricata 이식</button>
<button class="subtab" data-sub="lab-6" onclick="showSub('lab','lab-6')">6. flow_id 분석</button>
</div>
<div class="subpage on" id="lab-1">
<div class="card"><h3>1. Snort 설정 위치와 심볼릭 링크</h3><pre class="code">cd /usr/local/snort/etc/snort
vim /usr/local/snort/etc/snort/snort.lua
# 약 197줄 rules = [[ 경로 ]] 로 local.rules 파일 위치 확인 및 복사
# /etc 경로에 심볼릭 링크 생성
ln -s /usr/local/snort/etc/snort /etc/snort
ln -s 기존_룰_경로 /etc/snort/rules
# snort 서비스가 active라면 잠시 중지
systemctl stop snort</pre></div>
</div>
<div class="subpage" id="lab-2">
<div class="card"><h3>2. Snort 로그 설정</h3><pre class="code"># snort.lua 약 260번째 줄
alert_full = {file = true}
alert_json = {file = true}
log_pcap = {}</pre><p>alert_full은 사람이 읽기 쉬운 상세 로그, alert_json은 구조화 로그, log_pcap은 실제 패킷 원본 저장에 사용한다.</p></div>
</div>
<div class="subpage" id="lab-3">
<div class="card"><h3>3. HTTP 패킷 탐지 룰 작성</h3><pre class="code">cd /etc/snort/rules
vim local.rules
#alert icmp any any -> any any (msg:"ICMP Test Detected"; sid:1000001; rev:1;)
#alert tcp any any -> any any (msg:"TCP"; sid:1000002; rev:1;)
alert tcp any any -> any 80 (msg:"http server KONG"; sid:1000003; rev:1;)
alert tcp 내서버 any -> 접속자 any (msg:"내서버->접속자 tcp"; sid:1000004; rev:1;)
alert tcp 접속자 any -> 내서버 any (msg:"접속자->내서버 tcp"; sid:1000005; rev:1;)</pre><p>방향 연산자에서 A → B는 A에서 B로 가는 트래픽을 의미한다. 서버 방향과 접속자 방향 룰을 나누면 패킷 흐름을 설명하기 쉽다.</p></div>
</div>
<div class="subpage" id="lab-4">
<div class="grid g2">
<div class="card"><h3>4. 기존 로그 정리</h3><pre class="code">cd /var/log/snort
# 필요시 백업
cp alert_json.txt alert_json.txt.bak
# 실습 확인을 쉽게 하기 위해 삭제
rm *</pre></div>
<div class="card"><h3>5. Snort 캡처 실행</h3><pre class="code">snort -c /etc/snort/snort.lua -i ens160 -l /var/log/snort \
--daq afpacket --daq-dir /usr/local/snort/lib/daq -k none</pre></div>
</div>
<div class="card green" style="margin-top:14px"><h3>6. 로그 확인</h3><pre class="code">cd /var/log/snort
ls
vim alert_full.txt
vim alert_json.txt</pre><p>alert_full은 룰 정보, 발생 시간, 출발지/목적지 IP·포트, TCP/IP 헤더 정보를 보여준다. alert_json은 timestamp, pkt_num, proto, dir, src_ap, dst_ap, rule, action 같은 필드로 정리된다.</p></div>
</div>
<div class="subpage" id="lab-5">
<div class="card"><h3>7. Snort 룰을 Suricata에 이식</h3><pre class="code"># Snort 룰 확인
vim /etc/snort/rules/local.rules
# Suricata 룰에 붙여넣기
vim /etc/suricata/rules/local.rules
# 예시
alert icmp any any -> any any (msg:"ICMP Test Detected"; sid:1000001; rev:1;)
alert tcp any any -> any any (msg:"TCP"; sid:1000002; rev:1;)
alert tcp any any -> any 80 (msg:"http server KONG"; sid:1000003; rev:1;)
# Suricata 실행
suricata -c /etc/suricata/suricata.yaml -i 인터페이스 -l /var/log/suricata/</pre></div>
</div>
<div class="subpage" id="lab-6">
<div class="grid g2">
<div class="card"><h3>8. fast.log와 eve.json 확인</h3><pre class="code">cd /var/log/suricata
ls
cat fast.log | grep KONG
cat eve.json | grep '02:29:57.398101'
cat eve.json | grep '"flow_id":1428357619560671' > testeve.txt</pre></div>
<div class="card green"><h3>분석 포인트</h3><p>Snort JSON은 매칭 중심으로 탐지 결과를 구조화한다. Suricata eve.json은 event_type에 따라 alert, http, flow 이벤트를 함께 기록한다. flow_id를 기준으로 같은 통신 흐름을 연결하면 단일 alert가 아니라 전체 HTTP 요청/응답 흐름을 추적할 수 있다.</p></div>
</div>
</div>
</div>
<div class="panel">
<h2>실습 결론</h2>
<div class="grid g3">
<div class="card"><h3>Snort JSON</h3><p>timestamp, pkt_num, proto, dir, src_ap, dst_ap, rule, action 중심으로 매칭 결과를 보여준다.</p></div>
<div class="card green"><h3>Suricata eve.json</h3><p>alert, http, flow 등 다양한 이벤트를 함께 남기며 flow_id로 하나의 통신 흐름을 연결한다.</p></div>
<div class="card yellow"><h3>SIEM 관점</h3><p>event_type, flow_id, src_ip, dest_ip, http.url, alert.signature 같은 필드를 기준으로 검색과 상관분석을 하기 쉽다.</p></div>
</div>
</div>
</section>
<section class="page" id="page-conclusion">
<div class="panel">
<span class="kicker">Chapter 7</span>
<h2>결론</h2>
<p class="lead">이번 실습의 목표는 Suricata를 단순히 설치하고 실행하는 것이 아니라, IDS가 네트워크 패킷을 어떤 구조로 처리하고 탐지하는지 이해하는 것이다.</p>
<div class="grid g3" style="margin-top:16px">
<div class="card green"><h3>Snort</h3><p>룰 기반 탐지 원리를 학습하기 좋다. 어떤 패킷이 어떤 룰에 매칭되었는지 이해하기 쉽다.</p></div>
<div class="card yellow"><h3>Suricata</h3><p>탐지 결과뿐 아니라 HTTP, DNS, TLS, Flow 같은 네트워크 행위 정보를 함께 남길 수 있어 관제와 분석에 유리하다.</p></div>
<div class="card why"><h3>flow_id</h3><p>alert, http, flow 이벤트를 하나의 통신 흐름으로 연결해 단일 Alert가 아니라 전체 요청/응답 흐름을 추적할 수 있다.</p></div>
</div>
<div class="card" style="margin-top:16px">
<h3>발표 마지막 멘트</h3>
<p>IDS를 제대로 이해하려면 룰을 작성하는 것에서 끝나면 안 된다. 패킷이 어디서 들어오고, 어떻게 캡처되고, 어떤 흐름으로 재조립되며, 어떤 로그로 남는지까지 이해해야 한다. Suricata는 패킷 처리 구조, 멀티스레드, 룰셋, JSON 로그, SIEM 연동 개념을 한 번에 연결해서 학습할 수 있는 IDS/NSM 엔진이다.</p>
</div>
<div class="chips"><span class="chip hot">IDS 구조 이해</span><span class="chip">패킷 처리 흐름</span><span class="chip">룰 기반 탐지</span><span class="chip">메타데이터 분석</span><span class="chip">flow_id</span><span class="chip">EVE JSON</span><span class="chip">SIEM 연동</span></div>
</div>
</section>
<footer class="footer">Suricata 학습용 자료 · IDS 구조와 패킷 처리 흐름 학습</footer>
</div>
<script>
const netSteps = [
{t:"NIC", s:"패킷이 처음 들어오는 하드웨어", d:"네트워크 케이블을 통해 실제 패킷이 처음 들어오는 장치다. 전기·광 신호가 PHY를 거쳐 비트열이 되고, MAC 처리를 통해 이더넷 프레임으로 인식된다.\n\n보안 장비 관점에서는 모든 패킷 분석의 시작점이다.", tags:["PHY","MAC","Ethernet Frame"], note:"패킷은 애플리케이션으로 바로 들어오지 않는다. 먼저 NIC가 수신한다."},
{t:"RX Queue / RX Ring", s:"NIC의 수신 대기열과 RSS", d:"RX Queue는 NIC의 수신 큐이며 보통 내부적으로 RX Ring 구조를 사용한다. RX Ring은 descriptor들의 원형 배열이고, 각 descriptor는 실제 패킷 데이터가 저장된 RX Buffer의 메모리 주소와 상태 정보를 가진다.\n\n트래픽이 많아지면 이 구간에서 큐가 가득 차 패킷 드롭이 발생할 수 있다. RX Ring Buffer가 충분하면 순간적인 트래픽 폭증을 더 오래 버틸 수 있지만, CPU 처리량 부족 자체를 해결하지는 못한다.\n\nRSS(Receive Side Scaling)는 바로 이 수신 큐 분산과 연결된다. 패킷의 출발지 IP, 목적지 IP, 출발지 포트, 목적지 포트, 프로토콜을 기준으로 해시를 계산해 같은 흐름은 같은 RX Queue로 보내고, 서로 다른 흐름은 여러 큐로 분산한다.", tags:["RX Queue","RX Ring","Descriptor","RX Buffer","RSS"], note:"RSS는 여기, RX Queue/RX Ring 단계의 부하 분산 설명에 한정해서 보는 것이 자연스럽다.", code:"ethtool -l ens160\nethtool -g ens160\n\nNIC\n├─ RX Queue 1 → CPU Core 1\n├─ RX Queue 2 → CPU Core 2\n├─ RX Queue 3 → CPU Core 3\n└─ RX Queue 4 → CPU Core 4"},
{t:"DMA", s:"CPU를 거치지 않는 메모리 전송", d:"NIC는 DMA(Direct Memory Access)를 통해 CPU를 매번 호출하지 않고 패킷 데이터를 메모리 버퍼에 저장할 수 있다. CPU가 모든 바이트 복사를 직접 담당하지 않게 하여 수신 처리 부담을 줄인다.", tags:["Direct Memory Access","RX Buffer"], note:"DMA는 CPU 부담을 줄이는 하드웨어 수준의 최적화다."},
{t:"NIC Driver", s:"하드웨어와 커널의 연결 지점", d:"NIC Driver는 운영체제가 NIC 하드웨어를 제어하기 위해 사용하는 커널 모듈이다. RX Ring의 패킷을 확인하고 커널 네트워크 스택이 처리할 수 있는 형태로 넘긴다.", tags:["Kernel Module","ethtool -i"], note:"드라이버 정보는 ethtool -i로 확인한다.", code:"ethtool -i ens160"},
{t:"Interrupt / Polling / NAPI", s:"CPU와 패킷 수신의 연계", d:"NIC가 패킷 수신을 알리면 CPU가 해당 패킷 처리를 담당한다. 초기에는 인터럽트 방식이었지만, 패킷이 많아질수록 인터럽트 자체가 부담이 된다. 이를 보완하기 위해 폴링 방식이 사용되고, 폴링의 비효율을 줄이기 위해 NAPI 구조가 사용된다.", tags:["Interrupt","Polling","NAPI"], note:"고트래픽 환경에서는 인터럽트 폭주도 병목이 될 수 있다."},
{t:"skb 생성", s:"리눅스 커널의 패킷 자료구조", d:"skb는 socket buffer의 약자이며, 리눅스 커널이 네트워크 패킷을 표현하는 핵심 자료구조다. 패킷 길이, 상태, 프로토콜 정보, 헤더 위치 포인터, 실제 데이터 버퍼 포인터 등을 포함한다.\n\n이후 Ethernet, IP, TCP/UDP 계층 처리는 대부분 skb를 기준으로 진행된다.", tags:["sk_buff","Header Pointer","Data Buffer"], note:"skb는 한곳에 차곡차곡 모이는 저장소라기보다 커널이 패킷을 처리하기 위해 들고 다니는 자료구조로 이해하면 된다."},
{t:"Kernel Network Stack", s:"L2·L3·L4 계층 처리", d:"커널 네트워크 스택은 패킷을 계층별로 해석한다. Ethernet Layer에서는 이더넷 헤더를 확인하고, IP Layer에서는 출발지·목적지 IP, TTL, 프로토콜 번호, 라우팅, 단편화/재조립을 처리한다. TCP/UDP Layer에서는 포트, 연결 상태, 순서 번호, 재전송, 흐름 제어 등을 처리한다.", tags:["Ethernet","IP","TCP","UDP","iptables"], note:"iptables/nftables 같은 방화벽 정책도 이 경로 중간에서 적용될 수 있다."},
{t:"Socket Buffer", s:"애플리케이션 전달 전 수신 버퍼", d:"TCP/UDP 처리가 끝난 데이터는 애플리케이션 소켓의 수신 버퍼에 보관된다. 80번 포트로 들어온 TCP 데이터는 웹서버 프로세스가 가진 소켓 버퍼로 전달된다.\n\nTCP window size와 sliding window에서 말하는 버퍼가 이 구간과 연결된다. 이 공간의 크기와 애플리케이션 처리 속도에 따라 지연이나 병목이 발생할 수 있다.", tags:["Receive Buffer","TCP Window","Sliding Window"], note:"소켓 버퍼는 프로세스가 사용하는 소켓과 연결된 수신 대기 공간으로 이해하면 된다."},
{t:"Application", s:"사용자 공간 프로그램이 데이터 읽기", d:"최종적으로 nginx, sshd, Suricata, 웹브라우저 같은 사용자 공간 프로그램이 데이터를 읽는다. 일반 애플리케이션은 보통 이더넷 헤더나 IP 헤더 전체를 직접 보는 것이 아니라 커널이 처리한 TCP/UDP 데이터 또는 소켓 데이터를 읽는다.", tags:["User Space","nginx","sshd","Suricata"], note:"AF_PACKET 같은 캡처 방식은 일반 소켓 데이터 처리와 다른 위치에서 패킷을 볼 수 있다."}
];
const surSteps = [
{t:"Capture", s:"패킷을 Suricata 엔진 안으로 가져옴", d:"NIC 또는 PCAP 파일에서 패킷을 가져온다. 실시간 감시에서는 AF_PACKET, libpcap, NFQUEUE, DPDK, PF_RING 같은 캡처 방식을 사용할 수 있다.\n\n이번 실습의 핵심은 Linux 환경에서 사용하기 좋은 AF_PACKET이다.", tags:["AF_PACKET","libpcap","NFQUEUE","DPDK"], note:"NIC → RX Queue/Ring → Kernel → AF_PACKET → Suricata"},
{t:"Decode", s:"패킷 구조 해석", d:"Decoder가 Ethernet, IP, TCP/UDP 헤더를 확인하고 프로토콜을 판단한다. VXLAN, Teredo, Geneve 같은 터널링 패킷은 내부 패킷까지 풀어서 분석할 수 있다.", tags:["Ethernet","IP","TCP/UDP","VXLAN","Geneve"], note:"이 단계가 제대로 되어야 flow, stream, app-layer 분석이 가능하다."},
{t:"Defrag", s:"IP 조각화 패킷 재조립", d:"IP 계층에서 조각화된 패킷이 있다면 다시 합친다. 큰 UDP 데이터그램이나 특수한 공격 패킷은 IP fragmentation을 발생시킬 수 있고, 공격자는 탐지 우회를 위해 악의적으로 패킷을 조각내기도 한다.\n\nTCP는 자체적으로 세그먼트 단위로 나뉘지만, UDP는 데이터그램 단위 전송이므로 IP 계층 조각화가 나타날 수 있다.", tags:["IP Fragmentation","Reassembly","host-os-policy"], note:"운영체제마다 겹치는 fragment 처리 방식이 다를 수 있어 host-os-policy가 중요하다."},
{t:"Flow Tracking", s:"같은 통신 흐름 묶기", d:"Suricata는 패킷을 개별적으로만 보지 않고 같은 통신 흐름으로 묶어 관리한다. 기준은 보통 5-tuple이다.\n\n출발지 IP, 목적지 IP, 출발지 Port, 목적지 Port, 프로토콜을 기준으로 flow를 구분하고 flow_id를 부여한다.", tags:["5-tuple","flow_id","Session"], note:"alert, http, flow 이벤트가 따로 남아도 flow_id로 하나의 통신 흐름을 연결할 수 있다."},
{t:"Stream / Reassembly", s:"TCP 데이터 흐름 재조립", d:"TCP는 데이터를 여러 세그먼트로 나누어 전송한다. 공격 문자열도 하나의 패킷에 통째로 들어오지 않고 여러 패킷에 나뉘어 들어올 수 있다.\n\nSuricata는 stream tracking과 reassembly로 쪼개진 payload를 다시 이어 붙인다.", tags:["TCP Stream","Payload","Reassembly"], note:"예: UNI + ON SEL + ECT → UNION SELECT", code:"Packet 1: UNI\nPacket 2: ON SEL\nPacket 3: ECT\n\nUNI + ON SEL + ECT\n↓\nUNION SELECT"},
{t:"App-Layer Parser", s:"HTTP/DNS/TLS 같은 상위 프로토콜 해석", d:"TCP/UDP 데이터 이후에는 애플리케이션 계층 분석이 진행된다. Suricata는 HTTP, DNS, TLS, FTP, SSH 등을 해석하고 http_method, hostname, url, status, user_agent, content_type, redirect 같은 필드를 추출한다.", tags:["HTTP Parser","DNS","TLS","url","user_agent"], note:"이 단계 덕분에 eve.json에서 event_type: http 로그를 볼 수 있다."},
{t:"Detect Engine", s:"룰셋과 비교해 탐지", d:"Detect Engine은 패킷, flow, stream, app-layer 데이터를 대상으로 룰 조건을 검사한다. content, pcre, flow, http_uri, http_header, flowbits 같은 옵션이 사용된다.\n\n성능 최적화를 위해 prefilter, mpm, hyperscan을 활용해 후보 룰을 먼저 좁힌 뒤 정밀 검사를 수행한다.", tags:["Rule Matching","content","pcre","flowbits","MPM"], note:"단순 패킷 매칭이 아니라 재조립된 데이터와 HTTP 필드를 대상으로도 탐지할 수 있다."},
{t:"Output / Logging", s:"탐지 결과와 메타데이터 출력", d:"탐지가 발생하거나 메타데이터 기록 조건에 맞으면 로그가 생성된다. fast.log는 빠르게 보기 좋은 Alert 로그이고, eve.json은 구조화된 JSON 이벤트 로그다. pcap-log는 실제 패킷 원본을 저장하고 stats.log는 성능·상태 통계를 남긴다.", tags:["fast.log","eve.json","pcap-log","stats.log"], note:"SIEM 연동에서는 event_type, flow_id, src_ip, dest_ip, http.url, alert.signature 같은 필드가 중요하다."}
];
let state = { net:0, sur:0 };
function showPage(id){
document.querySelectorAll('.page').forEach(p=>p.classList.remove('on'));
document.getElementById('page-'+id).classList.add('on');
document.querySelectorAll('.tab').forEach(t=>t.classList.toggle('on', t.dataset.page===id));
window.scrollTo({top:0, behavior:'smooth'});
}
function showSub(group,id){
const parent=document.getElementById('page-'+group);
parent.querySelectorAll('.subpage').forEach(s=>s.classList.remove('on'));
document.getElementById(id).classList.add('on');
parent.querySelectorAll('.subtab').forEach(b=>b.classList.toggle('on', b.dataset.sub===id));
}
function toggleAcc(head){ head.parentElement.classList.toggle('open'); }
function renderStepper(kind,steps){
const flow=document.getElementById(kind==='net'?'netFlow':'surFlow');
flow.innerHTML=steps.map((x,i)=>`<div class="fstep ${i===0?'on':''}" onclick="setStep('${kind}',${i})">${x.t}<small>${String(i+1).padStart(2,'0')}</small></div>`).join('');
setStep(kind,0);
}
function setStep(kind,idx){
const steps=kind==='net'?netSteps:surSteps;
state[kind]=(idx+steps.length)%steps.length;
const s=steps[state[kind]];
const prefix=kind==='net'?'net':'sur';
document.querySelectorAll('#'+prefix+'Flow .fstep').forEach((el,i)=>el.classList.toggle('on',i===state[kind]));
document.getElementById(prefix+'Num').textContent=String(state[kind]+1).padStart(2,'0');
document.getElementById(prefix+'Title').textContent=s.t;
document.getElementById(prefix+'Sub').textContent=s.s;
document.getElementById(prefix+'Desc').textContent=s.d;
document.getElementById(prefix+'Note').textContent=s.note||'';
document.getElementById(prefix+'Tags').innerHTML=(s.tags||[]).map(x=>`<span class="chip hot">${x}</span>`).join('');
const code=document.getElementById(prefix+'Code');
if(s.code){code.textContent=s.code;code.style.display='block'}else{code.style.display='none'}
}
function moveStep(kind,delta){ setStep(kind,state[kind]+delta); }
renderStepper('net',netSteps);
renderStepper('sur',surSteps);
</script>
</body>
</html>