2015년 11월 24일 화요일

Snort 분석(WEB-MISC Checkpoint Firewall-1 HTTP parsing format string vulnerability attempt)

오늘 살펴볼 Snort 룰은 다음과 같다.

alert tcp $EXTERNAL_NET any -> $HTTP_SERVERS $HTTP_PORTS 
(msg:"WEB-MISC Checkpoint Firewall-1 HTTP parsing format string vulnerability attempt"; 
flow:to_server,established; 
content:"|3A|/"; offset:11; http_uri; 
  • URI 영역의 시작점부터 11byte 이후, '3A(:)' 패턴이 존재하는 패킷 중
pcre:"/^[^\x3a\x3f]{11,}\x3a\x2f/Usmi"; 
  • URI 영역의 시작점에서 '3A(:)' 또는 '3F(?)'를 제외한 패턴이 11개 이상 나열된 이후, '3A2F(:/)' 패턴이 존재하면 탐지 
  • content 옵션으로 한 번 걸렀으며, 왼쪽에서 오른쪽을 검사를 시도하다 일치하는 패턴이 나타나면 중지하는 패턴매칭 원리에 의해 수정자 'U(URI)'는 없어도 무방
  • 메타문자 '.'을 사용하지 않았는데 수정자 's'를 왜 사용하는지 모르겠음
  • 수정자 'm'은 앵커문자 '^(첫 번째 줄 검사)'나 '$(마지막 줄 검사)'의 줄 구분 해제 

metadata:service http; reference:bugtraq,9581; reference:cve,2004-0039; reference:nessus,12084; classtype:attempted-admin; sid:2381; rev:14;)

해당 룰은 2004년 체크포인트 방화벽 'Firewall-1'에 존재했던 포맷 스트링 취약점(CVE-2004-0039) 공격을 탐지한다. 포맷 스트링 공격이란 무엇일까?


프로그래밍 무식자다 보니 설명을 봐도 모르겠다(..) 그나마 관련된 취약점 정보를 보면 공격자가 전송한 악의적 웹 요청에 의해 응답 에러가 발생하는 과정에서 포맷 스트링에 공격자가 전송한 임의 코드가 영향을 주는 공격인 듯하다.

When Firewall-1 generates an error message in response to the invalid request, a portion of the input supplied by the attacker is included in the format string for a call to sprintf().

일단 해당 룰의 핵심 탐지패턴은 '3A2F(:/)'이다. 왜 해당 패턴을 탐지하려고 하는 걸까? 포맷 스트링 공격이 버퍼 오버플로우랑 유사 성격임을 감안했을 때, 아마도 쉘 실행을 위한 환경변수 패턴 탐지가 목적이 아닐까 한다.

이미지 링크

두 번째 궁금증. PCRE 옵션에 사용된 정규표현식 '^[^\x3a\x3f]{11,}'는 '3A(:)' 또는 '3F(?)'를 제외한 11개 이상의 문자열을 의미한다.

일단 '3A2F(:/)' 패턴이 왜 URI 영역의 시작 지점에서 최소 11byte 이후에 존재해야 하는지는 잘 모르겠다(..) 그런데 3A(:)'와 '3F(?)'는 왜 그 영역에서 제외했을까?

다음 그림의 정규표현식 '^.\{11,}:'에서 수량자 '\{11,}'는 메타문자 '.'의 검사 범위를 11개 이상으로 결정하며, 가능한 검사 범위를 최대한 검사하려는 특성에 의해 첫 번째 ':'이 있음에도 두 번째 ':', 즉 ':' 문자가 더는 존재하지 않음을 확인하고 나서야 검사를 중지한다.


그러나 '.'을, ':'을 제외한 임의 문자를 의미하는 '[^:]'으로 바꿔주면 ':'을 제외한 문자만을 검사해야 하기 때문에 첫 번째 ':' 문자를 만나자마자 검사는 중지된다. 검사 범위를 좁힐 수 있으며, 더 정밀한 검사가 가능해지는 것이다.


참고로 수량자 '^.\{11,}'를 '^.\{-11,}'로 바꿔도 수량자의 검사 범위를 최소로 제한함으로써 같은 결과를 얻을 수 있다.


'3F(?)'는 왜 제외했을까? 해당 룰은 URI 영역만을 검사하는데, URI는 URL과 '?'로 구분되는 변수 영역으로 나뉜다. 이 때 '[^?]'와 같은 정규표현식을 사용하면 '?'를 제외한 임의 문자만을 검사하게 되며, '?' 문자를 만나면 역시 검사는 중지된다.


결과적으로 정규표현식 '^[^\x3a\x3f]{11,}'는  '3A(:)'나 '3F(?)' 패턴을 만나면 검사가 중지된다. 이유는 모르겠지만 해당 룰 개발자는 URI 영역 중, 변수 영역을 제외한 URL 영역에서만 '3A2F(:/)'로 끝나는 패턴을 검사하고자 한 듯하다.


룰의 의도가 대강 파악이 됐다. (룰 근거를 남겨놓지 않으면 이렇게 의도가 뭐였는지 추정하느라 한 세월 걸림) 이제 과연 의도대로 동작했는지, 해당 룰에 의해 발생한 탐지로그에 쉘 환경변수 패턴이 존재하는지 여부를 확인해보자.

이 때 로그 전체를 대상으로 확인할 필요는 없다. 룰이 의도했던 것처럼 변수 영역을 제외한 URL 영역으로만 검사 범위를 좁히면 (눈의 피로와 함께) 검사 시간을 줄일 수 있기 때문이다.

확인 작업에 필요한 부분은 변수 영역을 제외한 URL 영역이니까 '?'로 시작하는 모든 문자열을 삭제해버리면 될까? 해당 룰이 URI 영역을 먼저 선택한 후, 변수 영역을 제외하는 식으로, 넓은 범위에서 좁은 범위로 단계적으로 검사 범위를 제한했다는 사실에 주목할 필요가 있다.

 '?'로 시작하는 모든 문자열을 삭제하면 다음 그림처럼 웹 요청 헤더 영역의 일부까지 검사 범위에 포함되는 경우가 발생한다. 요청자와의 상호작용이 필요없는 정적인 웹 콘텐츠는 변수 사용이 필요없기 때문에 '?'가 사용되지 않는 관계로 엉뚱한 영역의 '?'가 선택된 것.


'HTTP/1.'으로 시작하는 문자열을 먼저 삭제한 후, '?'로 시작하는 문자열을 삭제하면 해당 룰의 의도대로 '변수 영역을 제외한 URL 영역'만으로 검사 범위를 좁힐 수 있다.



이제 이렇게 정리된 탐지로그에서 정오탐 발생 분포를 확인하면 된다.

to be continued..

관련 글

댓글 없음:

댓글 쓰기

크리에이티브 커먼즈 라이선스