Snort
Snort는 프로토콜 분석, 콘텐츠 검색, 웜, 취약점 공격, 포트 스캔, 버퍼 오버플로우 등 다양한 공격을 탐지하는 OpenSource IDS
Snort의 구조
Snort는 네 가지 요소로 구성이 되어 있다.
Sniffer → Preprocessor → Detection Engine → Alert/Logging
1. Sniffer
네트워크를 도청하는데 쓰이는 하드웨어 또는 소프트웨어 장치 애플리케이션 또는 하드웨어 장치에서 해당 네트워크의 트래픽을 도청할 수 있다.
[ 용도 ]
- 네트워크 분석과 문제를 해결.
- 성능 분석과 벤치마킹 평문 비밀번호가 기타 데이터를 도청
2. Preprocessor
패킷 Sniffer로부터 전달받은 패킷을 특정한 플러그인으로 전달하여 패킷에서 특정한 종류의 행위를 찾는다. 패킷에서 특정한 행위를 찾은 뒤에 Detection Engine으로 전송하게 된다.
3. Detection Engine
Preprocessor로부터 패킷을 전달받아 패킷과 일치하는 Ruleset이 있다면 해당 패킷은 Alert/ Logging으로 전달된다.
4. Alert / Logging
Detection Engine과 일치하는 패킷이 있다면 경고가 발생하는데, 이때 경고는 로그 파일, SMB, SNMP 트랩 등으로 전달된다. Syslog와 같은 툴을 사용하면 E-mail을 통해 관리자에게 실시간으로 전달.
Snort Rule
snort rule / signature는 크게 헤더와 옵션 부분으로 구성
Rule Header - 처리 방식, 프로토콜, IP 주소, 포트 번호 등 처리할 패킷을 판단하는 기준 명시
Rule Option - 패킷을 탐지하기 위한 규칙을 명시
1. Rule Header(룰 헤더)
1. rule actions - 8가지
1) alert : 선택한 경고 방법에 따른 alert 발생 + 로그 기록
2) log : 로그를 저장
3) pass : 패킷을 무시
4) activate : alert 발생 + dynamic rule 활성화
5) dynamic : activate rule에 의해 활성화 + log rule과 동일하게 동작
6) drop : 패킷 차단 + 로그
7) reject : drop rule과 동일하게 패킷을 차단 + 로그, TCP인 경우 TCP Reset 전송, UPD인 경우 ICMP Port unreachable 메시지 전송
8) sdrop : 패킷 차단 but 로그 남기지 않음
2. protocols : 탐지할 프로토콜 4가지 TCP, UDP, ICMP, IP
3. IP Address
1) 모든 주소 : any
2) 단일 주소 : 192.168.0.1
3) 복수 주소 : [192.168.0.1 192.168.0.2] 또는 [192.168.0.0/24]
4) 부정 : !192.168.0.1 !192.168.0.0/24
5) 내부IP 주소 : $HOME_NET, 외부IP 주소 : $EXTERNAL_NET
4. Port Numbers
1) 모든 주소 : any
2) 단일 포트 : 80
3) 여러개 포트 : 1:500 (1~500까지)
4) 부정 : !80
5. Direction Operator : 방향 지시지
1) -> 단방향: 출발지 -> 목적지
2) <> 양방향
3) <- 방향지시자는 없음
헤더 사용예
action | protocol | ip address | port | direction | ip address | port |
alert | TCP | any | any | -> | 192.168.133.0/24 | 80 |
action | protocol | ip address | port | direction | ip address | port |
log | TCP | $EXTERNAL_NET | any | <> | $HOME_NET | 80 |
2. Rule Option(룰 옵션)
룰옵션은 General, Payload, Non-payload, post-payload 로 주요 4개로 분류되고 주로 Payload 탐지 룰이 사용
- 일반 옵션
1. msg : alert, log에서 저장될 메시지명 지정
2. reference : 공격 참조 정보를 제공
3. sid : 스노트 규칙을 유일하게 식별하는 식별자
- 100미만은 예약
- 100~100만은 스노트 지정 룰
- 100만 초과는 사용자 정의 룰
4. rev : 스노트 규칙의 버전. 수정 횟수
5. classtype : 공격 종류와 규칙을 분류
6. priority : 분류(classtype) 옵션에 의해 설정된 규칙 우선순위를 강제로 수정
7. metadata : Rule 작성자가 추가정보를 Key-Value 형식으로 포함
- 페이로드
1. content : 탐지할 패턴(문자열)을 설정하는 옵션. text이거나 binary 형태(헥사값) 일수 있음.
2. nocase : 패턴 매칭 시 대소문자 구별하지 않고 매칭
3. offset : 해당 옵션에서 지정한 바이트만큼 떨어진 위치부터 탐색 시작
4. depth : 패킷 데이터에서 찾을 내용의 범위를 지정하는 옵션
5. distance : 이전 content 설정값 매칭 탐색할 위치를 지정 (시작점 + 바이트 수 다음부터 해당 문자 검사)
6. within : 이전 content 설정값 매칭 후 매칭을 끝낼 상대 위치를 지정 ( 시작점부터 바이트 수 이내 범위에서 해당 문자 검사)
7. pcre : 스노트 규칙에서 사용할 수 있는 perl 호환 정규 표현식. '/'는 시작과 끝에 표기, 16진수 앞에는 \x
8. flags : TCP 프로토콜에서 제어플레그를 지정하는 것으로 SYN, FIN, URG, ACK을 지정할 수 있다.
- SYN 플래그는 flags:S, SYN, FIN 모두 탐지 : flags:SF
옵션 사용 예
사용 예 | 설명 | |
content | content:!"GET"; content:"/etc/passwd"; | GET 문자열 제외하고 /etc/passwd 문자열 검색 |
nocase | content:"ROOT"; nocase; | ROOT 문자가 대소문자 상관없이 검색 됨 |
offset | content:"hello"; offset:20; | 첫 20바이트 이후부터 문자 hello가 있는지 검색 |
depth |
content:"GET"; depth:4; | 처음부터 4바이트까지 GET 문자가 있는지 검색 |
content:"webshell.jsp"; offest:4; depth:20; | 처음 4바이트 이후부터의 20바이트 중에 webshell.jsp 문자열을 포함하는지 검사 | |
distance | content:"abc"; content:"def"; distance:3; | abc문자 찾은 이후에 3바이트만큼 뒤에서 def 문자가 있는지 검사 |
within | content:"GET"; depth:3; content:"downloads"; distance:10; within:9; | 처음 3바이트까지 GET문자가 있는지 확인하고, 그다음 10바이트만큼 떨어진 지점에서 9바이트 이내에 downloads라는 문자가 있는지 검사 |
pcre | pcre:"/(http|ftp) Traffic/" | http Traffic 또는 ftp Traffic 문자열 검색 |
pcre 사용을 위한 정규식 정리
pcre 사용 규칙 : pcre :"/정규식/";
- 참고 : http://www.perl.or.kr/perl_iyagi/regexp
메타문자
문자 | 내용 | 예시 | 설명 |
^ | 문자열의 시작 | ^t.e | the, tie, toe 가능 settle 불가능 |
$ | 문자열의 끝 | t.e$ | toe, necktie 가능 |
. | 개행문자를 제외한 임의의 한 글자 | t.e | the, tie,toe, settle 등이 가능 |
? | 0개 또는 1개 이상 반복되는 것과 매칭 | s?he | he 또는 she |
+ | 1개이상 반복된 것과 매칭 | s+he | she, sshe, ssssshe tshe 가능. he, the 불가능 |
* | 0개 이상 반복되는것과 매칭 | s*he | she, he, ssssshe, the tshe 가능 |
() | 서브 패턴(문자열을 하나로 묶음) | (eg|le)gs | eggs 또는 legs |
ba(na)+ | bana, banana, bananana 등 | ||
[] | 문자열 셋 | [a-z] | 소문자 |
[0-9a-zA-Z] | 모든 문자 | ||
h[aeo]y | hay, hey, hoy | ||
[^] | 문자열 셋 안의 ^는 제외한다는 의미 | h[^aeo]y | hay, hey, hoy를 제외 |
{} | a{m} : 정확하게 m번 반복되는 것과 매칭 | ba(na){2} | banana |
a{m,} : 최소 m개 반복되는 것과 매칭 | ba(na){1, 2} | bana, banana | |
a{m,n} : 최소 m개~n개까지 반복되는 것과 매칭 | ba(na){2, 5} | banana, bananana, banananana, banananana | |
o{2, 4}p | oop, ooop, oooop | ||
\ | 특수 문자 앞에 둠 |
옵션
옵션 | 내용 | 예시 |
i | 대소문자 구별하지 않음 | pcre:"/where/i" |
s | 줄이 넘어가도 문자열을 한줄로 인식 | pcre:"/where/s" |
x | 패턴에 존재하는 모든 공백 무시 | pcre:"/where/x" |
M | HTTP 메소드 패턴 일치 | pcre:"/get/Mi" |
U | 정규화된 URL 디코딩 문자열 패턴 매칭 | pcre:"/cisco/Ui" |
H | 정규화된 HTTP요청 메시지 Header 내용 패턴 매칭 | pcre:"/get/Hi" |
P | HTTP 요청 메시지 Body 내용 패턴 매칭 | pcre:"/select/Pi" |
S | HTTP 응답 코드 패턴 매칭 | pcre:"/200/S" |
Y | HTTP 응답 상태 메시지 패턴 매칭 | pcre:"/OK/Y" |
이스케이프 문자
기호 | 설명 | |
\\ | \ | |
\d | 모든 숫자 | |
\D | 숫자가 아닌 문자 | [^0-9] |
\s | 공백 | \t, \n, \r, \f, \v |
\S | 공백이 아닌 문자 | |
\w | _를 포함한 숫자 또는 문자 | [A-Za-z0-9_] |
\W | 숫자 또는 문자가 아닌 것 | |
\b | 단어와 공백 사이를 찾음 | |
[\b] | back space. \b와 혼동하면 안됨 | |
\B | 단어 경계가 아님 |
Snort 탐지룰 예시
1) log4j 관련 snort 탐지룰
(출처 : PIOLINK, https://www.piolink.com/kr/service/Security-Analysis.php?bbsCode=security&vType=view&idx=95)
#CVE-2021-44228
alert tcp any any -> any any (msg:"Apache_Log4j_RCE"; pcre:”/\x24(\x7b|%7B)(jndi:|rmi:|ldap:|dns:) /i")
alert tcp any any -> any any (msg:"Apache_Log4j_RCE"; pcre:"/\x24(\x7b|%7B)(lower:|upper:)?[jndilapsrmev]{1,4}/i")
alert tcp any any -> any any (msg:"Apache_Log4j_RCE"; pcre:"/\x24(\x7b|%7B)(\x3a\x3a\x2d(j|n|d|i)\x7d)/i")
#CVE-2021-45046
alert tcp any any -> any any (msg:"Apache_Log4j_DOS"; contents:"|0d 0a|X-Api-Version|3a 20|"; pcre:"/\x24\7bctx\x3a/i")
#CVE-2021-45105
alert tcp any any -> any any (msg:"Apache_Log4j_DOS"; contents:"|0d 0a|X-Api-Version|3a 20|"; pcre:"/(\x24\x7b){1,}[\x3a,\x2d,\x7b\,\x24]+\x7d/i")
x24 : $
x7b : {
x3a : :
x2d : -
x7d : }
SNORT RULE 관련 문제
Q1 : 모든 네트워크 대역에서 Telnet으로 접속하는 패킷 중 14번째 자리까지 'anonymous'가 포함된 트래픽에 대해서 'Dangerous' 메시지로 경고하는 rule을 만드시오.
(단, 기본적으로 TCP 프로토콜 경유를 탐지함.)
[필요한 룰 헤더]
1. action : alert
2. protocol : tcp
3. 출발지 IP : any
4. 출발지 Port : any
5. 방향 : ->
6. 도착지 IP : any
7. 도착지 Port : 23 (telnet 서비스)
[룰 옵션]
1. 경고 메시지 : msg:"Dangerous"
2. 문자열 탐지 : content:"anonymous"
3. 14번째 자리까지 탐지 : depth:14
4. sid:1000001 (사용자가 설정한 경우 100만 이상지정. 문제에 따로 언급이 없어 생략가능)
주의사항 : ';' 마지막까지 넣기
[결과]
alert tcp any any -> any 23 (msg:"Dangerous"; content:"anonymous"; depth:14; sid:1000001;) 또는
alert tcp any any -> any 23 (msg:"Dangerous"; content:"anonymous"; depth:14;)
Q2 : Snort 정책에서 10바이트에서 12바이트 중 00FF 바이트에 해당하는 내용을 찾으려고 한다.
보기의 rule에 빈칸을 채워 rule을 완성하시오.
alert tcp $EXTERNAL_NET any -> $INTERNAL_NET any (msg:"TEST"; ( A ):"|00FF|"; ( B ):9; ( C ):2; sid:10000001;)
(A) : content
(B) : offset
(C) : depth
Q3. Snot Rule을 보고 다음을 답하시오.
alert any any -> any 80 (msg : "XSS"; content : "GET"; offset:1; depth:3; content:"/login.php?p=<script>"; distance:1;)
1) content : "GET"; offset:1; depth:3; 구문의 의미 ?
페이로드에서 1바이트 띄고 3바이트 내에서 "GET" 문자열을 검사
2) content : "./login.php?p=<script>"; distance:1; 구문의 의미
앞의 매칭된 문자열에서 1byte 떨어진 지점에서 "./login.php?p=<script>" 문자열을 검사
3) "/Login.php?p=<script>" 이 탐지되지 않았다. 위의 룰을 어떻게 변경해야 하는 가?
> 대소문자 구별을 하지않도록 설정하는 nocase 구문을 추가해준다.
alert any any - > any 80 ( msg : "XSS"; content :"GET"; offset:1; depth:3; content:"/login.php?p=<script>"; distance:1; nocase;)
Q4. ①~⑤가 뜻하는 것은?
alert tcp any any -> any ① [443,465,523] ( ② content:"|18 03 00|"; depth: 3; ③ content:"|01|"; distance: 2; within: 1; ④ content:!"|00|"; within: 1; ⑤ msg: "SSLv3 Malicious Heartbleed Request V2"; sid: 1; )
① 목적지 포트가 443, 465, 523
② content에서 첫번째 3바이트를 바이너리 값으로 |18 03 00| 검사
③ ②번이 끝난 위치에서 2바이트 띄고 1바이트 값이 바이너리 값으로 |01| 검사
④ ③번이 끝난 위치에서 바로 1바이트 값이 바이너리 값 |00|이 아닌지(!) 검사
⑤ 위의 모든 조건 만족시 msg : "SSLv3 Malicious Heartbleed Request V2" 를 기록하고 해당 룰의 식별자를 1로 지정