-
침입 감지 시스템 (IDS: Intrusion Detection System)application 2025. 1. 4. 13:18
시작하기 전에
사이버 보안은 매우 중요한 주제다. "자동차" 사이버 보안은 사생활, 재산, 안전, 생명에 직접적인 위협이 될 수 있다.
자동차가 무선 통신으로 연결되는 네트워크가 증가할 때마다 더 많고 더 다양한 보안 위협에 노출된다. 차량 내외부의 시스템들 사이에 통신을 통한 협조 제어가 증가할수록 사고 피해의 심각성이 커질 위험이 증가할 개연성이 있다. 통신에 대한 적절한 보안이 필요하다.
통신 보안은 침입 감지부터 시작한다고 말해도 무방할 것이다. TSMaster로 CAN 통신 침입 감지 기능을 만들어본다.
[참고] 최신 차량들에는 침입 감지 시스템(IDS: Intrusion Detection System)이 장착되어 있다.
개요
- IDS 구상
- 트레이스 분석
- IDS 미니프로그램 코딩
- 침입 판정 기준값 데이터 준비
- 작동 확인
IDS 구상
- 아래의 기능들을 컨셉 수준에서 구현한다.
- 화이트 리스트 점검
- 메시지 길이 점검
- 메시지 전송 주기 점검
- 전송 주기가 일정한 메시지들이 대상이다. 이벤트가 발생할 때 전송되는 소위 이벤트 메시지들에는 전송 주기 점검이 무의미 하고 오히려 오감지의 우려가 있다.
- 대표적인 이벤트 메시지는 진단 통신 메시지다. 진단 통신 메시지의 침입 감지는 메시지의 내용을 확인하는 방식을 적용해야 한다.
- 위 기능들 외에도 다양한 점검 아이디어가 있다. 나는 CAN 통신 사양서나 진단 통신 사양서 같은 참고할 자료를 갖고 있지 않다. (다행이다. ^^) 내게는 침입이 없는 상태(내 오해일 수 있다.)의 내 차에서 받은 3분 30초 가량의 CAN 트레이스가 있다. 이를 참고 자료로 이용한다.
트레이스 분석
- 아래 순서로 분석했다.
- blf 파일을 asc 파일로 변환한다. (blf 파일을 직접 다룰 줄 알았다면 변환하지 않았을 것이다.)
- 원본 asc 파일을 메시지 아이디(m_id)별로 분리한 m_id.asc 파일들을 만든다.
- m_id별 전송 주기 분석
- CAN은 메시지 아이디로 우선 순위가 정해진다. 여러 메시지들이 동시에 버스를 사용하려고 할 때, 아이디가 낮은 메시지가 먼저 전송된다. 버스 사용 경쟁이 치열한 경우, 높은 메시지 아이디의 메시지는 전송이 지연될 수 있다. 다음 전송되는 메시지 기준으로 주기가 짧아 지는 효과가 생긴다.
- 메시지 전송 주기 변동폭이 (상대적으로) 큰 제이기들도 있다.
- 이런저런 이유로 전송 주기가 짧아진 하지만 정상적으로 전송된 메시지들을 침입으로 감지하지 않도록 전송 주기 점검 기준을 설정하기 위해 전송 주기 분석이 필요하다.
- 칩입이 있으면 메시지 전송 주기는 짧아진다.
- m_id별 전송 주기 분석을 위해 asc 파일을 분석한다. 분석하기 위해 수치 데이터 처리에 편리한 pandas를 사용할 것이다. asc를 pandas의 데이터프레임으로 변환해야 한다.
- 위 분석 과정 중에 발견한,
- m_id들로 화이트 리스트를 만든다.
- m_id별 데이터 길이 (dlc: data length code)를 정한다.
blf를 asc로 변환하기
- 메인 메뉴/ Analysis/ Log Converter 버튼을 클릭하여 TS Log Converter 창을 연다.
- Source File을 선택한 후, Destination File에서 ASC 아이콘을 클릭한 후, Convert 버튼을 클릭하여 변환한다.
- 내가 사용한 blf 파일을 첨부한다.
asc 파일을 m_id별로 분리하기
- 아래 링크의 주피터 노트북에서 시도한 방법으로 asc 파일을 m_id별로 분리 저장하였다.
- 트레이스를 이용한 RBS(Remaining Bus Simulation) :: hsl's tsmaster 사용기에서 ai가 작성한 코드를 활용하였다.
- asc 파일을 m_id별로 분리하기 :: hsl's tsmaster 사용기
asc 파일을 pandas 데이터프레임으로 변환하기
- 아래 링크의 주피터 노트북에서 시도한 방법으로 m_id별로 분리된 asc 파일을 pandas 데이터프레임으로 변환하였다.
- asc 파일을 pandas 데이터프레임으로 변환하기 :: hsl's tsmaster 사용기
전송 주기 분석
- 아래 링크의 주피터 노트북에서 시도한 방법으로 메시지 전송 주기를 분석하였다.
- CAN 메시지 전송 주기 분포 분석 :: hsl's tsmaster 사용기
IDS 미니프로그램 코딩
- 침입 감지 규칙들이 간단하여 코드도 간단하다. 코드 중간에 커멘트들이 충분한 설명이 되리라 생각한다.
- 메시지를 수신할 때마다 침입 메시지 여부를 확인한다.
- 침입 여부는 화이트 리스트, dlc, 전송 주기로 판정한다.
# CODE BLOCK BEGIN Global_Definitions from TSMaster import * # 침입 감지 판정 기준 전송 시간을 트레이스 파일을 분석해서 메시지별로 구했다. # 이 데이터를 미니프로그램에서 쉽게 불러올 수 있도록 파일에 저장했다. # 파이썬에서 변수를 저장하고 불러오는데 자주 사용되는 pickle 모듈을 이용한다. import pickle # 데이터 파일이 저장되어 있는 경로를 쉽게 참조하기 위해서 pathlib 모듈을 이용한다. from pathlib import Path # 데이터 파일에는 아래 정보가 들어있다. # white list용 메시지 아이디(m_id): 등록된 m_id가 아니면 침입으로 판정한다. # dlc: data length code. dlc가 다르면 침입으로 판정한다. # d_ts_min: 전송 주기가 이 값보다 작으면 침입으로 판정한다. # d_ts: ts의 diff라는 의미다. = 메시지 전송 간격 # ts: timestamp # ts_last: 마지막 메시지의 ts이다. # dlc, d_ts_min, ts_last는 모두 m_id별로 있다. # m_id를 키(key)로하는 사전형 변수 x를 정의하였다. # 예) # x[m_id][dlc] = 8 m_id 메시지의 dlc는 8 바이트이다. # x[m_id][d_ts_min] = 0.08 m_id 메시지의 침입 판정을 위한 최소 전송 간격은 d_ts_min이다. # x[m_id][ts_last] = ts m_id 메시지가 마지막으로 수신된 시간은 ts이다. # 변수 x를 pickle 파일에서 로드한다. path_to_pickle = Path(r'C:\data\tosun\projects\CySec_IDS\MiniProgram\PySrc')/'x.pkl' x = pickle.load(open(path_to_pickle, 'rb')) # 프로그램 사용과 관계된 파라미터이다. # 혹시 설명이 궁금하다면 ... # IDS 미니프로그램을 실행하고 온-라인 재생을 여러 번 하는 경우가 종종 생긴다. # 온-라인 재생이 종료되자마자 다음 온-라인 재생을 하기보다는 # 잠시 결과를 분석을 하고 온-라인 재생을 하는 경우가 대부분이다. # 미니프로그램 실행 중이라서 타이머는 계속 작동한다. # 다음 재생의 첫 메시지 수신 시각과 지난 재생의 마지막 메시지 수신 시각 차이가 크다. # 이런 경우 처리를 위해, 메시지 수신 간격이 아래 값 이상이면 ts_last를 초기화 한다. k_usec_skip_detection = 5_000_000 def detect_intrusion(ACAN: RawCAN) -> None: ''' 침입을 감지한다. ''' global x global k_usec_skip_detection # TSMaster에서 오프-라인 재생 중에 미니프로그램을 작동하는 경우와 # 온-라인 재생 중에 작동하는 경우가 있다. # 오프-라인 재생을 할 경우, CH1만 사용한다. # 온-라인 재생을 하는 경우, CH1은 Tx, CH2는 Rx이다. # 온-라인(is_connected()가 참)이고 채널이 Tx 채널이면 통과한다. # 오프-라인이면 채널을 따질 필요가 없다. if (app.is_connected()) and (ACAN.idx_chn == CH1): return # 메시지를 접수한 현재 시각 # 우선 ts를 저장한다. 연산 차이에 의한 영향을 배제하려고. ts = app.get_timestamp_us() # 화이트 리스트에 없는 메시지면 침입으로 감지한다. if ACAN.id not in x: app.log_text(f'{ACAN.id:x} not in white list', lvlOK) return # 메시지 길이가 맞지 않으면 (길거나 짧으면) 침입으로 감지한다. if ACAN.dlc != x[ACAN.id]['dlc']: app.log_text(f'{ACAN.id:x} wrong dlc', lvlOK) return # d_ts를 계산한다. if x[ACAN.id]['ts_last'] == 0: # 첫 메시지 수신: d_ts를기준값으로 한다. # 침입 감지가 안 된다. d_ts = x[ACAN.id]['d_ts_min'] else: d_ts = ts - x[ACAN.id]['ts_last'] # ts_last를 업데이트한다. x[ACAN.id]['ts_last'] = ts # 프로그램을 종료하지 않은 채로 한참 있다가 재생할 경우, # 첫 메시지의 d_ts 계산이 부정확한 경우가 발생한다. (변수의 범위를 넘어서) # 이런 오류 방지를 위해서, d_ts가 기준 이상이면 # x[ACAN.id]['ts_last']만 업데이트하고 침입 감지를 하지 않는다. if (d_ts > k_usec_skip_detection) or (d_ts < 0): # 5sec를 넘으면 # ts_last는 위에서 업데이트를 했다. return # d_ts가 기준보다 작으면, 즉, 메시지 간격이 너무 좁으면, 침입으로 감지한다. if d_ts < x[ACAN.id]['d_ts_min']: app.log_text(f'{ACAN.id:x} d_ts too short d_ts={d_ts:,} d_ts_min={x[ACAN.id]["d_ts_min"]:,}', lvlOK) return # CODE BLOCK END Global_Definitions # CODE BLOCK BEGIN Instance Instance = MpInstance('intrusion_detection') # CODE BLOCK END Instance # CODE BLOCK BEGIN On_CAN_Tx any MCwtMSwtMQ__ def on_can_tx_any(ACAN: RawCAN) -> None: # 오프-라인 재생 시에 메시지는 Tx된다. detect_intrusion(ACAN) # CODE BLOCK END On_CAN_Tx any # CODE BLOCK BEGIN On_CAN_Rx any MCwtMSwtMQ__ def on_can_rx_any(ACAN: RawCAN) -> None: # 온-라인 재생 시에 메시지는 Rx된다. detect_intrusion(ACAN) # CODE BLOCK END On_CAN_Rx any
침입 판정 기준값 데이터 준비
- 아래 링크의 주피터 노트북에서 시도한 방법으로 침입 판정 기준값 데이터를 준비하였다.
- 데이터를 x.pkl 파일에 저장한다. 위에 설명한 미니프로그램에서 로드하는 파일이다.
- x.pkl 파일을 미니프로그램에서 정한 경로에 복사한다.
- 침입 판정 기준값 데이터 준비 :: hsl's tsmaster 사용기
작동 확인
- 온-라인으로 재생하며 IDS 작동을 확인하기 위해 CAN 채널이 두 개 있는 TC1013 하드웨어를 이용한다. 채널 1으로 메시지들을 전송한다. 채널 2는 수신이다.
- Y-케이블을 이용하여 채널 1과 채널 2가 분기되어 있다. 채널 1과 2들 연결하기 위해 DB9 점프 케이블을 이용하였다. CAN H는 CAN H끼리 CAN L는 CAN L끼리 연결한다.
- TC1013의 하드웨어 설정에서 채널 1과 채널 2에 Termination Resistor를 적용하였다. (하드웨어 설정 방법은 CAN 트레이스 받기 - 하드웨어 설정 :: hsl's tsmaster 사용기를 참조하십시오.)
- 침입 메시지 전송을 위하여, CAN Transmit을 준비한다.
- 메인 메뉴/ Analysis/ Transmit 버튼을 클릭하여, CAN / CAN FD Transmit 창을 연다.
- 메시지를 추가하는 봉투에 + 기호가 있는 버튼을 클릭한다.
- Id와 DLC를 입력한다. 나는 아래 그림의 메시지들을 준비했다.
- 0x123과 0x345는 화이트 리스트에 없는 메시지이다. 이 메시지들을 전송하면 'not in white list' 검출이 되야한다.
- 0x220은 화이트 리스트에 있는 메시지다. DLC를 6과 8로 각각 준비했다. 6이 정상 DLC이다.
- DLC가 6인 정상 0x220 메시지를 전송하면 'd_ts too short' 검출이 되야한다.
- DLC가 8인 비정상 0x220 메시지를 전송하면 'wrong dlc' 검출이 되야한다.
- 메시지와 같은 행에 있는 삼각형 버튼을 클릭하면 해당 메시지가 전송된다.
- 미니프로그램을 컴파일하고 실행한다.
- blf 파일을 온-라인 재생한다.
- IDS 미니프로그래밍의 작동 모습은 아래 비디오에 보이는 것과 같다.
- 화이트 리스트, dlc, 전송 주기를 기준으로 침입 메시지들을 감지한다.
- 적지 않은 메시지들을 오감지한다.
- 비디오를 녹화할 때 평소 보다 수 배 오감지가 많았다. 비디오 녹화를 병행하면 컴퓨터에 부하가 커지면서 TSMaster가 평소보다 메시지 전송 주기를 정확하게 재현하지 못한 영향이 있을 것으로 짐작한다.
- 주로 0x300번대 메시지들이 오감지 되었다. 왜 그럴까?
- 의문에 관해서 약간 생각해봤다.
- IDS 오감지/ 민감 감지에 관한 고찰 :: hsl's tsmaster 사용기
결론
- TSMaster로 간단한 규칙의 IDS를 구현해보았다.
- IDS는 침입을 빠뜨리지 않고 감지하는 것이 중요한 만큼 정상 메시지를 오감지 하지 않는 것도 중요하다. 오감지 방지를 위해서 감지 조건을 느슨하게 해야한다. 그러면 침입 감지가 느슨해질 위험이 있다. 최적의 감지 성능을 위해 알고리즘들이 추가되어야 한다. (이것은 TSMaster 데모의 영역 바깥이다.)
- (모든 개발이 그렇듯이) IDS 개발은 단지 미니프로그램 개발에 국한되지 않는다. 데이터 처리를 위한 툴-체인 개발이 함께 필요하다.
추가
- 오감지 건수가 내 예상보다 많았다. 보다 정확한 타임스탬프를 사용하여 오감지 건수를 줄이는 방법을 찾아보았다.
'application' 카테고리의 다른 글
차량 형상 점검 (0) 2025.01.19 주행 중인 도로의 경사도 구하기 1/t.b.d. (1) 2025.01.15 침입 감지 시스템 (IDS) - 타임스탬프 보완 (0) 2025.01.05 CAN 데이터로 제동 성능 평가하기 (0) 2024.10.25