Snort는 다양한 전처리기(Preprocessor)를 제공 함으로써 여러가지 패킷 전처리 기능을 수행합니다. 

HTTP Inspection 은 HTTP 패킷의 URI에서 encode된 값을 찾아 decode하는 작업을 수행하게 됩니다. 


기본적으로 패킷을 decode하지 못하면 공격 명령을 encode함으로써 간단하게 Snort와 같은 IPS/IDS를 우회할 수 있게 됩니다. 

이런 우회 패킷에 대한 탐지를 수행하기 위해 꼭 필요한 HTTP Inspection 모듈의 정규화 과정에 대해 알아봅시다. 


HTTP Inspection Preprocessor에서는 HTTP패킷이 들어오면 기본적으로 다음과 같은 순서로 정규화 처리를 수행합니다. 


HTTP Inspection에 의해 설정에 따라 최대 2번 까지 '%' decode를 수행합니다. 

또한, 설정에 따라 unicode 및 '%U' decode를 수행 할 수 있습니다. 



'decode'나 '정규화'가 뭘 의미하는지 잘 모르시는 분들은 이 글을 보시면 됩니다. 


[스노트-snort] HTTP Inspection 전처리기의 모든 것



혹시 잘못된 정보가 있거나 궁금한 점이 있으시면 댓글 남겨주세요~ ^^


Posted by KT한
,

스노트에서 지원하는 pcre 옵션을 활용하면 정규표현식으로 시그니처를 표현할 수 있습니다. 정규표현식에 대한 이해는 필수 겠지만 pcre의 변경자(modifier) 옵션에 대한 이해까지 수반된다면 좀 더 손쉽게 다양한 표현식 작성이 가능해집니다. 


이번 포스트에서는 pcre의 modifier 옵션에 대해 다루고자 합니다. 



스노트에서 제공하는 pcre 문법입니다. 빨간색으로 칠한 부분에 대해 알아봅시다. 


pcre:[!]"(/<regex>/|m<delim><regex><delim>)[ismxAEGRUBPHMCOIDKYS]";




추천은 저를 춤추게 합니다 ^^


  • Perl과 호환되는 옵션들 


  •  i (PCRE_CASELESS) 

정규표현식에 설정한 패턴의 대문자와 소문자를 구별하지 않습니다. 가장 흔하게 쓰는 옵션이라고 할 수 있습니다. 


 문자열

 aAaAa
 시그니처  탐지 됨  pcre:"/aaa/i"; 
 탐지 안됨   pcre:"/aaa/"; 


  • s (PCRE_DOTALL) 

기본적으로 점(.)은 어떤 한 문자를 표현할 때 사용하는 메타문자입니다. 하지만 줄바꿈은 점(.)에 의해 매치가 되지 않습니다. 

s 옵션을 사용하면 점(.)으로 줄바꿈 까지도 매치가 가능합니다. 


 문자열

 aAaAa
 bBbBb 

 hex값
 61 41 61 41 61 0d 0a 62 42 62 42 62
 시그니처 탐지 됨 pcre:"/a..b/s"; 
 탐지 안됨 

 pcre:"/a..b/"; 


  • m (PCRE_MULTILINE) 

기본적으로 주어진 문자열을 한 줄로 취급합니다. 여러개의 줄바꿈이 존재하더라도 문자열의 처음과 끝 외에는 캐럿(^)과 달러($)에 의한 매치가 되지 않습니다. 

m옵션을 사용하면 줄바꿈(newline)의 바로 앞은 달러($)로 바로 다음은 캐럿(^)으로 매치할 수 있습니다. 

참고로, 캐럿(^)은 문자열의 처음, 달러($)는 문자열의 끝을 찾는 메타문자입니다. 


 문자열

 aAaAa
 bBbBb
 시그니처 탐지 됨

 pcre:"/^bB/m"; 

 탐지 안됨 

 pcre:"/^bB/"; 


  • x (PCRE_EXTENDED) 

패턴(시그니처)에 있는 이스케이프 처리되지 않은 모든 공백 문자를 무시합니다. 거의 사용하지 않는 옵션입니다. 


 문자열

 aAaAa
 시그니처 탐지 됨

 pcre:"/a A a/x"; 

 탐지 안됨 

 pcre:"/a A a/"; 



  • PCRE와 호환되는 옵션들 (일부 옵션 명이 다를 수 있음)


  • A  (PCRE_ANCHORED)

문자열의 시작에 매치도록 합니다. 캐럿(^)과 동일한 기능을 합니다. 


 문자열

 aabcdeab

 시그니처 탐지 됨

 pcre:"/ab/"; 

 탐지 안됨 

 pcre:"/ab/A"; 


  • E  (PCRE_DOLLAR_ENDONLY)

기본적으로 달러($)는 마지막 문자가 줄바꿈(뉴라인)일 경우에는 바로 직전의 문자에도 매칭합니다. (마지막이 아닌 줄바꿈은 제외) 

하지만, 이 옵션을 사용하면 달러($)는 오직 주어진 문자열의 마지막에만 매치됩니다.

이 변경자는 변경자 m과 함께 사용되면 무시됩니다. 


 문자열

 aAaAa

 시그니처 탐지 됨

 pcre:"/aAa/"; 

 탐지 안됨 

 pcre:"/aAa/E"; 


  • G (PCRE_UNGREEDY) 

기본적으로 PCRE는 greedy 하게 동작합니다. 이는 가능한 최대로 매치를 하게 됩니다. 

하지만, 이 옵션을 사용하면 lazy하게 동작하게 됩니다. 이는 가능한 최소로 매치를 하게 됩니다. 

greedy와 lazy는 아래 예시를 보면 쉽게 이해가 될겁니다. 


-Greey 방식

  표현식   <.*>

  문자열  Regex <b>Greedy</b> Style


-Lazy방식

  표현식   <.*?>

  문자열   Regex <i>Lazy</i> Style


 문자열

 <b>aaa</b>

 시그니처

 greedy

 pcre:"/<.*>/"; 

 pcre:"/<.*?>/G";

 lazy 

 pcre:"/<.*?>/"; 

 pcre:"/<.*>/G"; 



  • Snort에서만 사용하는 옵션들


  • R 

마지막에 패턴 매치된 부분부터 검사를 수행합니다. 

즉, content 옵션과 함께 사용하는 distance:0 과 동일한 문자열 버퍼에 대해 패턴 매치를 시도합니다.  


URI 버퍼 값에 대해서 패턴 매치를 시도합니다. 

즉, http_uri 혹은 uricontent와 동일한 문자열 버퍼에 대해서 패턴 매치를 시도합니다. 


  • I

정규화 작업을 하지 않은 URI 버퍼에 대해 패턴 매치를 시도합니다. 

즉, http_raw_uri 와 동일한 문자열 버퍼에 대해 패턴 매치를 시도합니다. 


  • P

정규화 되지 않은 HTTP request body 버퍼 값에 대해 패턴 매치를 시도합니다. 

즉, http_client_body와 동일한 문자열 버퍼에 대해서 패턴 매치를 시도합니다. 


  • H

정규화된 HTTP request나 response 헤더 버퍼 값에 대해서 패턴 매치를 시도합니다. 

즉, http_header와 동일한 문자열 버퍼에 대해서 패턴 매치를 시도합니다. 


  • D

정규화 되지 않은 HTTP request 나 response 헤더 버퍼값에 대해서  패턴 매치를 시도합니다. 

즉, http_raw_header와 동일한 문자열 버퍼에 대해서 패턴 매치를 시도합니다. 


  • M

정규화된 HTTP request method 버퍼값에 대해서 패턴 매치를 시도합니다. 

즉, http_method와 동일한 문자열 버퍼에 대해서 패턴 매치를 시도합니다. 


  • C

정규화된 HTTP request와 response cookie 버퍼값에 대해서 패턴 매치를 시도합니다. 

즉, http_cookie 와 동일한 문자열 버퍼에 대해서 패턴 매치를 시도합니다. 


  • K

정규화되지 않은 HTTP request와 response cookie 버퍼값에 대해서 패턴 매치를 시도합니다. 

즉, http_cookie 와 동일한 문자열 버퍼에 대해서 패턴 매치를 시도합니다. 


  • S

HTTP response status code 버퍼값에 대해서 패턴 매치를 시도합니다. 

즉, http_stat_code 와 동일한 문자열 버퍼에 대해서 패턴 매치를 시도합니다. 


  • Y

HTTP response status 메시지 버퍼값에 대해서 패턴 매치를 시도합니다. 

즉, http_stat_msg 와 동일한 문자열 버퍼에 대해서 패턴 매치를 시도합니다. 


  • B

HTTTP 관련 버퍼를 사용하지 않고 원본 패킷에 대해서 패턴 매치를 시도합니다. 

즉, rawbytes와 유사합니다.  


  • O

설정 파일(snort.conf)에서 지정한 pcre match limit 값을 무시하는 목적으로 사용합니다.  match limit은 pcre에 의해 너무 오랜 시간 수행 되는것을 방지하는 목적으로 검사 횟수를 제한 하는 값입니다.  

이 옵션을 사용하면, 해당 시그니처에 한해서 match recusion 횟수에 제한없이 탐지를 수행합니다. 



위 내용을 정리해보면 다음과 같습니다. 

 순번

 pcre

 유사한 content 옵션

 주의 사항

 1

 R

 distance:0;

 'U,I,P,H,D,M,C,K,S,Y' 옵션과 함께 사용 못함

 2

 U

 http_uri; or uricontent;

 'I' 옵션과 함께 사용 못함

 3

 I

 http_raw_uri; 'U' 옵션과 함께 사용 못함

 4

 P

 http_client_body; 

 5

 H

 http_header;

 'D' 옵션과 함께 사용 못함

 6

 D

 http_raw_header;

 'H' 옵션과 함께 사용 못함

 7

 M

 http_method; 

 8

 C

 http_cookie; 'K' 옵션과 함께 사용 못함

 9

 K

 http_raw_cookie; 'C' 옵션과 함께 사용 못함

 10

 S

 http_stat_code; 

 11

 Y

 http_stat_msg; 

 12

 B

 rawbytes;

 'U,I,P,H,D,M,C,K,S,Y' 옵션과 함께 사용 못함


▶ 정규표현식 관련 글 보기

[프로그래밍] 정규표현식 (Regular Expression) - 초급

Posted by KT한
,

스노트(Snort)는 보편적으로 사용되고 있는 IPS 오픈소스 입니다. (만약 생소하시다면 이전 포스팅 들을 참고하세요.)


오픈 소스이기에 소스를 공개하고 있음에도 워낙 분량이 방대하여 소스를 봐도 동작 방식을 이해하기란 쉽지 않습니다. 심지어 주요 함수에는 주석으로 친절한 설명까지 잘 남겨져 있음에도 완벽히 이해하기란 쉽지 않은것이 현실입니다. 물론, 소스를 열어서 확인 하는 사람은 극 소수겠죠. 


이번 포스팅에서는 스노트의 패턴 매칭 순서 및 동작 방식에 대한 이야기를 풀어 보고자 합니다. 

사실... 상당히 난해한 주제입니다.  



설명에 앞서 기본적인 용어를 하나 정의하고 가겠습니다. 

시그니처를 하나 예제로 살펴 봅시다. 


drop tcp 10.1.2.100 any > 10.1.1.100 22 (                                                 

        msg:"SSH Brute Force Attempt"; flow:established,to_server;              

        content:"SSH"; nocase; offset:0; depth:4;                                        

        detection_filter:track by_src, count 30, seconds 60; sid:1000001; rev:1;)


첫 번째 줄을 스노트에서는 RTN(Rule Tree Node)이라고 합니다. IP주소와 포트, 프로토콜 정보를 여기에다 저장합니다. 나머지 3 줄을 OTN(Option Tree Node)이라고 합니다. 실제 시그니처의 내용으로 공격 정보를 담고 있게 됩니다. 



추천은 저를 춤추게 합니다 ^^



자.. 그럼 본론으로 들어가서.. 

일반적으로 스노트는 시그니처의 RTN을 먼저 검사 한 후 OTN을 검사하는 순서로 진행한다고 생각하기 쉽습니다. 

자.. 아래 문제를 한번 풀어볼까요?


문제. 

4210 포트에서 80 포트의 HTTP 서버로 가는 패킷을 탐지하고자 하는데, 시그니처 중에 12345 에서 80으로 가는 패킷을 탐지하는 시그니처가 있다고 가정해봅시다. 
이 경우 옵션 부분인 OTN을 검사 할까요? 안할까요?

패킷:  


시그니처:
alert tcp any 12345 -> any 80 (msg:"abnormal traffic"; .... )



상식적으로 port값만 비교해 봐도 출발지 포트가 같지 않으므로 보나마나 탐지가 안된다고 결론을 내릴 수 있음에도, Snort는 목적지 포트인 80이 일치 되는것만 확인하고는 시그니처 탐지를 수행합니다. OTN을 모두 검사 한 후 RTN을 검사하는 과정에서야 출발지 포트가 해당되지 않는 다는걸 알게 되는 것이죠. 


그 이유에 대해 알고자 한다면 Aho-Corasick 매턴 매칭 알고리즘에 대해 먼저 알아야 합니다.
 
Aho-Corasick 알고리즘은 멀티 패턴 매칭 알고리즘으로 매우 잘 알려져 있습니다. 
Aho와 Corasick 두 사람이 고안해낸 이 알고리즘은 입력받은 패턴에 대해 매칭되는 모든 패턴들을 trie 구조로 만든 후 단 한번의 검사 만으로 검출하는것이 가능합니다. 


그림 1. Aho-Corasick diagram - 출저: 위키페디아



Snort에서는 시그니처의 패턴을 추출해서 위와 같은 맵을 생성하고, 패킷이 들어오면 이 맵에 의해 단 한 번 검사만으로 패턴 매치에 성공한 시그니처의 id를 얻을 수 있습니다. 

이게 아무리 효율적이라고 해도 port값 먼저 확인 하는게 더 효율적이지 않나 라는 의문은 여전히 남아 있을 겁니다. 

자! 이런 경우를 생각해봅시다. 
시그니처가 3,000개 정도 있는 경우를 생각해 봅시다. 하나의 패킷이 들어오면 3,000개의 시그니처에 대해 포트가(출발지,목적지) 일치 하는게 있는지 찾아야 합니다. 이 작업을 3,000번 한다고 생각해보세요. 생각보다 시간이 많이 걸립니다. 물론 시그니처가 늘어나면 시간은 선형적으로(linear) 증가 할 수 밖에 없는 구조가 되는겁니다. 

결국, 첫 단계에서 최소의 시간안에 최대한 유력한 시그니처를 걸러내는게 효율적이라는걸 알 수 있습니다. 이 작업을 Aho-Corasick 알고리즘을 활용해서 하는 겁니다. 한마디로 필터링을 하는 것이죠. 

그렇다고 모든 패턴을 죄다 뽑아서 Aho-Corasick을 수행하면 시간이 많이 걸리기 때문에, 스노트에서는 Aho-Corasick에 사용할 패턴은 각 시그니처 중에서 가장 긴 패턴 (longest pattern) 하나를 대표로 골라서 Aho-Corasick에 사용하도록 했습니다. (최신 버전에서는 시그니처를 만드는 사람이 Aho-Corasick에 사용될 longest pattern을 지정 할 수 있도록 'fast_pattern'이란 옵션을 지원합니다.) 이를 스노트에서는 멀티 패턴 탐색 엔진 - MPSE(Multi Pattern Search Engine)라고 합니다. 


스노트는 이런 MPSE 맵을 포트(port)별로 생성해서 관리를 합니다. 이를 소스에서는 'PORT_GROUP'이란 구조체로 사용 하고 있어서 포트 그룹이라고도 부릅니다. 그 이유는 MPSE맵이 너무 커지면 한 번의 매칭을 위해 비교해야 할 경우의 수가 늘어나게 되므로 성능 저하가 불가피 하기 때문입니다. 


아래 그림은 스노트에서 MPSE를 관리하는 구조를 그림으로 표현한 것입니다. 


그림 2. Snort Port table structure


먼저 프로토콜(TCP/UDP/ICMP/IP)별로 출발지/목적지 포트에 대해 각각 65535 개의 만큼의 배열을 가지고 있습니다. 각 배열에는 시그니처를 읽어 들이면서 MPSE가 생성 될 때 마다 해당 포트에 링크를 달아둡니다. 예를 들어 목적지 80 포트에 대해 탐지하는 시그니처가 있으면 MPSE를 생성 한 후 배열의 80번째 값에 달아 주는 식입니다. 

그렇다면 출발지/목적지 포트에 모두 특정 포트 값이 지정 되어 있다면 어떻게 할까요?
이런 경우 출발지/목적지 포트 그룹에 모두 추가해 주게 됩니다. 
둘 중 한 곳에만 해줘도 문제가 없을것 같은데.. 스노트는 왜 두 군데 모두 추가하는지 이해가 되지 않네요. 혹시 아시는분 계시면 댓글 남겨주세요~ ^^ 



여기까지 하면서 뭔가 빠진게 있는것 같다라는 생각이 들지 않나요? 


바로, 출발지/목적지 포트가 모두 'any'인 경우가 남았네요. 

출발지/목적지가 모두 'any'라면 Generic이라는 포트 그룹을 별도로 하나 더 두고 여기에 포함시킵니다. 말 그대로 특정 포트가 아닌 일반적이고 포괄적인 녀석들을 묶어 두는 겁니다. 



그림 3. Snort Generic Port table structure


당연히 포트 값 별로 MPSE를 관리할 필요는 없지만 대신 any-any 시그니처가 많아지면 MPSE의 크기가 많이 커지게 될 수 밖에 없습니다. 그렇기 때문에 가능하면 시그니처에 포트 정보를 넣어주는게 좋습니다. 



참고로, 시그니처에 패턴(content, uricontent)이 없다면 nc룰(no-content) 이라고 부르며 패턴이 없기 때문에 당연히 MPSE를 만드는 것도 불가능해집니다. 이런 시그니처들은 한 데 모아서 순차적으로 검사하도록 합니다. 



지금까지의 내용을 정리해보면 스노트는 시그니처를 아래와 같은 구조로 관리하게 됩니다. 


alert TCP any any -> 192.168.123.0/24 80 (msg:"GET KT"; content:"GET"; content:"KT"; sid:1)

alert TCP 20.20.20.0/24  5424  -> any 80 (msg:"GET OP"; content:"GET"; content:"OP"; sid:2)

alert TCP any any -> 132.42.10.0/24 80 (msg:"GET HT"; content:"GET"; content:"HT"; sid:3)





그림 3. Snort Rule Table structure


결과적으로 프로토콜이 일치하는 경우 포트 중 하나(출발지/목적지)가 일치 되면 패턴 매칭을 시도하게 되는 구조입니다. 

※ OTN과 RTN이 트리(tree)구조로 매달려 있는 것은 나중에 따로 포스팅 하겠습니다. 



OTN은 MPSE로 부터의 연결 점이 되는 root OTN이 하나 존재하고,

 패턴과 같이 시그니처의 옵션 정보를 가지고 있는 child OTN이 여러개 나올 수 있으며, 

시그니처 옵션의 마지막 정보이자 sid 와 RTN정보를 모두 포함하고 있는 leaf OTN 노드가 존재하게 됩니다. 



이제 어떤 구조로 시그니처를 관리하며 어떤 순서로 공격 패킷을 탐지 하는지 대충 감이 오시나요? 


Posted by KT한
,

그림 1. SURICATA 로고 


Suricata(수리카타)는 Open source기반의 IDS(Intrusion detection system)입니다. 사실 Open source 기반의 IDS/IPS라고 하면 Snort(스노트)가 대표적입니다. 거의 독보적이라고 할 정도로 오랜 시간 입지를 굳혀오고 있었지요. 오픈 소스의 특성상 많은 사람들이 사용하고 피드백을 주게 되면 그 만큼 오류 수정 및 기능 추가에 용의하게 됩니다. Snort는 오랜 시간 전 세계 많은 사용자의 도움으로 다양한 공격을 좀 더 정확하게 탐지하는 방법에 중점을 두고 발전을 해왔다고 봅니다. 


문제는, 그 사이 인터넷 세상은 집집마다 광 케이블을 통한 초고속 인터넷이 설치 되는가 하면 스마트폰 보급이 빠른 속도로 진행되면서 급속도로 팽창하게 됩니다. 그 결과 트래픽 양이 급격히 증가하면서 대용량 트래픽의 실시간 처리에 대한 이슈가 부각되게 됩니다. Snort는 구조상 단일 스레드(Single-thread)만 지원 하다 보니 처리 대용량 트래픽을 실시간으로 처리하기에 버거운 환경이 된 겁니다. 


Suricata는 Snort의 단점은 개선하면서 장점은 그대로 수용하여 이상적인 IDS/IPS를 개발하는 것이 기본적인 목표인것 같습니다. 아래는 Suricata의 주요 장점이라고 할 수 있는 내용입니다. 


1. 멀티 코어(Multicore)/멀티 스레드 (Multi-threading) 완벽 지원 (snort는 지원 불가. snort-3.0에서 시도 했으나 포기함.)

2. Snort 룰 완벽 호환 ( 기존 시스템에서 사용중인 snort 시그니처를 그대로 사용 할 수 있음.)

3. 하드웨어 밴더의 개발 지원으로 하드웨어 가속 지원. (GPU 가속)

4. 스크립터 언어(lua)로 시그니처 작성 가능 (snort 룰 포맷을 몰라도 시그니처 작성이 가능함.)

5. Snort의 대부분의 기능 모두 지원 



그림 2. suricata work flow


Suricata는 OISF(Open Information Security Foundation)에서 개발 한 것으로, 2009년 12월에 베타 버전이 나온 이후로.. 2012년 10월에는 Fedora 17버전에 포함되면서 엄청나게 빠른 속도로 기반을 잡아가고 있습니다. 

이제는 Fedora에서 '# yum install suricata'라는 명령 하나만으로 Suricata를 설치/사용 할 수 있는 환경이 된 것이죠. 


이처럼 급격한 성장은 OISF라는 단체에 대해 알고 나면 금방 이해가 될 겁니다.  

OISF는 미국의 해군 우주해양전쟁시스템센터(SPAWAR-Navy's Space and Naval Warfare Systems Command)국토안보부의 과학기술국 (Department of Homeland Security's Directorate for Science and Technology)오픈 보안기술(HOST-Homeland Open Security Technology) 프로그램의 일환으로 창립 되었습니다. 


그림 3. OISF 로고


이 재단의 목표는, 미국 정부 기관의 전반적인 보안 및 인터넷 보안을 위해 사용할 새로운 보안 시스템을 개발 하는 것입니다. 오픈 프로젝트여서 결과물에 대해서 사용자나 기관에서 사용 할 수 있도록 공개도 해줍니다. 


우리나라는 강 바닥 파는데 투자할 때 미국은 보안 소프트웨어에 대대적인 투자를 시작한것이죠. 이게 시각의 차이인가 싶네요. 


어쨌든, 미국의 국토안보부에서 재정 지원을 하는 만큼 재정적으로 부족함이 없을것 같네요. 


아래는 OISF의 파트너사 입니다. 


그림 4. OISF Partners


미국 처럼 큰 나라의 정부가 주관하는 프로젝트여서 그런지 많이 들어본 친숙한 회사들이 여럿 있습니다. 


어찌 보면 이제 시작인지도 모릅니다. 시간이 지나면서 점점 참여 업체가 많아지고.. 실제로 사용할 만한 수준이 되고 나면 급속도로 snort가 차지하고 있던 시장을 대체해 버릴지도 모르겠네요. 따지고 보면 snort는 한 업체의 제품이고 suricata는 미국의 범 정부 차원의 프로젝트 결과물이니 당연한 것인지도 모르겠네요. 


어쨌든, 한국 IPS시장도 현재는 Snort 일색인데.. 머지않은 미래에 큰 변화가 생길지도 모르겠네요. 


아래는 관련 사이트 링크 


Posted by KT한
,

모든 IPS(IDS)는 패킷에서 특정 패턴을 찾는 기능을 기본으로 합니다. 


스노트는 'content' 라는 이름을 사용하고 있습니다. 

이 옵션을 사용하면 패킷의 페이로드 전 부분에 대해 패턴을 찾게 됩니다. 

페이로드라 함은 아래의 그림에서 빨간색 박스로 표시해둔 부분을 말합니다. 


스노트 옵션 중 가장 기본이 되는 패턴을 지정하는 'content'옵션에 대해 알아봅시다. 


  • 기본 사용법
  1. content라는 키워드를 쓰고,                                                                  content
  2. 콜론(:)을 붙여 시작을 알립니다.                                                           content:
  3. 따옴표(")로 패턴이 시작됨을 지정하고,                                                content:"
  4. 탐지하고자 하는 패턴을 입력 합니다.                                                   content:"pat
  5. 따옴표(")를 한 번 더 붙여서 패턴이 끝남을 지정합니다.                     content:"pat"
  6. content가 끝났음을 세미콜론(;)을 붙여 명시합니다.                          content:"pat";


  • 옵션
  1. !     입력한 패턴이 매칭되지 않는지 검사 
  2. |     hex값을 표현할 때 사용
  3. \    특수 기호 escape 처리 할 때 사용


  • 사용 예
  1. content:"pattern";                       단순 패턴 
  2. content:"|20|hex|20 28|";         패턴 + Hex값
  3. content:"\"pattern\|";                 사용 불가한 패턴을 escape처리
  4. content:!"negate";                      패킷에 negate 패턴이 없는지 검사


  • 주의사항

다음 세 가지는 escape처리를 하지 않으면 사용 불가능한 기호입니다. 

;  \  "



  • 함께 사용하는 옵션들

순번 

옵션  

설명 

 1

nocase 

 대/소문자 구분 하지 않음

 2

rawbytes 

 decode하지 않은 raw data와 매칭 시도

 3

depth 

 payload에서 패턴 매칭을 할 끝 위치 지정

 4

offset 

 payload에서 패턴 매칭을 할 시작 위치 지정

 5

distance 

 이전 content에 매칭된 경우, 패턴 매칭을 시작할 상대 위치 지정

 6

within 

 이전 content에 매칭된 경우, 패턴 매칭을 끝 낼 상대 위치 지정  

 7

http_client_body 

 HTTP body 부분에 대해 패턴 매칭 시도

 8

http_cookie 

 HTTP cookie 부분에 대해 패턴 매칭 시도

 9

http_raw_cookie 

 HTTP cookie를 decode하지 않은 부분에 대해 패턴 매칭 시도

 10

http_header 

 HTTP header  부분에 대해 패턴 매칭 시도

 11

http_raw_header

 HTTP header를  decode하지 않은 부분에 대해 패턴 매칭 시도

 12

http_method 

 HTTP method  부분에 대해 패턴 매칭 시도

 13

http_uri 

 HTTP uri  부분에 대해 패턴 매칭 시도

 14

http_raw_uri 

 HTTP uri를  decode하지 않은 부분에 대해 패턴 매칭 시도

 15

http_stat_code 

 HTTP response 패킷의 stat code 부분에 대해 패턴 매칭 시도

 16

http_stat_msg 

 HTTP response 패킷의 stat msg 부분에 대해 패턴 매칭 시도

 17

fast_pattern 

 longest pattern 지정 - keyword처럼 동작함. 

※ HTTP 관련 옵션 참고 글


  • offset/depth/distance/within 동작 원리 

페이로드에서 패턴을 찾고자 하는 위치를 지정해 주는 이 옵션들을 사용하는 주된 이유는 오탐을 줄이기 위해서 입니다. 

더불어, 엔진 내부적으로는 성능 향상을 위해서도 중요한 역할을 합니다. 

페이로드 전체에 대해서 패턴 매칭을 시도하는 것보다 페이로드 일부분에 대해서 패턴 매칭을 시도하는데 걸리는 시간이 짧은건 당연할테니까요. 

아래의 테이블에 시그니처를 작성 했을 때 실제 패턴 매칭에 사용되는 버퍼를 케이스 별로 정리해 두었습니다. 

가장 이상적인 것은 패턴 매칭에 사용되는 버퍼의 크기와 시그니처에 작성된 패턴의 크기가 같은 경우겠죠? 


예) 패킷 페이로드 : 1234567890abcdefghijklmn

 순번

시그니처 

 패턴 매칭 버퍼 

 1

 content:"def";   1234567890abcdefghijklmn

 2

 content:"234"; offset:1; depth:5;  23456  

 3

 content:"123"; depth:3; content:"abc"; distance:5; within:8;   90abcdef

 4

  content:"abc"; distance:5; within:8;

 67890abc


  • 알아두면 뼈가되고 살이되는 정보 

fast_pattern 옵션을 얼마나 잘 활용하는가에 따라 초보자와 숙련가를 구분 할 수 있다고 해도 과언이 아닙니다. 

이 옵션을 사용하지 않아도 동일한 유해 패킷을 탐지 할 수 있기 때문입니다. 

그런데 궂이 왜 이런 옵션을 만들어둔 것일까요? 


fast_pattern은 특정 패턴을 longest pattern으로 지정한다고 했는데요.

기본적으로 스노트는 content에 입력한 패턴 중 길이가 가장 긴 녀석을 longest pattern이라고 부르고, 이런 패턴들을 모아서 Aho-Corasick 알고리즘에 의해 빠르게 검사해야할 시그니처를 걸러냅니다. (보통은 패턴의 길이가 길면 다른 패턴과 중복되지 않고 Unique한 경우가 많기 때문에 스노트에서는 가장 긴 패턴을 골라서 검사해야할 시그니처를 걸러내는 목적으로 사용하고 있는것같습니다. )

이 과정에서 얼마나 많은 시그니처를 걸러내느냐는 얼마나 빨리 공격을 탐지하는가와 직결되는 문제입니다. 

간혹 패턴의 길이는 짧지만 매우 Unique한 패턴이 있다면 이 패턴을 Keyword로 설정해서 Aho-Corasick알고리즘에 의한 필터링에 사용하는게 더 유리하겠죠? 

이것을 가능하게 해주는 옵션이 fast_pattern인 것입니다. 


※ fast_pattern은 부가적인 옵션과 함께 사용가능한데요.. 그 내용들도 알아두면 좀 더 완성도 높은 시그니처를 작성 할 수 있을겁니다. 


  • 몰라도 무관한 재미난 사실 

content에 입력한 값은 Hex값으로 입력 하더라도 문자로 표현할 수 있는 범위(0x20~0x7E)의 값이라면 문자로 변환해서 저장하고 있으며,  그 외의 값은 모두 Hex값으로 저장하고 있게 됩니다. 

이렇게 함으로써 Hex값에 대해서 nocase 옵션을 붙여주게 되면, 그 값이 문자열일 경우 대소문자를 구분하지 않고 탐지가 가능합니다. 

예) content:"|61 62 63|"; nocase;

'abc', 'Abc', 'ABC', 'aBc' 모두 탐지 가능 


단, 아래 4가지 값은 hex값으로 저장하고 있게 됩니다. 

 순번

 Hex값

기호 

 1

20 

'스페이스' 

 2

22 

 3

3B 

 4

7C 


찾는 내용이 없다면 [스노트/Snort] 카테고리의 다른 글을 참고해보세요~ ^^


Posted by KT한
,

Snort에는 여러가지 유용한 전처리기들이 존재합니다. 

그 중 HTTP inspection 모듈은 다양한 공격 패킷을 탐지하는데 매우 중요한 역할을 합니다. 

더불어 실시간으로  좀 더 정확하게 패킷을 검사하는데도 일조 하고 있죠. 



  • HTTPINSPECT PACKET FLOW 와 각 모듈별 역할 


1. Session Inspection Module

  - 'snort.conf' 파일에 정의해둔 http server port값과 비교해서 서버/클라이언트를 판단 

  - 또한, http inspect를 수행 할 지에 대한 판단도 함께 진행 

  - 현재는 Stateless 모드만 지원한다. (Stateful로 수행하기에는 좀 버거울 지도..)


2. HTTP Inspection Module

  - method/header/body/cookie등 HTTP패킷을 파트별로 분류하는 작업 수행 

  - pipeline request 패킷에 대한 처리도 함께 수행 함


3. HTTP Normalization Module

  - HTTP패킷에 대한 정규화작업을 수행  (하단 설명 참고)

  - 별도의 버퍼에 HTTP패킷을 파트별로 구분해둔 값을 설정 


4. HTTP Detection Module

  - 시그니처와 패턴 매칭 수행 

  - 위에서 설정한 별도의 버퍼에 대해서 탐지를 수행


5. HTTP Event Output Module

  - 매칭된 결과에 대한 출력 




  • 정규화(Normalization) 작업의 허와 실 


정규화는 인코딩된 URL값을 디코딩 하는 작업을 말합니다. 


인코딩은 흔히 다음과 같이 이루어 지게되죠. 


'&' -> %26 (hex값으로 26이 '&'이므로)



일반적으로 웹서버는 인코딩 된 값을 알아서 디코딩 해 주는데, 

중간에서 악성 패킷을 검사하는 보안 장비는 일반적으로 

장비 성능 이슈 때문에 디코딩을 완벽하게 수행하지는 않습니다. 


해커는 이 점을 악용해서 공격을 할때 인코딩을 한 패킷을 전송할 수도 있겠죠?


중간에 보안 장비가 있을 것을 대비해서 여러번 인코딩 한 패킷을 전송할 수도 있겠구요. 

아쉽게도 Snort(스노트)는 HTTP 패킷에 대해 최대 2번까지만 디코딩 작업을 수행합니다. 

다시 말하면 3번 인코딩한 패킷을 탐지 못한다는 뜻이됩니다. 



어쨌든, 

디코딩한 결과를 'uricontent'라는 옵션을 사용해서 시그니처를 작성 할 수 있습니다. 


기본적으로 uricontent는 http inspection모듈에 의해 normalization을 수행한 결과값을 가지고 있게되구요. 


일반적으로 uricontent는 HTTP 패킷의 uri 필드에  '%28' 과 같은 값을 '(' 와 같이 디코딩 하여 

uricontent:"("; 와 같이 시그니처를 작성 함으로써 인코딩 된 패킷을 탐지하는데 사용됩니다. 


만약, 

시그니처에 uricontent:"%33%34"와 같은 시그니처가 있다면 

실제 탐지하는 패킷은 %%%33%33%%%33%34 와 같은 패턴을 가지고 있겠죠.

 

무슨 말인지 어렵다구요? 

단계별로 알아보면.. 


%  %  %33 %33 % % %33 %34

%  % 3 3              % % 3 4                    - 1번째 디코딩

% 33                    % 34                         - 2번째 디코딩


물론, 한번 더 디코딩을 한다면 34가 됩니다.

 


주의사항:

HTTP패킷의 uri 필드에 '+' 가 있는경우,

snort에서는 '빈칸'으로 인식하고 Hex값 '20'으로 치환해버립니다. 


일반적으로 HTTP패킷의 body에서는 빈칸을 '+'로 표시하는데,

snort는 uri에 대해서도 동일하게 처리하고 있답니다. 


Posted by KT한
,
시작하면서..

스노트는 HTTP 패킷에 대해..
패킷 전체가 아닌 특정 필드값에서 패턴을 찾는 작업을 지원한다.
이는 오탐을 줄이는 동시에 성능을 향상시켜주는 효과가 있다.

스노트 사용에 어느정도 자신감이 생겼다면..
이 옵션을 사용하는 것을 강력히 추천한다.

기본적인 사용법은 메뉴얼을 보면 되겠지만
HTTP 패킷을 분석하는 일에 친숙하지 않은 사람들을 위해..
각 옵션들이 가리키는 필드에 대해 자세하게 알아보도록 하자.


추천은 저를 춤추게 합니다 ^^




먼저, HTTP관련 매칭 옵션들은 크게 다음 7가지가 있다.
이 옵션들은 'content'라는 패턴 매칭 옵션과 함께 사용해야 한다.

1. http_method
-HTTP 패킷의 method값을 저장하고 있다.
그러므로, 다른 옵션들과 비교해서 패킷의 가장 앞 부분을 가리킨다.

2. http_uri (http_raw_uri)
-HTTP 패킷의 uri값을 저장하고 있다.
'uricontent'옵션을 사용하는 것과 동일하다.
'raw'는 normalized(디코딩, 정규화)한 값과 하지 않은 값의 차이이다.   
(당연히 'raw'가 붙은것이 하지 않은 값이다.) 

참고로, 'http_uri'와 'rawbytes'옵션을 함께 사용하면 'http_raw_uri'와 동일하다고 생각하기 쉽지만..
이런 조합은 허용되지 않는다.

content + http_uri = uricontent (O)
content + http_uri + rawbytes  ≠ http_raw_uri  (X)
uricontent + rawbytes  ≠ http_raw_uri  (X)



 3. http_header (http_raw_header)
- HTTP 패킷의 header값을  저장하고 있다. 
request와 response에 모두 사용하는 옵션이다.
'raw'의 의미는 'http_raw_uri'와 동일하다.

4. http_cookie (http_raw_cookie)
- HTTP 패킷의 cookie값을  저장하고 있다. 
'raw'의 의미는 'http_raw_uri'와 동일하다.

5. http_client_body
- HTTP 패킷의 body값을  저장하고 있다. 
참고로, GET패킷에는 body가 없다. 
아래 예제에서 POST패킷에만 HTTP body를 가리키는 색이 칠해져 있는 이유이다. 


 사용전 확인사항 
snort.conf 파일에
'post_depth 0'을 반드시 지정해 주어야한다. (0은 body전체를 extract한다는 의미)
default 값이 -1인데 이는 body를 extract하지 않는 다는 의미이기 때문이다.
참고로, 이 값은 이전 버전의 snort와는 다를 수 있다. 

preprocessor http_inspect_server: server default \
    profile all ports { 80 8080 8180 } \
    post_depth 0 



6.
http_stat_code
- HTTP response의 status code 필드 값을  저장하고 있다.
코드 값에 대한 내용은 이 사이트를 참고하세요. 

※사용전 확인사항 
snort.conf 파일에
'extended_response_inspection'을 반드시 지정해 주어야한다 

preprocessor http_inspect_server: server default \
    profile all ports { 80 8080 8180 } \
    extended_response_inspection 


7. http_stat_msg
- HTTP response의 status message 필드값을  저장하고 있다. 
기본적인 설정 및 사용법은 'http_stat_code'와 동일하다. 


실제 패킷 예제를 통해 확실히 이해하자!
위에서 설명한 각 옵션들이 저장하고 있는 필드값을 각각에 맞는 색상으로 표시해 두었다. 


1. client request 패킷 (GET)

0000   47 45 54 20 2f 63 63 3f 61 3d 74 6f 70 2e 6c 6f  GET /cc?a=top.lo
0010   67 6f 26 72 3d 26 69 3d 37 38 30 30 30 43 30 31  go&r=&i=78000C01
0020   5f 30 30 30 30 30 30 30 37 32 31 46 37 26 6e 73  _0000000721F7&ns
0030   63 3d 6e 61 76 65 72 74 6f 70 2e 76 33 26 77 3d  c=navertop.v3&w=
0040   31 31 31 37 26 70 78 3d 33 32 38 26 70 79 3d 39  1117&px=328&py=9
0050   38 26 73 78 3d 33 32 38 26 73 79 3d 39 38 26 6d  8&sx=328&sy=98&m
0060   3d 31 26 75 3d 68 74 74 70 25 33 41 25 32 46 25  =1&u=http%3A%2F%
0070   32 46 77 77 77 2e 6e 61 76 65 72 2e 63 6f 6d 25  2Fwww.naver.com%
0080   32 46 20 48 54 54 50 2f 31 2e 31 0d 0a 48 6f 73  2F HTTP/1.1..Hos
0090   74 3a 20 63 63 2e 6e 61 76 65 72 2e 63 6f 6d 0d  t: cc.naver.com.
00a0   0a 43 6f 6e 6e 65 63 74 69 6f 6e 3a 20 6b 65 65  .Connection: kee
00b0   70 2d 61 6c 69 76 65 0d 0a 55 73 65 72 2d 41 67  p-alive..User-Ag
00c0   65 6e 74 3a 20 4d 6f 7a 69 6c 6c 61 2f 35 2e 30  ent: Mozilla/5.0
00d0   20 28 57 69 6e 64 6f 77 73 20 4e 54 20 36 2e 31   (Windows NT 6.1
00e0   29 20 41 70 70 6c 65 57 65 62 4b 69 74 2f 35 33  ) AppleWebKit/53
00f0   35 2e 37 20 28 4b 48 54 4d 4c 2c 20 6c 69 6b 65  5.7 (KHTML, like
0100   20 47 65 63 6b 6f 29 20 43 68 72 6f 6d 65 2f 31   Gecko) Chrome/1
0110   36 2e 30 2e 39 31 32 2e 37 37 20 53 61 66 61 72  6.0.912.77 Safar
0120   69 2f 35 33 35 2e 37 0d 0a 41 63 63 65 70 74 3a  i/535.7..Accept:
0130   20 74 65 78 74 2f 68 74 6d 6c 2c 61 70 70 6c 69   text/html,appli
0140   63 61 74 69 6f 6e 2f 78 68 74 6d 6c 2b 78 6d 6c  cation/xhtml+xml
0150   2c 61 70 70 6c 69 63 61 74 69 6f 6e 2f 78 6d 6c  ,application/xml
0160   3b 71 3d 30 2e 39 2c 2a 2f 2a 3b 71 3d 30 2e 38  ;q=0.9,*/*;q=0.8
0170   0d 0a 52 65 66 65 72 65 72 3a 20 68 74 74 70 3a  ..Referer: http:
0180   2f 2f 77 77 77 2e 6e 61 76 65 72 2e 63 6f 6d 2f  //www.naver.com/
0190   0d 0a 41 63 63 65 70 74 2d 45 6e 63 6f 64 69 6e  ..Accept-Encodin
01a0   67 3a 20 67 7a 69 70 2c 64 65 66 6c 61 74 65 2c  g: gzip,deflate,
01b0   73 64 63 68 0d 0a 41 63 63 65 70 74 2d 4c 61 6e  sdch..Accept-Lan
01c0   67 75 61 67 65 3a 20 65 6e 2d 55 53 2c 65 6e 3b  guage: en-US,en;
01d0   71 3d 30 2e 38 0d 0a 41 63 63 65 70 74 2d 43 68  q=0.8..Accept-Ch
01e0   61 72 73 65 74 3a 20 49 53 4f 2d 38 38 35 39 2d  arset: ISO-8859-
01f0   31 2c 75 74 66 2d 38 3b 71 3d 30 2e 37 2c 2a 3b  1,utf-8;q=0.7,*;
0200   71 3d 30 2e 33 0d 0a 43 6f 6f 6b 69 65 3a 20 4e  q=0.3..Cookie: N
0210   42 3d 47 49 33 44 43 4e 52 57 47 4d 33 54 41 4e  B=GI3DCNRWGM3TAN
0220   5a 52 3b 20 4e 4e 42 3d 5a 49 45 35 41 4a 35 4b  ZR; NNB=ZIE5AJ5K
0230   55 56 4f 55 34 3b 20 6e 70 69 63 3d 22 37 4d 58  UVOU4; npic="7MX
0240   49 78 4b 75 71 49 52 77 37 4f 69 47 61 53 2f 39  IxKuqIRw7OiGaS/9
0250   37 6e 6a 53 37 52 33 39 31 55 42 43 4e 49 63 2b  7njS7R391UBCNIc+
0260   2f 67 42 71 68 31 47 63 32 48 68 58 73 66 4e 65  /gBqh1Gc2HhXsfNe
0270   42 63 78 35 54 67 45 66 63 71 36 71 6b 43 41 3d  Bcx5TgEfcq6qkCA=
0280   3d 22 3b 20 6e 73 72 5f 61 63 6c 3d 31 3b 20 44  ="; nsr_acl=1; D
0290   41 5f 48 43 3d 4c 5a 31 31 36 38 30 35 38 30 2c  A_HC=LZ11680580,
02a0   4c 41 0d 0a 0d 0a                                LA....




2. Client Request 패킷 (POST)

0000   50 4f 53 54 20 2f 65 6e 67 69 6e 65 5f 70 72 6f  POST /engine_pro

0010   63 6f 6e 2e 6a 73 70 3f 70 72 6f 6d 6f 74 69 6f  con.jsp?promotio

0020   6e 33 20 48 54 54 50 2f 31 2e 31 0d 0a 52 65 66  n3 HTTP/1.1..Ref

0030   65 72 65 72 3a 20 2f 65 6e 67 69 6e 65 5f 70 72  erer: /engine_pr

0040   6f 63 6f 6e 2e 6a 73 70 3f 70 72 6f 6d 6f 74 69  ocon.jsp?promoti

0050   6f 6e 33 0d 0a 41 63 63 65 70 74 3a 20 74 65 78  on3..Accept: tex

0060   74 2f 2a 0d 0a 43 6f 6e 74 65 6e 74 2d 54 79 70  t/*..Content-Typ

0070   65 3a 20 61 70 70 6c 69 63 61 74 69 6f 6e 2f 78  e: application/x

0080   2d 77 77 77 2d 66 6f 72 6d 2d 75 72 6c 65 6e 63  -www-form-urlenc

0090   6f 64 65 64 0d 0a 55 73 65 72 2d 41 67 65 6e 74  oded..User-Agent

00a0   3a 20 4d 65 6c 4f 6e 20 50 6c 61 79 65 72 20 56  : MelOn Player V

00b0   33 2e 30 0d 0a 48 6f 73 74 3a 20 61 70 70 73 76  3.0..Host: appsv

00c0   72 2e 6d 65 6c 6f 6e 2e 63 6f 6d 0d 0a 43 6f 6e  r.melon.com..Con

00d0   74 65 6e 74 2d 4c 65 6e 67 74 68 3a 20 33 32 0d  tent-Length: 32.

00e0   0a 43 61 63 68 65 2d 43 6f 6e 74 72 6f 6c 3a 20  .Cache-Control:

00f0   6e 6f 2d 63 61 63 68 65 0d 0a 43 6f 6f 6b 69 65  no-cache..Cookie

0100   3a 20 57 4d 4f 4e 49 44 3d 56 32 64 2d 67 7a 36  : WMONID=V2d-gz6

0110   4e 31 47 2d 3b 20 4a 53 45 53 53 49 4f 4e 49 44  N1G-; JSESSIONID

0120   3d 4d 47 71 51 50 37 7a 30 70 34 79 33 35 59 78  =MGqQP7z0p4y35Yx

0130   4e 32 7a 4a 59 63 56 64 71 6b 59 37 4e 33 34 6e  N2zJYcVdqkY7N34n

0140   38 6e 54 76 59 36 34 58 4c 4a 53 54 47 58 76 58  8nTvY64XLJSTGXvX

0150   71 79 7a 78 4b 21 34 30 39 33 32 32 33 32 34 3b  qyzxK!409322324;

0160   20 58 54 56 49 44 3d 31 30 30 37 32 31 31 37 30   XTVID=100721170

0170   34 31 36 35 35 39 37 39 34 33 39 3b 20 58 54 4c  41655979439; XTL

0180   49 44 3d 31 36 37 33 34 31 33 30 0d 0a 0d 0a 74  ID=16734130....t

0190   72 65 65 70 6f 6c 65 0b 31 36 37 33 34 31 33 30  reepole.16734130

01a0   2a 31 32 37 39 36 39 39 34 35 36 35 35 36 0b     *1279699456556.

 

3. Server Response 패킷 
 

주의할 점은 header의 시작 지점이 status 메시지 직후에 오는 hex값 '0d 0a'를 포함한다는 것이다.
offset, depth와 같은 옵션을 함께 사용할꺼라면 반드시 기억해야 한다.

0000   48 54 54 50 2f 31 2e 31 20 32 30 30 20 4f 4b 0d  HTTP/1.1 200 OK.

0010   0a 44 61 74 65 3a 20 57 65 64 2c 20 32 31 20 4a  .Date: Wed, 21 J

0020   75 6c 20 32 30 31 30 20 30 38 3a 30 33 3a 35 33  ul 2010 08:03:53

0030   20 47 4d 54 0d 0a 53 65 72 76 65 72 3a 20 41 70   GMT..Server: Ap

0040   61 63 68 65 0d 0a 4c 61 73 74 2d 4d 6f 64 69 66  ache..Last-Modif

0050   69 65 64 3a 20 4d 6f 6e 2c 20 31 39 20 4a 75 6c  ied: Mon, 19 Jul

0060   20 32 30 31 30 20 31 31 3a 33 33 3a 32 35 20 47   2010 11:33:25 G

0070   4d 54 0d 0a 45 54 61 67 3a 20 22 31 34 38 61 63  MT..ETag: "148ac

0080   30 2d 64 32 2d 34 38 62 62 62 65 66 63 61 34 62  0-d2-48bbbefca4b

0090   34 30 22 0d 0a 41 63 63 65 70 74 2d 52 61 6e 67  40"..Accept-Rang

00a0   65 73 3a 20 62 79 74 65 73 0d 0a 43 6f 6e 74 65  es: bytes..Conte

00b0   6e 74 2d 4c 65 6e 67 74 68 3a 20 32 31 30 0d 0a  nt-Length: 210..

00c0   43 6f 6e 74 65 6e 74 2d 54 79 70 65 3a 20 74 65  Content-Type: te

00d0   78 74 2f 70 6c 61 69 6e 0d 0a 0d 0a              xt/plain....


Posted by KT한
,
스노트에서 고급 옵션이라고 볼 수 있는...
byte 관련 keyword에 대해 알아봅시다.

※ 이 글은 snort-2.9.1 버전을 기준으로 작성되었습니다. 

먼저, 이런 옵션들을 언제 왜 사용할까요?
일반적인 패킷에서 특정 패턴을 비교하는 것 만으로는 탐지 할 수 없는게 존재합니다. 

예를 들면, RPC 와 같은 프로토콜의 패킷을 처리할 때 요긴합니다. 
이런 패킷은 특정 위치에 버전, 타입과 같은 값을 넘겨 주기 때문에... 
그 특정 위치가 어딘지만 안다면 정확한 검증이 가능합니다. 

1. byte_test
특정 위치의 값을 비교/확인 하는데 사용. 

① 기본 포맷 
 

byte_test:<변환할 bytes>, [!]<연산자>, <비교할 값>, <offset> [, relative][, <endian>][, string, <숫자 형식>][, dce];


시작 위치부터 4개의 값(offset까지)은 필수 항목이다. 
순서 또한 고정되어 있으므로 위치를 헷갈리지 않도록 주의 해야한다.


② 옵션 항목 설명 
 
변환할 bytes: 몇 바이트의 패킷을 변환할지 지정
연산자: 변환한 값과 비교할 값을 비교할 때 사용할 연산자 
비교할 값: 변환된 값과 비교할 값
offset: 페이로드에서 변환할 바이트만큼 선택 할 시작위치 
relative: 마지막 패턴 매칭이 성공한 위치를 시작위치로 지정
즉, content와 같은 옵션과 같이 사용 할 경우, 패턴 매칭에 성공한 위치를 offset의 시작위치로 설정 

endian: 변환할 바이트 값의 endian 정보를 지정

▷참고: big endian 컴퓨터에서는 16진수 "4F52"를 저장공간에 "4F52"라고 저장 (만약 4F가 1000번지에 저장되었다면, 52는 1001번지에 저장될 것이다). 반면에, little endian 시스템에서 이것은 "524F"와 같이 저장.


string: 패킷에 문자열 포맷으로 되어있다고 지정
 

▷이는 글로 설명하기 쉽지 않으니 아래 예제를 참고하자. 

숫자 형식: 'string'와 함께 사용하며, 
문자열 포맷의 데이터의 숫자 형식을 지정 

dce: DCE/RPC preprocessor와 관련된 옵션으로 숫자의 endian을 결정하기 위해 사용. 
DEC/RPC preprocessor를 수행한 결과 endian이 무엇인지 알고있다. 


③ 옵션 유효값 
 
bytes : 1 ~ 10
연산자 : 부등호( <, =, >)  또는 bitwise값 (&, ^)
비교할 값 : 0 ~ 4294967295
offset : -65535 ~ 65535

endian : big 또는 little
숫자 형식 : hex, dec, oct


 예제 

만약 패킷이 다음과 같다고 하면..


00 00 00 00 00 00 00 06 73 79 73 74 65 6d 33 00 ........system3.



이 패킷을 탐지하는 시그니처는 다음처럼 작성 할 수 있다. 

⑴ byte_test: 1, =, 3, 14, string ; 
- 패킷의 14번째에 있는 1바이트 값이 3과 같은지 비교. 
   위 패킷에서 14번째 바이트는 33이다.
   ('6d'가 아님을 기억하세요!!  offset이 '0'이면 맨 처음 값을 사용한다!) 
  이 값을 10진수 string으로 처리한다고 했으니.. 결국 비교할 값은 '3'이 된다. 
 

⑵ byte_test: 1, =, 51, 14 , dec; 
- 패킷의 14번째에 있는 1바이트 값이 51과 같은지 비교
  33은 10진수로 51이므로.. 결국 비교할 값은 '51'이 된다.  
 

⑶ content:"system"; byte_test: 1, =, 51, 0, relative, dec ; 
- 'system'이라는 문자열을 찾고... 
   매칭이 이루어진 곳에서 0만큼 떨어진 곳의 1바이트 값이 51인지 비교한다. 
   relative 옵션을 썼다는것 빼고는 위의 예제와 동일하므로.. 이해하기 그리 어렵지 않다. 
   
 
⑷ content:"system"; byte_test: 1, =, 0x03, 0, relative, string, hex; 
- 위의 예제들을 모두 이해했다면.. 길기만 하지 별로 복잡하지 않다는 것을 알것이다. 
   다만 값을 string으로 처리해서 hex값으로 비교한다. 

 byte_test:1, &, 16, 14; 
- 패킷의 14번째에 있는 1바이트 값과 16을 비트 AND 연산을 한다.
   14번째 바이트 값(hex값 33)과 16을 2진수로 전환해서 비트 연산을 해보면.. 

   00 11 00 11 (16진수 33)
   00 01 00 00 (10진수 16)
& -----------------
   00 01 00 00   => 16 

  이와 같은 연산에 의해서 이 시그니처는 탐지가 된다. 


2. byte_jump
특정 위치의 값 만큼 탐지(매칭) 포인터를 이동/점프 하고자 할때 사용. 

① 기본 포맷 

 

byte_jump:<변환할 bytes>, <offset>
[, relative][, multiplier <mult_value>][, <endian>][, string, <숫자 형식>][, align][, from_beginning][, post_offset <adjustment value>][, dce];


시작 위치부터 2개의 값(offset까지)은 필수
 항목이다. 

순서 또한 고정되어 있으므로 위치를 헷갈리지 않도록 주의 해야한다.
 
 
② 옵션 항목 설명 

변환할 bytes: 몇 바이트의 패킷을 변환할지 지정
offset: 페이로드에서 변환할 바이트만큼 선택 할 시작위치 
relative마지막 패턴 매칭이 성공한 위치를 시작위치로 지정
multiplier <값>:  변환할 bytes 값에 곱해서 그 값만큼 jump하고자 할 때 사용
endian: 변환할 바이트 값의 endian 정보를 지정
string: 패킷에 문자열 포맷으로 되어있다고 지정
align: 변환할 bytes값을 32bit(4바이트) 단위로 반올림해서 처리  
RPC와 같은 트래픽은 32bit 단위로 사용되므로.. 이런 트래픽을 처리할 때 용의

예) jump할 bytes값이 9bytes로 나왔을 경우,
32bit 단위로 반올림하게 되면 12bytes가 된다. 
align 옵션을 사용했다면.. 비록 결과는 9였지만, 12bytes 만큼 jump하게 된다.

from_beginning: 현재 위치에서가 아닌 패킷의 시작 위치에서 jump
 값을 계산하는 것과 별개로 jump할 때만 사용됨 

post_offset <값>:  jump한 이후에 다음 매칭을 시도할 위치를 여기서 설정한 값 만큼 이동.
소스를 보신 분들이라면..
doe_ptr (
detection offset pointer)에 여기서 설정한 값을 더해준다고 하면 이해가 더 쉬울겁니다.

예) 다음 두 시그니처는 동일한 동작을 수행한다.  
1) content:"MM"; byte_jump:3,0,relative, post_offset 2; content:"AA";distance:0;
2) content:"MM"; byte_jump:3,0,relative; content:"AA"; distance:2;
 
dce: DCE/RPC preprocessor와 관련된 옵션으로 숫자의 endian을 결정하기 위해 사용. 
 

③ 옵션 유효값 
bytes : 1 ~ 10
offset : -65535 ~ 65535
mult_value : 0 ~ 65535
post_offset : -65535 ~ 65535
 

 예제 
 
 
⑴ content:"|00 00 00 01|"; byte_jump:4, 12, relative, align;
- 패턴 매칭이 이루어진 값 부터 12번째 부터 15번째(12번째 부터 4개) 까지의 bytes값 만큼 jump
만약 값이 4의 배수가 아니라면 반올림해서 그 값만큼 jump 
 
 

2. byte_extract 
특정 위치의 값을 변수로 저장.
값을 저장한 변수는 다음 옵션들에서 사용 가능.

ⓐ content/uricontent의 offset,depth,distance,within 값
ⓑ byte_test의 offset,value 값
ⓒ byte_jump의 offset 값
ⓓ  isdataat의 offset 값

① 기본 포맷 

byte_extract:<bytes_to_extract>, <offset>, <name> [, relative][, multiplier <multiplier value>][, <endian>][, string, <숫자 형식>][, align <align value>][, dce]


시작 위치부터 3개의 값(name까지)은 필수
 항목이다. 

순서 또한 고정되어 있으므로 위치를 헷갈리지 않도록 주의 해야한다.

② 옵션 항목 설명
(byte_test나 byte_jump에서 동일하게 사용되는 옵션 생략)

name:
발췌한 값을 저장한 변수 명
align <값>:  발췌한 값을 특정 bytes 단위로 반올림 하고자 할 때 사용. 


③ 옵션 유효값 
 
bytes : 1 ~ 10
offset : -65535 ~ 65535
mult_value : 0 ~ 65535
 
 
 예제 

 ⑴ byte_extract:1, 0, str_offset; content:"bad stuff"; offset:str_offset;
-  패킷의 시작위치에서 1바이트에 있는 값 만큼 떨어진 곳에서 "bad stuff" 문자열을 찾는다. 
 

Posted by KT한
,
  • Snort-2.9.1 버전에 대해..
대표적인 IDS/IPS 오픈소스인 스노트가 2.9.xx 버전이 나온지도 한참 지났네요.
2.8.xx 버전과 비교해서 많은 기능이 추가되었고, 수 많은 버그 또한 수정 되었지요. 
(물론, 모든 버그가 수정된건 아니겠지만..)

어쨌든.. 
지속적으로 추가되는 기능들 때문에.. 
처음 접하는 사람들에게는 조금 부담 스러울 수도 있을 정도로 복잡해져 가는것 같습니다. 

설치 과정부터 사용법까지 차근차근 포스팅 해보려고 합니다. 


혹시 몰라 페도라 17에 snort 설치 하는 법에 대한 영문 매뉴얼을 첨부했으니 필요하신분은 참고하세요.
  • 설치 과정
먼저, 사전에 설치 해야할 rpm 들이 있습니다. 'rpm.pbone.net' 혹은 구글링을 통해 다운 받아둡니다. 
'# rpm -i <패키지 이름>' 으로 설치 합니다. 
libpcap
libpcap-devel
pcre
pcre-devel
libdnet
libdnet-devel 


1.  daq 다운 

우선 아래 홈페이지에 접속해서 snort와 필수 유틸인 daq를 다운 받아야 합니다. 


스노트(snort) 공식 홈페이지 

rpm을 받으셔도 되고 tar로 묶인 소스 파일을 받으셔도 됩니다.


2. daq를 설치


1) tar파일을 받으셨다면..
압축을 풀어주시고..
README 파일에 나와있는 설치 순서에 따라 실행해주면 됩니다. 


   # ./configure

   # make

   # sudo make install


2) rpm을 받으셨다면 rpm명령으로 설치하시면 됩니다. 

# rpm -ivh daq-*.rpm 

이 과정에서 libpcap(버전 1.0.0 이상) 이나 
다른 필요 항목들이 설치되어 있는지 확인하는 과정을 거치게 됩니다.  

daq는 패킷을 처리하기 위한 필수 유틸로
이를 설치하지 않으면 snort가 정상적으로 설치되지 않습니다. 

(2.8.xx 버전에는 없었으나.. 2.9.xx에서 추가된 기능 같더군요. )


3. snort 설치


snort 홈페이지에서 tar확장자로 압축된 snort 파일을 다운 받아 압축을 풀고..
 
snort-2.9.1/doc/INSTALL 파일에 나와있는 설치 순서에 따라 실행해주면 됩니다.


1) 이전 버전의 snort가 설치되어 있다면.. 이를 제거해줘야 겠죠?

# sudo make uninstall


2) 필수 유틸들이 정상적으로 설치되어 있는지 확인합니다. 

libdnet, libpcap, libpcre 가 확인해야할 유틸들입니다. 

또한, 'which' 명령어를 써서 dnet-config, pcre-config, daq-modules-config 가 존재 하는지 확인합니다. 


예) # which daq-modules-config

/usr/local/bin/daq-modules-config


만약, 위의 것들중 없거나 설치되지 않은게 있다면 먼저 설치해 주어야 합니다. 


3) 설치를 시작합니다. 

snort 폴더에 있는 configure 를 실행합니다. 

만약 설정을 바꾸고 싶은게 있다면 '-h' 명령어로 세부 내용을 확인 후 설정값을 넣어주면 됩니다. 


예)

 # ./configure --enable-active-response --enable-reload --enable-react


4)  설치를 진행합니다. 

# make && sudo make install


5) 정상적으로 설치 되었는지 확인 후 실행하시면 됩니다. 

실행파일은 'src/snort' 파일로 생성되며,

'make install' 후에는 '/usr/local/bin/snort' 에도 들어가게 됩니다. 

※ bin 폴더에 넣어줌으로써 어떤 경로에서든 snort를 자유롭게 실행할 수 있게 되는 겁니다. 


daq가 정상적으로 설치 되었는지 확인 해보는 작업을 예로 들어보겠습니다. 


예) 

# snort --daq-list


Available DAQ modules:

pcap(v3): readback live multi unpriv 

ipq(v5): live inline multi 

ipfw(v2): live inline multi unpriv 

dump(v1): readback live inline multi unpriv 

afpacket(v4): live inline multi unpriv


만약 DAQ 모듈에 대한 정보가 정상적으로 출력되지 않는다면.. 

설치 과정에서 DAQ가 정상적으로 설치되지 않은 것입니다. 


6) 설정 적용 및 시그니처 파일 설정

기본적으로 '/etc/snort/snort.conf' 파일에서 원하는 설정 정보를 수정 및 적용 가능합니다. 

또한, '/etc/snort/rules/' 폴더에서 'rules'라는 확장자를 가진 파일에서는 시그니처를 설정 및 적용 할 수 있습니다. 


아래와 같이 설정 파일(snort.conf)에 시그니처 파일의 경로를 지정하면 해당 시그니처 파일의 경로를 찾아서 시그니처를 로드하게 됩니다. 

'/etc/'snort/rules'폴더를 변수로 설정 하고, 해당 경로의 'my.rules'를 include 함으로써 snort가 해당 시그니처 파일을 읽도록 설정해주는 내용입니다. 

var RULE_PATH /etc/snort/rules 

include $RULE_PATH/my.ruels 


7) 실행 옵션 지정

실행에 필요한 옵션 정보는 다음과 같이 조회가 가능합니다. 


# snort -?


'-D' 옵션은 데몬모드로 실행하도록 하는 옵션입니다. 

이런 내용은 위 명령어를 쓰면 모두 조회가 가능합니다. 



4. snort 사용 및 검증

우선 '-D'옵션을 사용해서 데몬 모드로 실행합니다. 


# snort -D -Q --daq afpacket -i eth1:eth2 --daq-var buffer_size_mb=64 -c /etc/snort/snort.conf 


시그니처가 정상적으로 탐지되고 있는지 확인하기 위해 snort에서 생성하는 alert 파일을 열어봅니다. 

# tail -f /var/log/snort/alert
  
[**] [1:225:7] test [**]
[Priority: 0]
11/04-17:36:58.370718 192.168.11.101:445 -> 192.168.9.148:49220
TCP TTL:127 TOS:0x0 ID:96 IpLen:20 DgmLen:1500 DF
***A**** Seq: 0x911E284F  Ack: 0x1E88D7E9  Win: 0xFC4E  TcpLen: 20


이벤트가 발생할 때마다 위와 같은 포맷의 결과를 확인할 수 있습니다. 

만약 snort가 동작중에 시그니처를 변경했다면.. 
다음 명령어로 snort를 종료하지 않고 설정을 다시 읽어들일 수 있습니다. 
 
# kill -SIGHUP <snort pid> 


만약 reload가 되지 않는다면..
'--enable-reload' 옵션을 주고 configure를 다시 수행 해보시기 바랍니다.  

이제 열심히 snort를 즐기기만 하면 됩니다!!
HAVE FUN! 


 

Posted by KT한
,