Class/Module Index [+]

Quicksearch

Rex::Proto::NTLM::Message

Constants

BASE
CONST
CRYPT
Type0

sub class definitions

Type1
Type2
Type3

Public Class Methods

decode64(str) click to toggle source
# File lib/rex/proto/ntlm/message.rb, line 80
def decode64(str)
        parse(Rex::Text::decode_base64(str))
end
downgrade_type_message(message) click to toggle source

Downgrading Type messages to LMv1/NTLMv1 and removing signing

# File lib/rex/proto/ntlm/message.rb, line 492
def self.downgrade_type_message(message)
        decode = Rex::Text.decode_base64(message.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) click to toggle source
# File lib/rex/proto/ntlm/message.rb, line 64
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) click to toggle source

Process Type 1 NTLM Messages, return a Base64 Type 2 Message

# File lib/rex/proto/ntlm/message.rb, line 402
def self.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)

        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(message.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\00"" + # 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) click to toggle source

Process Type 3 NTLM Message (in Base64)

from www.innovation.ch/personal/ronald/ntlm.html

struct {
        byte  protocol[8];  // 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'
        byte  type;         // 0x03
        byte  zero[3];

        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[2];

        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[2];

        short dom_len;      // domain string length
        short dom_len;      // domain string length
        short dom_off;      // domain string offset (always 0x40)
        byte  zero[2];

        short user_len;     // username string length
        short user_len;     // username string length
        short user_off;     // username string offset
        byte  zero[2];

        short host_len;     // host string length
        short host_len;     // host string length
        short host_off;     // host string offset
        byte  zero[6];

        short msg_len;      // message length
        byte  zero[2];

        short flags;        // 0x8201
        byte  zero[2];

        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
# File lib/rex/proto/ntlm/message.rb, line 367
def self.process_type3_message(message)
        decode = Rex::Text.decode_base64(message.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

Public Instance Methods

data_size() click to toggle source
# File lib/rex/proto/ntlm/message.rb, line 112
def data_size
        security_buffers.inject(0){|sum, a| sum += a[1].data_size}
end
decode64(str) click to toggle source
# File lib/rex/proto/ntlm/message.rb, line 106
def decode64(str)
        parse(Rex::Text::decode_base64(str))
end
dump_flags() click to toggle source
# File lib/rex/proto/ntlm/message.rb, line 93
def dump_flags
        CONST::FLAG_KEYS.each{ |k| print(k, "=", flag?(k), "\n") }
end
encode64() click to toggle source
# File lib/rex/proto/ntlm/message.rb, line 102
def encode64
        Rex::Text::encode_base64(serialize)
end
has_flag?(flag) click to toggle source
# File lib/rex/proto/ntlm/message.rb, line 85
def has_flag?(flag)
        (self[:flag].value & CONST::FLAGS[flag]) == CONST::FLAGS[flag]
end
head_size() click to toggle source
Alias for: size
serialize() click to toggle source
# File lib/rex/proto/ntlm/message.rb, line 97
def serialize
        deflag
        super + security_buffers.map{|n, f| f.value}.join
end
set_flag(flag) click to toggle source
# File lib/rex/proto/ntlm/message.rb, line 89
def set_flag(flag)
        self[:flag].value  |= CONST::FLAGS[flag]
end
size() click to toggle source
# File lib/rex/proto/ntlm/message.rb, line 116
def size
        head_size + data_size
end
Also aliased as: head_size

[Validate]

Generated with the Darkfish Rdoc Generator 2.