2013년 8월 15일 목요일

IDS 로그 분석

룰과 로그

대표적인 웹 해킹 공격으로 파일 업로드 및 URL 삽입 등을 이용한 웹쉘 공격이 있다. 웹쉘은 웹 기반에서 시스템을 조작할 수 있는 도구의 통칭인데, 2008 5KISA에서 운영하는 인터넷 침해대응센터에서 ASP 기반에서 동작하는 웹쉘의 실행 여부를 확인할 수 있는 다음과 같은 시그니처를 배포한 적이 있다. 

그리고 해당 시그니처를 기반으로 Snort 룰 옵션을 이용하여 다음과 같은 IDS 탐지룰이 만들어진 사례가 있다.

alert tcp any any -> any 80 (content:"?Action="; nocase; pcre:"/\?Action\=(MainMenu|Show|Course|getTerminalInfo|ServerInfo|Cmd1?Shell|EditFile|Servu|sql|Search|UpFile|DbManager|proxy|toMdb)/i";)

좀 복잡해 보이지만, 해석하면 이렇다.
  ①     alert tcp any any -> any 80
è  목적지 포트가 TCP 포트 80인 트래픽 중,
  ②     content:"?Action="; nocase;
è  대소문자 구분 없이('nocase;' 옵션) '?Action='이란 문자열 패턴이 포함된 트래픽을 1차 필터링 한 후,
  ③     pcre:"/\?Action\=(MainMenu|Show|Course|getTerminalInfo|ServerInfo|Cmd1?Shell|EditFile|Servu|sql|Search|UpFile|DbManager|proxy|toMdb)/i
è  '?Action=' 문자열 이후, 대소문자 구분 없이('/i' 옵션) '|'로 구분된 각각의 문자열 패턴으로 2차 필터링 한다.
è  pcre 옵션의 검사 범위를, content 옵션에 의해 '?Action='이란 문자열 패턴이 포함된 트래픽만으로 제한

참고로 2차 필터링은 정규표현식(ko.wikipedia.org/wiki/정규_표현식)으로 작성되었는데 'Regex Coach(www.weitz.de/regex-coach/)'란 도구를 이용하면 좀더 빠른 이해가 가능하다.


기회가 되면 Snort 룰 옵션(www.snort.org/docs)과 정규표현식에 대한 내용도 연재를 해볼까 한다. 일단 해당 룰에 의해서, 하루 동안 1,146개의 로그가 발생했다. 패턴이 일치하면 모두 공격일까? '?Action=' 'URL?변수='으로 구성되는 URI(Uniform Resource Identifier)의 구성 요소(변수)이며, 개발 과정에서 얼마든지 자유로운 표현이 가능하다. 공격자들이 'Action'이란 패턴을 공격 용도로 사용하니, 개발에 사용하지 말라고 할 수 없다는 얘기이다.

이 얘기는 공격과 정상 트래픽이 한글과 영어처럼 다른 영역의 패턴을 사용하지 않는 이상, 룰과 일치하는 패턴은 공격의 가능성을 의미할 뿐, 확정할 수 없다는 뜻이다. 결국 모든 로그에 대해서 룰 패턴을 포함한 전체 메시지의 의미를 분석해야 한다. 그런데 1분에 하나씩 로그를 분석해도 1,140분이 필요하다. 로그 전수 검사에 많은 인력과 시간이 필요함을 알 수 있다.


대량의 로그를 쉽게 분석할 수 있는 방법은 없을까? 발생한 로그는 해당 룰과 패턴이 일치하는 트래픽 패킷의 페이로드(Payload)를 저장한 것으로, 일반적으로 원시데이터라고 부른다. 그런데 이 원시데이터는 일정한 규칙 없이 패턴들이 나열된 텍스트의 집합, 즉 비정형 데이터이다. 그리고 이 비정형 데이터를 일정한 규칙으로 분류된 정형 데이터로 변환하면, 즉 텍스트를 정규화하면 일괄적인 분석이 가능해진다.

다음 그림을 보면 이해가 좀더 빠를 것이다. A 패턴으로 동작하는 룰에 의해 발생한 로그를 분석하려면 먼저 원시데이터에서 A 패턴을 찾고, 해당 패턴이 전체 메시지에서 어떤 의미로 사용되었는지를 파악해야 한다.



그런데 해당 원시데이터가 다음 그림처럼 A 패턴을 기준으로 분류된 정형 데이터라면 어떨까? 패턴의 의미 파악이 훨씬 쉬워질 뿐만 아니라, 원시데이터를 하나 하나 분석하지 않고, 일괄적으로 분석할 수 있음을 알 수 있다.


텍스트 정규화를 이용한 비정형 원시데이터 분석의 가능성을 알게 되었다. 이제 실제 사례를 살펴보자.


텍스트 정규화를 이용해서 대량의 로그를 분석해 보자. 먼저 어떤 규칙으로 정규화할지를 선택해야 한다. 탐지 패턴을 기준으로 분류하는 것도 좋은 시도이지만, 제시된 사례처럼 사용자의 웹 접속 과정에서 발생한 로그에 대해서 URI(웹 요청 정보), Referer(URI의 출발지), Host(URI의 목적지), User-Agent(요청 도구) 지시자 정보 기준에 의한 분류가 이루어지면, 어떤 도구를 이용해서, 어디에서, 어디로, 어떤 정보를 전송했는지에 대한 전체 발생 현황을 쉽게 파악할 수 있다

변환 작업은 최종적으로 엑셀의 '텍스트 나누기' 기능을 이용할 것이며, 이를 위해서는 분류를 원하는 텍스트에 '구분 기호'를 추가해야 한다.

먼저 해당 로그에서 URI를 추출해보자. 웹브라우저 등 웹 요청 정보를 전송하는 도구는, 지원하는 HTTP의 버전을 URI 이후에 표시한다. 이 특성을 이용하면 로그에서 URI 정보만을 추출할 수 있다. 다음 그림은 텍스트 에디터인 VI(www.vim.org)에서 '/HTTP\/.*' 이란 검색 명령어를 이용하여 URI를 제외한 정보를 검색한 화면이다


사용된 명령어의 의미는 다음과 같다.


검색이 가능하면 치환도 가능하다. 다음 그림은 Vi의 문자열 치환 기능을 이용한 명령어(:%s/http\/.*//i)를 입력하여 URI를 제외한 모든 정보를 삭제한 결과이다. URI 정보만 추출했음을 알 수 있다.


사용된 명령어의 의미는 다음과 같다.


이제 사용자가 과거에 요청한 URI이자, 현재 요청한 URI의 출발지인 Referer 정보를 추출해보자. Referer 정보의 값은 'Referer: ' 이후에 표시되며, 공백이 포함되지 않는다. 이런 특성을 이용하면 매우 쉽게 추출이 가능하다. 참고로 현재 요청한 URI의 목적지인 Host 정보 역시 값에 공백이 포함되지 않는다. 일단 검색 결과는 다음과 같다.


사용된 명령어의 의미는 다음과 같다.


URI 추출과 마찬가지로 검색 명령어를 이용해서 치환이 가능하다. 다음 그림은 ':%s/referrer:\s\S\+/&/i' 명령어를 이용하여 치환한 결과이다. 1,146개의 로그 중 1,074개만 치환됐는데, 그 이유는 상황이나 환경에 따라 HTTP 지시자가 사용되지 않을 수도 있기 때문이다.


사용된 명령어의 의미는 다음과 같다.


구분 기호로 한글 자음인 ''을 사용한 이유는 트래픽 정보를 표시하는데 사용되는 알파벳 등의 기호와 중복되는 것을 방지하기 위해서이며, 중복되지 않는다면 어떤 기호를 써도 상관 없다. 하지만 구분 기호가 통일되지 않고 중복된다면 텍스트 정규화는 실패할 것이다. 다음 그림은 치환이 끝난 로그를 엑셀로 옮긴 후, '텍스트 나누기' 기능을 이용하는 과정이다.


다음 그림을 보면 전체 로그가 Referer 정보를 기준으로 3개의 열로 분리됐음을 알 수 있다. 필요 없는 B D열의 정보는 삭제하면 된다.


Host 정보 역시 Referer와 같은 방식으로 분류하면 된다. 문제는 User-Agent 정보이다. Referer Host 정보의 값은 공백이 포함되지 않기 때문에 분류가 단순하지만, User-Agent 값은 공백이 포함되며, 다양한 표현 방식이 사용되기 때문에 분류하기가 매우 까다롭다. 그러나 정규표현식을 잘 활용하면 어느 정도 극복이 가능하다User-Agent 정보만을 추출해보자.


User-Agent 정보는 표시 형식에서 Referer Host와 같은 특성(공백이 없다)이 없기 때문에 User-Agent 지시자 다음에 표시되는 지시자 앞에서 검색을 멈춰야 한다. 사용된 명령어의 의미는 다음과 같다.


'\{-}'VI의 수량 옵션이 사용되었는데 pcre(Perl Compatible Regular Expressions) '*?'와 같은 기능이다. '*'은 패턴의 수량을 0개 이상으로 제한하는 수량자인데, 기본적으로 최대 범위를 검사하려는 성질이 있다. 그런데 0 또는 1개로 수량을 제한하는 '?'와 함께 쓰이면 최소 범위로 검사가 제한된다

다음 그림의 'w.*com' 'w로 시작해서 com으로 끝나는' 모든 패턴을 검사하는 정규표현식이다. 해당 표현식에 의해 일치하는 패턴을 보면, 'w'로 시작한 후, 'abc.com' 패턴을 통과해서 'img.abc.com'에서 검사가 멈췄음을 알 수 있다. 검사할 수 있는 'com' 패턴이 더 이상 안 나올 때까지 검사하는 것이다.



다음 그림을 보면 'abc.com' 패턴이 나오자마자 검사가 멈췄다. '?' '*'의 최대 범위 검사 성질을 최소로 제한하고 있음을 알 수 있다. 이런 성질을 잘 이용하면 정교한 패턴 검사가 가능해진다. 참고로 이런 성질 때문에 '*'는 탐욕적인 수량자, '*?'는 탐욕적이지 않은 수량자라고도 한다



'전방 탐색'이란 이란 기능도 사용되었는데 VI에서는 '\(\)\@=' 형식으로 사용하며, pcre에서는 '(?=)' 형식으로 사용한다. 간단히 설명하면 'abc\(de\)\@=' 'de'로 끝나는 'abc'만을 찾아주는 기능이다

다음 그림을 보면 좀더 이해가 빠를 것이다. 그림의 표현식들은 모두 '공백'으로 끝나는 'com'만을 검사하며, '공백'을 제외한 'com' 패턴만을 검사 결과로 보여주고 있다.



, 'User-Agent 지시자: \(다음 지시자:\)\@=' 형식을 이용하여 'User-Agent로 시작해서 다음 지시자가 표시되기 전까지의 정보'만을 검색한 것이다. HTTP 지시자는 지시자와 값이 ':'으로 구분되는 특성이 있는데, User-Agent 값에도 ':'이 사용될 수 있기 때문에 '[^\(v\|p\)]:' 형식을 이용하여 'rv:', 'http:'을 제외시켰다

그러나 User-Agent 값의 발생 양상에 따라 이런 형식은 얼마든지 변화가 가능함을 알아야 한다. 정규표현식은 매우 강력하고 편리한 패턴 검사 기능을 제공하지만 이러한 기능을 제대로 사용하기 위해서는 검사를 원하는 패턴을 결정하는 많은 경험을 쌓을 필요가 있다. 다음 그림은 ':%s/user-agent:\s\p\{-}\(\s\S\+[^\(v\|p\)]:\)\@=/&/i' 명령어를 이용하여 치환한 결과이다.


사용된 명령어의 의미는 다음과 같다.


최종 텍스트 정규화 결과는 다음 그림과 같다. 이제 정규화된 원시데이터를 이용해서 룰의 문제점을 찾고, 개선 방안을 도출하는 과정을 살펴보자.




텍스트 정규화를 이용해서 비정형 데이터를 정형 데이터로 바꾸었다. 이제 분석을 해보자. 과연 해당 룰은 ASP 기반의 웹쉘 공격을 정확하게 탐지했을까? 엑셀의 필터링 기능을 이용하면 간편하게 원하는 패턴을 검색할 수 있다.


'?Action=' URI 영역을 검색했는데 일치하는 패턴이 286(25%)뿐이다. 왜 이런 결과가 나왔을까?


Referer 영역을 검색해보니 901(78%)가 검색된다.


해당 룰은 '?Action=' 패턴을 필수로 검사하는데, 이때 사용된 옵션은 Content이다. 그런데 이 옵션은 패킷 페이로드의 전체 범위를 검사한다. URI 영역은 물론 Referer HTTP 헤더를 포함한 데이터 영역 전체를 검사한 결과인 것이다. '?변수=' 형식을 검사한 이유는 URI를 검사하겠다는 의미인데, 사용자가 과거에 요청한 URI Referer 영역까지 검사하면서 중복 탐지가 발생하고 있다. 결과적으로 로그 역시 중복으로 발생하고 있다.

룰의 문제점을 하나 발견했다. 아래와 같이 룰을 수정하면 하루에 발생한 로그량을 1,146개에서 286개로 줄일 수 있다. 'uricontent', 'http_uri'는 모두 패턴 검사 범위를 웹 요청 트래픽의 URI 영역으로 제한하라는 의미의 Snort 룰 옵션이다.

alert tcp any any -> any 80 (uricontent:"?Action="; nocase; pcre:"/\?Action\=(MainMenu|Show|Course|getTerminalInfo|ServerInfo|Cmd1?Shell|EditFile|Servu|sql|Search|UpFile|DbManager|proxy|toMdb)/i";)

alert tcp any any -> any 80 (content:"?Action="; nocase; http_uri; pcre:"/\?Action\=(MainMenu|Show|Course|getTerminalInfo|ServerInfo|Cmd1?Shell|EditFile|Servu|sql|Search|UpFile|DbManager|proxy|toMdb)/i";)

해당 룰은 ASP 기반에서 동작하는 웹쉘을 탐지하기 위한 것이다. 이번에는 다음 그림과 같은 필터 조건을 이용하여 정확한 탐지가 이루어지고 있는지 확인해보자.


'?Action='을 포함한 286개의 로그 중 'asp?Action=' 패턴이 없는 로그는 67(23%)이다. 참고로 엑셀에서 '?'를 일반 문자로 인식시키기 위해서 '~' 기호를 사용했다.


'php?action=' 등 해당 룰이 정확하게 ASP 기반에서 동작하는 웹쉘을 탐지하지 않고 있음을 알 수 있다. 아래와 같이 룰을 수정하면 하루에 발생하는 로그량은 219개로 줄어든다.

alert tcp any any -> any 80 (uricontent:".asp?Action="; nocase; pcre:"/\?Action\=(MainMenu|Show|Course|getTerminalInfo|ServerInfo|Cmd1?Shell|EditFile|Servu|sql|Search|UpFile|DbManager|proxy|toMdb)/i";)

alert tcp any any -> any 80 (content:".asp?Action="; nocase; http_uri; pcre:"/\?Action\=(MainMenu|Show|Course|getTerminalInfo|ServerInfo|Cmd1?Shell|EditFile|Servu|sql|Search|UpFile|DbManager|proxy|toMdb)/i";)

다음 그림은 최종 확인된 193개의 웹쉘 공격 현황이다. 1,146개보다는 219개에서 193(88%)의 공격을 찾는 것이 더 쉬울 것이다.


193개의 로그를 웹쉘 공격으로 판단한 근거는 무엇일까? 웹쉘 공격은 업로드한 웹쉘에 접속한 후, 다양한 명령을 'URI 변수=' 구조를 이용하여 전송하면서 이루어진다. 그런데 정상 웹 서비스에서도 'Action'이란 변수를 사용할 수 있으며, 역시 변수의 값으로 'Show1File'이나 'MainMenu'란 값을 사용할 수 있다

일반적인 웹 서비스와 동작 방식이 똑같다는 얘기이다. 연재 초기에 룰 패턴을 포함한 전체 메시지의 의미를 분석해야 한다고 했는데, 그것만으로 부족할 경우가 있다

그럴 땐 어떻게 해야 할까? 의외로 답은 간단하다. 사실 가장 간단한 방법은 해당 웹서버 관리자에게 'shell.asp'가 해당 웹사이트에서 정상적으로 서비스하는 컨텐츠인지 물어보는 것이지만 현실적으로 불가능한 경우가 많다. 그럴 땐 그냥 접속해보면 된다. 다음 그림은 해당 웹쉘에 접속한 화면이다. 정체불명의 로그인 페이지로 연결된다.

 
다음 그림은 Wireshark를 이용해서 공격자의 로그인 시도 트래픽을 캡쳐한 화면이다. 로그인 패스워드가 'sectest'임을 알 수 있다.


참고로 일반적인 웹 서비스는 데이터베이스와 연동하여 패스워드 인증 체계를 구현하지만 웹쉘 공격은 웹쉘 파일만으로 이루어지기 때문에 공격자들은 대부분 다음 그림처럼 파일 자체에 패스워드를 심어놓는다.


다음 그림은 웹쉘 로그인에 성공한 화면이다. 해당 웹쉘이 파일, 디렉토리에 대한 접근이 가능하며, 중국에서 만들어졌음을 알 수 있다.


로그 분석이 싱겁게 끝나 버렸다. 원시데이터를 체계적으로 분석할 수 있는 환경만 마련된다면 정작 로그 분석은 그리 어렵지 않다는 사실을 알게 되었다. 이처럼 로그 전수 검사를 실시하면,
  ① 룰의 문제점을 파악할 수 있고,
  ② 이를 통해 룰의 정확도를 높일 수 있으며,
  ③ 높아진 룰 정확도에 의해 로그 발생량이 줄면서 더 많은 공격을 더 빨리, 그리고 더 쉽게 찾아낼 수 있게 된다.

대량으로 발생하는 로그에 대해 그 동안 보안 분야가 체계적으로 대응하지 못했던 것이 사실이다. 최근에는 빅데이터가 유행하면서 빅데이터 솔루션을 이용하면 체계적으로 대량 로그에 대응할 수 있다는 주장도 제기되고 있다

그러나 대표적 빅데이터 사례로 꼽히는 구글의 '독감 예측 시스템'에서 구글이 검색어 전수 검사를 통해 단순히 검색어의 발생 현황 파악에 그치지 않고, 독감 예측이라는 통찰을 얻을 수 있었던 이유는 검색어라는 데이터가 검색어 발생 양상이라는 분석 목적에 부합하는, 즉 정확한 데이터였기 때문이다.

우리는 보안 분야의 데이터인 보안로그에 매우 많은 부정확한 로그가 포함되어 있다는 사실을 이미 알고 있다. 먼저 데이터를 정확하게 만드는 시도 없이 빅데이터 솔루션으로 데이터만을 수집한다면, 더 거대해진 데이터 속에서 공격을 찾아 헤매게 될 것이다

결국 로그 전수 검사를 통해 룰 정확도를 높이는 것이 보안 관점에서 올바른 빅데이터 활용이며, 그러한 경험이 충분히 쌓인 상태에서 더 많은 데이터를 활용하게 될 때, 더 큰 통찰을 이끌어내는 것도 가능해질 것이다.

댓글 없음:

댓글 쓰기

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