Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
17 changes: 17 additions & 0 deletions lib/metasploit_payloads/mettle.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ class Mettle

CMDLINE_MAX = 2000
CMDLINE_SIG = 'DEFAULT_OPTS'.freeze
CONFIG_BLOCK_MAX = 8192
CONFIG_BLOCK_SIG = 'CONFIG_BLOCK'.freeze
#
# Config is a hash. Valid keys are:
# :uri to connect to
Expand All @@ -36,6 +38,9 @@ def initialize(triple, config={})
def to_binary(format=:process_image)
bin = self.class.read(@platform, format)
unless @config.empty?
if @config[:config_block]
bin = add_config_block(bin, @config[:config_block])
end
params = generate_argv
bin = add_args(bin, params)
end
Expand All @@ -47,6 +52,10 @@ def to_binary(format=:process_image)
def generate_argv
cmd_line = 'mettle '
@config.each do |opt, val|
# :config_block is embedded into the binary via add_config_block (a
# TLV blob parsed natively); it is not a command-line option.
next if opt == :config_block

cmd_line << "-#{short_opt(opt)} \"#{val}\" "
end
if cmd_line.length > CMDLINE_MAX
Expand Down Expand Up @@ -77,6 +86,14 @@ def short_opt(opt)
end
end

def add_config_block(bin, config_bytes)
if config_bytes.length > CONFIG_BLOCK_MAX
raise Mettle::Error, 'mettle config block too large', caller
end
padded = config_bytes + "\x00" * (CONFIG_BLOCK_MAX - config_bytes.length)
bin.sub(CONFIG_BLOCK_SIG + "\x00" * (CONFIG_BLOCK_MAX - CONFIG_BLOCK_SIG.length), padded)
end

def add_args(bin, params)
if params[8] != "\x00"
bin.sub(CMDLINE_SIG + ' ' * (CMDLINE_MAX - CMDLINE_SIG.length), params)
Expand Down
50 changes: 50 additions & 0 deletions mettle/src/c2.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ struct c2_transport {
struct c2 *c2;
struct c2_transport_type *type;
void *ctx;
struct c2_transport_config *config;
};

struct c2_transport_type {
Expand Down Expand Up @@ -109,6 +110,7 @@ c2_remove_transports(struct c2 *c2)
if (t->type->cbs.free) {
t->type->cbs.free(t);
}
c2_transport_config_free(t->config);
free(t->uri);
free(t);
}
Expand Down Expand Up @@ -158,6 +160,54 @@ int c2_add_transport_uri(struct c2 *c2, const char *uri)
return -1;
}

void c2_verb_config_free(struct c2_verb_config *vc)
{
if (vc) {
free(vc->uri);
free(vc->prefix);
free(vc->suffix);
free(vc->uuid_prefix);
free(vc->uuid_suffix);
free(vc->uuid_get);
free(vc->uuid_header);
free(vc->uuid_cookie);
free(vc);
}
}

void c2_transport_config_free(struct c2_transport_config *tc)
{
if (tc) {
free(tc->proxy_url);
free(tc->proxy_user);
free(tc->proxy_pass);
free(tc->user_agent);
free(tc->custom_headers);
free(tc->cert_hash);
free(tc->c2_uuid);
c2_verb_config_free(tc->c2_get);
c2_verb_config_free(tc->c2_post);
free(tc);
}
}

struct c2_transport_config * c2_transport_get_config(struct c2_transport *t)
{
return t->config;
}

int c2_add_transport_uri_config(struct c2 *c2, const char *uri,
struct c2_transport_config *config)
{
int rc = c2_add_transport_uri(c2, uri);
if (rc == 0 && config) {
/* Find the last-added transport (tail of CDL) */
struct c2_transport *t = c2->transports->prev;
t->config = config;
}
return rc;
}

static struct c2_transport *
choose_next_transport(struct c2 *c2)
{
Expand Down
51 changes: 51 additions & 0 deletions mettle/src/c2.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,61 @@
#include <ev.h>
#include "buffer_queue.h"

/*
* C2 Profile configuration for GET/POST verbs
*/
struct c2_verb_config {
char *uri;
int enc_inbound;
int enc_outbound;
int enc_uuid;
void *prefix;
size_t prefix_len;
void *suffix;
size_t suffix_len;
char *uuid_prefix;
char *uuid_suffix;
int prefix_skip;
int suffix_skip;
char *uuid_get;
char *uuid_header;
char *uuid_cookie;
};

/*
* Per-transport configuration parsed from TLV config block
*/
struct c2_transport_config {
uint32_t comm_timeout;
uint32_t retry_total;
uint32_t retry_wait;
char *proxy_url;
char *proxy_user;
char *proxy_pass;
char *user_agent;
char *custom_headers;
void *cert_hash;
size_t cert_hash_len;
char *c2_uuid;
struct c2_verb_config *c2_get;
struct c2_verb_config *c2_post;
};

void c2_verb_config_free(struct c2_verb_config *vc);
void c2_transport_config_free(struct c2_transport_config *tc);

/*
* C2 Manager
*/
struct c2;

struct c2 * c2_new(struct ev_loop *loop);

int c2_add_transport_uri(struct c2 *c2, const char *uri);

int c2_add_transport_uri_config(struct c2 *c2, const char *uri,
struct c2_transport_config *config);

int c2_start(struct c2 *c2);

int c2_close(struct c2 *c2);
Expand Down Expand Up @@ -58,6 +107,8 @@ int c2_register_transport_type(struct c2 *c2, const char *proto,

struct c2_transport* c2_get_current_transport(struct c2 *c2);

struct c2_transport_config * c2_transport_get_config(struct c2_transport *t);

const char * c2_transport_uri(struct c2_transport *t);
const char * c2_transport_dest(struct c2_transport *t);
struct ev_loop * c2_transport_loop(struct c2_transport *loop);
Expand Down
Loading
Loading