Java tutorial
/* This software was developed by employees of the National Institute of * Standards and Technology (NIST), an agency of the Federal Government. * Pursuant to title 15 United States Code Section 105, works of NIST * employees are not subject to copyright protection in the United States * and are considered to be in the public domain. As a result, a formal * license is not needed to use the software. * * This software is provided by NIST as a service and is expressly * provided "AS IS". NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT * AND DATA ACCURACY. NIST does not warrant or make any representations * regarding the use of the software or the results thereof including, but * not limited to, the correctness, accuracy, reliability or usefulness of * the software. * * Permission to use this software is contingent upon your acceptance * of the terms of this agreement. */ package gov.nist.appvet.tool; import gov.nist.appvet.tool.util.Logger; import gov.nist.appvet.tool.util.SSLWrapper; import java.io.File; import java.io.IOException; import java.io.PrintWriter; import java.nio.charset.Charset; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Iterator; import java.util.List; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.FileItemFactory; import org.apache.commons.fileupload.FileUploadException; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.servlet.ServletFileUpload; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.mime.MultipartEntity; import org.apache.http.entity.mime.content.FileBody; import org.apache.http.entity.mime.content.StringBody; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.params.BasicHttpParams; import org.apache.http.params.HttpConnectionParams; import org.apache.http.params.HttpParams; @WebServlet("/AsynchronousService") public class AsynchronousService extends HttpServlet { private static final long serialVersionUID = 1L; private static final Logger log = Properties.log; public AsynchronousService() { super(); log.info("Master Key and Extra Field service ready."); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { FileItemFactory factory = new DiskFileItemFactory(); ServletFileUpload upload = new ServletFileUpload(factory); List items = null; FileItem fileItem = null; String appId = null; try { items = upload.parseRequest(request); } catch (FileUploadException e) { e.printStackTrace(); } // Get form fields Iterator iter = items.iterator(); FileItem item = null; while (iter.hasNext()) { item = (FileItem) iter.next(); if (item.isFormField()) { String incomingParameter = item.getFieldName(); String incomingValue = item.getString(); if (incomingParameter.equals("appid")) { appId = incomingValue; } log.debug("Received: " + incomingParameter + " = " + incomingValue); } else { // item should now hold the received file if (item != null) { fileItem = item; } } } // If app ID and file were received, send back HTTP 202 now if (appId != null && fileItem != null) { sendHttp202(response, "Received app " + appId + " for processing."); } else { sendHttp400(response, "Did not receive proper request."); return; } String appFilePath = null; String reportPath = null; String fileName = null; if (item != null) { fileName = getFileName(fileItem.getName()); if (!fileName.endsWith(".apk")) { sendHttp400(response, "Invalid app file: " + fileItem.getName()); return; } appFilePath = Properties.TEMP_DIR + "/" + appId + fileName; reportPath = Properties.TEMP_DIR + "/" + appId + "_report.txt"; log.debug("appFilePath: " + appFilePath); if (!saveFileUpload(fileItem, appFilePath)) { sendHttp500(response, "Could not save uploaded file"); return; } } else { log.error("File item was null."); return; } // Test app AndroidVulnerabilityScanner vulnerabilityScanner = new AndroidVulnerabilityScanner(appFilePath); boolean masterKeyFound = vulnerabilityScanner.hasMasterKey(); boolean extraFieldFound = vulnerabilityScanner.hasExtraField(); vulnerabilityScanner.close(); // Generate report String htmlReport = null; ToolStatus reportStatus = null; if (masterKeyFound) { reportStatus = ToolStatus.FAIL; htmlReport = generateReport(fileName, reportStatus, "Master Key vulnerability detected."); } if (extraFieldFound) { reportStatus = ToolStatus.FAIL; htmlReport = generateReport(fileName, reportStatus, "Extra Field vulnerability detected."); } if (!masterKeyFound && !extraFieldFound) { reportStatus = ToolStatus.PASS; htmlReport = generateReport(fileName, reportStatus, "No Master Key or Extra Field vulnerablity detected."); } // Write report file PrintWriter out = new PrintWriter(reportPath); out.write(htmlReport); out.close(); // Now send report sendReport(appId, reportStatus.name(), reportPath); boolean deleted = deleteFile(appFilePath); if (deleted) { log.debug("Deleted app " + appFilePath); } else { log.error("Could not delete app file " + appFilePath); } deleted = deleteFile(reportPath); if (deleted) { log.debug("Deleted report " + reportPath); } else { log.error("Could not delete report file " + reportPath); } // Clean up System.gc(); } private String generateReport(String fileName, ToolStatus status, String report) { StringBuffer htmlBuffer = new StringBuffer(); // htmlBuffer.append("ANDROID MASTER KEY AND EXTRA FIELD REPORT\n\n" // + new Date().toString() + "\n\n" // + "This report indicates the presence of the Android " // + "'Master Key' or 'Extra Field' vulnerabilities. This report " // + "will generate a FAIL if one or both of these vulnerabilities " // + "are detected, or a PASS if no vulnerabilities are detected. " // + "\n\n------------------------\n"); htmlBuffer.append("<HTML>\n"); htmlBuffer.append("<head>\n"); htmlBuffer.append("<style type=\"text/css\">\n"); htmlBuffer.append("h3 {font-family:arial;}\n"); htmlBuffer.append("p {font-family:arial;}\n"); htmlBuffer.append("</style>\n"); htmlBuffer.append("<title>Master Key Extra Field Report</title>\n"); htmlBuffer.append("</head>\n"); htmlBuffer.append("<body>\n"); String appVetImagesUrl = Properties.mainURL + "/images/nist-gray.png"; htmlBuffer.append("<img border=\"0\" width=\"100px\" src=\"" + appVetImagesUrl + "\" alt=\"appvet\" />"); htmlBuffer.append("<HR>\n"); htmlBuffer.append("<h3>Master Key Extra Field Report</h3>\n"); htmlBuffer.append("<pre>\n"); htmlBuffer.append("File: \t\t" + fileName + "\n"); final Date date = new Date(); final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd' 'HH:mm:ss.SSSZ"); final String currentDate = format.format(date); htmlBuffer.append("Date: \t\t" + currentDate + "\n\n"); if (status == ToolStatus.PASS) { htmlBuffer.append("Status: \t<font color=\"green\">" + status.name() + "</font>\n"); } else { htmlBuffer.append("Status: \t<font color=\"red\">" + status.name() + "</font>\n"); } htmlBuffer.append("Description: \t" + report + "\n\n"); htmlBuffer.append("</body>\n"); htmlBuffer.append("</HTML>\n"); return htmlBuffer.toString(); } public static String getFileName(String filePath) { String fileName = null; int lastBackSlash = filePath.lastIndexOf("\\"); int lastForwardSlash = filePath.lastIndexOf("/"); if (lastBackSlash == -1 && lastForwardSlash == -1) // No slashes found in file path fileName = filePath; else if (lastBackSlash >= 0) // Back slash detected fileName = filePath.substring(lastBackSlash + 1, filePath.length()); else // Forward slash detected fileName = filePath.substring(lastForwardSlash + 1, filePath.length()); return fileName; } private void sendHttp202(HttpServletResponse response, String message) { try { response.setStatus(HttpServletResponse.SC_ACCEPTED); response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println(message); out.flush(); out.close(); log.debug("Sent HTTP 202: " + message); } catch (IOException e) { e.printStackTrace(); } } private void sendHttp400(HttpServletResponse response, String message) { try { response.setStatus(HttpServletResponse.SC_BAD_REQUEST); response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println(message); out.flush(); out.close(); log.debug("Sent HTTP 400: " + message); } catch (IOException e) { e.printStackTrace(); } } private void sendHttp500(HttpServletResponse response, String message) { try { response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println(message); out.flush(); out.close(); log.debug("Sent HTTP 500: " + message); } catch (IOException e) { e.printStackTrace(); } } public boolean saveFileUpload(FileItem fileItem, String outputFilePath) { try { if (fileItem == null) { log.error("fileItem is NULL"); return false; } File file = new File(outputFilePath); fileItem.write(file); log.debug("Saved file " + outputFilePath); return true; } catch (IOException e) { log.error(e.getMessage()); return false; } catch (Exception e) { log.error(e.getMessage()); return false; } } public void sendReport(String appid, String toolrisk, String reportPath) { HttpParams httpParameters = new BasicHttpParams(); HttpConnectionParams.setConnectionTimeout(httpParameters, 30000); HttpConnectionParams.setSoTimeout(httpParameters, 1200000); HttpClient httpclient = new DefaultHttpClient(httpParameters); httpclient = SSLWrapper.wrapClient(httpclient); try { // To send reports back to AppVet, the following parameters must // be sent: // * command: SUBMIT_REPORT // * username: AppVet username // * password: AppVet password // * appid: The app ID // * toolid: The ID of this tool // * toolrisk: The risk assessment (PASS,FAIL,WARNING,ERROR) // * file: The report file. MultipartEntity entity = new MultipartEntity(); entity.addPart("command", new StringBody("SUBMIT_REPORT", Charset.forName("UTF-8"))); entity.addPart("username", new StringBody(Properties.appVetUsername, Charset.forName("UTF-8"))); entity.addPart("password", new StringBody(Properties.appVetPassword, Charset.forName("UTF-8"))); entity.addPart("appid", new StringBody(appid, Charset.forName("UTF-8"))); entity.addPart("toolid", new StringBody(Properties.toolId, Charset.forName("UTF-8"))); entity.addPart("toolrisk", new StringBody(toolrisk, Charset.forName("UTF-8"))); File report = new File(reportPath); FileBody fileBody = new FileBody(report); entity.addPart("file", fileBody); HttpPost httpPost = new HttpPost(Properties.appVetURL); httpPost.setEntity(entity); log.debug("Sending report to AppVet"); // Send the app to the tool final HttpResponse response = httpclient.execute(httpPost); httpPost = null; log.debug("Received: " + response.getStatusLine()); } catch (Exception e) { e.printStackTrace(); } } // TODO Return Common Vulnerability Scoring System (CVSS) here in lieu of // statuses. public boolean returnReport(HttpServletResponse response, ToolStatus reportStatus, String report) { try { response.setStatus(HttpServletResponse.SC_OK); // HTTP 200 response.setContentType("text/html"); response.setHeader("toolrisk", reportStatus.name()); PrintWriter out = response.getWriter(); out.println(report.toString()); out.flush(); out.close(); log.debug("Sent HTTP 200"); return true; } catch (IOException e) { e.printStackTrace(); return false; } } public boolean deleteFile(String sourceFilePath) { File file = new File(sourceFilePath); if (file.exists()) { return file.delete(); } else { log.error("File " + sourceFilePath + " does not exist"); return false; } } }