IDS 오감지/ 민감 감지에 관한 고찰
- IDS 미니프로그램이 잘 작동한다.
- 0x300번대 메시지들은 침입이 아닌데도 주기 기반 침입 감지가 발생한다.
- 혹시 0x300번대에 메시지들이 다른 번호대 메시지들 보다 많나? 그래서 전송 지연이 연쇄 작용을 일으키나? 하는 의문이 생겼다.
import pandas as pd
from pathlib import Path
import pickle
import plotly.express as px
import plotly.graph_objects as go
# 메시지별 d_ts 통계값을 저장한 xlsx 파일을 읽는다.
xlsx_d_ts_distribution = Path.cwd() / 'd_ts_distribution.xlsx'
df = pd.read_excel(xlsx_d_ts_distribution, sheet_name='Sheet1', header=0, index_col=0)
df.head(3)
|
count |
mean |
std |
min |
25% |
50% |
75% |
max |
042.asc |
384 |
0.999332 |
0.000104 |
0.999062 |
0.999282 |
0.999332 |
0.999387 |
0.999562 |
043.asc |
384 |
0.999332 |
0.000104 |
0.999062 |
0.999282 |
0.999332 |
0.999387 |
0.999561 |
044.asc |
387 |
0.991565 |
0.083612 |
0.040136 |
0.999277 |
0.999332 |
0.999386 |
0.999561 |
# index 컬럼을 m_id로 이름을 변경한다.
df = (
df.reset_index()
.rename(columns={'index': 'm_id'})
)
# m_id(message id)를 hex로 변환한다.
df['m_id'] = (
df['m_id']
.apply(lambda x: x.replace('.asc', ''))
.apply(lambda x: int(x, base=16))
.apply(lambda x: hex(x))
)
# 메시지를 자주 전송할 수록 큰 값을 가지도록 하고 싶다. 따라서 freq를 추가한다.
df['freq'] = 1 / df['mean']
df.head(3)
|
m_id |
count |
mean |
std |
min |
25% |
50% |
75% |
max |
freq |
0 |
0x42 |
384 |
0.999332 |
0.000104 |
0.999062 |
0.999282 |
0.999332 |
0.999387 |
0.999562 |
1.000669 |
1 |
0x43 |
384 |
0.999332 |
0.000104 |
0.999062 |
0.999282 |
0.999332 |
0.999387 |
0.999561 |
1.000669 |
2 |
0x44 |
387 |
0.991565 |
0.083612 |
0.040136 |
0.999277 |
0.999332 |
0.999386 |
0.999561 |
1.008507 |
# 앞에서 저장해두었던 m_id별 dlc 변수를 로드한다.
id_dlc = pickle.load(open('id_dlc.pkl', 'rb'))
# id_dlc를 df로 만든다.
df_dlc = pd.DataFrame(data=id_dlc.items(), columns=['m_id', 'dlc'])
# m_id를 hex로 변환한다.
df_dlc['m_id'] = df_dlc['m_id'].apply(lambda x: hex(x))
df_dlc.head(3)
|
m_id |
dlc |
0 |
0x42 |
8 |
1 |
0x43 |
8 |
2 |
0x44 |
8 |
# df와 df_dlc를 merge한다.
df = pd.merge(df, df_dlc, on='m_id', how='left')
df.sample(5)
|
m_id |
count |
mean |
std |
min |
25% |
50% |
75% |
max |
freq |
dlc |
58 |
0x5fa |
384 |
1.000835 |
0.001151 |
0.996349 |
1.000083 |
1.000736 |
1.000854 |
1.006901 |
0.999166 |
8 |
17 |
0x2b0 |
38394 |
0.010000 |
0.000136 |
0.007685 |
0.009983 |
0.010001 |
0.010015 |
0.012318 |
99.998823 |
6 |
39 |
0x500 |
3840 |
0.099983 |
0.000646 |
0.094257 |
0.099979 |
0.099984 |
0.100027 |
0.105708 |
10.001725 |
1 |
42 |
0x50c |
3839 |
0.100001 |
0.000518 |
0.096297 |
0.099983 |
0.100002 |
0.100023 |
0.103706 |
9.999922 |
8 |
28 |
0x38d |
19188 |
0.020010 |
0.000495 |
0.014686 |
0.019987 |
0.020005 |
0.020022 |
0.025327 |
49.974235 |
8 |
통신 부하를 시각화한다.
# 전송을 자주(freq)하면 할 수록 통신 부하에 차지하는 비중이 크다.
# 길이(dlc)가 길 수록 통신 부하에 차지하는 비중이 크다.
# 통신 부하를 나타내는 load_com을 정의한다.
df['load_com'] = df['freq'] * df['dlc']
# m_id가 hex로 되어있어 그래프에 m_id간 간격이 제대로 반영되지 않는다.
# m_id를 int로 변환한다.
df['m_id_int'] = df['m_id'].apply(lambda x: int(x, base=16))
fig = px.bar(
df,
x='m_id_int',
y='load_com',
hover_data=['m_id'],
title='통신 하중'
)
fig.update_layout(
xaxis = dict(
tickmode = 'array',
tickvals = df['m_id_int'],
ticktext = df['m_id']
),
height=600,
)
fig.show()
- 0x100번대, 0x200번대, 0x300번대 메시지들이 freq도 높고, dlc도 커서 통신 부하에 미치는 영향이 크다.
- 0x300번대 메시지들이 0x100번대 0x200번대 메시지들에 비해 많고 빽빽하게 인접하여 있다.
- 이런 시각화는 유용할 수 있을 것 같다.
가설
- 0x300번대 메시지들은 통신 부하에 미치는 영향도 크고 촘촘히 분포되어 있다.
- 0x300번대 메시지들은 0x100번대, 0x200번대 메시지들 보다 우선 순위가 낮다.
- 0x300번대 메시지들은 CAN 버스를 점유하기 위한 조정이 치열하고, 전송 지연이 발생할 가능성이 상대적으로 크다.
- 그래서 전송 주기가 상대적으로 들쭉날쭉하기 쉬운 것이 아닌가? 그래서 침입으로 오감지 되는 경우가 0x100번대와 0x200번대 메시지들에 비해서 잦은 것은 아닌가?
- 나는 이 가설을 증명하기 위해서 노력할 생각은 없다.
추가 고찰
인접 m_id 사이의 거리
- 인접 m_id 사이의 거리가 가까우면 CAN 버스 점유 조정에 시간이 지연이 늘어난다.
df['m_id_distance_up'] = df['m_id_int'].diff().fillna(0)
df['m_id_distance_down'] = df['m_id_int'].diff(-1).fillna(0)
px.scatter(
df,
x='m_id',
y=['m_id_distance_up', 'm_id_distance_down'],
title='인접 m_id간 거리'
)
- m_id 간격을 고려한 통신 부하 바 차트에서 시각화한 것을 다른 측면에서 본 것이다
- m_id 간격과 지연 시간을 함께 표시하면 뭔가 의미있는 관계를 볼 수 있을 수도 있겠다.
주기 대비 변동폭 비율
df['r_var_width'] = (df['max'] - df['min']) / df['mean']
px.bar(
df,
x='m_id',
y='r_var_width',
title='주기 대비 주기 변동폭 비율'
)
- 예상했던 것보다 주기 대비 변동폭이 비율이 높다. 통신 하중이 높은 0x100 - 0x300번대 메시지들의 비율이 평균 30%는 되는 것 같다.
- CAN이 이래서 deterministic 하지 않고, 그점이 기능 안전 관점에서 우려의 대상이 되는구나.
m_id 간격 vs 주기 대비 변동폭 비율
df['band'] = df['m_id_int'].div(256).round().astype(int).astype('category')
px.scatter(
df,
x='m_id_distance_up',
y='r_var_width',
hover_data=['m_id'],
color='band',
size='load_com',
title='인접 m_id간 간격 vs 주기 대비 주기 변동폭 비율',
height=800,
)
- 0x300번대 메시지들이 인접 메시지 아이디간 간격(m_id_distanc)은 작고, 전송 주기 변동 폭(r_var_width)은 크고 마커의 크기 (load_com)는 클 것이라고 기대했다.
- 셋 사이의 명확한 상관 관계를 찾지 못하겠다.