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
78 79 80 |
# File 'lib/rex/proto/ntlm/message.rb', line 78 def decode64(str) parse(Rex::Text::decode_base64(str)) end |
.downgrade_type_message(message) ⇒ Object
Downgrading Type messages to LMv1/NTLMv1 and removing signing
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 527 528 529 |
# File 'lib/rex/proto/ntlm/message.rb', line 490 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
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
# File 'lib/rex/proto/ntlm/message.rb', line 62 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
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 483 484 485 |
# File 'lib/rex/proto/ntlm/message.rb', line 400 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
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 391 392 393 |
# File 'lib/rex/proto/ntlm/message.rb', line 365 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
110 111 112 |
# File 'lib/rex/proto/ntlm/message.rb', line 110 def data_size security_buffers.inject(0){|sum, a| sum += a[1].data_size} end |
#decode64(str) ⇒ Object
104 105 106 |
# File 'lib/rex/proto/ntlm/message.rb', line 104 def decode64(str) parse(Rex::Text::decode_base64(str)) end |
#dump_flags ⇒ Object
91 92 93 |
# File 'lib/rex/proto/ntlm/message.rb', line 91 def dump_flags CONST::FLAG_KEYS.each{ |k| print(k, "=", flag?(k), "\n") } end |
#encode64 ⇒ Object
100 101 102 |
# File 'lib/rex/proto/ntlm/message.rb', line 100 def encode64 Rex::Text::encode_base64(serialize) end |
#has_flag?(flag) ⇒ Boolean
self
83 84 85 |
# File 'lib/rex/proto/ntlm/message.rb', line 83 def has_flag?(flag) (self[:flag].value & CONST::FLAGS[flag]) == CONST::FLAGS[flag] end |
#head_size ⇒ Object
108 |
# File 'lib/rex/proto/ntlm/message.rb', line 108 alias head_size size |
#serialize ⇒ Object
95 96 97 98 |
# File 'lib/rex/proto/ntlm/message.rb', line 95 def serialize deflag super + security_buffers.map{|n, f| f.value}.join end |
#set_flag(flag) ⇒ Object
87 88 89 |
# File 'lib/rex/proto/ntlm/message.rb', line 87 def set_flag(flag) self[:flag].value |= CONST::FLAGS[flag] end |
#size ⇒ Object
114 115 116 |
# File 'lib/rex/proto/ntlm/message.rb', line 114 def size head_size + data_size end |