1-- #!/usr/bin/env lua -> shebang line seems to be breaking tshark :-( 2 3-- Usage: tshark -q -Xlua_script:network2john.lua -r selected.pcap 4-- 5-- Wireshark in Fedora 25 doesn't have Lua enabled. Use Fedora 27 / Ubuntu or 6-- something else which has Wireshark with Lua support or compile Wireshark 7-- with Lua support. 8-- 9-- tshark -r selected.pcap -T pdml > data.pdml # use this for development! 10 11 12-- Extract RADIUS CHAP hashes from .pcap files. 13-- https://tools.ietf.org/html/rfc2865 -> The CHAP challenge value is found in 14-- the CHAP-Challenge Attribute (60) if present in the packet, otherwise in the 15-- Request Authenticator field. NOTE: We don't handle the former case yet. 16 17if not Listener then 18 print("Usage: tshark -q -Xlua_script:network2john.lua -r target.pcap") 19 os.exit(0) 20end 21tap_radius = Listener.new(nil, "radius") 22 23-- Extract RADIUS CHAP hashes from .pcap files. 24-- We can also parse the "radius.avp" entries for more flexibility? 25local f_code = Field.new("radius.code") 26local f_authenticator = Field.new("radius.authenticator") 27local f_username = Field.new("radius.User_Name") 28local f_ident = Field.new("radius.CHAP_Ident") 29local f_hash = Field.new("radius.CHAP_String") 30 31function tap_radius.packet(pinfo,tvb,tapdata) 32 local code = f_code() 33 34 if code.value == 1 then -- Access-Request 35 local canary = f_ident() 36 if canary then 37 local challenge = tostring(f_authenticator().value):lower() 38 local id = tostring(f_ident().value):lower() 39 local response = tostring(f_hash().value):lower() 40 local username = tostring(f_username().value) 41 local hash = string.format("%s:$chap$%s*%s*%s", username, id, challenge, response) 42 print(hash) 43 canary = nil 44 end 45 end 46end 47 48function tap_radius.draw() 49end 50 51-- Extract RADIUS authentication hashes from .pcap files. 52-- http://www.untruth.org/~josh/security/radius/radius-auth.html 53-- (An Analysis of the RADIUS Authentication Protocol) 54local f_code = Field.new("radius.code") 55local f_authenticator = Field.new("radius.authenticator") 56local f_username = Field.new("radius.User_Name") 57local f_upe = Field.new("radius.User_Password_encrypted") 58 59-- put the passed-in args into a table 60local args = {...} 61count = 0 62for i,v in ipairs(args) do 63 count = count + 1 64end 65 66function tap_radius.packet(pinfo,tvb,tapdata) 67 local code = f_code() 68 69 if count < 2 then 70 print("Usage: tshark -q -Xlua_script:network2john.lua -X lua_script1:<secret-or-password-value-here> -X lua_script1:0 -r target.pcap\n") 71 print("Note: -X lua_script1:<secret-or-password-value-here> -> this is used as either the user password or the shared secrert\n") 72 print("Note: Use -X lua_script1:0 to attack RADIUS shared secret\n") 73 print("Note: Use -X lua_script1:1 to attack user password") 74 os.exit(0) 75 end 76 77 -- print them out 78 if code.value == 1 then -- Access-Request 79 local canary = f_upe() 80 if canary then 81 local challenge = tostring(f_authenticator().value):lower() 82 local upe = tostring(f_upe().value):lower() 83 local username = tostring(f_username().value) 84 local secret = args[1] 85 local mode = args[2] 86 local hash = string.format("%s:$radius$1*%s*%s*%s*%s", username, mode, secret, challenge, upe) 87 print(hash) 88 canary = nil 89 end 90 end 91end 92 93function tap_radius.draw() 94end 95 96 97-- Extract EAP-MD5 hashes from .pcap files. 98tap_eap = Listener.new(nil, "eap") 99 100local f_code = Field.new("eap.code") 101local f_id = Field.new("eap.id") 102local f_etype = Field.new("eap.type") 103local f_identity = Field.new("eap.identity") 104local f_challenge = Field.new("eap.md5.value") 105local f_response = Field.new("eap.md5.value") 106 107local username = nil 108local challenge = nil 109local response = nil 110local id = nil 111 112function tap_eap.packet(pinfo,tvb,tapdata) 113 local code = f_code() 114 local etype = f_etype() 115 116 if code.value == 2 and etype.value == 1 then -- Response, Identity (extract username) 117 username = tostring(f_identity()) 118 end 119 120 if code.value == 1 and etype.value == 4 then -- Request, MD5-Challenge EAP 121 challenge = tostring(f_challenge().value):lower() 122 end 123 124 if code.value == 2 and etype.value == 4 then -- Response, MD5-Challenge EAP 125 response = tostring(f_response().value):lower() 126 id = tostring(f_id().value) 127 end 128 129 if username and challenge and response then 130 local hash = string.format("%s:$chap$%s*%s*%s", username, id, challenge, response) 131 print(hash) 132 username = nil 133 challenge = nil 134 response = nil 135 id = nil 136 end 137end 138 139function tap_eap.draw() 140end 141 142 143-- Extract SNMPv3 USM hashes from .pcap files. 144-- 145-- Special thanks goes to Peter Wu for making this script work! 146-- require "socket" 147 148-- function sleep(sec) 149-- socket.select(nil, nil, sec) 150-- end 151 152tap_snmp = Listener.new(nil, "snmp") 153 154local f_msgVersion = Field.new("snmp.msgVersion") 155local f_msgSecurityModel = Field.new("snmp.msgSecurityModel") 156local f_msgAuthoritativeEngineID = Field.new("snmp.msgAuthoritativeEngineID") 157local f_msgAuthenticationParameters = Field.new("snmp.msgAuthenticationParameters") 158local f_msgUserName = Field.new("snmp.msgUserName") 159local f_snmp = Field.new("snmp") 160local snmp_tip_printed = false 161 162 163function tap_snmp.packet(pinfo,tvb,tapdata) 164 if not snmp_tip_printed then 165 print("Set the SNMP_ALGORITHM environment variable for a speed boost, if you already know the algorithm being used. Read this script to know more.") 166 -- sleep(1) -- doesn't work reliably across distributions 167 snmp_tip_printed = true 168 end 169 local msgVersion = f_msgVersion() 170 local msgSecurityModel = f_msgSecurityModel() 171 local msgAuthoritativeEngineID = f_msgAuthoritativeEngineID() 172 local msgAuthenticationParameters = f_msgAuthenticationParameters() 173 local msgUserName = f_msgUserName() 174 175 local snmp_algorithm = os.getenv("SNMP_ALGORITHM") 176 local algorithm = 0 -- try both HMAC-MD5-96 and HMAC-SHA-96 (authProtocol) 177 if snmp_algorithm == "MD5" then 178 algorithm = 1 179 elseif snmp_algorithm == "SHA1" then 180 algorithm = 2 181 end 182 183 if msgSecurityModel then 184 if msgVersion.value ~= 3 then 185 return 186 end 187 if msgSecurityModel.value ~= 3 then 188 return 189 end 190 if msgAuthoritativeEngineID.len == 0 then 191 return 192 end 193 if msgAuthenticationParameters.len == 0 then 194 return 195 end 196 if msgAuthenticationParameters.len ~= 12 then -- this is known to be 96-bits 197 return 198 end 199 if msgUserName.len == 0 then 200 return 201 end 202 203 local snmp_field = f_snmp() 204 local snmp_payload = snmp_field.range() 205 local wholeMsg = snmp_payload:bytes():tohex():lower() 206 local AuthoritativeEngineID = tostring(msgAuthoritativeEngineID.value):lower() 207 local AuthenticationParameters = tostring(msgAuthenticationParameters.value):lower() 208 local UserName = tostring(msgUserName) 209 -- zero out the hash (is there a safer/better way to do this?) 210 local wholeMsgProper = wholeMsg:gsub(AuthenticationParameters, "000000000000000000000000") 211 local hash = string.format("%s:$SNMPv3$%s$%s$%s$%s$%s", UserName, algorithm, pinfo.number, 212 wholeMsgProper, AuthoritativeEngineID, AuthenticationParameters) 213 print(hash) 214 end 215end 216 217function tap_snmp.draw() 218end 219 220 221 222-- Extract DHCPv6 authentication hashes from .pcap files. 223-- NOTE: This requires Wireshark 2.9.0 (from git master) as of June, 2018. 224 225tap_dhcpv6 = Listener.new(nil, "dhcpv6") 226 227local f_algorithm = Field.new("dhcpv6.auth.algorithm") 228local f_hash= Field.new("dhcpv6.auth.md5_data") 229local f_dhcpv6 = Field.new("dhcpv6") 230 231function tap_dhcpv6.packet(pinfo,tvb,tapdata) 232 local canary = f_hash() 233 if not canary then 234 return 235 end 236 237 local algorithm = f_algorithm() 238 if algorithm.value ~= 1 then 239 return 240 end 241 242 local hash = tostring(canary.value):lower() 243 local dhcpv6_field = f_dhcpv6() 244 local dhcpv6_payload= dhcpv6_field.range() 245 local wholeMsg = dhcpv6_payload:bytes():tohex():lower() 246 local wholeMsgProper = wholeMsg:gsub(hash, "00000000000000000000000000000000") 247 local hash = string.format("%s:$rsvp$1$%s$%s", pinfo.number, wholeMsgProper, hash) 248 print(hash) 249end 250 251function tap_dhcpv6.draw() 252end 253 254 255 256-- Extract DHCPv4 authentication hashes from .pcap files. 257-- NOTE: This requires Wireshark 2.9.0 (from git master) as of June, 2018. 258 259tap_dhcpv4 = Listener.new(nil, "bootp") 260 261local f_algorithm = Field.new("bootp.option.dhcp_authentication.alg_delay") 262local f_hash= Field.new("bootp.option.dhcp_authentication.hmac_md5_hash") 263local f_dhcpv4 = Field.new("bootp") 264 265function tap_dhcpv4.packet(pinfo,tvb,tapdata) 266 local canary = f_hash() 267 if not canary then 268 return 269 end 270 271 local algorithm = f_algorithm() 272 if algorithm.value ~= 1 then 273 return 274 end 275 276 local hash = tostring(canary.value):lower() 277 local dhcpv4_field = f_dhcpv4() 278 local dhcpv4_payload= dhcpv4_field.range() 279 local wholeMsg = dhcpv4_payload:bytes():tohex():lower() 280 wholeMsg = string.sub(wholeMsg, 1, 6) .. "00" .. string.sub(wholeMsg, 9, 48) .. "00000000" .. string.sub(wholeMsg, 57) -- zero'ize hops and giaddr 281 local wholeMsgProper = wholeMsg:gsub(hash, "00000000000000000000000000000000") -- zero'ize the mac 282 local hash = string.format("%s:$rsvp$1$%s$%s", pinfo.number, wholeMsgProper, hash) 283 print(hash) 284end 285 286function tap_dhcpv4.draw() 287end 288 289 290 291-- Extract iSCSI CHAP hashes from .pcap files. 292-- 293-- WARNING: This code is unlikely to handle parallel login sessions well! 294 295tap_iscsi = Listener.new(nil, "iscsi") 296 297local f_opcode = Field.new("iscsi.opcode") 298local f_kv = Field.new("iscsi.keyvalue") 299 300local username = nil 301local challenge = nil 302local response = nil 303local id = nil 304 305function tap_iscsi.packet(pinfo,tvb,tapdata) 306 local opcode = f_opcode() 307 308 if opcode.value == 0x23 then -- extract CHAP_C, and CHAP_I 309 items = {f_kv()} 310 for index in pairs(items) do 311 item = tostring(items[index]) 312 if string.find(item, 'CHAP_C') then 313 challenge = item:gsub("CHAP_C=0x", "") -- robust? 314 end 315 if string.find(item, 'CHAP_I') then 316 id = item:gsub("CHAP_I=", "") -- robust? 317 end 318 end 319 end 320 321 if opcode.value == 0x3 then -- extract CHAP_N, and CHAP_R 322 items = {f_kv()} 323 for index in pairs(items) do 324 item = tostring(items[index]) 325 if string.find(item, 'CHAP_R') then 326 response = item:gsub("CHAP_R=0x", "") 327 end 328 if string.find(item, 'CHAP_N') then 329 username = item:gsub("CHAP_N=", "") 330 end 331 end 332 end 333 334 if username and challenge and response then 335 local hash = string.format("%s:$chap$%s*%s*%s", username, id, challenge, response) 336 print(hash) 337 username = nil 338 challenge = nil 339 response = nil 340 id = nil 341 end 342end 343 344function tap_iscsi.draw() 345end 346 347 348-- Extract DHCP OMAPI hashes from .pcap files. Tested with omshell, and pypureomapi. 349tap_omapi = Listener.new(nil, "omapi") 350 351local f_authid = Field.new("omapi.authid") 352local f_authlen = Field.new("omapi.authlength") 353local f_omapi = Field.new("omapi") 354local omapi_tip_printed = false 355 356function tap_omapi.packet(pinfo,tvb,tapdata) 357 if not omapi_tip_printed then 358 print("[WARNING] The DHCP OMAPI secret value is likely to be uncrackable under normal circumstances!") 359 omapi_tip_printed = true 360 end 361 362 local authid = f_authid() 363 if not authid then 364 return 365 end 366 if authid.value ~= 1 then 367 return 368 end 369 370 local authlen = f_authlen() 371 if authlen.value ~= 16 then 372 print("[DEBUG] omapi.authlength is not 16, please report this to us!") 373 return 374 end 375 376 local omapi_field = f_omapi() 377 local omapi_payload = omapi_field.range() 378 local wholeMsg = tostring(omapi_payload:bytes():tohex():lower()) 379 local payload = string.sub(wholeMsg, 8+1, -32-1) 380 local signature = string.sub(wholeMsg, -32) 381 local hash = string.format("%s:$rsvp$1$%s$%s", pinfo.number, payload, signature) 382 print(hash) 383end 384 385function tap_omapi.draw() 386end 387