Search
🔐

표준편차 3σ 규칙을 활용한 위협헌팅

위협 헌팅을 진행하다가 단순 화이트리스팅이나 블랙리스트, 시그니처에 기반한 방식이 아닌 통신량의 변화에 따른 결과를 구하고 싶었다. 이를 위해 통계의 기본이 되는 표준 편차의 3σ(시그마) 규칙을 활용해 급격한 변화를 보이는 통신을 추출하는 방식을 만들어 꽤 성공적인 성과를 얻었다.

표준 편차(standard deviation)

자료의 관찰값들이 얼마나 흩어져 있는지 나타내는 대표적인 지표다.
평균(m)이야 우리가 기존에 알다시피 모집단(population)의 데이터 개수 N으로 전체 값을 나눈 결과다.
위와 아래의 평균 값은 둘다 50이지만 분명히 다른 분포다. 첫 번째 행은 평균은 50, 모든 값도 50이지만 두 번째 행은 다양한 분포 값을 가지고 있다.
이런 관찰값들이 얼마나 흩어져 있는지를 살피기 위해 각 관찰값과 ‘관찰값들의 평균’과의 차이를 편차라 명한다.
편차들의 평균은 필연적으로 0이 된다. 즉 그냥 평균으로는 전체 편차의 크기를 정의하기 어렵다.
편차들의 값에 대한 지표를 얻기 위해 이를 제곱해서 분산으로 표현한다.
표준편차는 이렇게 구한 분산의 제곱근을 구한 값으로 여러 값의 분포 내에 어떤 수의 크고 작음을 얘기할 수 있다.

3σ 규칙(68-95-99.7 규칙)

표준편차에는 상당히 사용하기 좋은 흥미로운 규칙이 있다.
m+n×σ(n=1,2,3)m+n \times \sigma(n=1,2,3)
정규 분포를 따른다고 했을 때 신뢰구간에 따라 정규 분포의 특정 값을 위와 같이 나타낼 수 있고,
n 값이 1, 2, 3 일 때 정규분포의 약 68.27%, 95.45%, 99.73% 범위를 포함하는데, 각각의 백분율을 기억하기 위해 사용되는 약칭으로 68-95-99.7 규칙이라 부른다. (3 시그마 규칙이라 부르기도 한다.)
교육과정에서는 95%의 신뢰구간인 1.96σ, 99% 신뢰구간인 2.58σ를 자주 사용한다.
2시그마: 대중매체에 종종 나오는 설문조사가 주로 2시그마를 기준으로 쓰인다. 상위 약 2.28%를 산출할 수 있어서 수능 1등급 중반(백분위 98)으로, 원점수가 m+2σ정도라면 웬만해서는 1등급을 받는다

3σ 규칙을 활용한 비정상 통신 식별

평시 자주 통신하던 출발지IP가 아니면서 이 IP의 통신회수가 m+2.5σ(상위 1%)를 넘어선다면?
심지어 평소에 해당 목적지IP를 대상으로는 로그가 발생하지 않던 형식의 로그가 발생했다면 정상적인 일은 아닐 것이다.(ex. 방화벽 Deny로그)
사전 정보를 수집하고 통계를 만드는 과정, 통계를 기반으로 비정상 통신을 식별하는 과정 2개로 나눠진다.
목적지 IP별 통신회수 통계와 평시 자주 통신하던 출발지IP, 로그가 발생하는 체계들을 목록화한다.

1) 각 목적지 IP별 통신 정보 수집

일정 기간(ex: 7일)동안 모든 출발지, 목적지 IP 간의 통신회수와 방화벽 통신 방식(Allow, Deny)을 모두 구한다.
예를 위한 방화벽만 썼다. 방화벽 외에도 다양한 정보보호장비 체계에서 탐지됐는지 여부를 확인하는 등으로 확장하는 방식을 추천한다.
통신량을 기반으로 1일 단위 목적지IP를 기준으로 [통신회수 평균, 표준편차, 통신 회수 상위 10개 IP]를 구한다.
다음은 이에 해당하는 Splunk SPL 쿼리다. 각 쿼리 라인 아래에 주석을 기술했다.
핵심 기능 외에도 가시성을 위한 룩업 정보 연동이나 화이트리스트 처리들이 있어 쿼리문이 상당히 복잡하다.
일주일 단위로 야간에 자동 스케쥴러를 설정해 실행되게 설정했으며, 이를 통해 매주 통계 결과를 src_dest_summary.csv에 업데이트 시켰다.
|tstats count(src_ip) as C_sip, values(sourcetype) as fw_type where sourcetype=*allow* OR sourcetype=*deny* NOT src_ip="0.0.0.0" by src_ip, dest_ip, date_mday |search NOT [|inputlookup white_list.csv|fields src_ip] |eval comment=" ◆ C_sip : 출발지IP&목적지IP 통신 회수 ◆ fw_type : 출발지&목적지IP 방화벽 타입, 평소 allow만 뜨다가 deny가 뜨는 경우와 같은 예외 식별을 위함 (소스타입으로 추후 변경 가능) ■ Watch-All서버, 라우터 등을 제외하기 위한 화이트리스트 제외" |sort -C_sip |eval comment=" ■ 통신 회수 순으로 정렬" |stats dc(src_ip) as dc_sip, avg(C_sip) as avg_dip, stdev(C_sip) as stdev_dip, list(src_ip) as sorted_src, list(C_sip) as sorted_cnt, values(fw_type) as fw_type by dest_ip, date_mday |eval comment=" ◆ dc_sip : dest_ip 기준 통신하는 src_ip 중복제거 개수 ◆ avg_dip : dest_ip 기준 src_ip 통신 횟수 평균 ◆ stdev_dip : dest_ip 기준 src_ip 통신 횟수 표준편차 ◆ sorted_src : dest_ip 기준 통신량이 많은 순 src_ip (list는 sort된 그대로 들어옴) ◆ sorted_cnt : dest_ip 기준 통신량이 많은 순 src_ip 통신회수" |eval top10_src=mvindex(sorted_src,0,10), top10_cnt=mvindex(sorted_cnt,0,10) |eval comment=" ◆ top10_src : dest_ip 기준 통신량이 많은 순 src_ip 상위 10개 ◆ top10_cnt :dest_ip 기준 통신량이 많은 순 src_ip 상위 10개 통신회수" |lookup asset_list.csv IP as dest_ip OUTPUT Name as 자산명, Service as 서비스명 |eval comment=" ■ 목적지IP에 대한 정보가 룩업에 있을 경우 표시" |eval avg_dip=round(avg_dip,1), stdev_dip=round(stdev_dip,1), dayday=strftime(now(),"%Y-%m-%d") |eval comment=" ■ 소수점 처리 및 날짜 표시(1일 단위 수집으로 00시부터 24시간범위 수집하도록 스케줄 설정)" |table dayday,dest_ip, 자산명, 서비스명,dc_sip, avg_dip, stdev_dip, fw_type, top10_src, top10_cnt |fillnull value="-" |outputlookup src_dest_summary.csv
SQL
복사

2) 통계 기반 비정상 통신 식별

수집과정과 동일한 과정을 탐지하는 날짜를 기준으로 수행한다.
이렇게 수집한 결과에서 다음 조건에 해당하면 표에 값을 출력하도록 설정한다.
일주일 간 발생한 통신 분포에서 통신 회수가 상위 1% (평균m + 2.5 표준편차σ)
일주일 간 자주 통신하던 상위 10개 IP가 아닌 신규 IP
(내부 침해를 가정해 ON/OFF 필요) 내부 자산이나 사용자가 아닐 경우
그리고 다음 조건을 만족하면 추가적인 정보를 표시해 주목도를 높인다.
일주일 간 발생한 통신 분포에서 통신 회수가 상위 0.3% (평균m + 3 표준편차σ)
기존에 탐지되지 않던 새로운 소스타입 (방화벽 deny, allow) 탐지
아래는 Splunk SPL 쿼리문이다.
|tstats count(src_ip) as C_sip, values(sourcetype) as fw_type where sourcetype=*allow* OR sourcetype=*deny* NOT src_ip="0.0.0.0" by src_ip, dest_ip, date_mday |stats avg(C_sip) as C_sip, values(fw_type) as fw_type by src_ip, dest_ip |search NOT [|inputlookup white_list.csv|fields src_ip] |eval comment=" ◆ C_sip : 출발지IP&목적지IP 통신 회수 (일자 별 카운트 *date_mday) ◆ fw_type : 출발지&목적지IP 방화벽 타입, 평소 allow만 뜨다가 deny가 뜨는 경우와 같은 예외 식별을 위함 ■ Watch-All서버, 라우터 등을 제외하기 위한 화이트리스트 제외" |lookup src_dest_summary.csv dest_ip OUTPUT dest_name, dc_sip, avg_dip, stdev_dip, fw_type as origin_fw_type, top_src, top_cnt |eval comment=" ◆ dest_name : dest_ip 서버명 ◆ dc_sip : dest_ip 기준 통신하는 src_ip 중복제거 개수 ◆ avg_dip : dest_ip 기준 src_ip 통신 횟수 평균 ◆ stdev_dip : dest_ip 기준 src_ip 통신 횟수 표준편차 ◆ origin_fw_type : dest_ip 기준 발생한 방화벽 소스타입 종류 ◆ sorted_src : dest_ip 기준 통신량이 많은 순 src_ip (list는 sort된 그대로 들어옴) → 1일 이상 검색할 경우 중복IP가 있기 때문에 eventstats values()로 중복제거 ◆ sorted_cnt : dest_ip 기준 통신량이 많은 순 src_ip 통신회수 ◆ top_src : dest_ip 기준 통신량이 많은 순 src_ip 상위 10개 ◆ top_cnt :dest_ip 기준 통신량이 많은 순 src_ip 상위 10개 통신회수" |lookup user_information.csv "사용자IP" as src_ip OUTPUT "사용자" as user, "소속명" as user_gr |lookup asset_list.csv IP as src_ip OUTPUT Name as src_name, Service as src_Service |eval src_name = if(isnull(user),'src_name'." ".'src_Service','user_gr'." ".'user') |eval src_name = if(src_name="- -","-",src_name) |eval comment=" ■ 내부 사용자 정보 및 자산 정보에서 대응되는 이름이 있는지 확인하고 출력하는 과정 ◆ src_name : src_ip 사용자 또는 서버명" |eval temp=split('src_ip',".") | eval fieldA = mvindex(temp,0) | eval fieldB = mvindex(temp,1) |strcat fieldA "." fieldB ".0.0" IP_range |lookup IP_RANGE.csv IP as IP_range OUTPUT Name as src_range |eval comment=" ■ 출발지IP 대역 참조를 위해 대역대를 적혀있는 룩업에서 정보 가져오기 ◆ src_range : src_ip 대역" |fillnull value="-" |eval compare = if(match(top_src,src_ip),0,1) |where C_sip > avg_dip + stdev_dip * 2.5 AND compare = 1 AND src_name ="-" |eval comment=" ■ 다음 조건에 해당할 경우 비정상적인 통신 - 전주 대비 통신량이 상위 1% (평균+2.5 표준편차) - 전주에 탐지된 상위 통신 IP에 속하지 않는 신규 IP - (상황에 따라 ON/OFF)기존에 등록돼있지 않은 IP" |eval alert = if(C_sip > avg_dip + stdev_dip * 3,"μ+3σ","μ+2.5σ") |eval alert = if(match(origin_fw_type,fw_type),'alert','alert'." / 신규 소스타입") |eval comment=" ■ 특이사항 구분을 위한 설명 출력" |eval 평균대비 = round(C_sip/(avg_dip)*100,0)."%" |eval 기준값대비 = round(C_sip/(avg_dip+2.5*stdev_dip)*100,0)."%" |rename src_ip as 출발지IP, src_name as 출발지명, src_range as 출발지대역, dest_ip as 목적지IP, dest_name as 목적지명, C_sip as 접속회수, dc_sip as 기존접속IP수, fw_type as 방화벽, alert as 주의 |table 주의, 출발지IP, 출발지대역, 목적지IP, 목적지명, 접속회수, 평균대비, 기준값대비, 기존접속IP수, 방화벽
SQL
복사

결과 및 개선 소요

실제로 해당 방식을 통해 내부자가 아닌 IP에서 공격을 목적으로하는 접근을 다수 식별할 수 있었고, 방화벽 설정을 통해 성공적으로 차단했다. 단순한 개념이지만 통계를 활용한 위협헌팅에 집중해야한다는 점을 시사한다.
출발지 정보에 iplocation을 통해 지역 정보를 표현하거나, OSINT API를 연동해 출발지 IP 정보를 추가하는 등 판단 가능한 요소를 함께 추가한다면 좀 더 신속한 위협헌팅이 가능하겠다.

✓ 다른 [탐구생활] 포스트

Pretendard vs SUIT 최고의 한글 고딕 폰트
Design
Pretendard vs SUIT 최고의 한글 고딕 폰트
Design
︎ 더 많은 게시물을 보려면
︎ 작성자가 궁금하면?
 2023. Absolroot all rights reserved.