The vulnerability is Unrestricted Upload of File with Dangerous Type
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.UUID;
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
@WebServlet("/upload")
@MultipartConfig
public class FileUploadServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private static final String UPLOAD_DIR = "uploads";
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
try {
Part filePart = request.getPart("file");
String fileName = getFileName(filePart);
InputStream inputStream = filePart.getInputStream();
String newFileName = UUID.randomUUID().toString() + "_" + fileName;
writeToFile(inputStream, UPLOAD_DIR + "/" + newFileName);
out.println("<h1>Success!</h1>");
out.println("<p>Your file " + fileName + " has been uploaded as " + newFileName + ".</p>");
} catch (Exception e) {
out.println("<h1>Failed!</h1>");
out.println("<p>" + e.getMessage() + "</p>");
}
out.close();
}
private String getFileName(final Part part) {
final String partHeader = part.getHeader("content-disposition");
for (String content : partHeader.split(";")) {
if (content.trim().startsWith("filename")) {
return content.substring(content.indexOf('=') + 1).trim().replace("\"", "");
}
}
return null;
}
private void writeToFile(InputStream inputStream, String filePath) throws IOException {
// Insecure code - does not restrict file type
byte[] buffer = new byte[1024];
int bytesRead = 0;
while ((bytesRead = inputStream.read(buffer)) != -1) {
try (FileOutputStream outputStream = new FileOutputStream(filePath, true)) {
outputStream.write(buffer, 0, bytesRead);
}
}
}
}
To fix this vulnerability, you should add a check to verify the file type before uploading it. One way to do this is to use a MIME type validation library, such as Apache Tika.
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import org.apache.tika.Tika;
public class FileUploader {
public void uploadFile(InputStream inputStream, String fileName) throws IOException {
String mimeType = new Tika().detect(inputStream);
if (!mimeType.startsWith("image/") && !mimeType.equals("application/pdf")) {
throw new IOException("Invalid file type.");
}
OutputStream outputStream = new FileOutputStream(new File("uploads/" + fileName));
int read = 0;
byte[] bytes = new byte[1024];
while ((read = inputStream.read(bytes)) != -1) {
outputStream.write(bytes, 0, read);
}
outputStream.flush();
outputStream.close();
}
public static void main(String[] args) throws IOException {
FileUploader uploader = new FileUploader();
uploader.uploadFile(System.in, "safe.pdf");
}
}