1. 程式人生 > >networkx學習與攻擊轉移圖視覺化

networkx學習與攻擊轉移圖視覺化

接到一個任務,將攻擊轉移矩陣進行視覺化,生成攻擊轉移概率圖,便嘗試用python實現一下。

查閱資料,看大家都在用networkx和matplotlib進行視覺化,便邊學邊做,記錄一下學習筆記。

任務:將手裡了多個攻擊過程,如圖1所示,生成為攻擊轉移模型,如圖2所示

圖1:

 

圖2:


 

 

 

 

 

 

 

 

 

 

 

 

 

由於直接畫圖節點過多,於是對節點進行了對映。

過程

首先讀取檔案並以列表的形式表示:

f1 = open(path,'r')
list_lines = []
while True:
    line = f1.readline()
    if line:
        list_line = line[0:-1].split(',')#去掉回車符'\n'
        list_lines.append(list_line)
    else:
        break

 

然後讀取對映檔案,用字典儲存,方便後面的對映:

其格式如圖

#讀取對應檔案
fk = open('./killlinesort.txt','r')
dict_kill = {}
while True:
    linek = fk.readline()
    if linek:
        spilt_line = linek.split(' level')
        dict_kill[spilt_line[0]] = spilt_line[1].split(',')[1][0:-1]
    else:
        break

現在初始化轉移矩陣並統計轉移次數,最終得到轉移概率矩陣,這一步便開始進行對映

 

attack = []
for key in dict_kill:
    if dict_kill[key] not in attack:
        attack.append(dict_kill[key])
Matrix_tmp = pd.DataFrame(0, columns=attack, index=attack)
#計算轉移次數
for i in list_lines: #讀取攻擊過程
for index in range(len(i)-1):
fT = dict_kill[i[index]]
nT = dict_kill[i[index+1]]
if fT == nT:
continue
else:
Matrix_tmp[nT][fT] = Matrix_tmp[nT][fT] + 1
Matrix_P = Matrix_tmp.div((Matrix_tmp.apply(sum,axis=1)),axis=0).fillna(0)#計算轉移概率

 

由於我的對映檔案中的攻擊名稱比,要分析的那幾個攻擊過程中的攻擊名稱多,,有些節點之間沒有關係,所以要去掉孤立的節點

#去掉孤立的節點
attack1 = []
for i in attack:
    row = Matrix_P.loc[:,i].values[0:]
    columns1 = Matrix_P.loc[i,:].values[0:]
    if sum(row) == 0 and sum(columns1) == 0:
        continue
    else:
        attack1.append(i)#其中是對映完並去掉孤立節點以後的攻擊節點

為了方便接下來節點與邊進行對應,並且儲存轉移概率,用字典進行儲存源節點,目的節點,概率

#將轉移概率矩陣轉換成三元組用字典儲存
dict_tup = {}
final_attack = []#最後一步攻擊
for fattack in attack1:  # lines是行名也是源節點
    Max_P_Array = Matrix_P.loc[fattack].values[0:]
    if sum(Max_P_Array) == 0:
        final_attack.append(fattack)#記錄下每個攻擊過程的最後一步攻擊,作為廣度優先遍歷的起始點
    col_list = Matrix_P.columns.values.tolist()
    count = 0
    for values in Max_P_Array:
        if values <= 0:#篩選邊
            count += 1
            continue
        else:
            columns = col_list[count]#目的節點
            count += 1
            key = fattack + ',' + columns#結構為{‘源攻擊節點,目的攻擊節點’:轉移概率}
            dict_tup[key] = values

通過上述的資料處理和簡單的分析,得到需要的三元組,接下來將三元組進行視覺化

視覺化

在視覺化的任務中,由於邊和點的數量比較多,在嘗試了自帶的幾種佈局之後效果很差,於是決定自己定位每個節點的位置

通過不斷不斷不斷不斷不斷的嘗試,根據攻擊過程多步轉移的特點,最終採用廣度優先遍歷節點,為節點在圖中安放位置,將每輪遍歷的節點放在同一層

#遍歷有所節點
def findallnode(node_list,Matrix_P,pos_num):
    before_nodes = []#上一步的攻擊節點
    row_num = 1
    pos_count = 1
    for n in node_list:
        tran_p = Matrix_P.loc[:,n].values[0:]
        count = 0
        for i in tran_p:
            if i <= 0:
                count += 1
                continue
            else:
                before = attack[count]
                count += 1
                if not before in G.nodes:
                    before_nodes.append(before)
                    G.add_node(before,pos = (pos_count*5,(pos_num*5+((-1)**row_num)*3)))
                    #pos的位置可以認為是一個座標,同層節點之間間隔5,由於有些同層節點之間也有關係,擔心重合遮擋,所以y軸座標進行錯位
                    row_num += 1
                    pos_count += 1
    pos_num += 1
    #進行迭代,直到所有的節點都被遍歷,G.node的型別是list
    if (len(list(set(attack1)-set(G.nodes))) != 0):
        findallnode(before_nodes, Matrix_P, pos_num)

num = 1
#確定初始引數 for i in final_attack: G.add_node(i,pos = (num*10,0)) num+=1 findallnode(final_attack,Matrix_P,pos_num=1)

確定完節點位置之後將邊新增進去,對之前生成的字典進行遍歷,為每個邊新增概率值

#新增有向邊
for key in dict_tup:
    value = round(dict_tup[key],3)
    #print(value)
    list_key = key.split(',')
    list_key.append(value)
    tup = tuple(list_key)#得到三元組
    G.add_edge(str(tup[0]),str(tup[1]),p=tup[2])
pos=nx.get_node_attributes(G,'pos')#這個函式能一字典的形式儲存每個節點的座標
#pos結果為
{'DOWNLOAD FILE': (10, 0), 'keep connect': (20, 0), 'DIRECTORY discovery': (5, 2), 'FILE OPERATION': (10, 8), 'Password attacks': (15, 2), 
'Vulnerability exploit': (20, 8), 'Initial Access': (25, 2), 'UPLOAD FILE': (30, 8), 'WEBSHELL': (35, 2), 'DDOS': (5, 7), 'Command and Control': (10, 13),
'INFORMATION DISCLOSURE': (15, 7), 'ERROR OCCUR': (5, 12), '.': (0, 0)}

接著就是作圖,將節點和邊都畫出來

nx.draw_networkx_nodes(G, pos, node_size=50, node_color='gray')#將節點畫出,各個引數可以查詢關方文件,選擇需要的
nx.draw_networkx_edges(G, pos, width=1.5,arrowstyle='->',arrowsize=10,alpha=0.5,)#畫出邊
nx.draw_networkx_edge_labels(G,pos,label_pos=0.35,font_size=5,font_weight='bold')#label_pos是轉移概率在邊上的位置,font_weight中bold為加粗,預設是正常

由於文字比較多,無法在節點中展示,所以在節點上面進行展示

#由於pos中的座標是以元組的形式展示,而元組不能修改,所以先轉成list再進行替換
for key in pos:
    list_loc = list(pos[key])
    list_loc[1] += .7#上移的值,根據實際情況修改
    pos[key] = tuple(list_loc)
nx.draw_networkx_labels(G,pos,font_size=8,alpha=0.8)#畫出攻擊型別名稱

最後,生成檔案

#plt.show()#show()和savefig不能同時存在,不然生成的檔案是白板

plt.savefig('./****.png',pad_inches=20,dpi=300)#具體引數可以上網查詢

 

 

-----------------------------------------------------------------------------------------------------------------------------------------

參考資料

https://zhuanlan.zhihu.com/p/36700425

https://www.osgeo.cn/networkx/auto_examples/drawing/plot_weighted_graph.html#sphx-glr-auto-examples-drawing-plot-weighted-graph-py