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
81 82 83 |
# File 'lib/rex/proto/ntlm/message.rb', line 81 def decode64(str) parse(Rex::Text::decode_base64(str)) end |
.downgrade_type_message(message) ⇒ Object
Downgrading Type messages to LMv1/NTLMv1 and removing signing
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 527 528 529 530 531 532 |
# File 'lib/rex/proto/ntlm/message.rb', line 493 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
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
# File 'lib/rex/proto/ntlm/message.rb', line 65 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
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 483 484 485 486 487 488 |
# File 'lib/rex/proto/ntlm/message.rb', line 403 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
368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 |
# File 'lib/rex/proto/ntlm/message.rb', line 368 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
113 114 115 |
# File 'lib/rex/proto/ntlm/message.rb', line 113 def data_size security_buffers.inject(0){|sum, a| sum += a[1].data_size} end |
#decode64(str) ⇒ Object
107 108 109 |
# File 'lib/rex/proto/ntlm/message.rb', line 107 def decode64(str) parse(Rex::Text::decode_base64(str)) end |
#dump_flags ⇒ Object
94 95 96 |
# File 'lib/rex/proto/ntlm/message.rb', line 94 def dump_flags CONST::FLAG_KEYS.each{ |k| print(k, "=", flag?(k), "\n") } end |
#encode64 ⇒ Object
103 104 105 |
# File 'lib/rex/proto/ntlm/message.rb', line 103 def encode64 Rex::Text::encode_base64(serialize) end |
#has_flag?(flag) ⇒ Boolean
self
86 87 88 |
# File 'lib/rex/proto/ntlm/message.rb', line 86 def has_flag?(flag) (self[:flag].value & CONST::FLAGS[flag]) == CONST::FLAGS[flag] end |
#head_size ⇒ Object
111 |
# File 'lib/rex/proto/ntlm/message.rb', line 111 alias head_size size |
#serialize ⇒ Object
98 99 100 101 |
# File 'lib/rex/proto/ntlm/message.rb', line 98 def serialize deflag super + security_buffers.map{|n, f| f.value}.join end |
#set_flag(flag) ⇒ Object
90 91 92 |
# File 'lib/rex/proto/ntlm/message.rb', line 90 def set_flag(flag) self[:flag].value |= CONST::FLAGS[flag] end |
#size ⇒ Object
117 118 119 |
# File 'lib/rex/proto/ntlm/message.rb', line 117 def size head_size + data_size end |