웹 요청 트래픽은 'Request-Line(URI) + Header + Body' 구조로 이루어져 있으며, 그 중 Header 영역은 '\r\n(Carriage Return과 Line Feed, 0D0A)'으로 각 필드를 구분하는 여러 지시자(Directive)들로 구성되어 있다.
- VI 정규표현식 : ^.\{-}485454502f312e..\(0d\)\{-}0a
- PCRE 정규표현식 : ^.*?485454502f312e..(0d)?0a
- '485454502f312e'는 'HTTP/1.'의 HEX 표현이며, '..'을 추가해 버전 정보가 '1(31)' 또는 '0(30)'으로 마무리되는 모든 경우와 일치하도록 함
- '\(0d\)\{-}0a'는 없거나 하나 이상을 의미하는 수량자(*의 최소 동작 모드) '\{-}'를 이용해서 필드 구분자로 '0D0A(CRLF)' 또는 '0A(LF)'를 사용하는 모든 경우와 일치하도록 함
- RFC 규약을 보면 필드 구분자는 '0D0A(CRLF)'를 사용하도록 명시하고 있으나, '0A(LF)'도 허용한다고.
헷갈리게 하지 마 이놈들아
URI 영역을 삭제하면 'Header + Message-Body' 영역만 남는다.
가독성을 높이기 위해 남은 헤더 영역에서 지시자의 '제목:공백값' 형식을 '제목 | :공백값' 형식으로 바꿔보자. 사용한 VI 치환 명령어는 다음과 같다.
- %s/3a20.\{-}\(0d\)\{-}0a/ | & | /g
- '3a20'은 ':공백'의 HEX 표현
- '&'는 '치환 전 패턴'을 의미하는 VI 메타문자
- 'g(global)' 옵션은 일치하는 모든 패턴을 치환('g'가 없으면 최초 일치하는 패턴만 치환)
- '구분기호( | )'에서 오른쪽 공백( )이 왼쪽( )보다 하나 더 많은 이유는 짝수 단위의 HEX 구조를 유지하기 위해서^^;
최종 확인 결과 23개의 로그는 필드 구분자로 0D0A, 또는 0A를 사용한 2가지 유형으로 나뉘었으며, 00 패턴은 모두 0D0A0D0A(또는 0A0A) 이후, 즉 'Message-Body' 영역에서 발견되었다.
0D0A를 필드 구분자로 사용1 |
0D0A를 필드 구분자로 사용2 |
0A를 필드 구분자로 사용1 |
0A를 필드 구분자로 사용2 |
헤더 영역에 쓰레기값인 '00'이 사용되면 버퍼 오버플로우 시도로 판단한 듯 하다. (검사 위치 및 순서 조건이 없어서 의도대로 동작하지는 않았음)
그러나 이미 확인했듯이 0D0A대신 0A가 사용되었다고 해서 구분자 조작 시도는 아니며, 헤더 영역의 쓰레기값 역시 나오지 않았다. 결국 해당 로그는 모두 오탐.
그러나 이미 확인했듯이 0D0A대신 0A가 사용되었다고 해서 구분자 조작 시도는 아니며, 헤더 영역의 쓰레기값 역시 나오지 않았다. 결국 해당 로그는 모두 오탐.
이제 룰을 수정해보자. 그런데 룰 수정이 꼭 필요할까? 워낙 오래된 취약점인데다, Snort도 버린 마당에 굳이? '신호와 소음'이란 책에 이런 문구가 나온다.
여기저기 될 때까지 찔러보는 공격자를 무시하면 안된다. 설령 패치 등을 통해 취약점을 제거했다 하더라도 탐지로그를 통해 공격자의 동향을 파악함으로써 (폼 나는) '선제적 대응'이란 걸 하게 될 수도 있다.
alert tcp $EXTERNAL_NET any -> $HTTP_SERVERS $HTTP_PORTS
(msg:"DELETED WEB-IIS header field buffer overflow attempt";
flow:to_server,established;
content:"|00|"; http_header;
검사 위치를 HTTP 헤더 영역으로 제한했으며, 해당 룰 개발자의 의도를 존중하는 차원(사실은 정확한 공격 조건을 잘 몰라서-_-)에서 헤더 필드 구분자로 0A를 사용하는 경우만 탐지하는 방향으로 수정했다.
공격을 탐지하지 못한다고 당장 실망할 필요는 없다. 오탐만 줄어도 반은 성공이며, 이후 로그 발생 양상에 따라 수정 가능성은 무궁무진하니까.
사족
pcre 옵션에 사용한 '부정형 후방탐색' 정규표현식 '(?<!\x0D)'는 오버헤드가 좀 있기 때문에 Snort 자체 부정(!) 옵션을 사용하는 것이 성능상 유리할 수도 있다.
관련 글
우리의 적이 우리의 어느 곳을 칠지 예측할 수 있는데, 바로 우리가 가장 예상하지 못하는 곳이다 (644 페이지)
여기저기 될 때까지 찔러보는 공격자를 무시하면 안된다. 설령 패치 등을 통해 취약점을 제거했다 하더라도 탐지로그를 통해 공격자의 동향을 파악함으로써 (폼 나는) '선제적 대응'이란 걸 하게 될 수도 있다.
alert tcp $EXTERNAL_NET any -> $HTTP_SERVERS $HTTP_PORTS
(msg:"DELETED WEB-IIS header field buffer overflow attempt";
flow:to_server,established;
content:"|00|"; http_header;
- HTTP Header 영역에서 00 패턴 검사(필수)
- 'H' 옵션을 이용해서 HTTP Header 영역만 검사
- 'm' 옵션을 이용해서 각 지시자 행 중 0A로 끝나는 행이 있으면 탐지
- (?<!\x0D)\x0A$ : (0D0A가 아닌) 0A로 끝나는 행
검사 위치를 HTTP 헤더 영역으로 제한했으며, 해당 룰 개발자의 의도를 존중하는 차원(사실은 정확한 공격 조건을 잘 몰라서-_-)에서 헤더 필드 구분자로 0A를 사용하는 경우만 탐지하는 방향으로 수정했다.
공격을 탐지하지 못한다고 당장 실망할 필요는 없다. 오탐만 줄어도 반은 성공이며, 이후 로그 발생 양상에 따라 수정 가능성은 무궁무진하니까.
사족
pcre 옵션에 사용한 '부정형 후방탐색' 정규표현식 '(?<!\x0D)'는 오버헤드가 좀 있기 때문에 Snort 자체 부정(!) 옵션을 사용하는 것이 성능상 유리할 수도 있다.
- pcre:!"/\x3A\x20.+?\x0D\x0A$/mH";
- 0D0A로 끝나는 행은 탐지하지 않는다. (0D0A로 끝나지 않으면 탐지)
- 필드 구분자를 어떤 식으로 조작하는지에 대한 정보가 없기 때문에 정확도면에서도 유리할 수 있음
관련 글
댓글 없음:
댓글 쓰기