스노트에서 고급 옵션이라고 볼 수 있는...
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한
,