DataCon是由2019中國國際大數據產業博覽會組委會、貴州省公安廳指導,北京奇安信科技有限公司(360企業安全)和清華大學主辦的大數據安全分析比賽。

隨著大數據和人工智慧時代的到來,催生了很多新的安全技術方法,包括人工智慧、機器學習、可視化分析等,這些技術方法有別於傳統的安全檢測等技術,此次比賽與攻防演練實戰結合,重點考察選手利用這些新的技術方法對不同場景下的安全問題進行惡意流量分析、惡意代碼分析、追蹤溯源的能力。通過比賽豐富提升攻防演練的維度和價值,持續提升參賽者的安全能力和實戰經驗,有效培養選拔大數據安全人才。

題目 1: DNS惡意流量檢測:從數據包中識別出五種DNS攻擊流量所在packet id。

  • 題目要求:PDF
  • 得分:100.0
  • 名次:top 1

題目2:DGA域名識別與家族聚類:從數據包中識別出全部DGA域名並按家族聚類。

  • 題目要求:PDF
  • 得分:98.83
  • 名次:top 1

決賽現場答辯PPT: PDF

Q1 DNS惡意流量檢測

  • 解題思路:結合專家經驗在多個維度做統計特徵,濾出超越統計基線3sigma的異常行為,人工檢驗異常數據確認攻擊,然後編寫規則濾出該類攻擊全部數據包。

方案特點:

  1. 使用雲環境大數據分析組件,高效完成題目。
  2. 使用異常檢測方法,所使用的特徵空間能夠對數據集做完全線性二分類,達到100% precision和recall。

1.1 數據結構化處理

  • 原始pcap上傳至伺服器,使用 tshark -r q1_final.pcap -T ek > output_ek.json 解包並按照elasticsearch格式導出json。
  • 由於題目要求提交packet index,再將解出的39G json文件使用python腳本添加index列。

import json
path = output_ek.json
output = output_ek_index.json
with open(path) as f:
with open(output, w) as w:
index = 1
sep = $$$$$
while True:
line = f.readline()
if not line:
break
if timestamp in line:
out_line = str(index) + sep + line.strip() +

w.write(out_line)
if index % 10000 == 0:
print index
index += 1
print total:, index

  • 數據上傳到阿里雲大數據分析服務 MaxCompute 做包解析和結構化分析。

  • 解析後的數據阿里雲機器學習平臺 PAI 做演算法分析和可視化。

1.2 解題策略

通過對數據的初步人工瀏覽和簡單可視化分析發現:

  1. 數據經過脫敏,因此部分字元分佈、語義、信息熵等特徵會受到影響。
  2. 時間區間很短,因此並不適合用"對歷史行為建模以檢測未知"的思路來做。
  3. 數據完整,不存在缺失值填充的問題。
  4. 題中說明存在五種攻擊方式,且提交的是DNS query的packet id,表明出題人自信已經100%喫透了這1kw數據包。因此本次五種攻擊模式不會太複雜,每種攻擊流量都是"乾淨"的(可以用規則搞定答案全集,不存在模稜兩可、特徵模糊、人工難辨的情況),猜測攻擊包有可能是出題人自己造的。
  5. eth層、frame層、UDP層、TCP層的特徵高度統一,出題人沒有留下漏洞,因此重點分析DNS層即可。

據此,我的解題策略為:

  • 原始日誌->特徵工程->異常檢測->人工驗證(得到部分答案)->pattern提取->規則匹配->全部答案。

1.3 特徵工程

接下來開始思考本題的特徵維度。根據我的安全經驗,將DNS攻擊分為三種建模:

  1. 密集請求型:例如隨機子域名DDoS、反射型DDoS。其特徵為QPS高、時序特徵強,一般能夠可視化觀察到波峯。
  2. 漏洞攻擊型:例如針對DNS server的已知漏洞攻擊。其特徵為數量少、受DNS type影響,適合分類統計。如果批量PoC的話,則特徵同1。
  3. 數據傳輸型:例如DNS Tunnel、Malware DGA、PoC中的DNS回顯、SSRF重綁定等。其特徵在於域名文本特徵明顯、適用於規則匹配。

將DNS日誌的Request和Response join到一起,然後做統計特徵和文本特徵:

  1. DNS請求時序分佈
  2. QPS min/max/avg
  3. QPS均值
  4. QPS波動性
  5. 連接成功率
  6. DNS響應率
  7. TCP報文佔比
  8. 請求響應比
  9. 單域名平均訪問次數
  10. 單目標高頻訪問
  11. 多級子域名變化率
  12. DNS type時序分佈
  13. DNS type源IP分佈
  14. 長隨機域名
  15. DNS Tunnel特徵
  16. 部分DNS RCE
  17. 心跳包

代碼示例: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域名,然後對結果分別進行社區發現、社區聚合、標籤傳播擴展與降噪,最終得到結果。

方案特點:

  1. 使用改進的強社區發現方法和專家知識,將無監督問題轉化為有監督問題。
  2. 從種子樣本到二分類、社區發現、降噪,最終結果迴流到樣本集,不斷遞歸收斂最終獲取準確結果。
  3. 通過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)在此基礎上進行。

特徵維度

  1. 稀有TLD
  2. DGA家族互斥假設
  3. WHOIS特徵
  4. 域名訪問頻次
  5. 域名長度統計
  6. 源IP計數
  7. 信息熵
  8. 域名可讀性
  9. Markov概率
  10. N-Gram平均排名

對域名可讀性的解釋:

  1. 域名中包含的母音數目:合法域名為了讓人類記住會選一些好念(pronounceable)的域名,比如 google yahoo baidu等等有母音字母之類好唸的,而dga域名為了隨機性就不太好念,比如http://fryjntzfvti.biz域名裏母音字母佔的比重因此可以成為一個特徵。
  2. 域名中包含的母音字母佔整個域名的比例:這個特徵相當於對母音字母數目特徵的歸一化,因為域名有長有短。歸一化後的特徵更能體現出該域名中母音字母所在比例。
  3. 域名中包含的數字數目:正常來說,一個正常的域名中不可能包含太多的數字,但是DGA的域名是代碼隨機生成的,因此可能會包含較多的數字。但這句話也不是絕對的,反過來說,黑客也可以利用這個特點和安全人員展開攻防。
  4. 域名中包含的數字佔整個域名的比例:這個特徵的作用是對數字數目特徵的歸一化,因為域名有長有短。
  5. 域名中包含的重複字母組合數:一般來說,一個正常的域名會使用一些可讀性較好的英文字母組合而成,整個域名中不會大量重複出現同一個字母,但是dga域名則很容易出現這種情況。
  6. 域名中包含的連續輔音字母段字母總數:這個維度同樣也是從可讀性出發,一般來說,一個正常的單詞是由母音和輔音組合而成的,一般很少會出現一個單詞中突然出現一整段連續的輔音字母。
  7. 域名中包含的連續輔音數欄位數字總數:因為英文字母分佈裏輔音字母遠多於母音字母,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產出的社區做特徵工程,然後聚類以達到"合併同一家族社區"的效果。

社區合併特徵:

  1. TLD one-hot分佈 [com, org, net, biz, info]
  2. DNS SLD字符集 [a-zA-Z0-9]
  3. DNS SLD子域名長度變化區間 [16,32]

結果優化

這一步通過引入其他維度數據進一步提高精度和召回。

域名維度特徵:

  1. Only SLD+TLD && length(SLD) > 5
  2. Number of rdata < 5
  3. HTTP alive
  4. NXDOMAIN rate
  5. WHOIS existed
  6. WHOIS sinkhole
  7. Alexa rank < 1M
  8. IP malicious request rate
  9. DGA Generate Algorithm

社區維度特徵:

  1. NXDOMAIN≥ 20%
  2. Number of Domain names ≥ 4
  3. 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的社區邊定義很容易引入像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

  • github.com/rrenaud/Gibb
  • pc.nanog.org/static/pub
  • cloud.tencent.com/devel
  • github.com/360netlab/DG
  • botconf.eu/wp-content/u
  • usenix.org/sites/defaul
  • github.com/rmariko/secu
  • github.com/LittleHann/D
  • github.com/andrewaeva/D
  • github.com/LittleHann/d
  • github.com/360netlab/DG
  • github.com/baderj/domai
  • cdxy.me/?
  • github.com/shyoshyo/Dat
  • momomoxiaoxi.com/數據分析/2019/04/24/datacondns1/

推薦閱讀:

相關文章