package com.nvarghese.beowulf.sfe.webtest.tm.enumeration; import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.List; import org.bson.types.ObjectId; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.nvarghese.beowulf.common.http.txn.AbstractHttpTransaction; import com.nvarghese.beowulf.common.http.txn.HttpMethodType; import com.nvarghese.beowulf.common.http.txn.HttpTransactionFactory; import com.nvarghese.beowulf.common.http.txn.HttpTxnDAO; import com.nvarghese.beowulf.common.http.txn.HttpTxnDocument; import com.nvarghese.beowulf.common.http.txn.TransactionSource; import com.nvarghese.beowulf.common.scan.dao.ReportIssueDAO; import com.nvarghese.beowulf.common.scan.dto.config.Options; import com.nvarghese.beowulf.common.scan.model.ReportIssueDocument; import com.nvarghese.beowulf.common.scan.model.ReportIssueVariantDocument; import com.nvarghese.beowulf.common.utils.HttpUtils; import com.nvarghese.beowulf.common.webtest.ReportThreatType; import com.nvarghese.beowulf.common.webtest.ThreatSeverityType; import com.nvarghese.beowulf.sfe.ConfigurationManager; import com.nvarghese.beowulf.sfe.webtest.tm.AbstractTestModule; import com.nvarghese.beowulf.sfe.webtest.types.DirectoryTestType; public class DirectoryEnumerator extends AbstractTestModule implements DirectoryTestType { private static final String SMALL_DIR_LIST = "Small (100 directory names)"; private static final String MEDIUM_DIR_LIST = "Medium (300 directory names)"; private static final String LARGE_DIR_LIST = "Large (500 directory names)"; private static final String EXTRA_LARGE_DIR_LIST = "Extra large (819 directory names)"; static Logger logger = LoggerFactory.getLogger(DirectoryEnumerator.class); @Override public void testByDirectory(ObjectId txnObjId, String directory) { logger.info("Running the directory_enumerator module for the txnObjId: {} with data store: {}", txnObjId.toString(), scanInstanceDataStore .getDB().getName()); HttpTxnDAO txnDAO = new HttpTxnDAO(scanInstanceDataStore); HttpTxnDocument httpTxnDocument = txnDAO.getHttpTxnDocument(txnObjId); if (httpTxnDocument == null) return; AbstractHttpTransaction originalTxn = AbstractHttpTransaction.getObject(httpTxnDocument); List<String> directoryNames = loadDirectoryNames(); for (String newDirectory : directoryNames) { try { URI uri = new URI(originalTxn.getHostUriWithoutTrailingSlash() + directory + newDirectory + "/"); AbstractHttpTransaction testTransaction = HttpTransactionFactory.createTransaction(HttpMethodType.GET, uri, null, originalTxn .getURI().toString(), TransactionSource.ENUMERATION); testTransaction.execute(); if (HttpUtils.fileExists(testTransaction.getResponseStatusCode())) { logger.info("Detected directory `{}` by enumeration", uri.getPath()); ObjectId id = txnDAO.createHttpTxnDocument(testTransaction.toHttpTxnDocument()); testTransaction.setObjId(id); reportFinding(originalTxn, testTransaction, newDirectory); } else { } } catch (URISyntaxException e) { logger.error("Failed to execute the request. Reason: {}", e.getMessage(), e); } } } private List<String> loadDirectoryNames() { List<String> directoryNames = new ArrayList<String>(); boolean optionValue; for (Options options : optionsMap.values()) { optionValue = Boolean.valueOf(options.getOptionValue()); if (optionValue) { if (options.getOptionName().equalsIgnoreCase(SMALL_DIR_LIST)) { directoryNames.addAll(ConfigurationManager.getScannerConfiguration().getList("file_enumeration.small_directory_list")); } else if (options.getOptionName().equalsIgnoreCase(MEDIUM_DIR_LIST)) { directoryNames.addAll(ConfigurationManager.getScannerConfiguration().getList("file_enumeration.medium_directory_list")); } else if (options.getOptionName().equalsIgnoreCase(LARGE_DIR_LIST)) { directoryNames.addAll(ConfigurationManager.getScannerConfiguration().getList("file_enumeration.large_directory_list")); } else if (options.getOptionName().equalsIgnoreCase(EXTRA_LARGE_DIR_LIST)) { directoryNames.addAll(ConfigurationManager.getScannerConfiguration().getList("file_enumeration.extra_large_directory_list")); } } } return directoryNames; } private void reportFinding(AbstractHttpTransaction originalTransaction, AbstractHttpTransaction testTransaction, String newDirectory) { String uri = testTransaction.getURI().toString(); ReportIssueDAO issueDAO = new ReportIssueDAO(scanInstanceDataStore); ReportIssueDocument reportIssueDocument = issueDAO.findByUrlAndThreatTypeAndModuleNumber(uri, ReportThreatType.PRED_RESOURCE_LOCATION, moduleNumber, false); if (reportIssueDocument == null) { reportIssueDocument = new ReportIssueDocument(); reportIssueDocument.setThreatSeverityType(ThreatSeverityType.MEDIUM); reportIssueDocument.setThreatType(ReportThreatType.PRED_RESOURCE_LOCATION); reportIssueDocument.setIssueUrl(uri); reportIssueDocument.setModuleName(moduleName); reportIssueDocument.setModuleNumber(moduleNumber); // reasoning reportIssueDocument.setReasoning("A directory was discovered by guessing its name."); // remediation reportIssueDocument.setRemediation("Review the contents of the directory and remove if it is not required."); // references reportIssueDocument.setReferences("OWASP - http://www.owasp.org/index.php/Testing_for_Old," + "_Backup_and_Unreferenced_Files_(OWASP-CM-006)"); issueDAO.createReportIssueDocument(reportIssueDocument); } //set issue variant ReportIssueVariantDocument issueVariant = new ReportIssueVariantDocument(); String description = "The following directory was discovered by guessing its name:</br></br>"; description += "  Original Directory: " + uri + "</br>"; description += "  Discovered Directory: " + testTransaction.getURI() + "</br></br>"; description += "If the directory was not linked to by the website," + " they could lead an attacker to unintended areas."; issueVariant.setDescription(description); issueVariant.setOrigicalTxn(originalTransaction.getObjId()); issueVariant.setTestTxn(testTransaction.getObjId()); issueDAO.addReportIssueVariants(reportIssueDocument.getId(), issueVariant); } }