Unsafe JNI
主要解決問題:
1.system.currentTimeMillis();
使用SystemClock.now()替換。
2.isAssignableFrom();
使用新定義的isAssignableFromForCC()方法替換
/**
* Checks if one {@code Class} can be assigned to a variable of
* another {@code Class}.</p>
* @param cls: the Class to check, may be null
* @param tocls: the Class to try to assign into, returns false if null
* @return
*/
public static boolean isAssignableFromForCC( Class<?> cls, Class<?> tocls) {
return ClassUtils.isAssignable(cls, tocls);// use org.apache.commons.lang3.ClassUtils;
}
3.obj.hashCode()
使用新定義的hashCodeForCC()方法替換
public static int hashCodeForCC(Object obj) {
return ObjectUtils.hashCode(obj);//org.apache.commons.lang3.ObjectUtils;
}
4.getModifiers()
使用新定義的getModifiersForCC()方法替換
public static int getModifiersForCC(Class clazz) {
return ReflectUtils.getClassInfo(clazz).getModifiers();//org.springframework.cglib.core.ReflectUtils;
}
5.Thread.sleep(1000L);
TimeUnit.SECONDS.sleep(1);
6.Thread.currentThread().getContextClassLoader();
ClassUtils.class.getClassLoader();
Abstract
Java Native Interface(JNI)應用不當會導致 Java 應用程序容易受到其他語言的安全漏洞攻擊。
Explanation
當 Java 應用程序使用 JNI 調用以其他編程語言編寫的代碼時,會發生 Unsafe JNI 漏洞。 例如:以下 Java
代碼定義了一個名為 Echo 的類。 這個類聲明了一個本地方法(下文定義),使用 C 語言將控制台上輸入的
命令回顯給用戶。
class Echo { public native void runEcho(); static { System.loadLibrary("echo"); } public static void main(String[] args) { new Echo().runEcho(); } }
以下 C 語言代碼定義了在 Echo 類中實現的本地方法:
#include <jni.h> #include "Echo.h" //the java class above compiled with javah #include <stdio.h> JNIEXPORT void JNICALL Java_Echo_runEcho(JNIEnv *env, jobject obj) { char buf[64]; gets(buf); printf(buf); }
因為這個例子是在 Java 中實現的,所以看上去似乎可以避免諸如 buffer overflow 之類的內存問題。 雖然
Java 在內存安全方面做的很好,但是該保護機制並不適用於其他語言編寫的且通過 Java 本地接口 (Java
Native Interface,JNI) 訪問的源代碼中出現的漏洞。 盡管有 Java 提供的內存保護機制,但是這個例子中的 C
語言代碼仍然很容易受到 buffer overflow 的攻擊,因為它在沒有執行任何輸入檢查的情況下就使用了
gets()。 Sun Java(TM) 教程對 JNI 描述如下 [1]: 一旦有了 JNI 框架,您的本地方法就可以像 Java 代碼那
樣利用 Java 對象。 本地方法可以創建 Java 對象(包括數組和字符串),並且檢查和應用這些對象,以便執
行各種相關的任務。 本地方法也可以檢查和應用由 Java 應用程序代碼創建的對象。 本地方法甚至可以更新
由自己創建的或傳遞給它的 Java 對象,且更新后的對象可以應用到 Java 應用程序中。 因此,在應用程序
中,無論是本地語言還是 Java 語言都能創建、更新和訪問 Java 對象,並在兩種語言間共享這些對象。 通過
檢查本地方法實現的源代碼,可以輕松地發現上述例子中存在的漏洞。 根據不同的 C 語言源代碼和項目構建
方式,這種方式可能在某些情況下不可行,但是多數情況下還是可行的。 然而,這種能夠在 Java 方法和本
地方法間共享對象的能力會進一步加大潛在的風險。在 Java 中數據處理不當時,可能會導致本地代碼出現意
想不到的漏洞,同樣本地代碼中的不安全操作會破壞 Java 的數據結構。 通過 Java 應用程序訪問的本地代碼
中出現的漏洞,通常與由本地語言編寫的應用程序中存在的漏洞是一樣的。 這種攻擊面臨的唯一挑戰是:攻
擊者需要確定 Java 應用程序是否使用了本地代碼執行某些特定的操作。 可以用多種方法實現上述目的,包
括識別那些通常用本地代碼實現的某些特定行為,或者利用 Java 應用程序中 system information leak 的漏洞
(表明系統使用了 JNI) [2]。
Recommendation
審計所有構成某個特定應用程序的源代碼,包括在其他語言中執行的本地方法。 審計期間,要確保能夠正確
地解釋和處理 Java 和本地代碼在邊界檢查和其他行為之間的差別。 特別是確保在以下所有階段都正確處理
了共享對象: 對象被傳遞到本地代碼前、對象被本地代碼應用期間以及對象被返回給 Java 應用程序后。