數(shù)據(jù)分析與可視化:誰是安全圈的吃雞第一人
放假和小伙伴們打了幾把PUBG,大半年沒碰,居然也意外地躺著吃了次雞。吃雞這個游戲果然得4個認(rèn)識的人打(dai)戰(zhàn)(dai)術(shù)(wo)才更有趣。
由于身邊搞安全的人比較多,之前也會和一些安全圈的大佬一起玩,經(jīng)常會有些認(rèn)識或不認(rèn)識的黑闊大佬開著高科技帶著躺雞。當(dāng)然筆者也曾羞恥地開過掛帶妹(紀(jì)念號被封的第193天)。
那么這些黑闊大佬們,在不開掛的情況下,誰會是他們之中技術(shù)NO.1呢?帶著這樣的疑問,試著從數(shù)據(jù)分析的角度來看看誰會是安全圈的吃雞首人。
注:全文所指的“安全圈”是一個非常狹義的概念,在本文中僅覆蓋到小部分安全從業(yè)者玩家,所以標(biāo)題有些夸大。如有其他錯誤也歡迎指出。
一、數(shù)據(jù)收集
怎么才能知道哪些安全從業(yè)者在玩這個游戲,他們的ID又是什么呢?
在一些APP里可以查到玩家的戰(zhàn)績,其中比較有價值的是,還能看到每位玩家的好友列表。
那么可以有這么個思路,也就是一個廣度優(yōu)先遍歷:
- 確定一個初始的ID鏈表,并保證初始鏈表內(nèi)都是安全圈內(nèi)人士。
- 遍歷初始鏈表內(nèi)每一位玩家的所有好友。
- 當(dāng)鏈表內(nèi)H的好友J,同時也是鏈表內(nèi)另外兩位黑客的共同好友,那么認(rèn)為J也是安全圈內(nèi)人士,加入到鏈表尾處。
- 向后迭代重復(fù)2、3。
1. 動手實現(xiàn)
發(fā)現(xiàn)走的是https,掛上證書以MITM的方式來監(jiān)聽https流量:
可以發(fā)現(xiàn)數(shù)據(jù)是以json格式傳遞的,寫個python腳本來自動完成獲取數(shù)據(jù),單線程+限速(一方面不至于給別人家的api爬掛了另一方面也不至于觸發(fā)IDS、anti-CC等機(jī)制)。
腳本主要代碼是:
- def r_get(nickname,offset):
- #發(fā)送給api的request
- ...
- return json#返回一個json格式
- def get_friends(nickname):
- offset = 0
- res_js = r_get(nickname,str(offset))
- temp_friends = res_js['result']['board']
- if res_js['status'] == "ok":
- while len(res_js['result']['board']) == 30:
- offsetoffset = offset + 30
- res_js = r_get(nickname,str(offset))
- temp_friendstemp_friends = temp_friends + res_js['result']['board']
- print(" {0} 的好友人數(shù) {1}".format(res_js['result']['user_rank']['nickname'], len(temp_friends) -1 ))
- friends = []
- Wxname = ""
- Wxsex = ""
- Wxavatar = ""
- sql = ""
- for playerinfo in temp_friends:
- if playerinfo['nickname'] != res_js['result']['user_rank']['nickname']:
- friends.append(playerinfo['nickname'])
- elif playerinfo.has_key('heybox_info') == True:
- Wxname = playerinfo['heybox_info']['username']
- Wxsex = playerinfo['heybox_info']['sex']
- Wxavatar = playerinfo['heybox_info']['avartar']
- friends_s = ','.join(friends)
- sql = "INSERT INTO player (nickname,avatar,steamID,friends,Wxname,Wxsex,Wxavatar) \
- VALUES ('{0}','{1}','{2}','{3}','{4}','{5}','{6}')".format(res_js['result']['user_rank']['nickname'],res_js['result']['user_rank']['avatar'], res_js['result']['user_rank']['steam_id'],friends_s,Wxname,Wxsex,Wxavatar)
- return friends,sql
- else:
- print("獲取{0}的好友人數(shù)失敗, 返回{1}".format(res_js['result']['user_rank']['nickname'],res_js['msg']))
- return 1
- def record_rds(sql):
- #db操作
- def main():
- ...
筆者先確定一份初始安全圈列表,包括“Rickyhao”、“RicterZ”、“r3dr41n”、“PwnDog”等。這些人或是在bat、360等公司從事安全相關(guān)工作,或是筆者信安專業(yè)的同學(xué),或ID明顯帶有安全的特征(PwnDog),總之都是比較確信的安全圈人士。
以這些人為初始列表,很快就有幾位玩家被劃定為安全圈人士。
在遍歷到大約第50來位的時候也看到了自己的游戲昵稱:Omego555(正是剛才提到開掛帶妹被封的賬號)
遍歷到“wilson233”時發(fā)現(xiàn)直接跳過了,并沒有被納入到安全圈列表中,但筆者讀過wilson寫下的很多優(yōu)質(zhì)文章,他也是某甲方公司的安全從業(yè)者。
(該ID在后來的某次遍歷中也被納入了列表中,程序表現(xiàn)出一定的健壯性。 )
在數(shù)據(jù)量達(dá)到1000多的時候筆者手動終止了程序。原因是列表增長的速度越來越快,在單線程+限速的限制下程序遲遲看不到收斂的希望。另一方面筆者只是想做個小測試,并不需要太大規(guī)模的數(shù)據(jù)集。
2. 觀察數(shù)據(jù)集
初步觀察數(shù)據(jù)集,發(fā)現(xiàn)很多有意思的事情:比如在遍歷到第300多位玩家的時候,發(fā)現(xiàn)了一個ID帶得有“pkav”字樣的玩家”PKAV-xiaoL“(pkav是原來在烏云很有名氣的安全組織,其中一名成員“gainover”正是原烏云知識庫《安全圈有多大》一文的作者,筆者也是受到這篇文章的啟發(fā)才打算做這個小項目)。
隨著PKAV-xiaoL被確定到安全圈列表中,由于社交關(guān)系,更多的pkav成員也被添加進(jìn)列表中。
除了pkav-xxx,還看到了一些很眼熟的ID:比如【SparkZheng】—正是多個ios越獄的作者蒸米大大
比如【ma7h1as】,筆者大學(xué)時的隊友,現(xiàn)玄武實驗室大佬,多個Google/MS CVE獲得者,超級大黑客
再來看這位,從游戲昵稱看不出是誰,但微信昵稱告訴我們這個賬號的主人應(yīng)該是安全盒子的創(chuàng)始人王松。
當(dāng)然還有一些活躍在安全論壇,或者筆者有讀過的一些高質(zhì)量技術(shù)文章的作者的ID,眼熟的如”lightless233″、”LoRexxar”、”susu43″、”CurseRed”等,這里不再一一列舉。
除此之外還有一些玩家,比如這位:
筆者既不認(rèn)識他,也從未在安全論壇見過他的ID,只是猜想用“sudo”作為ID的人是安全從業(yè)者的可能性比較大吧。那么他真的會是安全圈人士嗎?
試著搜索一下:
找到了他的GitHub,并在其中發(fā)現(xiàn)了很多你懂的東西,很有趣對吧?
二、社群發(fā)現(xiàn)與社區(qū)關(guān)系
我們發(fā)現(xiàn)了很多安全圈的吃雞玩家,但是除了這些眼熟和有跡可循的ID,列表里躺著的絕大多數(shù)都是筆者沒見過,陌生的ID。為了弄清楚他們之間的社區(qū)關(guān)系。我們使用一些算法和可視化工具來幫助進(jìn)行數(shù)據(jù)分析。
先用環(huán)形關(guān)系圖看看:
圓上的每個紅點代表一位玩家,無數(shù)條灰邊則將各位玩家串聯(lián)起來。在這份數(shù)據(jù)集中一共有1270個節(jié)點,他們互相組成了共計14216次好友關(guān)系,形成了7128條灰邊。稱得上是復(fù)雜的社交網(wǎng)絡(luò)了。
我們使用無向圖來構(gòu)建力引導(dǎo)關(guān)系,雖然在安全領(lǐng)域的風(fēng)控、反欺詐方向中使用有向圖更為廣泛一些,但好友關(guān)系是雙向的,因此這里用無向圖。代碼如下:
- # -*- coding: UTF-8-*-
- from pyecharts import Graph
- import json
- import sys
- import sqlite3
- conn = sqlite3.connect('db2.db')
- c = conn.cursor()
- print "Opened database successfully";
- ccursor = c.execute("SELECT nickname,friends FROM player")
- nodes = []
- links = []
- temps = []
- for row in cursor:
- temps.append({"name":row[0],"friends":row[1].split(",")})
- nodes.append({"name":row[0],"symbolSize":5})
- for temp in temps:
- for friend in temp["friends"]:
- if {"name":friend,"symbolSize":5} in nodes:
- links.append({"source":temp["name"],"target":friend})
- graph = Graph("力導(dǎo)圖",width=1400,height=1600)
- graph.add(
- "",
- nodes,
- links,
- graph_layout = "force",
- label_pos="right",
- graph_repulsion=10,
- line_curve=0.2,
- )
- graph.render()
得到:
俗話說“物以類聚人以群分”,在我們的數(shù)據(jù)集中也同樣適用??梢杂^察到這份社交網(wǎng)絡(luò)其實是由多個小社區(qū)群落組成的,比如在最左下角的這個部分,這個小社區(qū)處于安全圈的邊緣地帶,很有可能不是安全從業(yè)者,我們放大來看:
這個“五邊形”是一個完全子圖。在這個小社區(qū)中,五個人都互為好友,也被稱作“派系(Clique)”,這五個人很有可能經(jīng)常一起開黑。
同時我們可以看到頂點這位玩家:
如果我們把上面的部分看做是安全圈的話,這位叫Feng_Bao的玩家卡在了安全圈與這個5人小社區(qū)“道路咽喉”的位置,這樣的節(jié)點具有較高的“中介中心性(Betweenness Centrality)”,往往具有不可替代的作用。在現(xiàn)實中類似房屋中介一樣,買房者與賣房者之間的聯(lián)系都得靠他。
除了中介中心性,在圖論中節(jié)點還有另外兩個重要性質(zhì):度中心性(Degree Centrality)以及緊密中心性(Closeness Centrality)。
一個節(jié)點與之相連的邊越多,這個節(jié)點的度中心性就越高,也就是好友越多,度中心性越高,很可能是具有較高名望的人,比如微博的大V,KOL。
緊密中心性則是衡量一個節(jié)點到其他所有節(jié)點的最短距離之和的指標(biāo),一個節(jié)點的緊密中心性越高那么他傳播信息的時候也就越不需要依賴其他人。
分別計算一下數(shù)據(jù)集中三個中心性排名靠前的玩家。
有沒有看到眼熟的ID呢:
確實看到一些眼熟的ID,但由于我們前面尋找安全圈的算法并不準(zhǔn)確,在收集數(shù)據(jù)的過程中很可能誤入到某些特定的圈子中。比如某些安全圈玩家同時又是二次元愛好者,那么很可能會把這份數(shù)據(jù)集帶入到”二次元圈“。為了盡量避免這種情況,我們使用一些社區(qū)發(fā)現(xiàn)算法來完成社區(qū)的尋找與分割。
社區(qū)發(fā)現(xiàn)算法用來發(fā)現(xiàn)網(wǎng)絡(luò)中的社區(qū)結(jié)構(gòu),多數(shù)是聚類類型的算法。使用社區(qū)發(fā)現(xiàn)算法可以幫助我們發(fā)現(xiàn)聯(lián)系相對緊密的社區(qū),從而幫助我們把安全圈和其他圈子的人分割開來。
常見的社區(qū)發(fā)現(xiàn)算法有:Girvan-Newman、Louvai、K-Clique、Label propagation等。
在Python下可以使用NetworkX來完成各類社區(qū)發(fā)現(xiàn)算法的調(diào)試,但NetworkX本身只是算法工具,并不具備可視化功能,而筆者聯(lián)調(diào)plt畫出來的圖實在奇丑無比。因此這里使用算法單一但可視化功能強悍的gephi來實現(xiàn)。
fast-unfolding是基于Modularity的算法,也是復(fù)雜網(wǎng)絡(luò)當(dāng)中進(jìn)行社團(tuán)劃分簡單高效、應(yīng)用最廣泛的算法。
用force atlas圖布局:
fast-unfolding:
除此之外Gephi還支持GN算法,但內(nèi)存要求較高,有興趣的同學(xué)可以嘗試下其他算法。
經(jīng)過30000余次迭代,最終得到了19個社區(qū),用圖像來表示是這樣的:
在社區(qū)發(fā)現(xiàn)算法中社區(qū)的數(shù)目和大小通常是不可知的,一般是用模塊度Modularity來檢查社區(qū)分類的合理性。由于本文采集的數(shù)據(jù)較少且這里的好友關(guān)系是雙向的,不像微博的關(guān)注/粉絲的機(jī)制能較準(zhǔn)確地找出圖的連通性,所以這里的社區(qū)發(fā)現(xiàn)效果并不理想。
筆者在使用NetworkX嘗試了多種算法和不同的參數(shù)后,最終選擇了一個樣本數(shù)量為1125的社區(qū),覆蓋了原數(shù)據(jù)集樣本總數(shù)的88.58%。在簡單觀察了這個社區(qū)的合理性后,決定使用這份數(shù)據(jù)集來做后續(xù)的戰(zhàn)績分析。
三、戰(zhàn)績爬取和分析
1. 誰是安全圈的吃雞第一人
拿到了要進(jìn)行戰(zhàn)績數(shù)據(jù)采集的玩家名單后,我們需要先確定幾個指標(biāo)來衡量一個玩家的吃雞技術(shù)水平,才能有指向性的進(jìn)行數(shù)據(jù)采集。筆者最終選取了數(shù)個指標(biāo),分別是:
- 歷史最高Rank,即最高段位
- 最近20場游戲的平均排名
- 最近20場的吃雞數(shù)和前10數(shù)
- 最近20場游戲的擊殺總數(shù)
- 最近20場游戲造成的總傷害
筆者還決定采集一些有趣的指標(biāo),能反映玩家的游戲習(xí)慣:
- 最近20場的武器使用情況
- 最近20場的死亡地點
- 最近20場的游戲總時長
爬蟲寫完后數(shù)據(jù)很快就抓取完畢。
先來看看安全圈玩家們最近20場游戲的情況
在最近的20場比賽中茍到排名前十次數(shù)最多的是【RickyHao】和【NeglectLee】兩位,達(dá)到驚人的17次,85%的前10率。
這一指標(biāo)在安全圈的平均值是6.33。
單獨看看吃雞情況:
在最近20場比賽中吃雞次數(shù)最多的是這位叫【qingfenggod】的玩家,達(dá)到了可怕的10次,近20場次中有一半的比賽都笑到了最后。前十次數(shù)第一的【RickyHao】則在吃雞數(shù)上排到了第二位,達(dá)到了8次。
而這一數(shù)值的平均值僅才0.71,兩位玩家都達(dá)到了10數(shù)倍。
【RickyHao】之所以在這一指標(biāo)上如此突出是因為最近20場次里包含了很多活動模式,而【qingfenggod】則大部分是在排位中獲得的,可以說是非常驚人的勝率了。
在KDA和傷害方面:
可以看到大部分玩家都集中在左下半部分,可以認(rèn)為正常玩家都在這一點簇群內(nèi), 即KDA<2,傷害<400的部分。
而KDA達(dá)到4傷害超過550的玩家僅有4位。KDA超過5傷害超過600的僅僅只有一位了。
但有一位玩家達(dá)到了令人窒息的:
- KD:8.4
- 傷害:1099.57
是第二名的近兩倍,是平均值的近10倍!!!!直接來到了散點圖的云端之上,這可是擊殺與死亡比啊,如果不是高科技的話這位玩家可能是職業(yè)級的水準(zhǔn)了。
這位玩家也正是剛才提到吃雞榜第一的【qingfenggod】。
同樣在吃雞榜中排第二的【RickyHao】,這一數(shù)據(jù)僅為:
- KD:3.7
- 傷害:461.18
排位第8位。
思考:其實這里已經(jīng)可以很直觀地分類出正常玩家、高級玩家、外掛玩家三大類別。如果是反外掛/風(fēng)控等場景,對于這種密度相差很大的簇群,可以嘗試使用kmeans這類基于距離的聚類算法來將樣本分為3~5類,并借助移動速度、平均移動距離等指標(biāo)來輔助判斷是否為外掛玩家。這里不作深入探究。
筆者更感興趣的是吃雞和槍法的關(guān)系,一個人的槍法越好,越容易吃雞嗎?吃雞對于筆者這樣熱衷伏地茍活的玩家會更友好嗎?
對于槍法這一表征,直接使用KD和damage來代替,再加上移動距離來分析這三類指標(biāo)與吃雞率的相關(guān)性
做個簡單的線性相關(guān)分析,計算Pearson系數(shù):
光從相關(guān)系數(shù)看,槍法和吃雞雖然是正相關(guān),但并不是呈現(xiàn)出非常強的相關(guān)性,頂多達(dá)到了中等程度相關(guān)。
而整場游戲的移動距離則和吃雞完全呈弱相關(guān)了,可能是吃雞這個游戲真的很看運氣吧。
而如果一位玩家只是想進(jìn)入游戲前十,則和個人槍法沒什么太大關(guān)系了,反而和移動距離關(guān)系較大。
換句話說,如果只是想沖進(jìn)前十,乖乖茍毒跑圈就可以了。
這也基本印證我們對游戲的理解。
如果說以上對最近二十場次游戲的分析還無法回答“誰是安全圈吃雞第一人”這個問題的話,那么歷史最高排位情況應(yīng)該能給出一個答案了。
那么誰的rank分值會是安全圈中最高的呢,我們同樣遍歷了1125位玩家的這一指標(biāo):
(注:官方API的提示中寫到,由于官方服務(wù)器問題,一些玩家的這一數(shù)據(jù)可能丟失或者有誤)
取四人TPP的排位情況,前三位分別是:
- Salmonnnnn:4094.7144
- syzhou:3906.409
- ph4nt0mer:3609.1436
通過觀察好友關(guān)系,筆者相信他們與安全圈關(guān)系密切(大家也可以搜索一下這些ID)。
寫到這里,“誰是安全圈的吃雞第一人?”這一問題已經(jīng)差不多給出了答案。
2. 玩家畫像
風(fēng)控、反APT等場景中經(jīng)常會用一些手段對黑客或者用戶進(jìn)行畫像。在這里筆者也做了一些研究玩家游戲習(xí)慣的工作,基于玩家的擊殺行為來畫像。
挑選一位玩家游戲記錄較多的玩家,以【sanmao2054】為例。
通過分析他550場次比賽中的的891次擊殺,來推測一下該玩家的游戲習(xí)慣,刻畫出這位玩家的游戲風(fēng)格。
從武器使用情況來看:
sanmao2054最鐘愛步槍,最常使用的是M416和AK47這兩把萬精油老款自動步槍,兩把槍的擊殺人數(shù)加起來超過了250次。
筆者最喜歡用的ScarL步槍在他的手里排在了優(yōu)先級非??亢蟮奈恢?。
在狙擊槍方面:
sanmao2054偏愛SKS這種連發(fā)狙擊步槍,擊殺次數(shù)達(dá)到了22次。而對于m24和kar98這種單發(fā)拉栓步槍就不太熱衷使用,兩把槍使用次數(shù)加起來也不過29次。
總體來看,這位玩家在狙擊槍的使用頻率上遠(yuǎn)不如步槍。所有狙擊槍的擊殺次數(shù)加起來都不及AK或者M(jìn)4的一半。
在沖鋒槍方面:
最愛的當(dāng)屬UMP,而vector緊隨其后,達(dá)到44次擊殺。要知道熱愛vector的玩家并不多,所以這可以算是這位玩家較明顯的特點。
其他:
空投槍的使用次數(shù)并不多,看來這位玩家對追夢沒什么興趣。
雖然是近身型玩家,但使用噴子的次數(shù)并不多。更偏向于自動武器。
而使用爆破手雷擊殺了高達(dá)31次,這是個非常亮眼的數(shù)據(jù)。
從擊殺距離來看:
平均擊殺距離排在第一位的自然是狙中之王,精準(zhǔn)度最強勁的AWM,達(dá)到了120多米。
排在第二的則是這位玩家最愛的SKS,達(dá)到111米了。
對于這位玩家最喜愛的m4和ak兩類步槍,平均擊殺距離僅只有19到24米。
從這里可以看出這位玩家偏好近距離作戰(zhàn),熱愛剛槍,對于殺傷力較大的自動步槍情有獨鐘。
sanmao2054的最遠(yuǎn)擊殺距離達(dá)到了285米,使用的卻是SKS這一款連狙步槍,也從側(cè)面印證此人剛槍的風(fēng)格。
從平均擊殺時間點來看:
sanmao2054在前期擊殺使用的基本都是手槍/沖鋒槍,DP28等武器,在中期會使用AK等自動步槍。后期則以空投槍為主。
有趣的一點是,這位玩家使用爆破手雷完成擊殺的時間點也比較靠后。
可以合理地推測出,他比較傾向于在最后使用手雷來打掃戰(zhàn)場,快速結(jié)束戰(zhàn)斗。這也是比較聰明的做法。
根據(jù)以上信息基本可以腦補一下這位玩家的打法是:
先跳傘到人多的區(qū)域,隨意撿起一兩把武器(甚至是手槍)就開始干架,成功擊殺對手后就尋找ak/m4等自動步槍過渡到中期,會留雷到后期來結(jié)束戰(zhàn)斗,在少數(shù)情況下后期也會去考慮空投槍。
用一些關(guān)鍵詞來描述sanmao2054可能會是:【剛槍小王子】、【步槍之王】、【不擅長狙擊】、【爆破手】、【使用vector的大手子】之類的。
最后用兩張安全圈所有玩家的死亡熱力圖來結(jié)束全文:
四、最后
本文僅是一個For fun的周末項目,涉及的數(shù)據(jù)有限。在真正的網(wǎng)絡(luò)攻防實踐中,數(shù)據(jù)挖掘和分析能為安全工程師帶來更多的便利,特別是在流量分析/異常檢測/溯源取證/風(fēng)控畫像等方面。