零基础java漏洞分析入门(二)

简介: 零基础java漏洞分析入门

漏洞分析



f9f250498b0a696c930121cfe3dc7c3e_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png


由上图工作流程我们可以看到,当一个 HTTP 请求被 Struts2 处理时,会经过一系列的 拦截器(Interceptor) ,这些拦截器可以是 Struts2 自带的,也可以是用户自定义的。例如下图 struts.xml 中的 package 继承自 struts-default ,而 struts-default 就使用了 Struts2 自带的拦截器。


44f5d1c38f118d56fd1adc51a89296c7_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png


找到默认使用的拦截器栈


e2e7a3ab12f69fb142c746726141d3ab_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png


在拦截器栈 defaultStack 中,我们需要关注 params 这个拦截器。其中, params拦截器 会将客户端请求数据设置到 值栈(valueStack) 中,后续 JSP 页面中所有的动态数据都将从值栈中取出。


1c24755f9480333e1d74572300c779a6_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png


f07028157aa8af02ef289ad75ed73110_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png


f9431580b8a734cde30ec73a35fbb98a_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png


在经过一系列的拦截器处理后,数据会成功进入实际业务 Action 。程序会根据 Action 处理的结果,选择对应的 JSP 视图进行展示,并对视图中的 Struts2 标签进行处理。如下图,在本例中 Action 处理用户登录失败时会返回 error 。


98796d4e00ab1ea0d438fdd1c3ef4a7a_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png


然后

/com/opensymphony/xwork2/DefaultActionInvocation.class:253


7096736ef14eed8bc6c849a02b846ecb_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png


继续往下,主要问题在translateVariables这个函数里


/**
* Converted object from variable translation.
*
* @param open
* @param expression
* @param stack
* @param asType
* @param evaluator
* @return Converted object from variable translation.
*/
public static Object translateVariables(char open, String expression, ValueStack stack, Class asType, ParsedValueEvaluator evaluator) {
// deal with the "pure" expressions first!
//expression = expression.trim();
Object result = expression;
while (true) {
int start = expression.indexOf(open + "{");
int length = expression.length();
int x = start + 2;
int end;
char c;
int count = 1;
while (start != -1 && x < length && count != 0) {
c = expression.charAt(x++);
if (c == '{') {
count++;
} else if (c == '}') {
count--;
}
}
end = x - 1;
if ((start != -1) && (end != -1) && (count == 0)) {
String var = expression.substring(start + 2, end);
Object o = stack.findValue(var, asType);
if (evaluator != null) {
o = evaluator.evaluate(o);
}
String left = expression.substring(0, start);
String right = expression.substring(end + 1);
if (o != null) {
if (TextUtils.stringSet(left)) {
result = left + o;
} else {
result = o;
}
if (TextUtils.stringSet(right)) {
result = result + right;
}
expression = left + o + right;
} else {
// the variable doesn't exist, so don't display anything
result = left + right;
expression = left + right;
}
} else {
break;
}
}
return XWorkConverter.getInstance().convertValue(stack.getContext(), result, asType);
}

第一次执行的时候 会取出%{username}的值,即%{1+1}


通过if ((start != -1) && (end != -1) && (count == 0))的判断,跳过return


617b6fd94ac1424a750192d9332ac62a_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png


通过Object o = stack.findValue(var, asType);把值赋给o


然后赋值给expression,进行下一次循环


d50b0074ca614b3a4a140826027fdb5c_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png


第二次循环会执行我们构造的OGNL表达式


可以看到执行后结果为2


4efd5119bd6eb36edaa15505338810b5_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png


然后再次循环,经过if判断过后return


后面经过处理后返回index.jsp


c39eb4268aaeb70a76391c5c80aa39cd_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png


漏洞成因呢就是在translateVariables函数中递归来验证OGNL表达式,造成了OGNL表达式的执行


漏洞修复


官方修复代码


public static Object translateVariables(char open, String expression, ValueStack stack, Class asType, ParsedValueEvaluator evaluator, int maxLoopCount) {
// deal with the "pure" expressions first!
//expression = expression.trim();
Object result = expression;
int loopCount = 1;
int pos = 0;
while (true) {
int start = expression.indexOf(open + "{", pos);
if (start == -1) {
pos = 0;
loopCount++;
start = expression.indexOf(open + "{");
}
if (loopCount > maxLoopCount) {
// translateVariables prevent infinite loop / expression recursive evaluation
break;
}
int length = expression.length();
int x = start + 2;
int end;
char c;
int count = 1;
while (start != -1 && x < length && count != 0) {
c = expression.charAt(x++);
if (c == '{') {
count++;
} else if (c == '}') {
count--;
}
}
end = x - 1;
if ((start != -1) && (end != -1) && (count == 0)) {
String var = expression.substring(start + 2, end);
Object o = stack.findValue(var, asType);
if (evaluator != null) {
o = evaluator.evaluate(o);
}
String left = expression.substring(0, start);
String right = expression.substring(end + 1);
String middle = null;
if (o != null) {
middle = o.toString();
if (!TextUtils.stringSet(left)) {
result = o;
} else {
result = left + middle;
}
if (TextUtils.stringSet(right)) {
result = result + right;
}
expression = left + middle + right;
} else {
// the variable doesn't exist, so don't display anything
result = left + right;
expression = left + right;
}
pos = (left != null && left.length() > 0 ? left.length() - 1: 0) +
(middle != null && middle.length() > 0 ? middle.length() - 1: 0) +
1;
pos = Math.max(pos, 1);
} else {
break;
}
}
return XWorkConverter.getInstance().convertValue(stack.getContext(), result, asType);
}

可以看到增加了对OGNL递归解析次数的判断,默认情况下只会解析第一层

if (loopCount > maxLoopCount) {
// translateVariables prevent infinite loop / expression recursive evaluation
break;
}


总结


入门找了S2-001跟着师傅们的文章学习了一下,原理还是很简单,就是调试java过程很费时间。


最后弹个计算器收尾吧,(不知道为什么mac

弹/System/Application/Calculator.app没弹成功



%{(new java.lang.ProcessBuilder(new java.lang.String[]{"calc.exe"})).start()}


0ae2fef37faaba124bddb777a927c2d5_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png


参考


https://mochazz.github.io/2020/06/16/Java代码审计之Struts2-001/#漏洞分析

https://xz.aliyun.com/t/2672

https://xz.aliyun.com/t/2044


相关文章
|
3天前
|
Java 开发工具 Windows
Java入门及环境变量
Java入门及环境变量
10 1
|
4天前
|
Java API 调度
[AIGC] 深入理解Java并发编程:从入门到进阶
[AIGC] 深入理解Java并发编程:从入门到进阶
|
4天前
|
Java Nacos 开发者
Java从入门到精通:4.2.1学习新技术与框架——以Spring Boot和Spring Cloud Alibaba为例
Java从入门到精通:4.2.1学习新技术与框架——以Spring Boot和Spring Cloud Alibaba为例
|
4天前
|
前端开发 Java 测试技术
Java从入门到精通:4.1.1参与实际项目,锻炼编程与问题解决能力
Java从入门到精通:4.1.1参与实际项目,锻炼编程与问题解决能力
|
4天前
|
Java 程序员 数据库连接
Java从入门到精通:3.3.2性能优化与调优——内存管理篇
Java从入门到精通:3.3.2性能优化与调优——内存管理篇
Java从入门到精通:3.3.2性能优化与调优——内存管理篇
|
4天前
|
Dubbo Java 应用服务中间件
Java从入门到精通:3.2.2分布式与并发编程——了解分布式系统的基本概念,学习使用Dubbo、Spring Cloud等分布式框架
Java从入门到精通:3.2.2分布式与并发编程——了解分布式系统的基本概念,学习使用Dubbo、Spring Cloud等分布式框架
|
4天前
|
SQL Java 数据库连接
Java从入门到精通:2.3.2数据库编程——了解SQL语言,编写基本查询语句
Java从入门到精通:2.3.2数据库编程——了解SQL语言,编写基本查询语句
|
4天前
|
SQL Java 数据库连接
Java从入门到精通:2.3.1数据库编程——学习JDBC技术,掌握Java与数据库的交互
ava从入门到精通:2.3.1数据库编程——学习JDBC技术,掌握Java与数据库的交互
|
4天前
|
设计模式 存储 前端开发
Java从入门到精通:2.2.1学习Java Web开发,了解Servlet和JSP技术,掌握MVC设计模式
Java从入门到精通:2.2.1学习Java Web开发,了解Servlet和JSP技术,掌握MVC设计模式
|
4天前
|
Java API
Java从入门到精通:2.1.5深入学习Java核心技术之文件操作
Java从入门到精通:2.1.5深入学习Java核心技术之文件操作