MSF-HTTPS默认证书检测

MSF-HTTPS默认证书检测

前言

进行过MSF的默认payload专项测试后,其他明文传输的payload方式或多或少都可以找到相关的流量特征,而HTTPS走的是标准TLS格式,数据完全加密,这样想检测HTTPS的payload难度就非常的大了。但是在TLS传输加密数据之前的证书交换协商过程却是明文传输的,我们可以从这部分入手来尝试检测MSF的HTTPS证书。

代码分析

经过生成多个payload样本后发现,样本的证书貌似是随机生成的,这样我们就需要去后台查看MSF的源代码找到证书的生成逻辑。

1
2
3
06/09/2020-15:35:55.502904 10.50.1.183:52691 -> 10.50.1.175:8888  TLS: Subject='C=US, ST=OH, O=Bosco-Kovacek, OU=multi.byte, CN=bosco.kovacek.org/emailAddress=multi.byte@bosco.kovacek.org' Issuerdn='C=US, ST=OH, O=Bosco-Kovacek, OU=multi.byte, CN=bosco.kovacek.org/emailAddress=multi.byte@bosco.kovacek.org'
06/12/2020-17:22:46.618026 10.50.1.183:58063 -> 10.50.1.175:8888 TLS: Subject='C=US, ST=NC, O=McKenzie, Cummerata and Vandervort, OU=input, CN=mckenzie.cummerata.vervort.net/emailAddress=input@mckenzie.cummerata.vervort.net' Issuerdn='C=US, ST=NC, O=McKenzie, Cummerata and Vandervort, OU=input, CN=mckenzie.cummerata.vervort.net/emailAddress=input@mckenzie.cummerata.vervort.net'
06/12/2020-17:22:46.979553 10.50.1.183:58064 -> 10.50.1.175:8888 TLS: Subject='C=US, ST=NC, O=McKenzie, Cummerata and Vandervort, OU=input, CN=mckenzie.cummerata.vervort.net/emailAddress=input@mckenzie.cummerata.vervort.net' Issuerdn='C=US, ST=NC, O=McKenzie, Cummerata and Vandervort, OU=input, CN=mckenzie.cummerata.vervort.net/emailAddress=input@mckenzie.cummerata.vervort.net'

MSF证书生成代码在文件lib/msf/core/cert_provider.rb里,代码如下:通过调用faker库的Address.state_abbr、Address.city、Company.name、Internet.domain_suffix等list,从中随机选择相关的词汇生成证书。

image-20200701104200259

检测方案

在了解证书的生成过程后,我们使用逆向思维同时也利用faker的list,将证书Subject进行拆分,逐个匹配faker list中的字典,查看是否均存在于字典中,若都存在则判断为MSF HTTPS SSL证书。

suricata lua脚本如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
suffix_list = {"Inc", "and Sons", "LLC", "Group"}

ou_list = {"auxiliary", "primary", "back.end", "digital", "open.source", "virtual", "cross.platform", "redundant", "online", "haptic", "multi.byte", "bluetooth", "wireless", "1080p", "neural", "optical", "solid.state", "mobile", "driver", "protocol", "bandwidth", "panel", "microchip", "program", "port", "card", "array", "interface", "system", "sensor", "firewall", "hard.drive", "pixel", "alarm", "feed", "monitor", "application", "transmitter", "bus", "circuit", "capacitor", "matrix", "back.up", "bypass", "hack", "override", "compress", "copy", "navigate", "index", "connect", "generate", "quantify", "calculate", "synthesize", "input", "transmit", "program", "reboot", "parse"}

last_name_list = {"Abbott", "Abernathy", "Abshire", "Adams", "Altenwerth", "Anderson", "Ankunding", "Armstrong", "Auer", "Aufderhar", "Bahringer", "Bailey", "Balistreri", "Barrows", "Bartell", "Bartoletti", "Barton", "Bashirian", "Batz", "Bauch", "Baumbach", "Bayer", "Beahan", "Beatty", "Bechtelar", "Becker", "Bednar", "Beer", "Beier", "Berge", "Bergnaum", "Bergstrom", "Bernhard", "Bernier", "Bins", "Blanda", "Blick", "Block", "Bode", "Boehm", "Bogan", "Bogisich", "Borer", "Bosco", "Botsford", "Boyer", "Boyle", "Bradtke", "Brakus", "Braun", "Breitenberg", "Brekke", "Brown", "Bruen", "Buckridge", "Carroll", "Carter", "Cartwright", "Casper", "Cassin", "Champlin", "Christiansen", "Cole", "Collier", "Collins", "Conn", "Connelly", "Conroy", "Considine", "Corkery", "Cormier", "Corwin", "Cremin", "Crist", "Crona", "Cronin", "Crooks", "Cruickshank", "Cummerata", "Cummings", "Dach", "D'Amore", "Daniel", "Dare", "Daugherty", "Davis", "Deckow", "Denesik", "Dibbert", "Dickens", "Dicki", "Dickinson", "Dietrich", "Donnelly", "Dooley", "Douglas", "Doyle", "DuBuque", "Durgan", "Ebert", "Effertz", "Emard", "Emmerich", "Erdman", "Ernser", "Fadel", "Fahey", "Farrell", "Fay", "Feeney", "Feest", "Feil", "Ferry", "Fisher", "Flatley", "Frami", "Franecki", "Friesen", "Fritsch", "Funk", "Gaylord", "Gerhold", "Gerlach", "Gibson", "Gislason", "Gleason", "Gleichner", "Glover", "Goldner", "Goodwin", "Gorczany", "Gottlieb", "Goyette", "Grady", "Graham", "Grant", "Green", "Greenfelder", "Greenholt", "Grimes", "Gulgowski", "Gusikowski", "Gutkowski", "Gutmann", "Haag", "Hackett", "Hagenes", "Hahn", "Haley", "Halvorson", "Hamill", "Hammes", "Hand", "Hane", "Hansen", "Harber", "Harris", "Hartmann", "Harvey", "Hauck", "Hayes", "Heaney", "Heathcote", "Hegmann", "Heidenreich", "Heller", "Herman", "Hermann", "Hermiston", "Herzog", "Hessel", "Hettinger", "Hickle", "Hilll", "Hills", "Hilpert", "Hintz", "Hirthe", "Hodkiewicz", "Hoeger", "Homenick", "Hoppe", "Howe", "Howell", "Hudson", "Huel", "Huels", "Hyatt", "Jacobi", "Jacobs", "Jacobson", "Jakubowski", "Jaskolski", "Jast", "Jenkins", "Jerde", "Johns", "Johnson", "Johnston", "Jones", "Kassulke", "Kautzer", "Keebler", "Keeling", "Kemmer", "Kerluke", "Kertzmann", "Kessler", "Kiehn", "Kihn", "Kilback", "King", "Kirlin", "Klein", "Kling", "Klocko", "Koch", "Koelpin", "Koepp", "Kohler", "Konopelski", "Koss", "Kovacek", "Kozey", "Krajcik", "Kreiger", "Kris", "Kshlerin", "Kub", "Kuhic", "Kuhlman", "Kuhn", "Kulas", "Kunde", "Kunze", "Kuphal", "Kutch", "Kuvalis", "Labadie", "Lakin", "Lang", "Langosh", "Langworth", "Larkin", "Larson", "Leannon", "Lebsack", "Ledner", "Leffler", "Legros", "Lehner", "Lemke", "Lesch", "Leuschke", "Lind", "Lindgren", "Littel", "Little", "Lockman", "Lowe", "Lubowitz", "Lueilwitz", "Luettgen", "Lynch", "Macejkovic", "MacGyver", "Maggio", "Mann", "Mante", "Marks", "Marquardt", "Marvin", "Mayer", "Mayert", "McClure", "McCullough", "McDermott", "McGlynn", "McKenzie", "McLaughlin", "Medhurst", "Mertz", "Metz", "Miller", "Mills", "Mitchell", "Moen", "Mohr", "Monahan", "Moore", "Morar", "Morissette", "Mosciski", "Mraz", "Mueller", "Muller", "Murazik", "Murphy", "Murray", "Nader", "Nicolas", "Nienow", "Nikolaus", "Nitzsche", "Nolan", "Oberbrunner", "O'Connell", "O'Conner", "O'Hara", "O'Keefe", "O'Kon", "Okuneva", "Olson", "Ondricka", "O'Reilly", "Orn", "Ortiz", "Osinski", "Pacocha", "Padberg", "Pagac", "Parisian", "Parker", "Paucek", "Pfannerstill", "Pfeffer", "Pollich", "Pouros", "Powlowski", "Predovic", "Price", "Prohaska", "Prosacco", "Purdy", "Quigley", "Quitzon", "Rath", "Ratke", "Rau", "Raynor", "Reichel", "Reichert", "Reilly", "Reinger", "Rempel", "Renner", "Reynolds", "Rice", "Rippin", "Ritchie", "Robel", "Roberts", "Rodriguez", "Rogahn", "Rohan", "Rolfson", "Romaguera", "Roob", "Rosenbaum", "Rowe", "Ruecker", "Runolfsdottir", "Runolfsson", "Runte", "Russel", "Rutherford", "Ryan", "Sanford", "Satterfield", "Sauer", "Sawayn", "Schaden", "Schaefer", "Schamberger", "Schiller", "Schimmel", "Schinner", "Schmeler", "Schmidt", "Schmitt", "Schneider", "Schoen", "Schowalter", "Schroeder", "Schulist", "Schultz", "Schumm", "Schuppe", "Schuster", "Senger", "Shanahan", "Shields", "Simonis", "Sipes", "Skiles", "Smith", "Smitham", "Spencer", "Spinka", "Sporer", "Stamm", "Stanton", "Stark", "Stehr", "Steuber", "Stiedemann", "Stokes", "Stoltenberg", "Stracke", "Streich", "Stroman", "Strosin", "Swaniawski", "Swift", "Terry", "Thiel", "Thompson", "Tillman", "Torp", "Torphy", "Towne", "Toy", "Trantow", "Tremblay", "Treutel", "Tromp", "Turcotte", "Turner", "Ullrich", "Upton", "Vandervort", "Veum", "Volkman", "Von", "VonRueden", "Waelchi", "Walker", "Walsh", "Walter", "Ward", "Waters", "Watsica", "Weber", "Wehner", "Weimann", "Weissnat", "Welch", "West", "White", "Wiegand", "Wilderman", "Wilkinson", "Will", "Williamson", "Willms", "Windler", "Wintheiser", "Wisoky", "Wisozk", "Witting", "Wiza", "Wolf", "Wolff", "Wuckert", "Wunsch", "Wyman", "Yost", "Yundt", "Zboncak", "Zemlak", "Ziemann", "Zieme", "Zulauf"}


state_abbr_list = {"AL", "AK", "AZ", "AR", "CA", "CO", "CT", "DE", "FL", "GA", "HI", "ID", "IL", "IN", "IA", "KS", "KY", "LA", "ME", "MD", "MA", "MI", "MN", "MS", "MO", "MT", "NE", "NV", "NH", "NJ", "NM", "NY", "NC", "ND", "OH", "OK", "OR", "PA", "RI", "SC", "SD", "TN", "TX", "UT", "VT", "VA", "WA", "WV", "WI", "WY"}


function string.trim(s)
return (string.gsub(s, "^%s*(.-)%s*$", "%1"))
end

function in_array(b,list)
if not list then
return false
end
if list then
for k, v in ipairs(list) do
if v == b then
return true
end
end
end
end


function init (args)
local needs = {}
needs["buffer"] = tostring(true)
return needs
end

function match(args)
subject = tostring(args["buffer"])
if subject ~= nil then
if string.match(string.trim(subject),"C=(%w+),%sST=(%w+),%sO=(.*),%sOU=(.*),%sCN=") ~= nil then
C,ST,O,OU = string.match(string.trim(subject),"C=(%w+),%sST=(%w+),%sO=(.*),%sOU=(.*),%sCN=")
if C == "US" then
-- SCLogInfo("detection tls_c")
-- SCLogInfo(ST)
if in_array(ST, state_abbr_list) then
-- SCLogInfo("detection tls_st")
if in_array(OU, ou_list) then
-- SCLogInfo("detection tls_ou\n")
if string.match(string.trim(O),"(%w+)%s+(%w+)") ~= 'nil' then
last_name, suffix = string.match(string.trim(O),"(%w+)%s+(%w+)")
if in_array(suffix, suffix_list) then
if in_array(last_name, last_name_list) then
return 1
end
end
end

if string.match(string.trim(O),"(%w+)-(%w+)") ~= 'nil' then
last_name1, last_name2 = string.match(string.trim(O),"(%w+)-(%w+)")
if in_array(last_name1, last_name_list) then
if in_array(last_name2, last_name_list) then
return 1
end
end
end
if string.match(string.trim(O),"(%w+),%s+(%w+)%s+and%s+(%w+)") ~= 'nil' then
last_name1, last_name2, last_name3 = string.match(string.trim(O),"(%w+),%s+(%w+)%s+and%s+(%w+)")
if in_array(last_name1, last_name_list) then
if in_array(last_name2, last_name_list) then
if in_array(last_name3, last_name_list) then
return 1
end
end
end
end
end
end
end
end
end
return 0
end
return 0

结论

当然,只要换了证书,本方法就不适用,只能从其他方面入手检测了。