Class: Rex::Proto::NTLM::Message
- Inherits:
-
Base::FieldSet
- Object
- Base::FieldSet
- Rex::Proto::NTLM::Message
- Defined in:
- lib/rex/proto/ntlm/message.rb
Defined Under Namespace
Constant Summary collapse
Class Method Summary collapse
- .decode64(str) ⇒ Object
-
.downgrade_type_message(message) ⇒ Object
Downgrading Type messages to LMv1/NTLMv1 and removing signing.
- .parse(str) ⇒ Object
-
.process_type1_message(message, nonce = "\x11\x22\x33\x44\x55\x66\x77\x88", win_domain = 'DOMAIN', win_name = 'SERVER', dns_name = 'server', dns_domain = 'example.com', downgrade = true) ⇒ Object
Process Type 1 NTLM Messages, return a Base64 Type 2 Message.
-
.process_type3_message(message) ⇒ Object
Process Type 3 NTLM Message (in Base64).
Instance Method Summary collapse
- #data_size ⇒ Object
- #decode64(str) ⇒ Object
- #dump_flags ⇒ Object
- #encode64 ⇒ Object
-
#has_flag?(flag) ⇒ Boolean
self.
- #head_size ⇒ Object
- #serialize ⇒ Object
- #set_flag(flag) ⇒ Object
- #size ⇒ Object
Methods inherited from Base::FieldSet
#[], #[]=, define, #disable, #enable, #initialize, int16LE, int32LE, int64LE, names, opts, #parse, prototypes, security_buffer, string, types
Constructor Details
This class inherits a constructor from Rex::Proto::NTLM::Base::FieldSet
Class Method Details
.decode64(str) ⇒ Object
75 76 77 |
# File 'lib/rex/proto/ntlm/message.rb', line 75 def decode64(str) parse(Rex::Text::decode_base64(str)) end |
.downgrade_type_message(message) ⇒ Object
Downgrading Type messages to LMv1/NTLMv1 and removing signing
487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 |
# File 'lib/rex/proto/ntlm/message.rb', line 487 def self.() decode = Rex::Text.decode_base64(.strip) type = decode[8,1].unpack("C").first if (type > 0 and type < 4) reqflags = decode[12..15] if (type == 1 or type == 3) reqflags = decode[20..23] if (type == 2) reqflags = reqflags.unpack("V") # Remove NEGOTIATE_NTLMV2_KEY and NEGOTIATE_ALWAYS_SIGN, this lowers the negotiation # down to LMv1/NTLMv1. if (reqflags & CONST::NEGOTIATE_NTLM2_KEY) == CONST::NEGOTIATE_NTLM2_KEY reqflags = reqflags - CONST::NEGOTIATE_NTLM2_KEY end if (reqflags & CONST::NEGOTIATE_ALWAYS_SIGN) == CONST::NEGOTIATE_ALWAYS_SIGN reqflags = reqflags - CONST::NEGOTIATE_ALWAYS_SIGN end # Return the flags back to the decode so we can base64 it again flags = reqflags.to_s(16) 0.upto(8) do |idx| if (idx > flags.length) flags.insert(0, "0") end end idx = 0 0.upto(3) do |cnt| if (type == 2) decode[23-cnt] = [flags[idx,1]].pack("C") else decode[15-cnt] = [flags[idx,1]].pack("C") end idx += 2 end end return Rex::Text.encode_base64(decode).delete("\n") # base64 encode and remove the returns end |
.parse(str) ⇒ Object
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
# File 'lib/rex/proto/ntlm/message.rb', line 59 def parse(str) m = Type0.new m.parse(str) case m.type when 1 t = Type1.parse(str) when 2 t = Type2.parse(str) when 3 t = Type3.parse(str) else raise ArgumentError, "unknown type: #{m.type}" end t end |
.process_type1_message(message, nonce = "\x11\x22\x33\x44\x55\x66\x77\x88", win_domain = 'DOMAIN', win_name = 'SERVER', dns_name = 'server', dns_domain = 'example.com', downgrade = true) ⇒ Object
Process Type 1 NTLM Messages, return a Base64 Type 2 Message
397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 |
# File 'lib/rex/proto/ntlm/message.rb', line 397 def self.(, nonce = "\x11\x22\x33\x44\x55\x66\x77\x88", win_domain = 'DOMAIN', win_name = 'SERVER', dns_name = 'server', dns_domain = 'example.com', downgrade = true) dns_name = Rex::Text.to_unicode(dns_name + "." + dns_domain) win_domain = Rex::Text.to_unicode(win_domain) dns_domain = Rex::Text.to_unicode(dns_domain) win_name = Rex::Text.to_unicode(win_name) decode = Rex::Text.decode_base64(.strip) type = decode[8,1].unpack("C").first if (type == 1) # A type 1 message has been received, lets build a type 2 message response reqflags = decode[12,4] reqflags = reqflags.unpack("V").first if (reqflags & CONST::REQUEST_TARGET) == CONST::REQUEST_TARGET if (downgrade) # At this time NTLMv2 and signing requirements are not supported if (reqflags & CONST::NEGOTIATE_NTLM2_KEY) == CONST::NEGOTIATE_NTLM2_KEY reqflags = reqflags - CONST::NEGOTIATE_NTLM2_KEY end if (reqflags & CONST::NEGOTIATE_ALWAYS_SIGN) == CONST::NEGOTIATE_ALWAYS_SIGN reqflags = reqflags - CONST::NEGOTIATE_ALWAYS_SIGN end end flags = reqflags + CONST::TARGET_TYPE_DOMAIN + CONST::TARGET_TYPE_SERVER tid = true tidoffset = 48 + win_domain.length tidbuff = [2].pack('v') + # tid type, win domain [win_domain.length].pack('v') + win_domain + [1].pack('v') + # tid type, server name [win_name.length].pack('v') + win_name + [4].pack('v') + # tid type, domain name [dns_domain.length].pack('v') + dns_domain + [3].pack('v') + # tid type, dns_name [dns_name.length].pack('v') + dns_name else flags = CONST::NEGOTIATE_UNICODE + CONST::NEGOTIATE_NTLM tid = false end type2msg = "NTLMSSP\0" + # protocol, 8 bytes "\x02\x00\x00\x00" # type, 4 bytes if (tid) type2msg += # Target security info, 8 bytes. Filled if REQUEST_TARGET [win_domain.length].pack('v') + # Length, 2 bytes [win_domain.length].pack('v') # Allocated space, 2 bytes end type2msg +="\x30\x00\x00\x00" + # Offset, 4 bytes [flags].pack('V') + # flags, 4 bytes nonce + # the nonce, 8 bytes "\x00" * 8 # Context (all 0s), 8 bytes if (tid) type2msg += # Target information security buffer. Filled if REQUEST_TARGET [tidbuff.length].pack('v') + # Length, 2 bytes [tidbuff.length].pack('v') + # Allocated space, 2 bytes [tidoffset].pack('V') + # Offset, 4 bytes (usually \x48 + length of win_domain) win_domain + # Target name data (domain in unicode if REQUEST_UNICODE) # Target information data tidbuff + # Type, 2 bytes # Length, 2 bytes # Data (in unicode if REQUEST_UNICODE) "\x00\x00\x00\x00" # Terminator, 4 bytes, all \x00 end type2msg = Rex::Text.encode_base64(type2msg).delete("\n") # base64 encode and remove the returns else # This is not a Type2 message type2msg = "" end return type2msg end |
.process_type3_message(message) ⇒ Object
Process Type 3 NTLM Message (in Base64)
from www.innovation.ch/personal/ronald/ntlm.html
struct { byte protocol; // ‘N’, ‘T’, ‘L’, ‘M’, ‘S’, ‘S’, ‘P’, ‘0’ byte type; // 0x03 byte zero;
short lm_resp_len; // LanManager response length (always 0x18) short lm_resp_len; // LanManager response length (always 0x18) short lm_resp_off; // LanManager response offset byte zero;
short nt_resp_len; // NT response length (always 0x18) short nt_resp_len; // NT response length (always 0x18) short nt_resp_off; // NT response offset byte zero;
short dom_len; // domain string length short dom_len; // domain string length short dom_off; // domain string offset (always 0x40) byte zero;
short user_len; // username string length short user_len; // username string length short user_off; // username string offset byte zero;
short host_len; // host string length short host_len; // host string length short host_off; // host string offset byte zero;
short msg_len; // message length byte zero;
short flags; // 0x8201 byte zero;
byte dom; // domain string (unicode UTF-16LE) byte user; // username string (unicode UTF-16LE) byte host; // host string (unicode UTF-16LE) byte lm_resp; // LanManager response byte nt_resp; // NT response } type_3_message
362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 |
# File 'lib/rex/proto/ntlm/message.rb', line 362 def self.() decode = Rex::Text.decode_base64(.strip) type = decode[8,1].unpack("C").first if (type == 3) lm_len = decode[12,2].unpack("v").first lm_offset = decode[16,2].unpack("v").first lm = decode[lm_offset, lm_len].unpack("H*").first nt_len = decode[20,2].unpack("v").first nt_offset = decode[24,2].unpack("v").first nt = decode[nt_offset, nt_len].unpack("H*").first dom_len = decode[28,2].unpack("v").first dom_offset = decode[32,2].unpack("v").first domain = decode[dom_offset, dom_len] user_len = decode[36,2].unpack("v").first user_offset = decode[40,2].unpack("v").first user = decode[user_offset, user_len] host_len = decode[44,2].unpack("v").first host_offset = decode[48,2].unpack("v").first host = decode[host_offset, host_len] return domain, user, host, lm, nt else return "", "", "", "", "" end end |
Instance Method Details
#data_size ⇒ Object
107 108 109 |
# File 'lib/rex/proto/ntlm/message.rb', line 107 def data_size security_buffers.inject(0){|sum, a| sum += a[1].data_size} end |
#decode64(str) ⇒ Object
101 102 103 |
# File 'lib/rex/proto/ntlm/message.rb', line 101 def decode64(str) parse(Rex::Text::decode_base64(str)) end |
#dump_flags ⇒ Object
88 89 90 |
# File 'lib/rex/proto/ntlm/message.rb', line 88 def dump_flags CONST::FLAG_KEYS.each{ |k| print(k, "=", flag?(k), "\n") } end |
#encode64 ⇒ Object
97 98 99 |
# File 'lib/rex/proto/ntlm/message.rb', line 97 def encode64 Rex::Text::encode_base64(serialize) end |
#has_flag?(flag) ⇒ Boolean
self
80 81 82 |
# File 'lib/rex/proto/ntlm/message.rb', line 80 def has_flag?(flag) (self[:flag].value & CONST::FLAGS[flag]) == CONST::FLAGS[flag] end |
#head_size ⇒ Object
105 |
# File 'lib/rex/proto/ntlm/message.rb', line 105 alias head_size size |
#serialize ⇒ Object
92 93 94 95 |
# File 'lib/rex/proto/ntlm/message.rb', line 92 def serialize deflag super + security_buffers.map{|n, f| f.value}.join end |
#set_flag(flag) ⇒ Object
84 85 86 |
# File 'lib/rex/proto/ntlm/message.rb', line 84 def set_flag(flag) self[:flag].value |= CONST::FLAGS[flag] end |
#size ⇒ Object
111 112 113 |
# File 'lib/rex/proto/ntlm/message.rb', line 111 def size head_size + data_size end |