Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
dc23aae
Tidied up up the build for make.bat and make-cmake.bat builds
OJ Jun 19, 2025
e424413
Small tweak to the RDI cmake file
OJ Jun 19, 2025
cf1086e
MC2 first pass clean compile
OJ Jun 30, 2025
636c322
Semi-working TLV-based configuration
OJ Jul 7, 2025
dba68a6
Support for different GET/POST uris
OJ Jul 10, 2025
b347997
More C2 options support, migration work
OJ Jul 15, 2025
1a94441
Tidying up, removal of TLVs and skip count support
OJ Jul 16, 2025
19e6eaf
Update WININET implementation for C2 support
OJ Jul 17, 2025
83aff75
UUID handling and transport refactoring
OJ Jul 23, 2025
63aa5d7
Better support for UUID in GET/HEADER/URI
OJ Jul 24, 2025
5d4579b
Fix transport commands and timeout handling
OJ Jul 28, 2025
89e5f41
Update workflow to use VS 2022 instead of VS 2019
OJ Jul 28, 2025
b7e42f7
Read POST responses
OJ Jul 29, 2025
56f981d
C2 encoding and content length for HTTP reads
OJ Jul 30, 2025
71f807e
Fix path to VS for workflow build
OJ Aug 6, 2025
1859176
Refactor java TLV names
zeroSteiner Sep 24, 2025
9d04713
Refactor to move TLVPacket and TLVType
zeroSteiner Sep 24, 2025
20882ec
Process the config block as a TLV packet
zeroSteiner Sep 26, 2025
10227fc
Rename C2_PROXY_HOST to C2_PROXY_URL for Windows
zeroSteiner Sep 29, 2025
3294589
Switch to the new TLV constants in Python
zeroSteiner Sep 29, 2025
a42e962
PATCH_URL is not PATCH_UUID
zeroSteiner Oct 1, 2025
abadd5b
Implement manual CRYPT_STRING_BASE64URI
OJ Mar 19, 2026
569fd4f
Use updated VS2022 configuration/install
OJ Mar 21, 2026
94c85c7
Fix compiler complaints
OJ Mar 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 20 additions & 3 deletions .github/workflows/windows_meterpreter.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,17 +43,34 @@ jobs:
script --return --command 'make docker'

windows:
runs-on: windows-2019
runs-on: windows-2022
timeout-minutes: 40
name: Meterpreter Visual Studio 2019 Build
name: Meterpreter Visual Studio 2022 Build
steps:
- name: Checkout code
uses: actions/checkout@v3
with:
submodules: 'recursive'

# https://github.com/actions/runner-images/issues/4051#issuecomment-916971476
- name: Install Dependencies
shell: pwsh
run: |-
Set-Location "C:\Program Files (x86)\Microsoft Visual Studio\Installer\"
dir
$InstallPath = "C:\Program Files\Microsoft Visual Studio\2022\Enterprise"
$WorkLoads = '--config "D:\a\metasploit-payloads\metasploit-payloads\c\meterpreter\vs-configs\vs2022.vsconfig"'
$Arguments = ('/c', "vs_installer.exe", 'modify', '--installPath', "`"$InstallPath`"", $WorkLoads, '--quiet', '--norestart', '--nocache')
$process = Start-Process -FilePath cmd.exe -ArgumentList $Arguments -Wait -PassThru -WindowStyle Hidden
if ($process.ExitCode -eq 0) {
Write-Host "components have been successfully added"
} else {
Write-Host "components were not installed"
exit 1
}

- name: Compile
shell: cmd
run: |-
cd c/meterpreter
"C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\Tools\VsDevCmd.bat" && make.bat
"C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\Tools\VsDevCmd.bat" && make.bat
10 changes: 4 additions & 6 deletions c/meterpreter/make-cmake.bat
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,16 @@ IF NOT EXIST "source\ReflectiveDLLInjection\.git" (
GOTO END
)

SET VS_TITLE=Visual Studio 16 2019
SET VS_VER=VS2019
SET VS_TITLE=Visual Studio 17 2022
SET VS_VER=VS2022
SET PTS_VER=v141_xp
SET PSSDK_VER=19
SET BUILD_64=Y
SET BUILD_86=Y
SET SNIFFER=OFF
SET DBGTRACE=OFF
SET DBGTRACE_VERBOSE=OFF
set DO_BUILD=Y
SET DO_BUILD=Y

IF "%1" == "NOBUILD" SET DO_BUILD=N
IF "%2" == "NOBUILD" SET DO_BUILD=N
Expand Down Expand Up @@ -102,9 +102,7 @@ IF "%BUILD_86%" == "Y" (
)
)

FOR /F "usebackq tokens=1,2 delims==" %%i IN (`wmic os get LocalDateTime /VALUE 2^>NUL`) DO IF '.%%i.'=='.LocalDateTime.' SET LDT=%%j
SET LDT=%LDT:~0,4%-%LDT:~4,2%-%LDT:~6,2% %LDT:~8,2%:%LDT:~10,2%:%LDT:~12,6%
echo Finished %ldt%
echo Finished %TIME%
GOTO END

:CLEAN
Expand Down
7 changes: 3 additions & 4 deletions c/meterpreter/make.bat
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,9 @@ SET PLAT=x64
GOTO RUN

:RUN
echo Started %TIME%
PUSHD workspace
msbuild.exe make.msbuild /target:%PREF%%PLAT% /p:PlatformToolset=%PTS_VER%
msbuild.exe make.msbuild /target:%PREF%%PLAT% /p:PlatformToolset=%PTS_VER% /p:XPDeprecationWarning=false
POPD

IF "%ERRORLEVEL%" == "0" (
Expand All @@ -80,9 +81,7 @@ IF "%ERRORLEVEL%" == "0" (
)
)

FOR /F "usebackq tokens=1,2 delims==" %%i IN (`wmic os get LocalDateTime /VALUE 2^>NUL`) DO IF '.%%i.'=='.LocalDateTime.' SET LDT=%%j
SET LDT=%LDT:~0,4%-%LDT:~4,2%-%LDT:~6,2% %LDT:~8,2%:%LDT:~10,2%:%LDT:~12,6%
echo Finished %ldt%
echo Finished %TIME%

GOTO END

Expand Down
2 changes: 1 addition & 1 deletion c/meterpreter/source/common/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ typedef struct ___u128 {
#ifdef DEBUGTRACE
#include "common_logging.h"
#define dprintf(...) real_dprintf(__VA_ARGS__)
#define INIT_LOGGING(metConfig) init_logging(metConfig->session.log_path);
#define INIT_LOGGING(path) init_logging(path);
#define SET_LOGGING_CONTEXT(api) set_logging_context(api->logging.get_logging_context(), api->logging.get_lock());
#if DEBUGTRACE == 1
#define vdprintf dprintf
Expand Down
2 changes: 1 addition & 1 deletion c/meterpreter/source/common/common_command_ids.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
#define COMMAND_ID_CORE_MIGRATE 14
#define COMMAND_ID_CORE_NATIVE_ARCH 15
#define COMMAND_ID_CORE_NEGOTIATE_TLV_ENCRYPTION 16
#define COMMAND_ID_CORE_PATCH_URL 17
#define COMMAND_ID_CORE_PATCH_UUID 17
#define COMMAND_ID_CORE_PIVOT_ADD 18
#define COMMAND_ID_CORE_PIVOT_REMOVE 19
#define COMMAND_ID_CORE_PIVOT_SESSION_DIED 20
Expand Down
61 changes: 2 additions & 59 deletions c/meterpreter/source/common/common_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,71 +23,14 @@ typedef CHARTYPE const * CSTRTYPE;
// Make sure we byte-align based on what we're given in the structure definitions
#pragma pack(push, 1)

typedef struct _MetsrvSession
typedef struct _MetsrvConfig
{
union
{
UINT_PTR handle;
BYTE padding[8];
} comms_handle; ///! Socket/handle for communications (if there is one).
DWORD exit_func; ///! Exit func identifier for when the session ends.
int expiry; ///! The total number of seconds to wait before killing off the session.
BYTE uuid[UUID_SIZE]; ///! UUID
BYTE session_guid[sizeof(GUID)]; ///! Current session GUID
#ifdef DEBUGTRACE
CHARTYPE log_path[LOG_PATH_SIZE]; ///! Location to place the log file. Only set when msfconsole specifies MeterpreterDebugLogging
#endif
} MetsrvSession;

typedef struct _MetsrvTransportCommon
{
CHARTYPE url[URL_SIZE]; ///! Transport url: scheme://host:port/URI
int comms_timeout; ///! Number of sessions to wait for a new packet.
int retry_total; ///! Total seconds to retry comms for.
int retry_wait; ///! Seconds to wait between reconnects.
} MetsrvTransportCommon;

typedef struct _MetsrvTransportProxy
{
CHARTYPE hostname[PROXY_HOST_SIZE]; ///! Proxy hostname.
CHARTYPE username[PROXY_USER_SIZE]; ///! Proxy username.
CHARTYPE password[PROXY_PASS_SIZE]; ///! Proxy password.
} MetsrvTransportProxy;

typedef struct _MetsrvTransportHttp
{
MetsrvTransportCommon common;
MetsrvTransportProxy proxy;
CHARTYPE ua[256]; ///! User agent string.
BYTE ssl_cert_hash[CERT_HASH_SIZE]; ///! Expected SSL certificate hash.
CHARTYPE custom_headers[1]; ///! Custom headers to add to outbound requests (arb length, NULL terminated).
} MetsrvTransportHttp;

typedef struct _MetsrvTransportTcp
{
MetsrvTransportCommon common;
} MetsrvTransportTcp;

typedef struct _MetsrvTransportNamedPipe
{
MetsrvTransportCommon common;
} MetsrvTransportNamedPipe;

typedef struct _MetsrvExtension
{
DWORD size; ///! Size of the extension.
BYTE dll[1]; ///! Array of extension bytes (will be more than 1).
} MetsrvExtension;

typedef struct _MetsrvConfig
{
MetsrvSession session;
MetsrvTransportCommon transports[1]; ///! Placeholder for 0 or more transports
// Extensions will appear after this
// After extensions, we get a list of extension initialisers
// <name of extension>\x00<datasize><data>
// <name of extension>\x00<datasize><data>
// \x00
BYTE config_packet[1]; ///! Pointer to the configuration packet
} MetsrvConfig;

// We force 64bit alignment for HANDLES and POINTERS in order
Expand Down
65 changes: 44 additions & 21 deletions c/meterpreter/source/common/common_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ typedef enum
{
PACKET_TLV_TYPE_REQUEST = 0, ///< Indicates a request packet.
PACKET_TLV_TYPE_RESPONSE = 1, ///< Indicates a response packet.
PACKET_TLV_TYPE_CONFIG = 2, ///< Indicates a configuration packet.
PACKET_TLV_TYPE_PLAIN_REQUEST = 10, ///< Indicates a plain request packet.
PACKET_TLV_TYPE_PLAIN_RESPONSE = 11, ///< Indicates a plain response packet.
} PacketTlvType;
Expand Down Expand Up @@ -90,6 +91,15 @@ typedef enum
/*! @brief An indication of whether the content written to the channel should be compressed. */
#define CHANNEL_FLAG_COMPRESS (1 << 1)

//! No encoding at all
#define C2_ENCODING_NONE 0
//! Base64 encoding
#define C2_ENCODING_B64 1
//! Base64 encoding with URI-safe characters
#define C2_ENCODING_B64URI 2
//! URL encoding
#define C2_ENCODING_URL 3

/*! @brief Type definition with defines `TlvMetaType` as an double-word. */
typedef DWORD TlvMetaType;

Expand Down Expand Up @@ -145,21 +155,6 @@ typedef enum
TLV_TYPE_LIB_LOADER_NAME = TLV_VALUE(TLV_META_TYPE_STRING, 412), ///! Represents the name of the ReflectiveLoader function (string).
TLV_TYPE_LIB_LOADER_ORDINAL = TLV_VALUE(TLV_META_TYPE_UINT, 413), ///! Represents the ordinal of the ReflectiveLoader function (int).

// Transport switching
TLV_TYPE_TRANS_TYPE = TLV_VALUE(TLV_META_TYPE_UINT, 430), ///! Represents the type of transport to switch to.
TLV_TYPE_TRANS_URL = TLV_VALUE(TLV_META_TYPE_STRING, 431), ///! Represents the new URL of the transport to use.
TLV_TYPE_TRANS_UA = TLV_VALUE(TLV_META_TYPE_STRING, 432), ///! Represents the user agent (for http).
TLV_TYPE_TRANS_COMM_TIMEOUT = TLV_VALUE(TLV_META_TYPE_UINT, 433), ///! Represents the communications timeout.
TLV_TYPE_TRANS_SESSION_EXP = TLV_VALUE(TLV_META_TYPE_UINT, 434), ///! Represents the session expiration.
TLV_TYPE_TRANS_CERT_HASH = TLV_VALUE(TLV_META_TYPE_RAW, 435), ///! Represents the certificate hash (for https).
TLV_TYPE_TRANS_PROXY_HOST = TLV_VALUE(TLV_META_TYPE_STRING, 436), ///! Represents the proxy host string (for http/s).
TLV_TYPE_TRANS_PROXY_USER = TLV_VALUE(TLV_META_TYPE_STRING, 437), ///! Represents the proxy user name (for http/s).
TLV_TYPE_TRANS_PROXY_PASS = TLV_VALUE(TLV_META_TYPE_STRING, 438), ///! Represents the proxy password (for http/s).
TLV_TYPE_TRANS_RETRY_TOTAL = TLV_VALUE(TLV_META_TYPE_UINT, 439), ///! Total time (seconds) to continue retrying comms.
TLV_TYPE_TRANS_RETRY_WAIT = TLV_VALUE(TLV_META_TYPE_UINT, 440), ///! Time (seconds) to wait between reconnect attempts.
TLV_TYPE_TRANS_HEADERS = TLV_VALUE(TLV_META_TYPE_STRING, 441), ///! List of custom headers to send with the requests.
TLV_TYPE_TRANS_GROUP = TLV_VALUE(TLV_META_TYPE_GROUP, 442), ///! A single transport grouping.

// session/machine identification
TLV_TYPE_MACHINE_ID = TLV_VALUE(TLV_META_TYPE_STRING, 460), ///! Represents a machine identifier.
TLV_TYPE_UUID = TLV_VALUE(TLV_META_TYPE_RAW, 461), ///! Represents a UUID.
Expand All @@ -176,9 +171,37 @@ typedef enum
TLV_TYPE_PIVOT_STAGE_DATA = TLV_VALUE(TLV_META_TYPE_RAW, 651), ///! Represents the data to be staged on new connections.
TLV_TYPE_PIVOT_NAMED_PIPE_NAME = TLV_VALUE(TLV_META_TYPE_STRING, 653), ///! Represents named pipe name.

TLV_TYPE_EXTENSIONS = TLV_VALUE(TLV_META_TYPE_COMPLEX, 20000), ///! Represents an extension value.
TLV_TYPE_USER = TLV_VALUE(TLV_META_TYPE_COMPLEX, 40000), ///! Represents a user value.
TLV_TYPE_TEMP = TLV_VALUE(TLV_META_TYPE_COMPLEX, 60000), ///! Represents a temporary value.
TLV_TYPE_SESSION_EXPIRY = TLV_VALUE(TLV_META_TYPE_UINT, 700), ///! Session expiration time
TLV_TYPE_EXITFUNC = TLV_VALUE(TLV_META_TYPE_UINT, 701), ///! identifier of the exit function to use
TLV_TYPE_DEBUG_LOG = TLV_VALUE(TLV_META_TYPE_STRING, 702), ///! path to write debug log
TLV_TYPE_EXTENSION = TLV_VALUE(TLV_META_TYPE_GROUP, 703), ///! Group containing extension info
TLV_TYPE_C2 = TLV_VALUE(TLV_META_TYPE_GROUP, 704), ///! a C2/transport grouping
TLV_TYPE_C2_COMM_TIMEOUT = TLV_VALUE(TLV_META_TYPE_UINT, 705), ///! the timeout for this C2 group
TLV_TYPE_C2_RETRY_TOTAL = TLV_VALUE(TLV_META_TYPE_UINT, 706), ///! number of times to retry this C2
TLV_TYPE_C2_RETRY_WAIT = TLV_VALUE(TLV_META_TYPE_UINT, 707), ///! how long to wait between reconnect attempts
TLV_TYPE_C2_URL = TLV_VALUE(TLV_META_TYPE_STRING, 708), ///! base URL of this C2 (scheme://host:port/uri)
TLV_TYPE_C2_URI = TLV_VALUE(TLV_META_TYPE_STRING, 709), ///! URI to append to base URL (for HTTP(s)), if any
TLV_TYPE_C2_PROXY_URL = TLV_VALUE(TLV_META_TYPE_STRING, 710), ///! Proxy URL
TLV_TYPE_C2_PROXY_USER = TLV_VALUE(TLV_META_TYPE_STRING, 711), ///! Proxy user name
TLV_TYPE_C2_PROXY_PASS = TLV_VALUE(TLV_META_TYPE_STRING, 712), ///! Proxy password
TLV_TYPE_C2_GET = TLV_VALUE(TLV_META_TYPE_GROUP, 713), ///! A grouping of params associated with GET requests
TLV_TYPE_C2_POST = TLV_VALUE(TLV_META_TYPE_GROUP, 714), ///! A grouping of params associated with POST requests
TLV_TYPE_C2_HEADERS = TLV_VALUE(TLV_META_TYPE_STRING, 715), ///! Custom headers
TLV_TYPE_C2_UA = TLV_VALUE(TLV_META_TYPE_STRING, 716), ///! User agent
TLV_TYPE_C2_CERT_HASH = TLV_VALUE(TLV_META_TYPE_RAW, 717), ///! Expected SSL certificate hash
TLV_TYPE_C2_PREFIX = TLV_VALUE(TLV_META_TYPE_RAW, 718), ///! Data to prepend to the outgoing payload
TLV_TYPE_C2_SUFFIX = TLV_VALUE(TLV_META_TYPE_RAW, 719), ///! Data to append to the outgoing payload
TLV_TYPE_C2_ENC = TLV_VALUE(TLV_META_TYPE_UINT, 720), ///! Request encoding flags (Base64|URL|Base64url)
TLV_TYPE_C2_PREFIX_SKIP = TLV_VALUE(TLV_META_TYPE_UINT, 721), ///! Size of prefix to skip (in bytes)
TLV_TYPE_C2_SUFFIX_SKIP = TLV_VALUE(TLV_META_TYPE_UINT, 722), ///! Size of suffix to skip (in bytes)
TLV_TYPE_C2_UUID_COOKIE = TLV_VALUE(TLV_META_TYPE_STRING, 723), ///! Name of the cookie to put the UUID in
TLV_TYPE_C2_UUID_GET = TLV_VALUE(TLV_META_TYPE_STRING, 724), ///! Name of the GET parameter to put the UUID in
TLV_TYPE_C2_UUID_HEADER = TLV_VALUE(TLV_META_TYPE_STRING, 725), ///! Name of the header to put the UUID in
TLV_TYPE_C2_UUID = TLV_VALUE(TLV_META_TYPE_STRING, 726), ///! The UUID string to use for the C2 transport

TLV_TYPE_EXTENSIONS = TLV_VALUE(TLV_META_TYPE_COMPLEX, 20000), ///! Represents an extension value.
TLV_TYPE_USER = TLV_VALUE(TLV_META_TYPE_COMPLEX, 40000), ///! Represents a user value.
TLV_TYPE_TEMP = TLV_VALUE(TLV_META_TYPE_COMPLEX, 60000), ///! Represents a temporary value.
} TlvType;

#ifndef QWORD
Expand All @@ -188,19 +211,19 @@ typedef unsigned __int64 QWORD;
#define ntohq( qword ) ( (QWORD)ntohl( qword & 0xFFFFFFFF ) << 32 ) | ntohl( qword >> 32 )
#define htonq( qword ) ntohq( qword )

typedef struct
typedef struct _TlvHeader
{
DWORD length;
DWORD type;
} TlvHeader;

typedef struct
typedef struct _Tlv
{
TlvHeader header;
PUCHAR buffer;
} Tlv;

typedef struct
typedef struct _PacketHeader
{
BYTE xor_key[4];
BYTE session_guid[sizeof(GUID)];
Expand Down
Loading
Loading