More SMB stuff

git-svn-id: file:///home/svn/incoming/trunk@2863 4d416f70-5f16-0410-b530-b9f4589650da
This commit is contained in:
HD Moore 2005-09-22 04:04:06 +00:00
parent 579a3db148
commit 04abd76d8d
5 changed files with 380 additions and 69 deletions

View File

@ -1,52 +0,0 @@
$:.unshift(File.join(File.dirname(__FILE__), '../../lib'))
require 'rex/struct2'
# Create a NetBIOS session packet template
def self.make_nbs (template)
Rex::Struct2::CStructTemplate.new(
[ 'uint8', 'Type', 0 ],
[ 'uint8', 'Flags', 0 ],
[ 'uint16n', 'PayloadLen', 0 ],
[ 'template', 'Payload', template ]
).create_restraints(
[ 'Payload', 'PayloadLen', nil, true ]
)
end
# The SMB header template
SMB_HDR = Rex::Struct2::CStructTemplate.new(
[ 'uint32n', 'Magic', 0xff534d42 ],
[ 'uint8', 'Command', 0 ],
[ 'uint32v', 'ErrorClass', 0 ],
[ 'uint8', 'Flags1', 0 ],
[ 'uint16v', 'Flags2', 0 ],
[ 'uint16v', 'ProcessIDHigh', 0 ],
[ 'uint32v', 'Signature1', 0 ],
[ 'uint32v', 'Signature2', 0 ],
[ 'uint16v', 'Reserved1', 0 ],
[ 'uint16v', 'TreeID', 0 ],
[ 'uint16v', 'ProcessID', 0 ],
[ 'uint16v', 'UserID', 0 ],
[ 'uint16v', 'MultiplexID', 0 ],
[ 'uint8', 'WordCount', 0 ]
)
# A SMB template for SMB Tree Connect requests
SMB_TREE_CONN_HDR_PKT = Rex::Struct2::CStructTemplate.new(
[ 'template', 'SMB', SMB_HDR ],
[ 'uint8', 'AndX', 0 ],
[ 'uint8', 'Reserved1', 0 ],
[ 'uint16v', 'AndXOffset', 0 ],
[ 'uint16v', 'Flags', 0 ],
[ 'uint16v', 'PasswordLen', 0 ],
[ 'uint16v', 'ByteCount', 0 ],
[ 'string', 'Payload' ]
).create_restraints(
[ 'Payload', 'ByteCount', nil, true ]
)
SMB_TREE_CONN_PKT = self.make_nbs(SMB_TREE_CONN_HDR_PKT)
x = SMB_TREE_CONN_PKT.make_struct
p x.to_s

View File

@ -84,8 +84,11 @@ UTILS = Rex::Proto::SMB::Utils
when CONST::SMB_COM_SESSION_SETUP_ANDX
return smb_parse_session_setup(pkt, data)
when CONST::SMB_COM_TREE_CONNECT_ANDX
return smb_parse_tree_connect(pkt, data)
else
puts "Unknown" + pkt['Payload']['SMB'].v['Command'].to_s
puts "Unknown >> " + pkt['Payload']['SMB'].v['Command'].to_s
return pkt
end
@ -114,24 +117,59 @@ UTILS = Rex::Proto::SMB::Utils
return res
end
# Process SMB error responses
if (pkt['Payload']['SMB'].v['WordCount'] == 0)
return pkt
end
puts "Unknown WordCount: " + pkt['Payload']['SMB'].v['WordCount'].to_s
return pkt
end
# Process incoming SMB_COM_SESSION_SETUP_ANDX packets
def smb_parse_session_setup(pkt, data)
# Process NTLM negotiate responses
# Process NTLMv2 negotiate responses
if (pkt['Payload']['SMB'].v['WordCount'] == 4)
res = CONST::SMB_SETUP_NTLMV2_RES_PKT.make_struct
res.from_s(data)
return res
end
# Process NTLMv1 and LANMAN responses
if (pkt['Payload']['SMB'].v['WordCount'] == 3)
res = CONST::SMB_SETUP_RES_PKT.make_struct
res.from_s(data)
return res
end
# Process SMB error responses
if (pkt['Payload']['SMB'].v['WordCount'] == 0)
return pkt
end
puts "Unknown WordCount: " + pkt['Payload']['SMB'].v['WordCount'].to_s
return pkt
end
# Process incoming SMB_COM_TREE_CONNECT_ANDX packets
def smb_parse_tree_connect(pkt, data)
if (pkt['Payload']['SMB'].v['WordCount'] == 3)
res = CONST::SMB_TREE_CONN_RES_PKT.make_struct
res.from_s(data)
return res
end
# Process SMB error responses
if (pkt['Payload']['SMB'].v['WordCount'] == 0)
return pkt
end
puts "Unknown WordCount: " + pkt['Payload']['SMB'].v['WordCount'].to_s
return pkt
end
# Request a SMB session over NetBIOS
def session_request (name = '*SMBSERVER')
@ -237,9 +275,120 @@ UTILS = Rex::Proto::SMB::Utils
return nil
end
# Authenticate using clear-text passwords
def session_setup_clear(user = '', pass = '', domain = '')
data = ''
data << pass + "\x00"
data << user + "\x00"
data << domain + "\x00"
data << self.native_os + "\x00"
data << self.native_lm + "\x00"
pkt = CONST::SMB_SETUP_LANMAN_PKT.make_struct
self.smb_defaults(pkt['Payload']['SMB'])
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_SESSION_SETUP_ANDX
pkt['Payload']['SMB'].v['Flags1'] = 0x18
pkt['Payload']['SMB'].v['Flags2'] = 0x2001
pkt['Payload']['SMB'].v['WordCount'] = 10
pkt['Payload'].v['AndX'] = 255
pkt['Payload'].v['MaxBuff'] = 0xffdf
pkt['Payload'].v['MaxMPX'] = 2
pkt['Payload'].v['VCNum'] = 1
pkt['Payload'].v['PasswordLen'] = pass.length + 1
pkt['Payload'].v['Capabilities'] = 64
pkt['Payload'].v['SessionKey'] = self.session_id
pkt['Payload'].v['Payload'] = data
self.smb_send(pkt.to_s)
ack = self.smb_recv_parse
# Make sure the response we received was the correct type
if (ack['Payload']['SMB'].v['Command'] != CONST::SMB_COM_SESSION_SETUP_ANDX)
return nil
end
if (ack['Payload']['SMB'].v['ErrorClass'] != 0)
return ack
end
if (ack['Payload'].v['Action'] != 1 and user.length > 0)
self.auth_user = user
end
self.auth_user_id = ack['Payload']['SMB'].v['UserID']
info = ack['Payload'].v['Payload'].split(/\x00/)
self.peer_native_os = info[0]
self.peer_native_lm = info[1]
self.default_domain = info[2]
# XXX what to do on error?
return ack
end
# Authenticate using NTLMv1
def session_setup_ntlmv1(user = '', pass = '', domain = '')
# Authenticate using extended security negotiation
hash_lm = pass.length > 0 ? CRYPT.lanman_des(pass, self.challenge_key) : ''
hash_nt = pass.length > 0 ? CRYPT.ntlm_md4(pass, self.challenge_key) : ''
data = ''
data << hash_lm
data << hash_nt
data << user + "\x00"
data << domain + "\x00"
data << self.native_os + "\x00"
data << self.native_lm + "\x00"
pkt = CONST::SMB_SETUP_NTLMV1_PKT.make_struct
self.smb_defaults(pkt['Payload']['SMB'])
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_SESSION_SETUP_ANDX
pkt['Payload']['SMB'].v['Flags1'] = 0x18
pkt['Payload']['SMB'].v['Flags2'] = 0x2001
pkt['Payload']['SMB'].v['WordCount'] = 13
pkt['Payload'].v['AndX'] = 255
pkt['Payload'].v['MaxBuff'] = 0xffdf
pkt['Payload'].v['MaxMPX'] = 2
pkt['Payload'].v['VCNum'] = 1
pkt['Payload'].v['PasswordLenLM'] = hash_lm.length
pkt['Payload'].v['PasswordLenNT'] = hash_nt.length
pkt['Payload'].v['Capabilities'] = 64
pkt['Payload'].v['SessionKey'] = self.session_id
pkt['Payload'].v['Payload'] = data
self.smb_send(pkt.to_s)
ack = self.smb_recv_parse
# Make sure the response we received was the correct type
if (ack['Payload']['SMB'].v['Command'] != CONST::SMB_COM_SESSION_SETUP_ANDX)
return nil
end
if (ack['Payload']['SMB'].v['ErrorClass'] != 0)
return ack
end
if (ack['Payload'].v['Action'] != 1 and user.length > 0)
self.auth_user = user
end
self.auth_user_id = ack['Payload']['SMB'].v['UserID']
info = ack['Payload'].v['Payload'].split(/\x00/)
self.peer_native_os = info[0]
self.peer_native_lm = info[1]
self.default_domain = info[2]
# XXX what to do on error?
return ack
end
# Authenticate using extended security negotiation (NTLMv2)
def session_setup_ntlmv2(user = '', pass = '', domain = '', name = 'WORKSTATION1')
data = ''
@ -339,13 +488,97 @@ UTILS = Rex::Proto::SMB::Utils
if (ack['Payload']['SMB'].v['Command'] != CONST::SMB_COM_SESSION_SETUP_ANDX)
return nil
end
# We want to see no error message
if (ack['Payload']['SMB'].v['ErrorClass'] != 0)
return nil
end
return ack
end
self.auth_user_id = ack['Payload']['SMB'].v['UserID']
# XXX what do on error?
return ack
end
# Connect to a specified share with an optional password
def tree_connect(share = 'IPC$', pass = '')
data = ''
data << pass + "\x00"
data << share + "\x00"
data << '?????' + "\x00"
pkt = CONST::SMB_TREE_CONN_PKT.make_struct
self.smb_defaults(pkt['Payload']['SMB'])
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_TREE_CONNECT_ANDX
pkt['Payload']['SMB'].v['Flags1'] = 0x18
pkt['Payload']['SMB'].v['Flags2'] = 0x2001
pkt['Payload']['SMB'].v['WordCount'] = 4
pkt['Payload'].v['AndX'] = 255
pkt['Payload'].v['PasswordLen'] = pass.length + 1
pkt['Payload'].v['Capabilities'] = 64
pkt['Payload'].v['Payload'] = data
self.smb_send(pkt.to_s)
ack = self.smb_recv_parse
# Make sure the response we received was the correct type
if (ack['Payload']['SMB'].v['Command'] != CONST::SMB_COM_TREE_CONNECT_ANDX)
return nil
end
if (ack['Payload']['SMB'].v['ErrorClass'] != 0)
return ack
end
self.last_tree_id = ack['Payload']['SMB'].v['TreeID']
info = ack['Payload'].v['Payload'].split(/\x00/)
return ack
end
# Connect to a specified share with an optional password
def trans (pipe, param = '', body = '', setup_count = 0, setup_data = '')
# null-terminate the pipe parameter if needed
if (pipe[-1] != 0)
pipe << "\x00"
end
data = pipe + param + body
pkt = CONST::SMB_TRANS_PKT.make_struct
self.smb_defaults(pkt['Payload']['SMB'])
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_TRANSACTION
pkt['Payload']['SMB'].v['Flags1'] = 0x18
pkt['Payload']['SMB'].v['Flags2'] = 0x2001
pkt['Payload']['SMB'].v['WordCount'] = 14 + setup_count
pkt['Payload'].v['AndX'] = 255
pkt['Payload'].v['PasswordLen'] = pass.length + 1
pkt['Payload'].v['Capabilities'] = 64
pkt['Payload'].v['Payload'] = data
self.smb_send(pkt.to_s)
ack = self.smb_recv_parse
# Make sure the response we received was the correct type
if (ack['Payload']['SMB'].v['Command'] != CONST::SMB_COM_TRANSACTION)
return nil
end
if (ack['Payload']['SMB'].v['ErrorClass'] != 0)
return ack
end
self.last_tree_id = ack['Payload']['SMB'].v['TreeID']
info = ack['Payload'].v['Payload'].split(/\x00/)
return ack
end
# public methods
attr_accessor :native_os, :native_lm, :encrypt_passwords, :extended_security

View File

@ -12,7 +12,7 @@ class Rex::Proto::SMB::Client::UnitTest < Test::Unit::TestCase
Klass = Rex::Proto::SMB::Client
@@host = '192.168.10.184'
@@host = '192.168.0.42'
@@port = 139
def test_smb_session_request
@ -40,7 +40,17 @@ class Rex::Proto::SMB::Client::UnitTest < Test::Unit::TestCase
ok = c.session_setup_ntlmv2
assert_kind_of(Rex::Struct2::CStruct, ok)
ok = c.session_setup_ntlmv1
assert_kind_of(Rex::Struct2::CStruct, ok)
ok = c.session_setup_clear
assert_kind_of(Rex::Struct2::CStruct, ok)
ok = c.tree_connect
assert_kind_of(Rex::Struct2::CStruct, ok)
end

View File

@ -55,7 +55,7 @@ end
# A raw NetBIOS session template
NBRAW_HDR_PKT = Rex::Struct2::CStructTemplate.new(
[ 'string', 'Payload' ]
[ 'string', 'Payload', nil, '']
)
NBRAW_PKT = self.make_nbs(NBRAW_HDR_PKT)
@ -93,7 +93,7 @@ SMB_NEG_HDR_PKT = Rex::Struct2::CStructTemplate.new(
[ 'template', 'SMB', SMB_HDR ],
[ 'uint16v', 'ByteCount', 0 ],
[ 'string', 'Payload' ]
[ 'string', 'Payload', nil, '' ]
).create_restraints(
[ 'Payload', 'ByteCount', nil, true ]
)
@ -116,7 +116,7 @@ SMB_NEG_RES_LM_HDR_PKT = Rex::Struct2::CStructTemplate.new(
[ 'uint16v', 'KeyLength', 0 ],
[ 'uint16v', 'Reserved1', 0 ],
[ 'uint16v', 'ByteCount', 0 ],
[ 'string', 'EncryptionKey' ]
[ 'string', 'EncryptionKey', nil, '' ]
).create_restraints(
[ 'EncryptionKey', 'ByteCount', nil, true ]
)
@ -140,7 +140,7 @@ SMB_NEG_RES_NT_HDR_PKT = Rex::Struct2::CStructTemplate.new(
[ 'uint8', 'KeyLength', 0 ],
[ 'uint16v', 'ByteCount', 0 ],
[ 'string', 'GUID', 16, '' ],
[ 'string', 'SecurityBlob' ]
[ 'string', 'SecurityBlob', nil, '' ]
)
SMB_NEG_RES_NT_PKT = self.make_nbs(SMB_NEG_RES_NT_HDR_PKT)
@ -154,6 +154,64 @@ SMB_NEG_RES_ERR_HDR_PKT = Rex::Struct2::CStructTemplate.new(
SMB_NEG_RES_ERR_PKT = self.make_nbs(SMB_NEG_RES_ERR_HDR_PKT)
# A SMB template for SMB Session Setup responses (LANMAN/NTLMV1)
SMB_SETUP_RES_HDR_PKT = Rex::Struct2::CStructTemplate.new(
[ 'template', 'SMB', SMB_HDR ],
[ 'uint8', 'AndX', 0 ],
[ 'uint8', 'Reserved1', 0 ],
[ 'uint16v', 'AndXOffset', 0 ],
[ 'uint16v', 'Action', 0 ],
[ 'uint16v', 'SecurityBlobLen', 0 ],
[ 'uint16v', 'ByteCount', 0 ],
[ 'string', 'Payload', nil, '' ]
).create_restraints(
[ 'Payload', 'ByteCount', nil, true ]
)
SMB_SETUP_RES_PKT = self.make_nbs(SMB_SETUP_RES_HDR_PKT)
# A SMB template for SMB Session Setup requests (LANMAN)
SMB_SETUP_LANMAN_HDR_PKT = Rex::Struct2::CStructTemplate.new(
[ 'template', 'SMB', SMB_HDR ],
[ 'uint8', 'AndX', 0 ],
[ 'uint8', 'Reserved1', 0 ],
[ 'uint16v', 'AndXOffset', 0 ],
[ 'uint16v', 'MaxBuff', 0 ],
[ 'uint16v', 'MaxMPX', 0 ],
[ 'uint16v', 'VCNum', 0 ],
[ 'uint32v', 'SessionKey', 0 ],
[ 'uint16v', 'PasswordLen', 0 ],
[ 'uint32v', 'Reserved2', 0 ],
[ 'uint16v', 'ByteCount', 0 ],
[ 'string', 'Payload', nil, '' ]
).create_restraints(
[ 'Payload', 'ByteCount', nil, true ]
)
SMB_SETUP_LANMAN_PKT = self.make_nbs(SMB_SETUP_LANMAN_HDR_PKT)
# A SMB template for SMB Session Setup requests (NTLMV1)
SMB_SETUP_NTLMV1_HDR_PKT = Rex::Struct2::CStructTemplate.new(
[ 'template', 'SMB', SMB_HDR ],
[ 'uint8', 'AndX', 0 ],
[ 'uint8', 'Reserved1', 0 ],
[ 'uint16v', 'AndXOffset', 0 ],
[ 'uint16v', 'MaxBuff', 0 ],
[ 'uint16v', 'MaxMPX', 0 ],
[ 'uint16v', 'VCNum', 0 ],
[ 'uint32v', 'SessionKey', 0 ],
[ 'uint16v', 'PasswordLenLM', 0 ],
[ 'uint16v', 'PasswordLenNT', 0 ],
[ 'uint32v', 'Reserved2', 0 ],
[ 'uint32v', 'Capabilities', 0 ],
[ 'uint16v', 'ByteCount', 0 ],
[ 'string', 'Payload', nil, '' ]
).create_restraints(
[ 'Payload', 'ByteCount', nil, true ]
)
SMB_SETUP_NTLMV1_PKT = self.make_nbs(SMB_SETUP_NTLMV1_HDR_PKT)
# A SMB template for SMB Session Setup requests (NTLMV2)
SMB_SETUP_NTLMV2_HDR_PKT = Rex::Struct2::CStructTemplate.new(
[ 'template', 'SMB', SMB_HDR ],
@ -168,12 +226,13 @@ SMB_SETUP_NTLMV2_HDR_PKT = Rex::Struct2::CStructTemplate.new(
[ 'uint32v', 'Reserved2', 0 ],
[ 'uint32v', 'Capabilities', 0 ],
[ 'uint16v', 'ByteCount', 0 ],
[ 'string', 'Payload' ]
[ 'string', 'Payload', nil, '' ]
).create_restraints(
[ 'Payload', 'ByteCount', nil, true ]
)
SMB_SETUP_NTLMV2_PKT = self.make_nbs(SMB_SETUP_NTLMV2_HDR_PKT)
# A SMB template for SMB Session Setup responses (NTLMV2)
SMB_SETUP_NTLMV2_RES_HDR_PKT = Rex::Struct2::CStructTemplate.new(
[ 'template', 'SMB', SMB_HDR ],
@ -183,12 +242,73 @@ SMB_SETUP_NTLMV2_RES_HDR_PKT = Rex::Struct2::CStructTemplate.new(
[ 'uint16v', 'Action', 0 ],
[ 'uint16v', 'SecurityBlobLen', 0 ],
[ 'uint16v', 'ByteCount', 0 ],
[ 'string', 'Payload' ]
[ 'string', 'Payload', nil, '' ]
).create_restraints(
[ 'Payload', 'ByteCount', nil, true ]
)
SMB_SETUP_NTLMV2_RES_PKT = self.make_nbs(SMB_SETUP_NTLMV2_RES_HDR_PKT)
# A SMB template for SMB Tree Connect requests
SMB_TREE_CONN_HDR_PKT = Rex::Struct2::CStructTemplate.new(
[ 'template', 'SMB', SMB_HDR ],
[ 'uint8', 'AndX', 0 ],
[ 'uint8', 'Reserved1', 0 ],
[ 'uint16v', 'AndXOffset', 0 ],
[ 'uint16v', 'Flags', 0 ],
[ 'uint16v', 'PasswordLen', 0 ],
[ 'uint16v', 'ByteCount', 0 ],
[ 'string', 'Payload', nil, '' ]
).create_restraints(
[ 'Payload', 'ByteCount', nil, true ]
)
SMB_TREE_CONN_PKT = self.make_nbs(SMB_TREE_CONN_HDR_PKT)
# A SMB template for SMB Tree Connect requests
SMB_TREE_CONN_RES_HDR_PKT = Rex::Struct2::CStructTemplate.new(
[ 'template', 'SMB', SMB_HDR ],
[ 'uint8', 'AndX', 0 ],
[ 'uint8', 'Reserved1', 0 ],
[ 'uint16v', 'AndXOffset', 0 ],
[ 'uint16v', 'OptionalSupport', 0 ],
[ 'uint16v', 'ByteCount', 0 ],
[ 'string', 'Payload', nil, '' ]
).create_restraints(
[ 'Payload', 'ByteCount', nil, true ]
)
SMB_TREE_CONN_RES_PKT = self.make_nbs(SMB_TREE_CONN_RES_HDR_PKT)
# A SMB template for SMB Transaction requests
SMB_TRANS_HDR_PKT = Rex::Struct2::CStructTemplate.new(
[ 'template', 'SMB', SMB_HDR ],
[ 'uint16v', 'ParamCountTotal', 0 ],
[ 'uint16v', 'DataCountTotal', 0 ],
[ 'uint16v', 'ParamCountMax', 0 ],
[ 'uint16v', 'DataCountMax', 0 ],
[ 'uint8', 'SetupCountMax', 0 ],
[ 'uint8', 'Reserved1', 0 ],
[ 'uint16v', 'Flags', 0 ],
[ 'uint32v', 'Timeout', 0 ],
[ 'uint16v', 'Reserved1', 0 ],
[ 'uint16v', 'ParamCount', 0 ],
[ 'uint16v', 'ParamOffset', 0 ],
[ 'uint16v', 'DataCount', 0 ],
[ 'uint16v', 'DataOffset', 0 ],
[ 'uint8', 'SetupCount', 0 ],
[ 'uint8', 'Reserved3', 0 ],
[ 'string', 'SetupData', nil, '' ], # SetupCount * 2
[ 'uint16v', 'ByteCount', 0 ],
[ 'string', 'Payload', nil, '' ]
).create_restraints(
[ 'Payload', 'ByteCount', nil, true ],
[ 'SetupData', 'SetupCount', nil, true, nil, nil, proc { |i| i * 2 }, nil ]
)
SMB_TRANS_PKT = self.make_nbs(SMB_TRANS_HDR_PKT)
end
end
end

View File

@ -90,7 +90,7 @@ require 'rex/text'
)
)
)
puts "Returning: " + blob.length.to_s
return blob
end