1 // Copyright 2021 Code Intelligence GmbH 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package com.code_intelligence.jazzer.sanitizers 16 17 import com.code_intelligence.jazzer.api.FuzzerSecurityIssueHigh 18 import com.code_intelligence.jazzer.api.HookType 19 import com.code_intelligence.jazzer.api.Jazzer 20 import com.code_intelligence.jazzer.api.MethodHook 21 import com.code_intelligence.jazzer.api.MethodHooks 22 import java.lang.invoke.MethodHandle 23 24 /** 25 * Detects unsafe calls that lead to attacker-controlled class loading. 26 * 27 * Guide the fuzzer to load honeypot class via [Class.forName] or [ClassLoader.loadClass]. 28 */ 29 @Suppress("unused_parameter", "unused") 30 object ReflectiveCall { 31 32 @MethodHooks( 33 MethodHook(type = HookType.BEFORE, targetClassName = "java.lang.Class", targetMethod = "forName", targetMethodDescriptor = "(Ljava/lang/String;)Ljava/lang/Class;"), 34 MethodHook(type = HookType.BEFORE, targetClassName = "java.lang.Class", targetMethod = "forName", targetMethodDescriptor = "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;"), 35 MethodHook(type = HookType.BEFORE, targetClassName = "java.lang.ClassLoader", targetMethod = "loadClass", targetMethodDescriptor = "(Ljava/lang/String;)Ljava/lang/Class;"), 36 MethodHook(type = HookType.BEFORE, targetClassName = "java.lang.ClassLoader", targetMethod = "loadClass", targetMethodDescriptor = "(Ljava/lang/String;Z)Ljava/lang/Class;"), 37 ) 38 @JvmStatic loadClassHooknull39 fun loadClassHook(method: MethodHandle?, alwaysNull: Any?, args: Array<Any?>, hookId: Int) { 40 val className = args[0] as? String ?: return 41 Jazzer.guideTowardsEquality(className, HONEYPOT_CLASS_NAME, hookId) 42 } 43 44 @MethodHooks( 45 MethodHook(type = HookType.BEFORE, targetClassName = "java.lang.Class", targetMethod = "forName", targetMethodDescriptor = "(Ljava/lang/Module;Ljava/lang/String;)Ljava/lang/Class;"), 46 MethodHook(type = HookType.BEFORE, targetClassName = "java.lang.ClassLoader", targetMethod = "loadClass", targetMethodDescriptor = "(Ljava/lang/Module;Ljava/lang/String;)Ljava/lang/Class;"), 47 ) 48 @JvmStatic loadClassWithModuleHooknull49 fun loadClassWithModuleHook(method: MethodHandle?, alwaysNull: Any?, args: Array<Any?>, hookId: Int) { 50 val className = args[1] as? String ?: return 51 Jazzer.guideTowardsEquality(className, HONEYPOT_CLASS_NAME, hookId) 52 } 53 54 @MethodHooks( 55 MethodHook(type = HookType.BEFORE, targetClassName = "java.lang.Runtime", targetMethod = "load"), 56 MethodHook(type = HookType.BEFORE, targetClassName = "java.lang.Runtime", targetMethod = "loadLibrary"), 57 MethodHook(type = HookType.BEFORE, targetClassName = "java.lang.System", targetMethod = "load"), 58 MethodHook(type = HookType.BEFORE, targetClassName = "java.lang.System", targetMethod = "loadLibrary"), 59 MethodHook(type = HookType.BEFORE, targetClassName = "java.lang.System", targetMethod = "mapLibraryName"), 60 MethodHook(type = HookType.BEFORE, targetClassName = "java.lang.ClassLoader", targetMethod = "findLibrary"), 61 ) 62 @JvmStatic loadLibraryHooknull63 fun loadLibraryHook(method: MethodHandle?, alwaysNull: Any?, args: Array<Any?>, hookId: Int) { 64 if (args.isEmpty()) { return } 65 val libraryName = args[0] as? String ?: return 66 if (libraryName == HONEYPOT_LIBRARY_NAME) { 67 Jazzer.reportFindingFromHook( 68 FuzzerSecurityIssueHigh("load arbitrary library"), 69 ) 70 } 71 Jazzer.guideTowardsEquality(libraryName, HONEYPOT_LIBRARY_NAME, hookId) 72 } 73 } 74