Do first commands refactoring
parent
52b41ab4f8
commit
80aef690a0
|
@ -12,11 +12,24 @@ module Msf
|
||||||
module Exploit::Remote::SMB::Server
|
module Exploit::Remote::SMB::Server
|
||||||
# This mixin provides a minimal SMB server
|
# This mixin provides a minimal SMB server
|
||||||
module Share
|
module Share
|
||||||
|
require 'msf/core/exploit/smb/server/share/command'
|
||||||
require 'msf/core/exploit/smb/server/share/information_level'
|
require 'msf/core/exploit/smb/server/share/information_level'
|
||||||
require 'msf/core/exploit/smb/server/share/sub_command'
|
require 'msf/core/exploit/smb/server/share/sub_command'
|
||||||
|
|
||||||
|
include Msf::Exploit::Remote::SMB::Server::Share::Command::Close
|
||||||
|
include Msf::Exploit::Remote::SMB::Server::Share::Command::Negotiate
|
||||||
|
include Msf::Exploit::Remote::SMB::Server::Share::Command::NtCreateAndx
|
||||||
|
include Msf::Exploit::Remote::SMB::Server::Share::Command::ReadAndx
|
||||||
|
include Msf::Exploit::Remote::SMB::Server::Share::Command::SessionSetupAndx
|
||||||
include Msf::Exploit::Remote::SMB::Server::Share::InformationLevel::Find
|
include Msf::Exploit::Remote::SMB::Server::Share::InformationLevel::Find
|
||||||
include Msf::Exploit::Remote::SMB::Server::Share::InformationLevel::Query
|
include Msf::Exploit::Remote::SMB::Server::Share::InformationLevel::Query
|
||||||
|
include Msf::Exploit::Remote::SMB::Server::Share::SubCommand::Trans2
|
||||||
|
include Msf::Exploit::Remote::SMB::Server::Share::SubCommand::Trans2::FindFirst2
|
||||||
|
include Msf::Exploit::Remote::SMB::Server::Share::SubCommand::Trans2::QueryFileInformation
|
||||||
|
include Msf::Exploit::Remote::SMB::Server::Share::SubCommand::Trans2::QueryPathInformation
|
||||||
|
include Msf::Exploit::Remote::SMB::Server::Share::InformationLevel::Find
|
||||||
|
include Msf::Exploit::Remote::SMB::Server::Share::InformationLevel::Query
|
||||||
|
include Msf::Exploit::Remote::SMB::Server::Share::SubCommand::Trans2
|
||||||
include Msf::Exploit::Remote::SMB::Server::Share::SubCommand::Trans2::FindFirst2
|
include Msf::Exploit::Remote::SMB::Server::Share::SubCommand::Trans2::FindFirst2
|
||||||
include Msf::Exploit::Remote::SMB::Server::Share::SubCommand::Trans2::QueryFileInformation
|
include Msf::Exploit::Remote::SMB::Server::Share::SubCommand::Trans2::QueryFileInformation
|
||||||
include Msf::Exploit::Remote::SMB::Server::Share::SubCommand::Trans2::QueryPathInformation
|
include Msf::Exploit::Remote::SMB::Server::Share::SubCommand::Trans2::QueryPathInformation
|
||||||
|
@ -133,283 +146,6 @@ module Msf
|
||||||
smb_error(cmd, c, CONST::SMB_STATUS_SUCCESS)
|
smb_error(cmd, c, CONST::SMB_STATUS_SUCCESS)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
|
||||||
# Responds to a client CLOSE request
|
|
||||||
#
|
|
||||||
def smb_cmd_close(c, buff)
|
|
||||||
dprint("[SMB_CMD_CLOSE]")
|
|
||||||
pkt = CONST::SMB_CLOSE_PKT.make_struct
|
|
||||||
pkt.from_s(buff)
|
|
||||||
|
|
||||||
pkt = CONST::SMB_CLOSE_RES_PKT.make_struct
|
|
||||||
smb_set_defaults(c, pkt)
|
|
||||||
|
|
||||||
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_CLOSE
|
|
||||||
pkt['Payload']['SMB'].v['Flags1'] = 0x88
|
|
||||||
pkt['Payload']['SMB'].v['Flags2'] = FLAGS2
|
|
||||||
pkt['Payload']['SMB'].v['WordCount'] = 0
|
|
||||||
|
|
||||||
c.put(pkt.to_s)
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# Negotiates a SHARE session with the client
|
|
||||||
#
|
|
||||||
def smb_cmd_negotiate(c, buff)
|
|
||||||
dprint("[SMB_CMD_NEGOTIATE]")
|
|
||||||
pkt = CONST::SMB_NEG_PKT.make_struct
|
|
||||||
pkt.from_s(buff)
|
|
||||||
|
|
||||||
dialects = pkt['Payload'].v['Payload'].gsub(/\x00/, '').split(/\x02/).grep(/^\w+/)
|
|
||||||
|
|
||||||
dialect = dialects.index("NT LM 0.12") || dialects.length-1
|
|
||||||
|
|
||||||
pkt = CONST::SMB_NEG_RES_NT_PKT.make_struct
|
|
||||||
smb_set_defaults(c, pkt)
|
|
||||||
|
|
||||||
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_NEGOTIATE
|
|
||||||
pkt['Payload']['SMB'].v['Flags1'] = 0x88
|
|
||||||
pkt['Payload']['SMB'].v['Flags2'] = FLAGS2
|
|
||||||
pkt['Payload']['SMB'].v['WordCount'] = 17
|
|
||||||
pkt['Payload'].v['Dialect'] = dialect
|
|
||||||
pkt['Payload'].v['SecurityMode'] = 2 # SHARE Security Mode
|
|
||||||
pkt['Payload'].v['MaxMPX'] = 50
|
|
||||||
pkt['Payload'].v['MaxVCS'] = 1
|
|
||||||
pkt['Payload'].v['MaxBuff'] = 4356
|
|
||||||
pkt['Payload'].v['MaxRaw'] = 65536
|
|
||||||
pkt['Payload'].v['SystemTimeLow'] = lo
|
|
||||||
pkt['Payload'].v['SystemTimeHigh'] = hi
|
|
||||||
pkt['Payload'].v['ServerTimeZone'] = 0x0
|
|
||||||
pkt['Payload'].v['SessionKey'] = 0
|
|
||||||
pkt['Payload'].v['Capabilities'] = 0x0080f3fd
|
|
||||||
pkt['Payload'].v['KeyLength'] = 8
|
|
||||||
pkt['Payload'].v['Payload'] = Rex::Text.rand_text_hex(8)
|
|
||||||
|
|
||||||
c.put(pkt.to_s)
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# Sets up an SMB session in response to a SESSION_SETUP_ANDX request
|
|
||||||
#
|
|
||||||
def smb_cmd_session_setup(c, buff)
|
|
||||||
dprint("[SMB_CMD_SESSION_SETUP]")
|
|
||||||
pkt = CONST::SMB_SETUP_RES_PKT.make_struct
|
|
||||||
smb_set_defaults(c, pkt)
|
|
||||||
|
|
||||||
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_SESSION_SETUP_ANDX
|
|
||||||
pkt['Payload']['SMB'].v['Flags1'] = 0x88
|
|
||||||
pkt['Payload']['SMB'].v['Flags2'] = FLAGS2
|
|
||||||
pkt['Payload']['SMB'].v['WordCount'] = 3
|
|
||||||
pkt['Payload'].v['AndX'] = 0x75
|
|
||||||
pkt['Payload'].v['Reserved1'] = 00
|
|
||||||
pkt['Payload'].v['AndXOffset'] = 96
|
|
||||||
pkt['Payload'].v['Action'] = 0x1 # Logged in as Guest
|
|
||||||
pkt['Payload'].v['Payload'] =
|
|
||||||
Rex::Text.to_unicode("Unix", 'utf-16be') + "\x00\x00" + # Native OS # Samba signature
|
|
||||||
Rex::Text.to_unicode("Samba 3.4.7", 'utf-16be') + "\x00\x00" + # Native LAN Manager # Samba signature
|
|
||||||
Rex::Text.to_unicode("WORKGROUP", 'utf-16be') + "\x00\x00\x00" + # Primary DOMAIN # Samba signature
|
|
||||||
tree_connect_response = ""
|
|
||||||
tree_connect_response << [7].pack("C") # Tree Connect Response : WordCount
|
|
||||||
tree_connect_response << [0xff].pack("C") # Tree Connect Response : AndXCommand
|
|
||||||
tree_connect_response << [0].pack("C") # Tree Connect Response : Reserved
|
|
||||||
tree_connect_response << [0].pack("v") # Tree Connect Response : AndXOffset
|
|
||||||
tree_connect_response << [0x1].pack("v") # Tree Connect Response : Optional Support
|
|
||||||
tree_connect_response << [0xa9].pack("C") # Access Mask for just Read and Exec
|
|
||||||
tree_connect_response << [0x00].pack("C")
|
|
||||||
tree_connect_response << [0x12].pack("C")
|
|
||||||
tree_connect_response << [0x00].pack("C")
|
|
||||||
tree_connect_response << [0].pack("v") # Tree Connect Response : Word Parameter
|
|
||||||
tree_connect_response << [0].pack("v") # Tree Connect Response : Word Parameter
|
|
||||||
tree_connect_response << [13].pack("v") # Tree Connect Response : ByteCount
|
|
||||||
tree_connect_response << "A:\x00" # Service
|
|
||||||
tree_connect_response << "#{Rex::Text.to_unicode("NTFS")}\x00\x00" # Extra byte parameters
|
|
||||||
# Fix the Netbios Session Service Message Length
|
|
||||||
# to have into account the tree_connect_response,
|
|
||||||
# need to do this because there isn't support for
|
|
||||||
# AndX still
|
|
||||||
my_pkt = pkt.to_s + tree_connect_response
|
|
||||||
original_length = my_pkt[2, 2].unpack("n").first
|
|
||||||
original_length = original_length + tree_connect_response.length
|
|
||||||
my_pkt[2, 2] = [original_length].pack("n")
|
|
||||||
c.put(my_pkt)
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# Responds to a client NT_CREATE_ANDX request
|
|
||||||
#
|
|
||||||
def smb_cmd_create(c, buff)
|
|
||||||
dprint("[SMB_CMD_CREATE]")
|
|
||||||
smb = @state[c]
|
|
||||||
pkt = CONST::SMB_CREATE_PKT.make_struct
|
|
||||||
pkt.from_s(buff)
|
|
||||||
|
|
||||||
# Tries to do CREATE and X
|
|
||||||
payload = pkt['Payload'].v['Payload'].gsub(/\x00/, '').gsub(/.*\\/, '\\').chomp.strip.split('\\').last
|
|
||||||
file = file_name
|
|
||||||
path = path_name
|
|
||||||
|
|
||||||
if payload.nil?
|
|
||||||
payload = file
|
|
||||||
end
|
|
||||||
|
|
||||||
if payload.length.to_s.eql?('1') or payload.eql?(path)
|
|
||||||
fid = smb[:dir_id].to_i
|
|
||||||
attribs = 0x10 # Ordinary Dir
|
|
||||||
eof = 0
|
|
||||||
isdir = 1
|
|
||||||
else
|
|
||||||
fid = smb[:file_id].to_i
|
|
||||||
attribs = 0x80 # File Attributes
|
|
||||||
eof = exe_contents.length
|
|
||||||
isdir = 0
|
|
||||||
end
|
|
||||||
|
|
||||||
pkt = CONST::SMB_CREATE_RES_PKT.make_struct
|
|
||||||
smb_set_defaults(c, pkt)
|
|
||||||
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_NT_CREATE_ANDX
|
|
||||||
pkt['Payload']['SMB'].v['Flags1'] = 0x88
|
|
||||||
pkt['Payload']['SMB'].v['Flags2'] = FLAGS2
|
|
||||||
pkt['Payload']['SMB'].v['WordCount'] = 42
|
|
||||||
pkt['Payload'].v['AndX'] = 0xff # no further commands
|
|
||||||
pkt['Payload'].v['OpLock'] = 0x3 # Grant Oplock on File
|
|
||||||
pkt['Payload'].v['FileID'] = fid
|
|
||||||
pkt['Payload'].v['Action'] = 0x1 # The file existed and was opened
|
|
||||||
pkt['Payload'].v['CreateTimeLow'] = lo
|
|
||||||
pkt['Payload'].v['CreateTimeHigh'] = hi
|
|
||||||
pkt['Payload'].v['AccessTimeLow'] = lo
|
|
||||||
pkt['Payload'].v['AccessTimeHigh'] = hi
|
|
||||||
pkt['Payload'].v['WriteTimeLow'] = lo
|
|
||||||
pkt['Payload'].v['WriteTimeHigh'] = hi
|
|
||||||
pkt['Payload'].v['ChangeTimeLow'] = lo
|
|
||||||
pkt['Payload'].v['ChangeTimeHigh'] = hi
|
|
||||||
pkt['Payload'].v['Attributes'] = attribs
|
|
||||||
pkt['Payload'].v['AllocLow'] = 0x100000
|
|
||||||
pkt['Payload'].v['AllocHigh'] = 0
|
|
||||||
pkt['Payload'].v['EOFLow'] = eof
|
|
||||||
pkt['Payload'].v['EOFHigh'] = 0
|
|
||||||
pkt['Payload'].v['FileType'] = 0
|
|
||||||
pkt['Payload'].v['IPCState'] = 0x7
|
|
||||||
pkt['Payload'].v['IsDirectory'] = isdir
|
|
||||||
|
|
||||||
# As above, if payload is a file or "\" send found response
|
|
||||||
if (payload.downcase.eql?(file.downcase)) or payload.length.to_s.eql?('1') or payload.eql?(path)
|
|
||||||
connect_response = ""
|
|
||||||
# GUID
|
|
||||||
connect_response << ([0].pack("C") * 16)
|
|
||||||
# File ID
|
|
||||||
connect_response << ([0].pack("C") * 6)
|
|
||||||
# Access Rights
|
|
||||||
connect_response << [0xff].pack("C")
|
|
||||||
connect_response << [0x01].pack("C")
|
|
||||||
connect_response << [0x1f].pack("C")
|
|
||||||
connect_response << [0].pack("C")
|
|
||||||
connect_response << ([0].pack("C") * 4) # Guest access
|
|
||||||
connect_response << ([0].pack("C") * 2) # Byte Count
|
|
||||||
|
|
||||||
my_pkt = pkt.to_s + connect_response
|
|
||||||
original_length = my_pkt[2, 2].unpack("n").first
|
|
||||||
original_length = original_length + connect_response.length
|
|
||||||
my_pkt[2, 2] = [original_length].pack("n")
|
|
||||||
c.put(my_pkt)
|
|
||||||
else
|
|
||||||
# Otherwise send not found
|
|
||||||
pkt = CONST::SMB_CREATE_RES_PKT.make_struct
|
|
||||||
smb_set_defaults(c, pkt)
|
|
||||||
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_NT_CREATE_ANDX
|
|
||||||
pkt['Payload']['SMB'].v['ErrorClass'] = 0xC0000034 # OBJECT_NAME_NOT_FOUND
|
|
||||||
pkt['Payload']['SMB'].v['Flags1'] = 0x88
|
|
||||||
pkt['Payload']['SMB'].v['Flags2'] = FLAGS2
|
|
||||||
c.put(pkt.to_s)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# Responds to a client READ_ANDX request
|
|
||||||
# This function sends chunks of the payload to the client
|
|
||||||
# by reading the offset and length requested by the client
|
|
||||||
# and sending the appropriate chunk of the payload
|
|
||||||
#
|
|
||||||
def smb_cmd_read(c, buff)
|
|
||||||
dprint("[SMB_CMD_READ]")
|
|
||||||
pkt = CONST::SMB_READ_PKT.make_struct
|
|
||||||
pkt.from_s(buff)
|
|
||||||
|
|
||||||
offset = pkt['Payload'].v['Offset']
|
|
||||||
length = pkt['Payload'].v['MaxCountLow']
|
|
||||||
|
|
||||||
pkt = CONST::SMB_READ_RES_PKT.make_struct
|
|
||||||
smb_set_defaults(c, pkt)
|
|
||||||
|
|
||||||
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_READ_ANDX
|
|
||||||
pkt['Payload']['SMB'].v['Flags1'] = 0x88
|
|
||||||
pkt['Payload']['SMB'].v['Flags2'] = FLAGS2
|
|
||||||
pkt['Payload']['SMB'].v['WordCount'] = 12
|
|
||||||
pkt['Payload'].v['AndX'] = 0xff # no more commands
|
|
||||||
pkt['Payload'].v['Remaining'] = 0xffff
|
|
||||||
pkt['Payload'].v['DataLenLow'] = length
|
|
||||||
pkt['Payload'].v['DataOffset'] = 59
|
|
||||||
pkt['Payload'].v['DataLenHigh'] = 0
|
|
||||||
pkt['Payload'].v['Reserved3'] = 0
|
|
||||||
pkt['Payload'].v['Reserved4'] = 0x0a
|
|
||||||
pkt['Payload'].v['ByteCount'] = length
|
|
||||||
pkt['Payload'].v['Payload'] = exe_contents[offset, length]
|
|
||||||
c.put(pkt.to_s)
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# Responds to client TRANSACTION2 requests and dispatches the request off to
|
|
||||||
# other functions dependent on what the sub_command is. Commands supported
|
|
||||||
# include:
|
|
||||||
# QUERY_FILE_INFO (Basic, Standard and Internal)
|
|
||||||
# QUERY_PATH_INFO (Basic and Standard)
|
|
||||||
#
|
|
||||||
def smb_cmd_trans(c, buff)
|
|
||||||
dprint("[SMB_CMD_TRANS]")
|
|
||||||
# Client socket is c
|
|
||||||
pkt = CONST::SMB_TRANS2_PKT.make_struct
|
|
||||||
pkt.from_s(buff)
|
|
||||||
|
|
||||||
sub_command = pkt['Payload'].v['SetupData'].unpack("v").first
|
|
||||||
ar = Rex::Text.to_hex(buff, '').to_s
|
|
||||||
mdc = ar[86..89].unpack('n*').reverse.pack('n*').to_i(16)
|
|
||||||
|
|
||||||
case sub_command
|
|
||||||
when CONST::TRANS2_QUERY_FILE_INFO_BASIC
|
|
||||||
dprint("\t[query_file_info_basic]")
|
|
||||||
smb_cmd_trans_query_path_info_standard(c, buff)
|
|
||||||
when CONST::TRANS2_QUERY_FILE_INFO_STANDARD
|
|
||||||
dprint("\t[query_file_info_standard]")
|
|
||||||
loi = ar[148..151].unpack('n*').reverse.pack('n*').to_i(16)
|
|
||||||
case loi
|
|
||||||
when CONST::SMB_QUERY_PATH_STANDARD_INFO
|
|
||||||
dprint("\t\t[smb_cmd_trans_query_path_info_standard]")
|
|
||||||
smb_cmd_trans_query_path_info_standard(c, buff)
|
|
||||||
when CONST::SMB_QUERY_FILE_STANDARD_INFO_BASIC
|
|
||||||
dprint("\t\t[smb_cmd_trans_query_file_info_basic]")
|
|
||||||
smb_cmd_trans_query_file_info_basic(c, buff)
|
|
||||||
when CONST::SMB_QUERY_FILE_NETWORK_OPEN_INFO
|
|
||||||
dprint("\t\t[smb_cmd_trans_query_file_info_network]")
|
|
||||||
smb_cmd_trans_query_file_info_network(c, buff)
|
|
||||||
else
|
|
||||||
dprint("\t\tUnknown LOI [smb_cmd_trans_query_path_info_standard] - #{loi.to_s}")
|
|
||||||
smb_cmd_trans_query_file_info_standard(c, buff)
|
|
||||||
end
|
|
||||||
when CONST::TRANS2_QUERY_PATH_INFO
|
|
||||||
smb_cmd_trans2_query_path_information(c, buff)
|
|
||||||
when CONST::TRANS2_FIND_FIRST2
|
|
||||||
smb_cmd_trans2_find_first2(c, buff)
|
|
||||||
else
|
|
||||||
dprint("\t[UNKNOWN SUBCOMMAND]")
|
|
||||||
pkt = CONST::SMB_TRANS_RES_PKT.make_struct
|
|
||||||
smb_set_defaults(c, pkt)
|
|
||||||
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_TRANSACTION2
|
|
||||||
pkt['Payload']['SMB'].v['Flags1'] = 0x88
|
|
||||||
pkt['Payload']['SMB'].v['Flags2'] = FLAGS2
|
|
||||||
pkt['Payload']['SMB'].v['ErrorClass'] = 0xc0000225 # NT_STATUS_NOT_FOUND
|
|
||||||
c.put(pkt.to_s)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
# -*- coding: binary -*-
|
||||||
|
|
||||||
|
module Msf
|
||||||
|
module Exploit::Remote::SMB::Server
|
||||||
|
module Share
|
||||||
|
module Command
|
||||||
|
require 'msf/core/exploit/smb/server/share/command/close'
|
||||||
|
require 'msf/core/exploit/smb/server/share/command/negotiate'
|
||||||
|
require 'msf/core/exploit/smb/server/share/command/nt_create_andx'
|
||||||
|
require 'msf/core/exploit/smb/server/share/command/read_andx'
|
||||||
|
require 'msf/core/exploit/smb/server/share/command/session_setup_andx'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,30 @@
|
||||||
|
# -*- coding: binary -*-
|
||||||
|
|
||||||
|
module Msf
|
||||||
|
module Exploit::Remote::SMB::Server
|
||||||
|
module Share
|
||||||
|
module Command
|
||||||
|
module Close
|
||||||
|
#
|
||||||
|
# Responds to a client CLOSE request
|
||||||
|
#
|
||||||
|
def smb_cmd_close(c, buff)
|
||||||
|
dprint("[SMB_CMD_CLOSE]")
|
||||||
|
pkt = CONST::SMB_CLOSE_PKT.make_struct
|
||||||
|
pkt.from_s(buff)
|
||||||
|
|
||||||
|
pkt = CONST::SMB_CLOSE_RES_PKT.make_struct
|
||||||
|
smb_set_defaults(c, pkt)
|
||||||
|
|
||||||
|
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_CLOSE
|
||||||
|
pkt['Payload']['SMB'].v['Flags1'] = 0x88
|
||||||
|
pkt['Payload']['SMB'].v['Flags2'] = FLAGS2
|
||||||
|
pkt['Payload']['SMB'].v['WordCount'] = 0
|
||||||
|
|
||||||
|
c.put(pkt.to_s)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,47 @@
|
||||||
|
# -*- coding: binary -*-
|
||||||
|
|
||||||
|
module Msf
|
||||||
|
module Exploit::Remote::SMB::Server
|
||||||
|
module Share
|
||||||
|
module Command
|
||||||
|
module Negotiate
|
||||||
|
#
|
||||||
|
# Negotiates a SHARE session with the client
|
||||||
|
#
|
||||||
|
def smb_cmd_negotiate(c, buff)
|
||||||
|
dprint("[SMB_CMD_NEGOTIATE]")
|
||||||
|
pkt = CONST::SMB_NEG_PKT.make_struct
|
||||||
|
pkt.from_s(buff)
|
||||||
|
|
||||||
|
dialects = pkt['Payload'].v['Payload'].gsub(/\x00/, '').split(/\x02/).grep(/^\w+/)
|
||||||
|
|
||||||
|
dialect = dialects.index("NT LM 0.12") || dialects.length-1
|
||||||
|
|
||||||
|
pkt = CONST::SMB_NEG_RES_NT_PKT.make_struct
|
||||||
|
smb_set_defaults(c, pkt)
|
||||||
|
|
||||||
|
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_NEGOTIATE
|
||||||
|
pkt['Payload']['SMB'].v['Flags1'] = 0x88
|
||||||
|
pkt['Payload']['SMB'].v['Flags2'] = FLAGS2
|
||||||
|
pkt['Payload']['SMB'].v['WordCount'] = 17
|
||||||
|
pkt['Payload'].v['Dialect'] = dialect
|
||||||
|
pkt['Payload'].v['SecurityMode'] = 2 # SHARE Security Mode
|
||||||
|
pkt['Payload'].v['MaxMPX'] = 50
|
||||||
|
pkt['Payload'].v['MaxVCS'] = 1
|
||||||
|
pkt['Payload'].v['MaxBuff'] = 4356
|
||||||
|
pkt['Payload'].v['MaxRaw'] = 65536
|
||||||
|
pkt['Payload'].v['SystemTimeLow'] = lo
|
||||||
|
pkt['Payload'].v['SystemTimeHigh'] = hi
|
||||||
|
pkt['Payload'].v['ServerTimeZone'] = 0x0
|
||||||
|
pkt['Payload'].v['SessionKey'] = 0
|
||||||
|
pkt['Payload'].v['Capabilities'] = 0x0080f3fd
|
||||||
|
pkt['Payload'].v['KeyLength'] = 8
|
||||||
|
pkt['Payload'].v['Payload'] = Rex::Text.rand_text_hex(8)
|
||||||
|
|
||||||
|
c.put(pkt.to_s)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,100 @@
|
||||||
|
# -*- coding: binary -*-
|
||||||
|
|
||||||
|
module Msf
|
||||||
|
module Exploit::Remote::SMB::Server
|
||||||
|
module Share
|
||||||
|
module Command
|
||||||
|
module NtCreateAndx
|
||||||
|
#
|
||||||
|
# Responds to a client NT_CREATE_ANDX request
|
||||||
|
#
|
||||||
|
def smb_cmd_create(c, buff)
|
||||||
|
dprint("[SMB_CMD_CREATE]")
|
||||||
|
smb = @state[c]
|
||||||
|
pkt = CONST::SMB_CREATE_PKT.make_struct
|
||||||
|
pkt.from_s(buff)
|
||||||
|
|
||||||
|
# Tries to do CREATE and X
|
||||||
|
payload = pkt['Payload'].v['Payload'].gsub(/\x00/, '').gsub(/.*\\/, '\\').chomp.strip.split('\\').last
|
||||||
|
file = file_name
|
||||||
|
path = path_name
|
||||||
|
|
||||||
|
if payload.nil?
|
||||||
|
payload = file
|
||||||
|
end
|
||||||
|
|
||||||
|
if payload.length.to_s.eql?('1') or payload.eql?(path)
|
||||||
|
fid = smb[:dir_id].to_i
|
||||||
|
attribs = 0x10 # Ordinary Dir
|
||||||
|
eof = 0
|
||||||
|
isdir = 1
|
||||||
|
else
|
||||||
|
fid = smb[:file_id].to_i
|
||||||
|
attribs = 0x80 # File Attributes
|
||||||
|
eof = exe_contents.length
|
||||||
|
isdir = 0
|
||||||
|
end
|
||||||
|
|
||||||
|
pkt = CONST::SMB_CREATE_RES_PKT.make_struct
|
||||||
|
smb_set_defaults(c, pkt)
|
||||||
|
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_NT_CREATE_ANDX
|
||||||
|
pkt['Payload']['SMB'].v['Flags1'] = 0x88
|
||||||
|
pkt['Payload']['SMB'].v['Flags2'] = FLAGS2
|
||||||
|
pkt['Payload']['SMB'].v['WordCount'] = 42
|
||||||
|
pkt['Payload'].v['AndX'] = 0xff # no further commands
|
||||||
|
pkt['Payload'].v['OpLock'] = 0x3 # Grant Oplock on File
|
||||||
|
pkt['Payload'].v['FileID'] = fid
|
||||||
|
pkt['Payload'].v['Action'] = 0x1 # The file existed and was opened
|
||||||
|
pkt['Payload'].v['CreateTimeLow'] = lo
|
||||||
|
pkt['Payload'].v['CreateTimeHigh'] = hi
|
||||||
|
pkt['Payload'].v['AccessTimeLow'] = lo
|
||||||
|
pkt['Payload'].v['AccessTimeHigh'] = hi
|
||||||
|
pkt['Payload'].v['WriteTimeLow'] = lo
|
||||||
|
pkt['Payload'].v['WriteTimeHigh'] = hi
|
||||||
|
pkt['Payload'].v['ChangeTimeLow'] = lo
|
||||||
|
pkt['Payload'].v['ChangeTimeHigh'] = hi
|
||||||
|
pkt['Payload'].v['Attributes'] = attribs
|
||||||
|
pkt['Payload'].v['AllocLow'] = 0x100000
|
||||||
|
pkt['Payload'].v['AllocHigh'] = 0
|
||||||
|
pkt['Payload'].v['EOFLow'] = eof
|
||||||
|
pkt['Payload'].v['EOFHigh'] = 0
|
||||||
|
pkt['Payload'].v['FileType'] = 0
|
||||||
|
pkt['Payload'].v['IPCState'] = 0x7
|
||||||
|
pkt['Payload'].v['IsDirectory'] = isdir
|
||||||
|
|
||||||
|
# As above, if payload is a file or "\" send found response
|
||||||
|
if (payload.downcase.eql?(file.downcase)) or payload.length.to_s.eql?('1') or payload.eql?(path)
|
||||||
|
connect_response = ""
|
||||||
|
# GUID
|
||||||
|
connect_response << ([0].pack("C") * 16)
|
||||||
|
# File ID
|
||||||
|
connect_response << ([0].pack("C") * 6)
|
||||||
|
# Access Rights
|
||||||
|
connect_response << [0xff].pack("C")
|
||||||
|
connect_response << [0x01].pack("C")
|
||||||
|
connect_response << [0x1f].pack("C")
|
||||||
|
connect_response << [0].pack("C")
|
||||||
|
connect_response << ([0].pack("C") * 4) # Guest access
|
||||||
|
connect_response << ([0].pack("C") * 2) # Byte Count
|
||||||
|
|
||||||
|
my_pkt = pkt.to_s + connect_response
|
||||||
|
original_length = my_pkt[2, 2].unpack("n").first
|
||||||
|
original_length = original_length + connect_response.length
|
||||||
|
my_pkt[2, 2] = [original_length].pack("n")
|
||||||
|
c.put(my_pkt)
|
||||||
|
else
|
||||||
|
# Otherwise send not found
|
||||||
|
pkt = CONST::SMB_CREATE_RES_PKT.make_struct
|
||||||
|
smb_set_defaults(c, pkt)
|
||||||
|
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_NT_CREATE_ANDX
|
||||||
|
pkt['Payload']['SMB'].v['ErrorClass'] = 0xC0000034 # OBJECT_NAME_NOT_FOUND
|
||||||
|
pkt['Payload']['SMB'].v['Flags1'] = 0x88
|
||||||
|
pkt['Payload']['SMB'].v['Flags2'] = FLAGS2
|
||||||
|
c.put(pkt.to_s)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,44 @@
|
||||||
|
# -*- coding: binary -*-
|
||||||
|
|
||||||
|
module Msf
|
||||||
|
module Exploit::Remote::SMB::Server
|
||||||
|
module Share
|
||||||
|
module Command
|
||||||
|
module ReadAndx
|
||||||
|
#
|
||||||
|
# Responds to a client READ_ANDX request
|
||||||
|
# This function sends chunks of the payload to the client
|
||||||
|
# by reading the offset and length requested by the client
|
||||||
|
# and sending the appropriate chunk of the payload
|
||||||
|
#
|
||||||
|
def smb_cmd_read(c, buff)
|
||||||
|
dprint("[SMB_CMD_READ]")
|
||||||
|
pkt = CONST::SMB_READ_PKT.make_struct
|
||||||
|
pkt.from_s(buff)
|
||||||
|
|
||||||
|
offset = pkt['Payload'].v['Offset']
|
||||||
|
length = pkt['Payload'].v['MaxCountLow']
|
||||||
|
|
||||||
|
pkt = CONST::SMB_READ_RES_PKT.make_struct
|
||||||
|
smb_set_defaults(c, pkt)
|
||||||
|
|
||||||
|
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_READ_ANDX
|
||||||
|
pkt['Payload']['SMB'].v['Flags1'] = 0x88
|
||||||
|
pkt['Payload']['SMB'].v['Flags2'] = FLAGS2
|
||||||
|
pkt['Payload']['SMB'].v['WordCount'] = 12
|
||||||
|
pkt['Payload'].v['AndX'] = 0xff # no more commands
|
||||||
|
pkt['Payload'].v['Remaining'] = 0xffff
|
||||||
|
pkt['Payload'].v['DataLenLow'] = length
|
||||||
|
pkt['Payload'].v['DataOffset'] = 59
|
||||||
|
pkt['Payload'].v['DataLenHigh'] = 0
|
||||||
|
pkt['Payload'].v['Reserved3'] = 0
|
||||||
|
pkt['Payload'].v['Reserved4'] = 0x0a
|
||||||
|
pkt['Payload'].v['ByteCount'] = length
|
||||||
|
pkt['Payload'].v['Payload'] = exe_contents[offset, length]
|
||||||
|
c.put(pkt.to_s)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,57 @@
|
||||||
|
# -*- coding: binary -*-
|
||||||
|
|
||||||
|
module Msf
|
||||||
|
module Exploit::Remote::SMB::Server
|
||||||
|
module Share
|
||||||
|
module Command
|
||||||
|
module SessionSetupAndx
|
||||||
|
#
|
||||||
|
# Sets up an SMB session in response to a SESSION_SETUP_ANDX request
|
||||||
|
#
|
||||||
|
def smb_cmd_session_setup(c, buff)
|
||||||
|
dprint("[SMB_CMD_SESSION_SETUP]")
|
||||||
|
pkt = CONST::SMB_SETUP_RES_PKT.make_struct
|
||||||
|
smb_set_defaults(c, pkt)
|
||||||
|
|
||||||
|
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_SESSION_SETUP_ANDX
|
||||||
|
pkt['Payload']['SMB'].v['Flags1'] = 0x88
|
||||||
|
pkt['Payload']['SMB'].v['Flags2'] = FLAGS2
|
||||||
|
pkt['Payload']['SMB'].v['WordCount'] = 3
|
||||||
|
pkt['Payload'].v['AndX'] = 0x75
|
||||||
|
pkt['Payload'].v['Reserved1'] = 00
|
||||||
|
pkt['Payload'].v['AndXOffset'] = 96
|
||||||
|
pkt['Payload'].v['Action'] = 0x1 # Logged in as Guest
|
||||||
|
pkt['Payload'].v['Payload'] =
|
||||||
|
Rex::Text.to_unicode("Unix", 'utf-16be') + "\x00\x00" + # Native OS # Samba signature
|
||||||
|
Rex::Text.to_unicode("Samba 3.4.7", 'utf-16be') + "\x00\x00" + # Native LAN Manager # Samba signature
|
||||||
|
Rex::Text.to_unicode("WORKGROUP", 'utf-16be') + "\x00\x00\x00" + # Primary DOMAIN # Samba signature
|
||||||
|
tree_connect_response = ""
|
||||||
|
tree_connect_response << [7].pack("C") # Tree Connect Response : WordCount
|
||||||
|
tree_connect_response << [0xff].pack("C") # Tree Connect Response : AndXCommand
|
||||||
|
tree_connect_response << [0].pack("C") # Tree Connect Response : Reserved
|
||||||
|
tree_connect_response << [0].pack("v") # Tree Connect Response : AndXOffset
|
||||||
|
tree_connect_response << [0x1].pack("v") # Tree Connect Response : Optional Support
|
||||||
|
tree_connect_response << [0xa9].pack("C") # Access Mask for just Read and Exec
|
||||||
|
tree_connect_response << [0x00].pack("C")
|
||||||
|
tree_connect_response << [0x12].pack("C")
|
||||||
|
tree_connect_response << [0x00].pack("C")
|
||||||
|
tree_connect_response << [0].pack("v") # Tree Connect Response : Word Parameter
|
||||||
|
tree_connect_response << [0].pack("v") # Tree Connect Response : Word Parameter
|
||||||
|
tree_connect_response << [13].pack("v") # Tree Connect Response : ByteCount
|
||||||
|
tree_connect_response << "A:\x00" # Service
|
||||||
|
tree_connect_response << "#{Rex::Text.to_unicode("NTFS")}\x00\x00" # Extra byte parameters
|
||||||
|
# Fix the Netbios Session Service Message Length
|
||||||
|
# to have into account the tree_connect_response,
|
||||||
|
# need to do this because there isn't support for
|
||||||
|
# AndX still
|
||||||
|
my_pkt = pkt.to_s + tree_connect_response
|
||||||
|
original_length = my_pkt[2, 2].unpack("n").first
|
||||||
|
original_length = original_length + tree_connect_response.length
|
||||||
|
my_pkt[2, 2] = [original_length].pack("n")
|
||||||
|
c.put(my_pkt)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -8,6 +8,61 @@ module Msf
|
||||||
require 'msf/core/exploit/smb/server/share/sub_command/trans2/find_first2'
|
require 'msf/core/exploit/smb/server/share/sub_command/trans2/find_first2'
|
||||||
require 'msf/core/exploit/smb/server/share/sub_command/trans2/query_file_information'
|
require 'msf/core/exploit/smb/server/share/sub_command/trans2/query_file_information'
|
||||||
require 'msf/core/exploit/smb/server/share/sub_command/trans2/query_path_information'
|
require 'msf/core/exploit/smb/server/share/sub_command/trans2/query_path_information'
|
||||||
|
|
||||||
|
#
|
||||||
|
# Responds to client TRANSACTION2 requests and dispatches the request off to
|
||||||
|
# other functions dependent on what the sub_command is. Commands supported
|
||||||
|
# include:
|
||||||
|
# QUERY_FILE_INFO (Basic, Standard and Internal)
|
||||||
|
# QUERY_PATH_INFO (Basic and Standard)
|
||||||
|
#
|
||||||
|
def smb_cmd_trans(c, buff)
|
||||||
|
dprint("[SMB_CMD_TRANS]")
|
||||||
|
# Client socket is c
|
||||||
|
pkt = CONST::SMB_TRANS2_PKT.make_struct
|
||||||
|
pkt.from_s(buff)
|
||||||
|
|
||||||
|
sub_command = pkt['Payload'].v['SetupData'].unpack("v").first
|
||||||
|
ar = Rex::Text.to_hex(buff, '').to_s
|
||||||
|
mdc = ar[86..89].unpack('n*').reverse.pack('n*').to_i(16)
|
||||||
|
|
||||||
|
case sub_command
|
||||||
|
when CONST::TRANS2_QUERY_FILE_INFO_BASIC
|
||||||
|
dprint("\t[query_file_info_basic]")
|
||||||
|
smb_cmd_trans_query_path_info_standard(c, buff)
|
||||||
|
when CONST::TRANS2_QUERY_FILE_INFO_STANDARD
|
||||||
|
dprint("\t[query_file_info_standard]")
|
||||||
|
loi = ar[148..151].unpack('n*').reverse.pack('n*').to_i(16)
|
||||||
|
case loi
|
||||||
|
when CONST::SMB_QUERY_PATH_STANDARD_INFO
|
||||||
|
dprint("\t\t[smb_cmd_trans_query_path_info_standard]")
|
||||||
|
smb_cmd_trans_query_path_info_standard(c, buff)
|
||||||
|
when CONST::SMB_QUERY_FILE_STANDARD_INFO_BASIC
|
||||||
|
dprint("\t\t[smb_cmd_trans_query_file_info_basic]")
|
||||||
|
smb_cmd_trans_query_file_info_basic(c, buff)
|
||||||
|
when CONST::SMB_QUERY_FILE_NETWORK_OPEN_INFO
|
||||||
|
dprint("\t\t[smb_cmd_trans_query_file_info_network]")
|
||||||
|
smb_cmd_trans_query_file_info_network(c, buff)
|
||||||
|
else
|
||||||
|
dprint("\t\tUnknown LOI [smb_cmd_trans_query_path_info_standard] - #{loi.to_s}")
|
||||||
|
smb_cmd_trans_query_file_info_standard(c, buff)
|
||||||
|
end
|
||||||
|
when CONST::TRANS2_QUERY_PATH_INFO
|
||||||
|
smb_cmd_trans2_query_path_information(c, buff)
|
||||||
|
when CONST::TRANS2_FIND_FIRST2
|
||||||
|
smb_cmd_trans2_find_first2(c, buff)
|
||||||
|
else
|
||||||
|
dprint("\t[UNKNOWN SUBCOMMAND]")
|
||||||
|
pkt = CONST::SMB_TRANS_RES_PKT.make_struct
|
||||||
|
smb_set_defaults(c, pkt)
|
||||||
|
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_TRANSACTION2
|
||||||
|
pkt['Payload']['SMB'].v['Flags1'] = 0x88
|
||||||
|
pkt['Payload']['SMB'].v['Flags2'] = FLAGS2
|
||||||
|
pkt['Payload']['SMB'].v['ErrorClass'] = 0xc0000225 # NT_STATUS_NOT_FOUND
|
||||||
|
c.put(pkt.to_s)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue