#!/usr/bin/env python # coding: utf-8 # In[1]: import pandas as pd import numpy as np from mlxtend.preprocessing import TransactionEncoder from mlxtend.frequent_patterns import association_rules, fpgrowth from prefixspan import PrefixSpan df = pd.read_csv("ts_data_accident-2020_sample.csv", low_memory=False, encoding='ISO-8859-1') pd.set_option('display.max_columns',None) df=df[['RISK_V2','INST_NM','DRULE_ATT_TYPE_CODE1','TW_ATT_IP','TW_ATT_PORT','TW_DMG_IP','TW_DMG_PORT','ACCD_DMG_PROTO_NM','TW_ATT_CT_NM','ACCD_FIND_MTD_CODE','DRULE_NM']].dropna() len(df) ##################### NTM section ##################### NTM_df=df[df['ACCD_FIND_MTD_CODE']==1] NTM_df # Pick out it in order to get the asset, risk, intent, black IP out RISK_V2=NTM_df['RISK_V2'] RISK_V2_FILTERED=RISK_V2.dropna() ## 결측값 제거. import json from pandas import json_normalize # modified def get_asset_desc(asset_field): if asset_field == 'ASSETS_VAL_1': return '공인-전체IP대역(유선)' elif asset_field == 'ASSETS_VAL_2': return '공인-전체IP대역(무선)' elif asset_field == 'ASSETS_VAL_3': return '공인-WEB서버' elif asset_field == 'ASSETS_VAL_4': return '공인-내부응용서버' elif asset_field == 'ASSETS_VAL_5': return '공인-DB서버' elif asset_field == 'ASSETS_VAL_6': return '공인-패치서버' elif asset_field == 'ASSETS_VAL_7': return '공인-네트워크' elif asset_field == 'ASSETS_VAL_8': return '공인-보안' elif asset_field == 'ASSETS_VAL_9': return '공인-업무용PC' elif asset_field == 'ASSETS_VAL_10': return '공인-비업무용PC' elif asset_field == 'ASSETS_VAL_11': return '공인-기타' elif asset_field == 'ASSETS_VAL_12': return '사설-전체IP대역(유선)' elif asset_field == 'ASSETS_VAL_13': return '사설-전체IP대역(무선)' elif asset_field == 'ASSETS_VAL_14': return '사설-WEB서버' elif asset_field == 'ASSETS_VAL_15': return '사설-내부응용서버' elif asset_field == 'ASSETS_VAL_16': return '사설-DB서버' elif asset_field == 'ASSETS_VAL_17': return '사설-패치서버' elif asset_field == 'ASSETS_VAL_18': return '사설-네트워크' elif asset_field == 'ASSETS_VAL_19': return '사설-보안' elif asset_field == 'ASSETS_VAL_20': return '사설-업무용PC' elif asset_field == 'ASSETS_VAL_21': return '사설-비업무용PC' elif asset_field == 'ASSETS_VAL_22': return '사설-기타' else: return '' def get_intent_desc(intent_field): if intent_field == 'INTENT_VAL_1': return '파괴' elif intent_field == 'INTENT_VAL_2': return '유출' elif intent_field == 'INTENT_VAL_3': return '지연' elif intent_field == 'INTENT_VAL_4': return '잠복' elif intent_field == 'INTENT_VAL_5': return '단순침입' elif intent_field == 'INTENT_VAL_6': return 'MD5' elif intent_field == 'INTENT_VAL_0': return 'Default' else: return '' def get_source_desc(source_field): if source_field=='SOURCE_VAL_1': return '북한IP' if source_field=='SOURCE_VAL_3': return 'ECSC Black IP' else: return '' # New assets column ## ASSETS_VAL을 아예 JSON항목으로 만들어서 새로운 데이터프레임으로 생성. risk_df = pd.DataFrame() for risk in RISK_V2_FILTERED: risk = risk.replace("'", "\"") #json으로 만들려고. json_string = json.loads(risk) json_df = json_normalize(json_string) risk_df = pd.concat([risk_df,json_df],ignore_index=True) #DataFrame 합쳐주기. ignore_index = True를 해야 index가 재구성 된다. risk_df_column_names = risk_df.columns assets_df = [] intents_df = [] sources_df = [] def filter_all(risk): for i in range(0,len(risk)): risks=[] intents=[] sources=[] for column in risk_df_column_names: # filter_asset if 'ASSETS_VAL_' in column and risk.iloc[i][column]: risk_key_desc = 'RISK_V2.' + column + '=' + get_asset_desc(column) risks.append(risk_key_desc) # filter_intent if 'INTENT_VAL_' in column and risk.iloc[i][column]: intent_key_desc = 'RISK_V2.' + column + '=' + get_intent_desc(column) intents.append(intent_key_desc) if 'SOURCE_VAL_' in column and risk.iloc[i][column]: source_key_desc='RISK_V2.' + column + '=' + get_source_desc(column) sources.append(source_key_desc) assets_df.append(risks) intents_df.append(intents) sources_df.append(sources) filter_all(risk_df) ## 여기까지 내가 만든 것. ## ASSETS_VAL 확인 NTM_df['ASSETS_VAL'] = assets_df NTM_df['ASSETS_VAL'] = NTM_df['ASSETS_VAL'].astype(str) NTM_df['ASSETS_VAL'] = NTM_df['ASSETS_VAL'].str.replace('[','',regex=True) NTM_df['ASSETS_VAL'] = NTM_df['ASSETS_VAL'].str.replace(']','',regex=True) # NTM_df['ASSETS_VAL'] NTM_df['INTENT_VAL'] = intents_df NTM_df['INTENT_VAL'] = NTM_df['INTENT_VAL'].astype(str) NTM_df['INTENT_VAL'] = NTM_df['INTENT_VAL'].str.replace('[','',regex=True) NTM_df['INTENT_VAL'] = NTM_df['INTENT_VAL'].str.replace(']','',regex=True) # NTM_df['INTENT_VAL'] NTM_df['SOURCE_VAL'] = sources_df NTM_df['SOURCE_VAL'] = NTM_df['SOURCE_VAL'].astype(str) NTM_df['SOURCE_VAL'] = NTM_df['SOURCE_VAL'].str.replace('[','',regex=True) NTM_df['SOURCE_VAL'] = NTM_df['SOURCE_VAL'].str.replace(']','',regex=True) # NTM_df['SOURCE_VAL'] NTM_df.drop(columns=['RISK_V2'], inplace=True) ##################### 여기서부터 진행하시면 됩니다. ##################### ##################### 아래 12개 아이템(12. 장비 ACCD_FIND_MTD_CODE 제외)에 대해서 모든 아이템 조합에 알고리즘 적용하기##################### # It should be 13 columns in total # 1. 기관 INST_NM # 2. 공격 DRULE_ATT_TYPE_CODE1 # 3. 자산 ASSETS_VAL # 4. 위협공격ip TW_ATT_IP # 5. 위협공격port TW_ATT_PORT # 6. 위협피해ip TW_DMG_IP # 7. 위협피해port TW_DMG_PORT # 8. 위협피해프로토콜 ACCD_DMG_PROTO_NM # 9. 공격국가 TW_ATT_CT_NM # 10. 의도(7개) INTENT_VAL # 11. IP/URL 가중치 SOURCE_VAL # 12. 장비 ACCD_FIND_MTD_CODE # 13. 탐지규칙명 DRULE_NM NTM_df.isna().sum() # Change the Nan to zero NTM_df['ACCD_DMG_PROTO_NM']=NTM_df['ACCD_DMG_PROTO_NM'].replace(np.nan,'') NTM_df['INST_NM']=NTM_df['INST_NM'].replace(np.nan,'') NTM_df['DRULE_ATT_TYPE_CODE1']=NTM_df['DRULE_ATT_TYPE_CODE1'].replace(np.nan,'') NTM_df['TW_ATT_IP']=NTM_df['TW_ATT_IP'].replace(np.nan,0) NTM_df['TW_ATT_PORT']=NTM_df['TW_ATT_PORT'].replace(np.nan,0) NTM_df['TW_DMG_IP']=NTM_df['TW_DMG_IP'].replace(np.nan,0) NTM_df['TW_DMG_PORT']=NTM_df['TW_DMG_PORT'].replace(np.nan,0) NTM_df['TW_ATT_CT_NM']=NTM_df['TW_ATT_CT_NM'].replace(np.nan,'') NTM_df['ASSETS_VAL']=NTM_df['ASSETS_VAL'].replace(np.nan,0) NTM_df['INTENT_VAL']=NTM_df['INTENT_VAL'].replace(np.nan,0) NTM_df['SOURCE_VAL']=NTM_df['SOURCE_VAL'].replace(np.nan,0) NTM_df['DRULE_NM']=NTM_df['DRULE_NM'].replace(np.nan,'') # Check NaN out again NTM_df.isna().sum() # # Merge all # # Make one string from all of elements NTM_df['Combined']=NTM_df['INST_NM'].astype(str)+' '+NTM_df['TW_ATT_IP'].astype(str)+' '+NTM_df['TW_ATT_PORT'].astype(str)+' '+NTM_df['TW_DMG_IP'].astype(str)+' '+NTM_df['TW_DMG_PORT'].astype(str) +' '+NTM_df['ACCD_DMG_PROTO_NM'].astype(str)+' '+NTM_df['TW_ATT_CT_NM']+' '+NTM_df['ASSETS_VAL']+' '+NTM_df['INTENT_VAL']+' '+NTM_df['SOURCE_VAL']+' '+NTM_df['DRULE_ATT_TYPE_CODE1']+' '+NTM_df['DRULE_NM'] NTM_com=NTM_df['Combined'] ## 내가 만든 컴바인 ## 모든 조합을 돌릴거면, [1,2,3,4,5] 처럼 배열의 원소로 만들어서 넣는게 가장 베스트 아닌가. ## 그런데 순서를 다 바꿔줘야 하는데, 그건 어떻게 할 것인지 내일 물어보자. data_len = len(NTM_df) hwan_list = [] for i in range(0,data_len): accd_dmg_proto_nm = NTM_df.loc[i]['ACCD_DMG_PROTO_NM'] inst_nm = NTM_df.loc[i]['INST_NM'] drule_att_type_code1 = NTM_df.loc[i]['DRULE_ATT_TYPE_CODE1'] tw_att_ip = NTM_df.loc[i]['TW_ATT_IP'] tw_att_port = NTM_df.loc[i]['TW_ATT_PORT'] tw_dmg_ip = NTM_df.loc[i]['TW_DMG_IP'] tw_dmg_port = NTM_df.loc[i]['TW_DMG_PORT'] tw_att_ct_nm = NTM_df.loc[i]['TW_ATT_CT_NM'] assets_val = NTM_df.loc[i]['ASSETS_VAL'] intent_val = NTM_df.loc[i]['INTENT_VAL'] source_val = NTM_df.loc[i]['SOURCE_VAL'] drule_nm = NTM_df.loc[i]['DRULE_NM'] null_check_list = [accd_dmg_proto_nm, inst_nm, drule_att_type_code1, tw_att_ip, tw_att_port, tw_dmg_ip, tw_dmg_port, tw_att_ct_nm, assets_val, intent_val, source_val, drule_nm] not_null_arr = [] ## 리스트안에 빈 값을 빼버리자. for item in null_check_list: if item and item != '[]': not_null_arr.append(item) hwan_list.append(not_null_arr) new_ps = PrefixSpan(hwan_list) # new_ps : hwan_list안에 순서대로 null값을 제외한 모든값들이 [1,2,3,4,5,6] 이런식으로 들어가 있는데, # 이 값을 PrefixSpan 수행한 코드. ## 여기도 내 코드 test_ntm = new_ps.frequent(1) test_ntm_df = pd.DataFrame(test_ntm) test_ntm_df.rename(columns={0:'Frequency', 1:'Cause'}, inplace=True) print(test_ntm_df) test_sort_values = test_ntm_df.sort_values(by=['Frequency'],ascending=False,ignore_index=True) # test_sort_values : PrefixSpan을 수행하여 Frequency가 나온 값. Frequency 를 기준으로 정렬했는데, 2900만가지나 된다. # Effect Rule Name Case 1. prefix_NTM_df = test_sort_values for i in range(0,len(prefix_NTM_df)): drules=['Attack','DDOS','HACK','MAIL','Malwr','WEB'] for drule in drules: if drule in prefix_NTM_df.Cause[i]: prefix_NTM_df.Effect[i] = drule elif prefix_NTM_df.Cause[i] == NaN: prefix_NTM_df.Effect[i] = '' # Effect Rule Name Case 2. prefix_NTM_df = test_sort_values for i in range(0,len(prefix_NTM_df)): drules=['Attack','DDOS','HACK','MAIL','Malwr','WEB'] for drule in drules: iloc_value = prefix_NTM_df.iloc[i]['Cause'] if drule in iloc_value: prefix_NTM_df.Cause[i] = drule # Case 1을 20분동안 돌렸는데도 결과가 나오질 않아서 iloc으로 바꾸어 Case2로 돌려보았다. 이것도 오래걸리는 중.. # Rule Name 적용한 코드는 prefix_NTM_df 에 적용.