/// <summary> /// The end web request event. /// </summary> /// <param name="webRequestContext"> /// The web request context. /// </param> /// <param name="testCase"> /// The test case. /// </param> /// <param name="parameterKey"> /// The parameter key. /// </param> /// <param name="parameterValue"> /// The parameter value. /// </param> private void EndWebRequestEvent( WebRequestContext webRequestContext, TestCase testCase, string parameterKey, string parameterValue) { HttpWebResponseHolder response = webRequestContext.ResponseHolder; // valid response type? if (string.IsNullOrEmpty(response.ResponseContent) || IsContentTypeValid(testCase, response.ResponseContentType)) { BrowserHelper.ReleaseBrowser(webRequestContext); return; } // run detectors this.Context.RunDetectors( response, this.TestTarget, this.GetType().Name, testCase, parameterKey, parameterValue); // execute client callback this.ExecuteCheckForVulnerabilities( webRequestContext, testCase, parameterKey, parameterValue); }
/// <summary> /// Overriding the Check Vulnerability implementation because we just want to look in the response headers. /// </summary> /// <param name="webRequestContext"> /// The web Request Context. /// </param> /// <param name="testcase"> /// The test case. /// </param> /// <param name="testedParam"> /// The tested Parameter. /// </param> /// <param name="testValue"> /// The tested Val. /// </param> /// <seealso cref="M:BackScatterScannerLib.Engine.TestBase.CheckForVuln(WebRequestContext,TestCase,string,string)"/> protected override void CheckForVulnerabilities( WebRequestContext webRequestContext, TestCase testcase, string testedParam, string testValue) { HttpWebResponseHolder response = webRequestContext.ResponseHolder; var fromHeaderValue = response.Headers["From"]; if (response.Headers == null || string.IsNullOrWhiteSpace(fromHeaderValue)) { return; } // Have we injected a from header and does it contain the domain we are attempting to redirect to? if (fromHeaderValue.IndexOf("*****@*****.**", StringComparison.InvariantCultureIgnoreCase) > -1) { Vulnerabilities.Enqueue(new Vulnerability { Title = "HTTP Response Splitting - Newline Injection", Level = (int)VulnerabilityLevelEnum.High, TestedParam = testedParam, TestedVal = testValue, HttpResponse = response, Evidence = $"From : {fromHeaderValue}", MatchString = testcase.MatchString, TestPlugin = GetType().Name }); } }
/// <summary> /// The check secure cookies over http. /// </summary> /// <param name="responseTarget"> /// The response target. /// </param> /// <param name="testParameter"> /// The tested parameter. /// </param> /// <param name="testValue"> /// The tested val. /// </param> /// <param name="response"> /// The current response. /// </param> /// <param name="testCase"> /// The test case. /// </param> private void CheckSecureCookiesOverHttp( ITarget responseTarget, string testParameter, string testValue, HttpWebResponseHolder response, TestCase testCase) { bool isHttp = responseTarget.Uri.OriginalString.StartsWith( "http://", StringComparison.InvariantCultureIgnoreCase); if (!isHttp || response.Cookies == null) { return; } foreach (Cookie cookie in response.Cookies.Cast <Cookie>().Where(cookie => cookie.Secure)) { this.AddVulnerability( "Information Leakage - Secured cookie exchanged over non-secure http.", testParameter, testValue, cookie.Name, response, testCase, VulnerabilityLevelEnum.Info); } }
/// <summary> /// Inspects the page response content. /// </summary> /// <param name="requestTarget"> /// The request Target. /// </param> /// <param name="responseTarget"> /// The response Target. /// </param> /// <param name="response"> /// The current Response. /// </param> /// <param name="plugIn"> /// The plug In. /// </param> /// <param name="testCase"> /// The test Case. /// </param> /// <param name="testParameter"> /// The tested Parameter. /// </param> /// <param name="testValue"> /// The tested Val. /// </param> /// <seealso cref="M:BackScatterScannerLib.Engine.TestBase.InspectResponse(ITarget,ITarget,HttpWebResponseHolder,string,TestCase,string,string)"/> public override void InspectResponse( ITarget requestTarget, ITarget responseTarget, HttpWebResponseHolder response, string plugIn, TestCase testCase, string testParameter, string testValue) { var evidence = new StringBuilder(); foreach (Match e in Regex.Matches(response.ResponseContent, FolderPattern, RegexOptions.IgnoreCase)) { evidence.AppendLine(e.Value); } foreach (Match e in Regex.Matches(response.ResponseContent, FilePattern, RegexOptions.IgnoreCase)) { evidence.AppendLine(e.Value); } if (evidence.Length > 0) { this.AddVulnerability( "Information Leakage - Directory Browsing Is Enabled", testParameter, testValue, evidence.ToString(), response, testCase, VulnerabilityLevelEnum.High); } }
/// <summary> /// Check authentication information disclosure. /// </summary> /// <param name="testParameter"> /// The tested Parameter. /// </param> /// <param name="testValue"> /// The tested Val. /// </param> /// <param name="response"> /// The current Response. /// </param> /// <param name="testCase"> /// The test Case. /// </param> private void CheckAuthInformationDisclosure( string testParameter, string testValue, HttpWebResponseHolder response, TestCase testCase) { if (string.IsNullOrEmpty(response.ResponseContent)) { return; } if (response.ResponseContent.IndexOfOi("username") > -1) { this.AddVulnerability( "Possible user name information disclosure found.", testParameter, testValue, string.Empty, response, testCase, VulnerabilityLevelEnum.Low); } if (response.ResponseContent.IndexOfOi("password") > -1) { this.AddVulnerability( "Possible password information disclosure found.", testParameter, testValue, string.Empty, response, testCase, VulnerabilityLevelEnum.Medium); } }
/// <summary> /// The inspect response. /// </summary> /// <param name="requestTarget"> /// The request target. /// </param> /// <param name="responseTarget"> /// The response target. /// </param> /// <param name="response"> /// The current response. /// </param> /// <param name="plugIn"> /// The plug in. /// </param> /// <param name="testCase"> /// The test case. /// </param> /// <param name="testParameter"> /// The tested parameter. /// </param> /// <param name="testValue"> /// The tested val. /// </param> public override void InspectResponse( ITarget requestTarget, ITarget responseTarget, HttpWebResponseHolder response, string plugIn, TestCase testCase, string testParameter, string testValue) { if (response.RequestAbsolutUri.IndexOfOi("https://") != -1 && response.Headers.IsNotEmpty()) { // Check for cache-control violation in response header. string cacheControl = response.Headers[CacheControl]; if (!string.IsNullOrWhiteSpace(cacheControl)) { // http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.2 if (cacheControl.IndexOfOi("no-store") == -1 && cacheControl.IndexOfOi("no-cache") == -1 && cacheControl.IndexOfOi("max-age") == -1 && cacheControl.IndexOfOi("private") == -1) { this.AddVulnerability( "HTTPS pages should not be cached", testParameter, testValue, CacheControl + ": " + cacheControl, response, testCase, VulnerabilityLevelEnum.Low); } } } }
/// <summary> /// Inside a test check to see if the match string gets found on the response page,regex used for matching /// if that is the case then log a vulnerabilities. /// </summary> /// <param name="webRequestContext">web request context</param> /// <param name="testCase">test case</param> /// <param name="testParameter">tested parameter</param> /// <param name="testValue">tested value</param> protected virtual void CheckForVulnerabilities( WebRequestContext webRequestContext, TestCase testCase, string testParameter, string testValue) { HttpWebResponseHolder response = webRequestContext.ResponseHolder; if (string.IsNullOrEmpty(testCase.MatchString)) { return; } MatchCollection matches = Regex.Matches( response.ResponseContent, testCase.MatchString, RegexOptions.IgnoreCase); if (matches.Count > 0) { this.Vulnerabilities.Enqueue(new Vulnerability { Title = testCase.TestName, Level = 1, TestedParam = testParameter, TestedVal = testValue, HttpResponse = response, MatchString = testCase.MatchString, TestPlugin = GetType().Name }); } }
/// <inheritdoc/> protected override void CheckForVulnerabilities( WebRequestContext webRequestContext, TestCase testcase, string testedParam, string testValue) { HttpWebResponseHolder response = webRequestContext.ResponseHolder; if (response.StatusCode >= HttpStatusCode.OK && response.StatusCode < HttpStatusCode.Ambiguous) { return; } try { var evidence = ExtractEvidence(response.ResponseContent, TestTarget.Content); if (!string.IsNullOrEmpty(evidence)) { this.AddVulnerability( testcase.TestName, testedParam, testValue, evidence, response, testcase, VulnerabilityLevelEnum.Info); } } catch (OutOfMemoryException ex) { Logger.WriteError(ex); } }
/// <summary> /// Inside a test check to see if the match string gets found on the response page,regex used for /// matching if that is the case then log a vulnerability. /// </summary> /// <param name="webRequestContext"> /// The web Request Context. /// </param> /// <param name="testcase"> /// The test case. /// </param> /// <param name="testedParam"> /// The tested parameter. /// </param> /// <param name="testValue"> /// The tested Val. /// </param> /// <seealso cref="M:BackScatterScannerLib.Engine.TestBase.CheckForVuln(WebRequestContext,TestCase,string,string)"/> protected override void CheckForVulnerabilities( WebRequestContext webRequestContext, TestCase testcase, string testedParam, string testValue) { HttpWebResponseHolder response = webRequestContext.ResponseHolder; if (response.ResponseUri != null && response.ResponseUri.Host.IndexOf(response.RequestHost, StringComparison.InvariantCultureIgnoreCase) == -1 && response.RequestHost.IndexOf(response.ResponseUri.Host, StringComparison.InvariantCultureIgnoreCase) == -1 && response.ResponseUri.Host.IndexOf("ikeahackers.net", StringComparison.InvariantCultureIgnoreCase) > -1) { this.AddVulnerability( testcase.TestName, testedParam, testValue, response.ResponseUri.Host, response, testcase, VulnerabilityLevelEnum.High); } }
/// <summary> /// Inside a test check to see if the match string gets found on the response page,regex used for /// matching if that is the case then log a vulnerability. /// </summary> /// <param name="webRequestContext"> /// The web Request Context. /// </param> /// <param name="testCase"> /// The test Case. /// </param> /// <param name="testParameter"> /// The tested Parameter. /// </param> /// <param name="testValue"> /// The tested Val. /// </param> /// <seealso cref="M:BackScatterScannerLib.Engine.TestBase.CheckForVuln(WebRequestContext,TestCase,string,string)"/> protected override void CheckForVulnerabilities( WebRequestContext webRequestContext, TestCase testCase, string testParameter, string testValue) { HttpWebResponseHolder response = webRequestContext.ResponseHolder; if (string.IsNullOrWhiteSpace(response.ResponseContent)) { return; } if (response.ResponseContent.IndexOfOi("<system.web>") > -1 && response.ResponseContent.IndexOfOi("</system.web>") > -1) { this.AddVulnerability( this.Name, testParameter, testValue, "Directory traversal attack succeeded.", response, testCase, VulnerabilityLevelEnum.High); } }
/// <summary> /// The check possible ports exposure. /// </summary> /// <param name="headerName"> /// The header name. /// </param> /// <param name="headerValue"> /// The header value. /// </param> /// <param name="testParameter"> /// The tested parameter. /// </param> /// <param name="testValue"> /// The tested val. /// </param> /// <param name="response"> /// The current response. /// </param> /// <param name="testCase"> /// The test case. /// </param> private void CheckPossiblePortsExposure( string headerName, string headerValue, string testParameter, string testValue, HttpWebResponseHolder response, TestCase testCase) { try { var uri = new Uri(headerValue); if (!uri.IsDefaultPort) { this.AddVulnerability( "Possible ports exposed.", testParameter, testValue, $"{headerName}={headerValue}", response, testCase, VulnerabilityLevelEnum.Low); } } catch (UriFormatException) { } }
/// <summary> /// Check response status. /// </summary> /// <param name="currentresponse"> /// The current response. /// </param> /// <returns> /// A string. /// </returns> private static string CheckResponseStatus(HttpWebResponseHolder currentresponse) { if (StatusCodes.Contains(currentresponse.StatusCode)) { return("HTTP Status: " + currentresponse.StatusCode); } return(string.Empty); }
/// <summary> /// Inspects the page response content. /// </summary> /// <param name="requestTarget"> /// The request Target. /// </param> /// <param name="responseTarget"> /// The response Target. /// </param> /// <param name="response"> /// The current Response. /// </param> /// <param name="plugIn"> /// The plug In. /// </param> /// <param name="testCase"> /// The test Case. /// </param> /// <param name="testParameter"> /// The tested Parameter. /// </param> /// <param name="testValue"> /// The tested Val. /// </param> /// <seealso cref="M:BackScatterScannerLib.Engine.TestBase.InspectResponse(ITarget,ITarget,HttpWebResponseHolder,string,TestCase,string,string)"/> public override void InspectResponse( ITarget requestTarget, ITarget responseTarget, HttpWebResponseHolder response, string plugIn, TestCase testCase, string testParameter, string testValue) { if (string.IsNullOrEmpty(response?.ResponseContent)) { return; } string contentType = response.ResponseContentType; // test for empty content type if (string.IsNullOrWhiteSpace(contentType)) { this.AddVulnerability( "Content type header is missing.", testParameter, testValue, "Content type header is missing.", response, testCase, VulnerabilityLevelEnum.Low); return; } // test that we don't have utf7 char-set if (contentType.IndexOf("utf-7", StringComparison.InvariantCultureIgnoreCase) > -1) { this.AddVulnerability( "Charset of the page should not be utf-7.", testParameter, testValue, response.Headers.ToString(), response, testCase, VulnerabilityLevelEnum.Low); } // test if the page is html and the content type is not text/html if (HtmlHelper.ContentIsHtml(response.ResponseContent) && contentType.IndexOfOi("text/html") == -1 && contentType.IndexOfOi("application / xhtml + xml") == -1) { this.AddVulnerability( "Html content type mismatched.", testParameter, testValue, response.Headers.ToString(), response, testCase, VulnerabilityLevelEnum.Low); } }
/// <summary> /// The inspect response. /// </summary> /// <param name="requestTarget"> /// The request target. /// </param> /// <param name="responseTarget"> /// The response target. /// </param> /// <param name="response"> /// The current response. /// </param> /// <param name="plugIn"> /// The plug in. /// </param> /// <param name="testCase"> /// The test case. /// </param> /// <param name="testParameter"> /// The tested parameter. /// </param> /// <param name="testValue"> /// The tested val. /// </param> public override void InspectResponse( ITarget requestTarget, ITarget responseTarget, HttpWebResponseHolder response, string plugIn, TestCase testCase, string testParameter, string testValue) { var dom = new HtmlDocument(); try { dom.LoadHtml(response.ResponseContent); } catch (Exception) { // ignore parsing errors - we don't know which errors are possible here. return; } if (response.RequestAbsolutUri.IndexOf("https://", StringComparison.InvariantCultureIgnoreCase) != -1) { // Check for cache-control violation in HTML meta elements. HtmlNodeCollection metaElements = dom.DocumentNode.SelectNodes("//meta"); if (metaElements != null) { foreach (HtmlNode metaElement in metaElements) { string httpEquiv = metaElement.GetAttributeValue("http-equiv", string.Empty).Trim(); if (httpEquiv.Equals("cache-control", StringComparison.InvariantCultureIgnoreCase)) { string content = metaElement.GetAttributeValue("content", string.Empty).Trim(); if (content.IndexOfOi("no-store") == -1 && content.IndexOfOi("no-cache") == -1 && content.IndexOfOi("max-age") == -1 && content.IndexOfOi("private") == -1) { this.AddVulnerability( "HTTPS pages should not be cached", testParameter, testValue, metaElement.OuterHtml, response, testCase, VulnerabilityLevelEnum.Low); break; } } } } } }
/// <summary> /// The inspect response. /// </summary> /// <param name="requestTarget"> /// The request target. /// </param> /// <param name="responseTarget"> /// The response target. /// </param> /// <param name="response"> /// The current response. /// </param> /// <param name="plugIn"> /// The plug in. /// </param> /// <param name="testCase"> /// The test case. /// </param> /// <param name="testParameter"> /// The tested parameter. /// </param> /// <param name="testValue"> /// The tested val. /// </param> public virtual void InspectResponse( ITarget requestTarget, ITarget responseTarget, HttpWebResponseHolder response, string plugIn, TestCase testCase, string testParameter, string testValue) { }
/// <summary> /// Verifies a vulnerability object has the basic plumbing correct. /// </summary> /// <param name="vuln"> /// The vuln. /// </param> /// <param name="instance"> /// The instance. /// </param> /// <param name="responseHolder"> /// The response holder. /// </param> public static void AssertBasicVulnProperties( Vulnerability vuln, PluginBaseAbstract instance, HttpWebResponseHolder responseHolder) { vuln.TestPlugin.ShouldEqual(instance.GetType().Name); vuln.HttpResponse.ShouldEqual(responseHolder); vuln.TestedParam.ShouldEqual("testedParam"); vuln.TestedVal.ShouldEqual("testedValue"); }
/// <summary> /// Check dot net error. /// </summary> /// <param name="currentresponse"> /// The current response. /// </param> /// <returns> /// A string. /// </returns> private static string CheckDotNetError(HttpWebResponseHolder currentresponse) { foreach (var dotNetException in DotNetExceptions .Where( dotNetException => currentresponse.ResponseContent.IndexOf( dotNetException, StringComparison.InvariantCultureIgnoreCase) > -1)) { return(dotNetException); } return(string.Empty); }
/// <summary> /// Inspects the page response content. /// </summary> /// <param name="requestTarget"> /// The request Target. /// </param> /// <param name="responseTarget"> /// The response Target. /// </param> /// <param name="response"> /// The current Response. /// </param> /// <param name="plugIn"> /// The plug In. /// </param> /// <param name="testCase"> /// The test Case. /// </param> /// <param name="testParameter"> /// The tested Parameter. /// </param> /// <param name="testValue"> /// The tested Val. /// </param> /// <seealso cref="M:BackScatterScannerLib.Engine.TestBase.InspectResponse(ITarget,ITarget,HttpWebResponseHolder,string,TestCase,string,string)"/> public override void InspectResponse( ITarget requestTarget, ITarget responseTarget, HttpWebResponseHolder response, string plugIn, TestCase testCase, string testParameter, string testValue) { var dom = new HtmlDocument(); try { dom.LoadHtml(response.ResponseContent); } catch (Exception) { // ignore parsing errors - we don't know which errors are possible here. return; } HtmlNodeCollection inputElements = dom.DocumentNode.SelectNodes("//input"); if (inputElements != null) { foreach (HtmlNode node in inputElements) { string inputType = node.GetAttributeValue("type", "text"); if (inputType.Equals("password", StringComparison.InvariantCultureIgnoreCase)) { // Pages with password fields should be served over HTTPS. if ( response.RequestAbsolutUri.IndexOf( "https://", StringComparison.InvariantCultureIgnoreCase) == -1) { this.AddVulnerability( "Password fields should only be served over HTTPS", testParameter, testValue, response.RequestAbsolutUri, response, testCase, VulnerabilityLevelEnum.Low); } } } } }
/// <summary> /// Inspects the page response content. /// </summary> /// <param name="requestTarget"> /// The request Target. /// </param> /// <param name="responseTarget"> /// The response Target. /// </param> /// <param name="response"> /// The current Response. /// </param> /// <param name="plugIn"> /// The plug In. /// </param> /// <param name="testCase"> /// The test Case. /// </param> /// <param name="testParameter"> /// The tested Parameter. /// </param> /// <param name="testValue"> /// The tested Val. /// </param> /// <seealso cref="M:BackScatterScannerLib.Engine.TestBase.InspectResponse(ITarget,ITarget,HttpWebResponseHolder,string,TestCase,string,string)"/> public override void InspectResponse( ITarget requestTarget, ITarget responseTarget, HttpWebResponseHolder response, string plugIn, TestCase testCase, string testParameter, string testValue) { var dom = new HtmlDocument(); try { dom.LoadHtml(response.ResponseContent); } catch (Exception) { // ignore parsing errors - we don't know which errors are possible here. return; } HtmlNodeCollection inputElements = dom.DocumentNode.SelectNodes("//input"); if (inputElements != null) { foreach (HtmlNode node in inputElements) { string inputType = node.GetAttributeValue("type", "text"); if (inputType.Equals("password", StringComparison.InvariantCultureIgnoreCase)) { // Password input fields should have auto-complete disabled. bool autocomplete = node.GetAttributeValue("autocomplete", false); if (autocomplete) { this.AddVulnerability( "Password input has autocomplete enabled", testParameter, testValue, node.OuterHtml, response, testCase, VulnerabilityLevelEnum.Info); } } } } }
/// <summary> /// Executes the tests. /// </summary> /// <seealso cref="M:BackScatterScannerLib.Engine.TestBase.DoTests()"/> public override void DoTests() { var newUrlCrossDomain = TestTarget.Uri.GetLeftPart(UriPartial.Authority) + "/" + "clientaccesspolicy.xml"; var webRequestContext = Context.SendRequest(new ContextSendRequestParameter { Url = newUrlCrossDomain, AllowRedirect = false }); try { HttpWebResponseHolder responseDomain = webRequestContext.ResponseHolder; if (string.IsNullOrEmpty(responseDomain.ResponseContent) || responseDomain.StatusCode != HttpStatusCode.OK) { Context.ReleaseBrowser(webRequestContext.Browser); return; } var root = XElement.Parse(responseDomain.ResponseContent); // Check CrossDomain.xml should not contain a global wildcard character. var badDomains = root.Descendants().Where(e => e.Attribute("uri") != null && e.Attribute("uri").Value == "*"); foreach (var e in badDomains) { this.AddVulnerability( "Trust of all domains", string.Empty, string.Empty, e.ToString(), responseDomain, null, VulnerabilityLevelEnum.Medium); } } finally { Context.ReleaseBrowser(webRequestContext.Browser); } }
/// <summary> /// Inspects the page response content. /// </summary> /// <param name="requestTarget"> /// The request Target. /// </param> /// <param name="responseTarget"> /// The response Target. /// </param> /// <param name="response"> /// The current Response. /// </param> /// <param name="plugIn"> /// The plug In. /// </param> /// <param name="testCase"> /// The test Case. /// </param> /// <param name="testParameter"> /// The tested Parameter. /// </param> /// <param name="testValue"> /// The tested Val. /// </param> /// <seealso cref="M:BackScatterScannerLib.Engine.TestBase.InspectResponse(ITarget,ITarget,HttpWebResponseHolder,string,TestCase,string,string)"/> public override void InspectResponse( ITarget requestTarget, ITarget responseTarget, HttpWebResponseHolder response, string plugIn, TestCase testCase, string testParameter, string testValue) { if (string.IsNullOrEmpty(response?.ResponseContent) || response.Headers == null) { return; } bool isHttp = responseTarget.Uri.OriginalString.StartsWith( "http://", StringComparison.InvariantCultureIgnoreCase); for (var i = 0; i < response.Headers.Count; i++) { string key; try { key = response.Headers.GetKey(i); } catch { continue; } // don't consider empty header value var value = response.Headers[i]; if (string.IsNullOrEmpty(value)) { continue; } this.CheckContentTypeOptionsMisconfiguration(key, value, testParameter, testValue, response, testCase); this.CheckXssProtectionMisconfiguration(key, value, testParameter, testValue, response, testCase); this.CheckExposedTokens(isHttp, key, value, testParameter, testValue, response, testCase); this.CheckPossiblePortsExposure(key, value, testParameter, testValue, response, testCase); } }
/// <summary> /// Inspects the page response content. /// </summary> /// <param name="requestTarget"> /// The request Target. /// </param> /// <param name="responseTarget"> /// The response Target. /// </param> /// <param name="response"> /// The current Response. /// </param> /// <param name="plugIn"> /// The plug In. /// </param> /// <param name="testCase"> /// The test Case. /// </param> /// <param name="testParameter"> /// The tested Parameter. /// </param> /// <param name="testValue"> /// The tested Val. /// </param> /// <seealso cref="M:BackScatterScannerLib.Engine.TestBase.InspectResponse(ITarget,ITarget,HttpWebResponseHolder,string,TestCase,string,string)"/> public override void InspectResponse( ITarget requestTarget, ITarget responseTarget, HttpWebResponseHolder response, string plugIn, TestCase testCase, string testParameter, string testValue) { string evidence = CheckResponseStatus(response); if (!string.IsNullOrEmpty(evidence)) { this.AddVulnerability( "Server Error", testParameter, testValue, evidence, response, testCase, VulnerabilityLevelEnum.Medium); } // check .net exceptions, in case the response is empty than return if (string.IsNullOrEmpty(response.ResponseContent)) { return; } evidence = CheckDotNetError(response); if (!string.IsNullOrEmpty(evidence)) { this.AddVulnerability( ".Net Exception", testParameter, testValue, evidence, response, testCase, VulnerabilityLevelEnum.Medium); } }
/// <summary> /// The check content type options misconfiguration. /// </summary> /// <param name="headerName"> /// The header name. /// </param> /// <param name="headerValue"> /// The header value. /// </param> /// <param name="testParameter"> /// The tested parameter. /// </param> /// <param name="testValue"> /// The tested val. /// </param> /// <param name="response"> /// The current response. /// </param> /// <param name="testCase"> /// The test case. /// </param> private void CheckContentTypeOptionsMisconfiguration( string headerName, string headerValue, string testParameter, string testValue, HttpWebResponseHolder response, TestCase testCase) { if (headerName.IndexOf("x-content-type-options", StringComparison.InvariantCultureIgnoreCase) > -1 && headerValue.IndexOf("nosniff", StringComparison.InvariantCultureIgnoreCase) == -1) { this.AddVulnerability( this.Name, testParameter, testValue, $"x-content-type-options={headerValue}", response, testCase, VulnerabilityLevelEnum.Low); } }
/// <summary> /// The check xss protection misconfiguration. /// </summary> /// <param name="headerName"> /// The header name. /// </param> /// <param name="headerValue"> /// The header value. /// </param> /// <param name="testParameter"> /// The tested parameter. /// </param> /// <param name="testValue"> /// The tested val. /// </param> /// <param name="response"> /// The current response. /// </param> /// <param name="testCase"> /// The test case. /// </param> private void CheckXssProtectionMisconfiguration( string headerName, string headerValue, string testParameter, string testValue, HttpWebResponseHolder response, TestCase testCase) { if (headerName.IndexOf("x-xss-protection", StringComparison.InvariantCultureIgnoreCase) > -1 && headerValue.IndexOf("0", StringComparison.InvariantCultureIgnoreCase) > -1) { this.AddVulnerability( this.Name, testParameter, testValue, headerName + "=" + headerValue, response, testCase, VulnerabilityLevelEnum.Medium); } }
/// <summary> /// Inside a test check to see if the match string gets found on the response page,regex used for /// matching if that is the case then log a vulnerability. /// </summary> /// <param name="webRequestContext"> /// The web Request Context. /// </param> /// <param name="testCase"> /// The test Case. /// </param> /// <param name="testedParam"> /// The tested Parameter. /// </param> /// <param name="testValue"> /// The tested Val. /// </param> /// <seealso cref="M:BackScatterScannerLib.Engine.TestBase.CheckForVuln(WebRequestContext,TestCase,string,string)"/> protected override void CheckForVulnerabilities( WebRequestContext webRequestContext, TestCase testCase, string testedParam, string testValue) { HttpWebResponseHolder response = webRequestContext.ResponseHolder; try { string[] sqlerrors = { "sql syntax", "sql error", "syntax error" }; var evidence = sqlerrors.FirstOrDefault( e => response.ResponseContent.IndexOf(e, StringComparison.InvariantCultureIgnoreCase) > -1); if (!string.IsNullOrEmpty(evidence) || (testCase.TestName.Equals(TimingTestCase, StringComparison.InvariantCultureIgnoreCase) && response.Latency.TotalSeconds >= BaselineLatencyInSeconds + TimeOutInSeconds + 1)) { this.AddVulnerability( testCase.TestName, testedParam, testValue, evidence ?? TimingTestCase, response, testCase, VulnerabilityLevelEnum.High); } } catch (Exception ex) { Logger.WriteError(ex); } }
/// <summary> /// The check exposed tokens. /// </summary> /// <param name="isHttp"> /// The is http. /// </param> /// <param name="headerName"> /// The header name. /// </param> /// <param name="headerValue"> /// The header value. /// </param> /// <param name="testParameter"> /// The tested parameter. /// </param> /// <param name="testValue"> /// The tested val. /// </param> /// <param name="response"> /// The current response. /// </param> /// <param name="testCase"> /// The test case. /// </param> private void CheckExposedTokens( bool isHttp, string headerName, string headerValue, string testParameter, string testValue, HttpWebResponseHolder response, TestCase testCase) { // check if we expose token headers over http if (isHttp && headerName.IndexOf(TokenSubstring, StringComparison.InvariantCultureIgnoreCase) > -1) { this.AddVulnerability( "Possible exposed secret over non secure protocol.", testParameter, testValue, headerName + "=" + headerValue, response, testCase, VulnerabilityLevelEnum.Info); } }
/// <summary> /// The inspect response. /// </summary> /// <param name="requestTarget"> /// The request target. /// </param> /// <param name="responseTarget"> /// The response target. /// </param> /// <param name="response"> /// The current response. /// </param> /// <param name="plugIn"> /// The plug in. /// </param> /// <param name="testCase"> /// The test case. /// </param> /// <param name="testParameter"> /// The tested parameter. /// </param> /// <param name="testValue"> /// The tested val. /// </param> public override void InspectResponse( ITarget requestTarget, ITarget responseTarget, HttpWebResponseHolder response, string plugIn, TestCase testCase, string testParameter, string testValue) { string accessControlAllowOrigin = response.Headers["Access-Control-Allow-Origin"]; if (!string.IsNullOrWhiteSpace(accessControlAllowOrigin) && accessControlAllowOrigin.IndexOf("*", StringComparison.InvariantCultureIgnoreCase) != -1) { bool matchFound = false; foreach (string allowedDomain in this.whiteListDomains) { if (Regex.Match(accessControlAllowOrigin, allowedDomain).Success) { matchFound = true; break; } } if (!matchFound) { Vulnerabilities.Enqueue(new Vulnerability { TestPlugin = GetType().Name + " (via " + plugIn + ")", Title = "Access-Control-Allow-Origin has wildcard for domain not in WebSec white list", Level = (int)VulnerabilityLevelEnum.Low, Evidence = accessControlAllowOrigin, HttpResponse = response }); } } }
/// <summary> /// Add vulnerability. /// </summary> /// <param name="title">vulnerability title</param> /// <param name="testParameter">tested parameter</param> /// <param name="testValue">tested value</param> /// <param name="evidence">the evidence</param> /// <param name="response">web response ( mandatory )</param> /// <param name="testCase">test case</param> /// <param name="vulnerabilityLevel">vulnerability Level</param> protected void AddVulnerability( string title, string testParameter, string testValue, string evidence, HttpWebResponseHolder response, TestCase testCase, VulnerabilityLevelEnum vulnerabilityLevel) { Require.NotNull(() => response); this.Vulnerabilities.Enqueue(new Vulnerability { Title = title, Level = (int)vulnerabilityLevel, TestedParam = testParameter, TestedVal = testValue, HttpResponse = response, Evidence = evidence, MatchString = testCase == null ? string.Empty : testCase.MatchString, TestPlugin = GetType().Name }); }
/// <summary> /// The inspect response. /// </summary> /// <param name="requestTarget"> /// The request target. /// </param> /// <param name="responseTarget"> /// The response target. /// </param> /// <param name="response"> /// The current response. /// </param> /// <param name="plugIn"> /// The plug in. /// </param> /// <param name="testCase"> /// The test case. /// </param> /// <param name="testParameter"> /// The tested parameter. /// </param> /// <param name="testValue"> /// The tested val. /// </param> public override void InspectResponse( ITarget requestTarget, ITarget responseTarget, HttpWebResponseHolder response, string plugIn, TestCase testCase, string testParameter, string testValue) { string accessControlAllowMethods = response.Headers["Access-Control-Allow-Methods"]; if (!string.IsNullOrWhiteSpace(accessControlAllowMethods) && accessControlAllowMethods.ContainsAnyOi(new[] { "put", "delete", "options" })) { Vulnerabilities.Enqueue(new Vulnerability { TestPlugin = GetType().Name + " (via " + plugIn + ")", Title = "Access-Control-Allow-Methods allows methods other than GET and POST", Level = (int)VulnerabilityLevelEnum.Low, Evidence = accessControlAllowMethods, HttpResponse = response }); } }
/// <summary> /// Inspects the page response content. /// </summary> /// <param name="requestTarget"> /// The request Target. /// </param> /// <param name="responseTarget"> /// The response Target. /// </param> /// <param name="response"> /// The current Response. /// </param> /// <param name="plugIn"> /// The plug In. /// </param> /// <param name="testCase"> /// The test Case. /// </param> /// <param name="testParameter"> /// The tested Parameter. /// </param> /// <param name="testValue"> /// The tested Val. /// </param> /// <seealso cref="M:BackScatterScannerLib.Engine.TestBase.InspectResponse(ITarget,ITarget,HttpWebResponseHolder,string,TestCase,string,string)"/> public override void InspectResponse( ITarget requestTarget, ITarget responseTarget, HttpWebResponseHolder response, string plugIn, TestCase testCase, string testParameter, string testValue) { // if this is a fiddler error page just return, nothing to test for if (IsFiddlerErrorPage(response.ResponseContent)) { Logger.WriteError("Fiddler error {0}", response.ResponseContent); return; } // ipv4 and ipv6 match var addressMatch = Regex.Matches( response.ResponseContent, @"(127\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})|(192\.168\.[0-9]{1,3}\.[0-9]{1,3})|(10\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})|(172\.1[6-9]\.[0-9]{1,3}\.[0-9]{1,3})|(172\.2[0-9]\.[0-9]{1,3}\.[0-9]{1,3})|(^172\.3[0-1]\.[0-9]{1,3}\.[0-9]{1,3})", RegexOptions.IgnoreCase); if (addressMatch.Count > 0) { var evidence = new StringBuilder(); foreach (Match match in addressMatch) { // the class IPAdress allows addresses like "::" to pass as valid ip, protect against these cases if (!CheckIpValidity(match.Value)) { continue; } // The regex patterns are a rough comparison, let the IPAddress parser make the final call IPAddress address; if (IPAddress.TryParse(match.Value, out address)) { evidence.AppendLine(match.Value); } } if (evidence.Length > 0) { this.AddVulnerability( "Information Leakage - IP Address Disclosure", testParameter, testValue, evidence.ToString(), response, testCase, VulnerabilityLevelEnum.Low); } } var filePathMatch = Regex.Matches( response.ResponseContent, @"([A-Z]{1}:\\[A-Z0-9\\\.]{0,})|(\\\\[A-Z0-9_-]{1,}[A-Z0-9\\\.]{0,})", RegexOptions.IgnoreCase); // UNC if (filePathMatch.Count > 0) { var evidence = new StringBuilder(); foreach (Match match in filePathMatch) { // check UNC path validity if (!CheckPathValidity(match.Value)) { continue; } evidence.AppendLine(match.Value); } if (evidence.Length > 0) { this.AddVulnerability( "Information Leakage - File Path Disclosure", testParameter, testValue, evidence.ToString(), response, testCase, VulnerabilityLevelEnum.Low); } } // check for exchange secure cookies over http this.CheckSecureCookiesOverHttp(responseTarget, testParameter, testValue, response, testCase); this.CheckAuthInformationDisclosure(testParameter, testValue, response, testCase); }