2016년 3월 20일 일요일

LogParser 활용(Web Log 이상징후 분석 - 4th)

지난 시간에 웹 로그 구성요소 중 하나인 HTTP 응답코드 발생 추이 분석을 통해서 이상징후 분석의 가능성을 살펴봤었다. 오늘은 URL 발생 추이를 분석해보자. 

참고로 Windows 웹 로그 필드 중 cs-uri-stem은 URL, cs-uri-query는 '변수=값' 영역에 해당된다.


일단 cs-uri-stem의 전체 발생 분포를 확인해보자.

① select cs-uri-stem, count(*)
② from d:\ex.log
③ group by cs-uri-stem
④ order by count(*) desc


특정 이미지 파일이 전체 발생량의 25%쯤을 차지하는 듯하다. 그런데 문제는 사용자가 접근을 시도한 cs-uri-stem의 종류가 1,027개나 된다. 알파고면 모를까, 어느 세월에 1,027개의 발생 추이를 분석하나?


경로를 제외한 웹 문서만의 발생 분포 확인을 통해 분석 범위를 좁혀보자. 경로를 제외하면 cs-uri-stem의 종류는 654개로 줄어든다.

① select extract_suffix(cs-uri-stem,0,'/'), count(*)
② from d:\ex.log
③ group by extract_suffix(cs-uri-stem,0,'/')
④ order by count(*) desc


하지만 여전히 많다. 아예 웹 문서의 확장자만을 추출해보자. 웹 문서 확장자만으로 범위를 좁힌 결과, cs-uri-stem의 종류는 다시 51개로 줄어들었다. 그런데 가만 보니 동일한 확장자의 대소문자가 따로 존재한다.

① select extract_extension(cs-uri-stem), count(*)
② from d:\ex.log
③ group by extract_extension(cs-uri-stem)
④ order by count(*) desc


대소문자 구분도 없애보자. 'to_lowercase' 함수를 이용하면 결과값을 소문자로 변환할 수 있다. 참고로 대문자로의 변환은 'to_uppercase' 함수. 이제 발생 추이를 분석해야할 cs-uri-stem의 종류는 48개. 생각보다 별로 안 줄었다(..)

① select to_lowercase(extract_extension(cs-uri-stem)), count(*)
 from d:\ex.log
③ group by to_lowercase(extract_extension(cs-uri-stem))
④ order by count(*) desc



고정적인 서비스를 운영하는 상태에서 사용자가 접근을 시도하는 웹 문서의 종류는 일정 수의 범위 안에 머물 것이다. 

웹 문서 종류에 대한 발생 추이 분석이 이상징후 분석의 좋은 조건이 될 수 있다는 뜻이다. 한 번 해보자. 방법은 시간대별 웹 문서 종류의 개수를 구하는 것.

종류의 개수를 구하는 것이기 때문에 종류가 중복되면 안 된다. 예를 들면 00:00 시에 3개의 웹 문서(a.jpg, b.jpg, c.html)에 대한 접근이 발생했다면 전체 발생량은 3개지만 종류는 확장자의 중복을 제거한 2개이기 때문이다.

중복을 제거하려면 'distinct' 함수를 사용하면 된다. 웹 문서만을 추출하는 다음 그림은 8만 줄이 넘는 로그에서 줄 단위로 웹 문서를 추출하기 때문에 결과값 역시 8만 개가 넘는다.

① select extract_suffix(cs-uri-stem,0,'/')
② from d:\ex.log


그러나 'distinct' 함수를 이용해서 중복을 제거하면 654개만이 조회된다. 'distinct' 함수의 유용함을 알 수 있는 대목.

① select distinct extract_suffix(cs-uri-stem,0,'/')
② from d:\ex.log


count 함수를 이용해서 중복을 제거한 개수만을 구할 수도 있다. 그리고 이 때는 단일 필드의 개수를 구하는 것이기 때문에 'group by'문을 이용한 집계 기준은 필요 없다.

① select count(distinct extract_suffix(cs-uri-stem,0,'/'))
② from d:\ex.log


문제는 단순히 중복을 제거한 웹 문서 종류의 개수가 필요한 게 아니라 시간대별 개수가 필요하다는 것.

distinct 집계 결과를 시간 기준으로 다시 집계(count)를 해야 하는데 아쉽게도 LogParser는 아직까지 해당 기능을 지원하지 않는다. 이거랑 테이블 조인 기능만 지원해주면 정말 원이 없겠구만.


꼼수를 부려보자. 일단 중복을 제거한 시간대별 웹 문서 종류 집계. 중복을 제거하더라도 해당 시간대에 발생한 웹 문서의 종류가 다르다면 시간대는 웹 문서 종류의 개수만큼 표시되며, 결과적으로 시간대별로 발생한 웹 문서 종류의 중복을 제거하는 효과가 있다.



00:00시에 발생한 웹 문서의 종류는 6개라는 사실을 알 수 있다.

① select distinct to_string(time, 'hh:mm'), to_lowercase(extract_extension(cs-uri-stem))
 from d:\ex.log

해당 결과를 'uri.csv' 파일로 저장한 후, 시간대별 웹 문서 종류의 개수를 구한 결과는 다음과 같다.

① select time, count(ext)
 from d:\uri.csv
③ group by time


공격이 발생하기 전, 사용자가 접근을 시도한 웹 문서의 종류는 분당 10개를 넘지 않았지만, 공격이 발생한 시점에서는 최대 37개까지 증가했음을 알 수 있다.


중복을 제거하지 않았다면 어땠을까? 판단은 여러분의 몫이다. 확실한 건 데이터를 분석하는 조건이나 상태가 다양해질수록 데이터를 보는 눈은 정확해진다는 것.

① select to_string(time, 'hh:mm'), count(to_lowercase(extract_extension(cs-uri-stem)))
 from d:\ex.log
③ group by to_string(time, 'hh:mm')


공격자가 취약점 스캔 과정에서 다양한 웹 문서에 접근했기 때문에 웹 문서 종류의 발생 추이에서 특이점을 찾기가 수월했다. 하지만 특정 웹 문서에만 집중적으로 접근했다면 특이점을 느끼지 못하고 그냥 지나쳤을 것이다. 

한 두 가지 이상징후 분석에만 매달려서는 결국 운빨에 좌우되기 쉽다는 뜻(..) 웹 로그 등 발생한 상태를 사실 그대로 기록한 로그는 그 상태의 개수만 세도 정말 많은 의미를 얻어낼 수 있다. 

그리고 데이터베이스는 험난한 여정이 될 수도 있는 그 과정을 수월하게 통과할 수 있도록 도와준다. 데이터 분석할 땐 역시 데이터베이스가 장땡.

웹 문서 종류 개수의 발생 추이를 확인해봤으니, 넓은 범위에서 좁은 범위로 분석의 범위를 좁혀가는 차원에서 다음 시간에는 웹 문서 종류의 개별 발생 추이를 확인해볼까 한다.

관련 글

댓글 없음:

댓글 쓰기

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