AXGATE SSL VPN

Download 0
Last updated Jul 20, 2026

AXGATE SSLVPN - 동일 계정 동시 다중 위치 접속

1시간 내 동일 계정이 서로 다른 국가 또는 여러 네트워크(ASN)의 공인 IP에서 VPN 로그인에 성공한 경우를 탐지합니다.

Overview

Priority High
Type Batch
Schedule Every month/Every day/Every hour/Every 30 mins */30 * * * *
Message AXGATE SSLVPN - 동일 계정 동시 다중 위치 접속: $user 계정이 $span_min분 내 국가 $country_cnt개($country_list) / IP $ip_cnt개에서 로그인 성공
Output field order user, span_min, country_cnt, asn_cnt, ip_cnt, country_list, ip_list, first_login_dt, last_login_dt, travel_verdict, req_speed_kmh, move_km, hop_min, _time, evt_country, src_ip
MITRE Techniques T1078
MITRE tactics TA0001 Initial Access· TA0003 Persistence· TA0004 Privilege Escalation· TA0005 Defense Evasion
Referenced objects Network range 내부망 대역3
Origin User proposal 이정표

Query

1table from=$("from") to=$("to") *:SSLVPN_AXGATE 2| search _schema == "axgate-sslvpn-userauth" and action == "login" and lower(result) == "success" 3| matchnet invert=t field=src_ip guid="bb994ca4-1471-4b91-89f2-99a61bd529b5" verify=f 4| lookup geoip src_ip output country as src_country, asn as src_asn 5| stats dc(src_country) as country_cnt, dc(src_asn) as asn_cnt, dc(src_ip) as ip_cnt, 6 values(src_country) as country_list, values(src_ip) as ip_list, 7 min(_time) as first_login_dt, max(_time) as last_login_dt by user 8| search country_cnt >= 2 or asn_cnt >= 3 9| eval span_min = datediff(first_login_dt, last_login_dt, "min") 10| eval country_list = if(isnull(country_list), "", strjoin(", ", country_list)) 11| sort -country_cnt, -asn_cnt 12| join type=left user [ 13 table from=$("from") to=$("to") *:SSLVPN_AXGATE 14 | search _schema == "axgate-sslvpn-userauth" and action == "login" and lower(result) == "success" 15 | matchnet invert=t field=src_ip guid="bb994ca4-1471-4b91-89f2-99a61bd529b5" verify=f 16 | lookup geoip src_ip output country as evt_country, asn as evt_asn, latitude as lat, longitude as lon 17 | search isnull(lat) == false 18 | sort user, _time 19 | prev user, lat, lon, _time 20 | eval move_km = if(user == prev_user and isnull(prev_lat) == false, round(geodist(lat, lon, prev_lat, prev_lon), 0), 0) 21 | eval hop_min = if(user == prev_user and isnull(prev__time) == false, datediff(prev__time, _time, "min"), 0) 22 | eval req_speed_kmh = if(hop_min > 0, round(move_km / (hop_min / 60.0), 0), 0) 23 | eval travel_verdict = case(req_speed_kmh > 1000, "물리적불가능(항공초과)", req_speed_kmh > 300, "이동의심", 1 == 1, "이동가능") 24 | order _time, user, evt_country, move_km, hop_min, req_speed_kmh, travel_verdict, evt_asn, src_ip ] 25| sort -country_cnt, -asn_cnt, user, _time

30분마다 최근 1시간의 사용자 인증 로그를 조회합니다. 내부망 대역(사설 IP)을 제외한 로그인 성공 이벤트를 계정별로 집계하여, 출발지 국가가 2개 이상이거나 출발지 ASN이 3개 이상인 계정을 탐지합니다. span_min은 첫 로그인과 마지막 로그인 사이의 시간(분)입니다. 근거 로그로 해당 계정의 로그인 이벤트를 시간순으로 조인하고, geoip 좌표와 직전 로그인을 비교(prev, geodist)하여 이동 거리(move_km), 시간 간격(hop_min), 필요 이동 속도(req_speed_kmh)를 계산합니다. 필요 속도가 1,000km/h를 넘으면 물리적불가능(항공초과), 300km/h를 넘으면 이동의심으로 travel_verdict에 표시합니다. AXGATE SSL VPN은 로그인 1건이 2개의 레코드로 기록되어 한쪽에만 좌표가 조회될 수 있으므로, 좌표가 있는 레코드만 남긴 뒤 직전 로그인을 비교합니다.

Threat analysis

짧은 시간 안에 물리적으로 이동할 수 없는 거리의 두 위치에서 로그인이 성공하면(불가능 이동) 계정이 탈취되어 정상 사용자와 공격자가 동시에 사용하고 있을 가능성이 높습니다. 여러 사람이 하나의 VPN 계정을 공유하는 경우에도 동일한 패턴이 나타나며, 이는 접근 통제·감사 추적을 무력화하는 정책 위반입니다. travel_verdict가 물리적불가능(항공초과)이면 계정 도용의 강한 근거로 볼 수 있습니다.

False positives

모바일 회선과 유선·Wi-Fi 회선을 번갈아 사용하면 동일 국가 내에서도 ASN이 여러 개로 집계될 수 있습니다. 오탐이 많으면 ASN 조건(asn_cnt >= 3)을 상향하거나 국가 조건만 사용하도록 조정합니다. 해외 로밍, 사설 VPN·프록시 사용, 클라우드 경유 접속은 geoip 위치가 실제 위치와 달라 불가능 이동으로 보일 수 있습니다. geoip 좌표는 국가·도시 단위의 근사값이므로, 가까운 두 지점 사이의 짧은 간격 로그인은 속도가 과대 계산될 수 있습니다. 판정 시 move_km와 hop_min을 함께 확인합니다.

Response actions

근거 로그의 각 로그인 시각·국가·출발지 IP를 확인하고 사용자에게 본인 접속 여부를 확인합니다. 불가능 이동으로 판정되고 본인 접속이 확인되지 않으면 모든 VPN 세션을 종료하고 비밀번호를 초기화합니다. 계정 공유로 확인되면 사용자별 개별 계정 발급과 다중 인증(MFA) 적용을 요청합니다.

No comments yet.