1.2 解題策略
通過對數據的初步人工瀏覽和簡單可視化分析發現:
數據經過脫敏,因此部分字元分佈、語義、信息熵等特徵會受到影響。
時間區間很短,因此並不適合用"對歷史行為建模以檢測未知"的思路來做。
數據完整,不存在缺失值填充的問題。
題中說明存在五種攻擊方式,且提交的是DNS query的packet id,表明出題人自信已經100%喫透了這1kw數據包。因此本次五種攻擊模式不會太複雜,每種攻擊流量都是"乾淨"的(可以用規則搞定答案全集,不存在模稜兩可、特徵模糊、人工難辨的情況),猜測攻擊包有可能是出題人自己造的。
eth層、frame層、UDP層、TCP層的特徵高度統一,出題人沒有留下漏洞,因此重點分析DNS層即可。
據此,我的解題策略為:
原始日誌->特徵工程->異常檢測->人工驗證(得到部分答案)->pattern提取->規則匹配->全部答案。
1.3 特徵工程
接下來開始思考本題的特徵維度。根據我的安全經驗,將DNS攻擊分為三種建模:
密集請求型:例如隨機子域名DDoS、反射型DDoS。其特徵為QPS高、時序特徵強,一般能夠可視化觀察到波峯。
漏洞攻擊型:例如針對DNS server的已知漏洞攻擊。其特徵為數量少、受DNS type影響,適合分類統計。如果批量PoC的話,則特徵同1。
數據傳輸型:例如DNS Tunnel、Malware DGA、PoC中的DNS回顯、SSRF重綁定等。其特徵在於域名文本特徵明顯、適用於規則匹配。
將DNS日誌的Request和Response join到一起,然後做統計特徵和文本特徵:
DNS請求時序分佈
QPS min/max/avg
QPS均值
QPS波動性
連接成功率
DNS響應率
TCP報文佔比
請求響應比
單域名平均訪問次數
單目標高頻訪問
多級子域名變化率
DNS type時序分佈
DNS type源IP分佈
長隨機域名
DNS Tunnel特徵
部分DNS RCE
心跳包
代碼示例:SRC_IP維度的部分統計特徵
select
src_ip,
max(index_rsp_cnt) as max_index_rsp_cnt,
avg(index_rsp_cnt) as avg_index_rsp_cnt,
stddev(index_rsp_cnt) as stddev_index_rsp_cnt,
count(distinct index) as all_req_cnt,
count(distinct text_dns_qry_name) as domain_req_cnt,
count(distinct timestamp_sec) as alive_seconds,
abs(max(timestamp_sec)-min(timestamp_sec)) as alive_period,
cast(count(distinct timestamp_sec) as double)/cast(abs(max(timestamp_sec)-min(timestamp_sec)+1) as double) as alive_density,
count(distinct text_dns_qry_name) as uniq_domain_cnt,
count(distinct text_dns_qry_type) as uniq_qr_type_cnt,
case when count(index_rqs_success) > 0 then sum(index_rqs_success)/cast(count(index_rqs_success) as double) else 0 end as rqs_success_rate,
case when count(index_resp_success) > 0 then sum(index_resp_success)/cast(count(index_resp_success) as double) else 0 end as resp_success_rate,
max(dns_dns_count_queries) as max_dns_count_queries,
avg(dns_dns_count_queries) as avg_dns_count_queries,
stddev(dns_dns_count_queries) as stddev_dns_count_queries
from (
select *,
unix_timestamp(_time) timestamp_sec,
trim(json_extractor(layer_dns,text_dns_qry_type)) as text_dns_qry_type,
trim(json_extractor(layer_dns,dns_dns_count_queries)) as dns_dns_count_queries,
count(distinct r_index) over (partition by index) as index_rsp_cnt,
case when r_index is not null then 1 else 0 end as index_rqs_success,
case when trim(json_extractor(r_layer_dns,dns_flags_dns_flags_rcode)) = 3 then 0 else 1 end as index_resp_success
from ${t1}
where layer_dns <> -- 去除TCP握手包
) _
group by src_ip
1.4 異常檢測
將以上統計特徵通過全量數據建立基線,然後在每個特徵維度濾出超越3sigma的異常值。
以下是針對時頻異常的基線(stddev)和過濾示例代碼:
-- 分母拉長到全量時間線
select /*+mapjoin(a)*/
_time,
src_ip
from (
select
_time
from ${t1}
) a join (
select src_ip
from ${t2}
) b on 1=1
-- stddev計算
select
*,
sqrt(pow_sum/16273.0) as stddev_qps
from (
select
*,
sum(pow_qps) over (PARTITION by src_ip) as pow_sum
from (
select
a.*,
b.avg_qps,
pow(abs(a.normalized_qry_cnt-b.avg_qps),2) as pow_qps
from (
select * from ${t1}
) a join (
select * from ${t2}
) b on a.src_ip = b.src_ip
) _
) __
-- 3sigma過濾
select
*
from ${t1}
where qry_qps_stddev > 0.08776535453791778*3
order by qry_qps_stddev desc limit 999
做題過程中,每一輪在確認了每種攻擊流量之後,將其從全量流量中去除並重新計算baseline和異常。
1.5 人工驗證及過濾
將以上異常檢測濾出的IP按照異常維度數量排序,依次人工確認是否為攻擊行為,然後通過規則濾出存在攻擊的數據包。
xy@x-8 ~/D/D/a/finall_100_2> cat traffic.csv | grep ",5" | wc -l
72
xy@x-8 ~/D/D/a/finall_100_2> cat traffic.csv | grep ",4" | wc -l
33200
xy@x-8 ~/D/D/a/finall_100_2> cat traffic.csv | grep ",3" | wc -l
5055
xy@x-8 ~/D/D/a/finall_100_2> cat traffic.csv | grep ",2" | wc -l
5292
xy@x-8 ~/D/D/a/finall_100_2> cat traffic.csv | grep ",1" | wc -l
34184
這裡前四種攻擊(子域名爆破、域傳送、非法域更新、反射DDoS)人工識別之後提交答案獲得80分,最後一種攻擊沒有找到,此時還剩3次check機會,於是排序出三種最明顯的數據提交進行fuzz,碰撞出最後一種答案。
1.6 總結
從結果來看,本題最高效的特徵如下:
DNS type。
src_ip維度的統計分析特徵(QPS、域名數量、請求響應數),因為出題人將src_ip的行為做的非常乾淨,找到了IP就找到了攻擊。
分析方法只用了3sigma異常基線一種,人工排序觀察Top的異常結果,確認攻擊後寫規則撈出全部同類攻擊。
本題由於沒有給標註數據,更考驗選手的安全知識,異常流量擺在面前要能看出是攻擊纔行。可以把單個攻擊源的行為多樣化,加入一些正常行為,同時把某種攻擊拆成多源、多次,以加大解題難度。
Q2 DGA域名檢測與家族聚類
解題思路:首先通過專家經驗做強關聯社區發現洗出一部分DGA域名,以此為正樣本訓練二分類模型識別DGA域名,然後對結果分別進行社區發現、社區聚合、標籤傳播擴展與降噪,最終得到結果。
方案特點:
使用改進的強社區發現方法和專家知識,將無監督問題轉化為有監督問題。
從種子樣本到二分類、社區發現、降噪,最終結果迴流到樣本集,不斷遞歸收斂最終獲取準確結果。
通過DGA公開家族特徵、whois特徵、http響應特徵等擴展數據增強結果。
解題策略
解題前沒有label數據,屬於零先驗知識數據挖掘,因此不能直接設計單個model進行multiclass多分類一步得到所有DGA家族分類。
針對這種場景,我們設計了一個 種子樣本生成-二分類-社區發現-降噪與傳播-更新種子樣本 的循環工作流,在每次迭代過程中的"降噪與傳播"部分引入專家經驗,在每次迭代中提高精度和召回,最終逼近正確答案。
上述過程可以基於阿里雲的MaxCompute大數據組件進行pipeline編程,自動串接成一個循環工作流,得到dga家族聚類結果。
DGA域名發現(二分類)
本題中,並沒有全網視角的DNS-IP網狀信息,因此不適合用deep-walk、graph embedding等方式進行關聯聚類。出題人提供的是一個pcap壓縮包,內部數據是一個gateway/網路流量旁路鏡像設備在一段時間內的抓包。
整個時序上的特徵比較弱,不適合進行時序和深度網路建模,因此,特徵工程向量化的思路還是進行expert feature engineering
DGA中的檢測對象是text_dns_qry_name,因此我們以text_dns_qry_name為group by聚類主體進行特徵向量化,後續的二分類建模(binary classification)和無監督聚類(unsupervised cluster)在此基礎上進行。
特徵維度
稀有TLD
DGA家族互斥假設
WHOIS特徵
域名訪問頻次
域名長度統計
源IP計數
信息熵
域名可讀性
Markov概率
N-Gram平均排名
對域名可讀性的解釋:
域名中包含的母音數目:合法域名為了讓人類記住會選一些好念(pronounceable)的域名,比如 google yahoo baidu等等有母音字母之類好唸的,而dga域名為了隨機性就不太好念,比如http://fryjntzfvti.biz
域名裏母音字母佔的比重因此可以成為一個特徵。
域名中包含的母音字母佔整個域名的比例:這個特徵相當於對母音字母數目特徵的歸一化,因為域名有長有短。歸一化後的特徵更能體現出該域名中母音字母所在比例。
域名中包含的數字數目:正常來說,一個正常的域名中不可能包含太多的數字,但是DGA的域名是代碼隨機生成的,因此可能會包含較多的數字。但這句話也不是絕對的,反過來說,黑客也可以利用這個特點和安全人員展開攻防。
域名中包含的數字佔整個域名的比例:這個特徵的作用是對數字數目特徵的歸一化,因為域名有長有短。
域名中包含的重複字母組合數:一般來說,一個正常的域名會使用一些可讀性較好的英文字母組合而成,整個域名中不會大量重複出現同一個字母,但是dga域名則很容易出現這種情況。
域名中包含的連續輔音字母段字母總數:這個維度同樣也是從可讀性出發,一般來說,一個正常的單詞是由母音和輔音組合而成的,一般很少會出現一個單詞中突然出現一整段連續的輔音字母。
域名中包含的連續輔音數欄位數字總數:因為英文字母分佈裏輔音字母遠多於母音字母,dga更可能連續反覆出現輔音字母,而合法域名為了好念多是母音輔音交替。
特徵選擇
為了提高模型訓練效率,需要進行feature selection。我們在截圖過程中嘗試了PCA、基尼指數/熵增益評估、XBboost特徵重要性評估等方法。
從結果上看,前40%的特徵貢獻了95%以上的分類熵增益,特徵裁剪後,可以提高20%計算效率,但本題數據集很小,提高時間有限。
下列為部分排序結果如下:
colname feature_importance
dns_count_labels_avg 7.098254584511219e-7
dns_resp_name_len 0.48685101592518043
dns_flags_rcode_min 0.09380669054958125
dns_qry_name_len 0.08286261820522951
dns_qry_name_consecutive_consonant 0.05165039925351584
dns_qry_name_count_digits 0.046638077601526357
dns_resp_type_min 0.03279234892125366
dns_qry_name_markov_p 0.03226292786968624
dns_flags_rcode_avg 0.03052527051736504
dns_flags_recavail_min 0.028058550159497347
dns_qry_name_entropy 0.02484754211205459
dns_flags_recavail_avg 0.01629423237968943
dns_count_auth_rr_min 0.015600932601233563
dns_qry_name_digits_rate 0.009893560714853046
src_ip_cn 0.008147846032435051
text_dns_qry_name_ngram_freq_rank 0.007359642440535176
dns_qry_name_vowels_rate 0.004839688721567736
dns_qry_name_count_repeat_letter 0.004262471145899436
dns_resp_type_max 0.0038532152488795776
dns_resp_type_avg 0.0023972406346633437
dns_qry_name_count_vowels 0.001883909214152896
ngram_op_rate_avg 0.0017827386086246898
dns_flags_rcode_max 0.0016479222857123728
...
排名top頭部頭部的特徵也符合我們的專家經驗。也可以理解為基於專家經驗抽取的特徵,從PAC可學習理論的角度來說,已經相當於代入了大量的先驗知識,先驗知識相當於一種約束,縮小了待搜索的參數空間。這導致模型擬合能力的提升,但是犧牲了泛化能力。
在比賽的前中期我們通過該方法拿到90%左右的recall預估,但是再往上提高就十分困難,即發生了over-fitting,我們在比賽的中後期開始調整為肉雞IP在短時間窗口的行為視角,在每輪的迭代中加入肉雞ip在timewindow中的cluster聚類結果,最終將部分家族的dga recall優化到100%。
XGBoost模型訓練
模型訓練參數:
-DmaxLeafCount="32"
-DsampleRatio="0.7"
-DfeatureRatio="0.7"
-DtreeCount="800"
-DminLeafSampleCount="500"
-Dshrinkage="0.02"
二分類結果
初步打標出1.4w DGA域名,距離目標12443左右的數據只有2k+的差距,為下一步做社區發現提供了比較好的條件。
域名社區發現
域名和肉雞組成的2元關係,可以抽象為一個社交網路,社交網路中的節點就是domain域名,社交節點之間的聯結就是是否以及擁有多少共同的肉雞。
需要注意的是,同一個dga家族的域名會被同一批src ip訪問,可能因為malware運行時間的關係,每個域名的count(src_ip)不一定完全相同,但是不會差很多,因此適合用pylouvain進行社區發現。在進行pylouvain之前,要做的一件很重要的事情是:降噪!盡量將非dga域名訪問記錄剔除只留下不同家族dga域名的訪問記錄,然後跑pylouvain才能得到較好的效果。如果不做降噪就直接進行社區發現會遇到很嚴重的over-community cluster的問題。
本題最理想情況下,降噪後的節點已經滿足「社區內部內聚、社區之間極度稀疏」,這樣pylouvain只要運行一次就可以直接得到結果。但是降噪不能做到100%純凈,因此還需要後續的社區dga節點提純步驟。
圖節點與邊的定義
節點(node):domain
關係邊(edge):count(distinct src_ip) group by domain_in, domain_out
-- 基於"共同src_ip"這一共現邏輯關係,建立節點matrix
set odps.sql.mapjoin.memory.max=8096;
drop table if exists xiaohan_datacon_q2_dns_data_suspicious_dga_for_pylouvain_matrix;
create table xiaohan_datacon_q2_dns_data_suspicious_dga_for_pylouvain_matrix as
select
/*+mapjoin(b)*/
a.src_ip as ip,
a.domain as a_domain,
b.domain as b_domain
from (
select src_ip,domain
from xiaohan_datacon_q2_dns_data_suspicious_dga_for_pylouvain
) a join (
select src_ip,domain
from xiaohan_datacon_q2_dns_data_suspicious_dga_for_pylouvain
) b on a.src_ip=b.src_ip
;
-- 去除自連接,去除雙向連接的重複
drop table if exists xiaohan_datacon_q2_dns_data_suspicious_dga_for_pylouvain_matrix_delete_selfloop;
create table xiaohan_datacon_q2_dns_data_suspicious_dga_for_pylouvain_matrix_delete_selfloop as
select
a_domain as node1_id,
b_domain as node2_id,
count(distinct ip) as weight -- 重複qry的IP數量代表權重
from xiaohan_datacon_q2_dns_data_suspicious_dga_for_pylouvain_matrix
where
a_domain > b_domain -- 去除自連接,去除雙向連接的重複
group by
a_domain,
b_domain
;
社區發現結果
經過一輪社區發現後會得到54個dga family,部分社區如下圖:
顯然本題中不可能有這麼多家族。這是現實中一個非常正常的情況,由於botnet活躍的時間斷不一致,有可能感染了同一種DGA的bot出現在不同時間,因此其訪問的DGA沒有重合。接下來要對多個社區做聚合和提純。
社區合併
對上文中每個louvain產出的社區做特徵工程,然後聚類以達到"合併同一家族社區"的效果。
社區合併特徵:
TLD one-hot分佈 [com, org, net, biz, info]
DNS SLD字符集 [a-zA-Z0-9]
DNS SLD子域名長度變化區間 [16,32]
結果優化
這一步通過引入其他維度數據進一步提高精度和召回。
域名維度特徵:
Only SLD+TLD && length(SLD) > 5
Number of rdata < 5
HTTP alive
NXDOMAIN rate
WHOIS existed
WHOIS sinkhole
Alexa rank < 1M
IP malicious request rate
DGA Generate Algorithm
社區維度特徵:
NXDOMAIN≥ 20%
Number of Domain names ≥ 4
Query in a short times
最終結果:
線上得分 98.8300
主要問題和待提高的地方
結合malware reverse engine進行輔助和分析確認。我們隊在比賽過程中針對這道題的現實意義進行了討論,dga檢測與識別,毫無疑問是要進行實時防禦,或者說是準實時防禦,即dns sinkhole,這就是一個典型的「雙百場景」,即「recall 100% + precision 100%」。
dga C&C本質上是黑客的一種隱蔽通信手段,如果不能100% recall識別,漏報一個等於防禦失敗。反過來,dns域名是一個互聯網核心基礎設施,如果在骨幹網設備上產生攔截誤報,影響是非常巨大的。這和Xorddos馬的自我繁殖防禦類似。從這個角度來說,這道題我們沒有拿到100%,等於防禦失敗了。
在工程化中,這道題最有效的方法是是對dga malware進行監控和逆向分析,通過精確的dga generate function,提前預知未來可能產生的dga域名,從而進行提前防禦,當然也要關注dga生成演算法與常規域名的碰撞問題。
社區節點間邊權重計算方式需要優化:在實際場景中,一臺機器可能中多個木馬,而且在中馬的同時可能正在進行其他的高頻業務訪問行為,因此只基於簡單的共享同一個肉雞ip的社區邊定義很容易引入像http:// msn.com 這種誤報,對邊權重的計算需要引入更多肉雞-域名行為時序上的特徵。
計算效率
IO:從pcap中讀取dns數據過程較慢,將數據導入MaxCompute之後,效率大大提高。
FE:對domain列進行groupby,然後對其他列進行操作,這裡groupby一次需要10min,跑2-gram需要20min。
Xgboost:訓練模型,15min完成,預測10s內完成。
pylouvain:200w edge,1.6w vertex,1min內完成收斂。
LPA:1min完成收斂。
nxNetwork可視化:30s完成數據載入,2min完成圖形渲染。
比賽結果
Ref
https:// github.com/rrenaud/Gibb erish-Detector
https:// pc.nanog.org/static/pub lished/meetings/NANOG71/1444/20171004_Gong_A_Dga_Odyssey__v1.pdf
https:// cloud.tencent.com/devel oper/article/1142855
https:// github.com/360netlab/DG A/tree/master/code
https://www. botconf.eu/wp-content/u ploads/2015/12/OK-P06-Plohmann-DGArchive.pdf
https://www. usenix.org/sites/defaul t/files/conference/protected-files/security16_slides_plohmann.pdf
https:// github.com/rmariko/secu rity-ids/blob/0696255b7f2600429a3129bdc1b271d3c4db20ae/ids.py
https:// github.com/LittleHann/D GA-1/blob/master/dga_algorithms/Conficker.cpp
https:// github.com/andrewaeva/D GA/blob/master/dga_algorithms/Matsnu.py
https:// github.com/LittleHann/d ga-collection/tree/master/dgacollection
https:// github.com/360netlab/DG A/tree/master/code
https:// github.com/baderj/domai n_generation_algorithms/tree/e2ed68a9813b2265652a79291a74b4c23fc13bf0
https://www. cdxy.me/? p=805
https:// github.com/shyoshyo/Dat acon-9102-DNS
http:// momomoxiaoxi.com/ 數據分析/2019/04/24/datacondns1/
推薦閱讀: