스노트에서 지원하는 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한
,

모든 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한
,