private Region ConstructRegion(AnalyzeContext context, FlexMatch regionFlexMatch, string fingerprint)
        {
            int indexOffset  = regionFlexMatch.Value.String.IndexOf(fingerprint);
            int lengthOffset = fingerprint.Length - regionFlexMatch.Length;

            if (indexOffset == -1)
            {
                // If we can't find the fingerprint in the match, that means we matched against
                // base64-decoded content (and therefore there is no region refinement to make).
                indexOffset  = 0;
                lengthOffset = 0;
            }

            var region = new Region
            {
                CharOffset = regionFlexMatch.Index + indexOffset,
                CharLength = regionFlexMatch.Length + lengthOffset,
            };

            return(_fileRegionsCache.PopulateTextRegionProperties(
                       region,
                       context.TargetUri,
                       populateSnippet: true,
                       fileText: context.FileContents));
        }
        private Result ConstructResult(
            Uri targetUri,
            string ruleId,
            FailureLevel level,
            Region region,
            FlexMatch flexMatch,
            string fingerprint,
            MatchExpression matchExpression,
            IList <string> arguments)
        {
            var location = new Location()
            {
                PhysicalLocation = new PhysicalLocation
                {
                    ArtifactLocation = new ArtifactLocation
                    {
                        Uri = targetUri,
                    },
                    Region = region,
                },
            };

            Dictionary <string, string> fingerprints = BuildFingerprints(fingerprint);

            string messageId = matchExpression.SubId ?? "Default";

            var result = new Result()
            {
                RuleId  = ruleId,
                Level   = level,
                Message = new Message()
                {
                    Id        = messageId,
                    Arguments = arguments,
                },
                Locations    = new List <Location>(new[] { location }),
                Fingerprints = fingerprints,
            };

            if (matchExpression.Fixes?.Count > 0)
            {
                // Build arguments that may be required for fix text.
                var argumentNameToValueMap = new Dictionary <string, string>();

                foreach (KeyValuePair <string, int> kv in matchExpression.ArgumentNameToIndexMap)
                {
                    argumentNameToValueMap["{" + kv.Key + "}"] = arguments[kv.Value];
                }

                foreach (SimpleFix fix in matchExpression.Fixes.Values)
                {
                    ExpandArguments(fix, argumentNameToValueMap);
                    AddFixToResult(flexMatch, fix, result);
                }
            }

            return(result);
        }
        private void RunMatchExpression(FlexMatch binary64DecodedMatch, AnalyzeContext context, MatchExpression matchExpression)
        {
            FailureLevel level = matchExpression.Level;

            if (!string.IsNullOrEmpty(matchExpression.ContentsRegex))
            {
                RunMatchExpressionForContentsRegex(binary64DecodedMatch, context, matchExpression, level);
            }
            else if (!string.IsNullOrEmpty(matchExpression.FileNameAllowRegex))
            {
                RunMatchExpressionForFileNameRegex(context, matchExpression, level);
            }
            else
            {
                // Both FileNameAllowRegex and ContentRegex are null or empty.
            }
        }
        private static string ValidateConnectionString(ref string message, string host, string connString, out bool shouldRetry)
        {
            shouldRetry = true;
            try
            {
                using var connection = new SqlConnection(connString);
                connection.OpenAsync().GetAwaiter().GetResult();
            }
            catch (ArgumentException)
            {
                // This exception means that some illegal chars, etc.
                // have snuck into the connection string
                return(nameof(ValidationState.NoMatch));
            }
            catch (Exception e)
            {
                if (e is SqlException sqlException)
                {
                    if (sqlException.ErrorCode == unchecked ((int)0x80131904))
                    {
                        if (e.Message.Contains("Login failed for user"))
                        {
                            return(ReturnUnauthorizedAccess(ref message, asset: host));
                        }

                        FlexMatch match = RegexEngine.Match(e.Message, ClientIPExpression);
                        if (match.Success)
                        {
                            message     = match.Value;
                            shouldRetry = false;
                            return(nameof(ValidationState.Unknown));
                        }
                    }
                }

                return(ReturnUnhandledException(ref message, e, asset: host));
            }

            return(ReturnAuthorizedAccess(ref message, asset: host));
        }
        private void AddFixToResult(FlexMatch flexMatch, SimpleFix simpleFix, Result result)
        {
            result.Fixes ??= new List <Fix>();

            string replacementText = flexMatch.Value.String.Replace(simpleFix.Find, simpleFix.ReplaceWith);

            var fix = new Fix()
            {
                Description = new Message()
                {
                    Text = simpleFix.Description
                },
                ArtifactChanges = new List <ArtifactChange>(new[]
                {
                    new ArtifactChange()
                    {
                        ArtifactLocation = result.Locations[0].PhysicalLocation.ArtifactLocation,
                        Replacements     = new List <Replacement>(new[]
                        {
                            new Replacement()
                            {
                                DeletedRegion = new Region()
                                {
                                    CharOffset = flexMatch.Index,
                                    CharLength = flexMatch.Length,
                                },
                                InsertedContent = new ArtifactContent()
                                {
                                    Text = replacementText,
                                },
                            },
                        }),
                    },
                }),
            };

            result.Fixes.Add(fix);
        }
        private void RunMatchExpressionForContentsRegex(
            FlexMatch binary64DecodedMatch,
            AnalyzeContext context,
            MatchExpression matchExpression,
            FailureLevel level)
        {
            string filePath   = context.TargetUri.GetFilePath();
            string searchText = binary64DecodedMatch != null
                                                   ? Decode(binary64DecodedMatch.Value)
                                                   : context.FileContents;

            foreach (FlexMatch flexMatch in _engine.Matches(searchText, matchExpression.ContentsRegex))
            {
                if (!flexMatch.Success)
                {
                    continue;
                }

                ReportingDescriptor reportingDescriptor = this;

                Regex regex =
                    CachedDotNetRegex.GetOrCreateRegex(matchExpression.ContentsRegex,
                                                       RegexDefaults.DefaultOptionsCaseInsensitive);

                Match match = regex.Match(flexMatch.Value);

                string refinedMatchedPattern = match.Groups["refine"].Value;

                IDictionary <string, string> groups = match.Groups.CopyToDictionary(regex.GetGroupNames());

                Debug.Assert(!groups.ContainsKey("scanTargetFullPath"));
                groups["scanTargetFullPath"] = filePath;

                if (matchExpression.Properties != null)
                {
                    foreach (KeyValuePair <string, string> kv in matchExpression.Properties)
                    {
                        // We will never allow a group returned by a dynamically executing
                        // regex to overwrite a static value in the match expression. This
                        // allows the match expression to provide a default value that
                        // may be replaced by the analysis.
                        if (!groups.ContainsKey(kv.Key))
                        {
                            groups[kv.Key] = kv.Value;
                        }
                    }
                }

                if (string.IsNullOrEmpty(refinedMatchedPattern))
                {
                    refinedMatchedPattern = flexMatch.Value;
                }

                string levelText = level.ToString();

                Validation state            = 0;
                string     fingerprint      = null;
                string     validatorMessage = null;
                string     validationPrefix = string.Empty;
                string     validationSuffix = string.Empty;

                if (_validators != null && matchExpression.IsValidatorEnabled)
                {
                    state = _validators.Validate(reportingDescriptor.Name,
                                                 context.DynamicValidation,
                                                 ref refinedMatchedPattern,
                                                 ref groups,
                                                 ref levelText,
                                                 ref fingerprint,
                                                 ref validatorMessage,
                                                 out bool pluginSupportsDynamicValidation);

                    if (!Enum.TryParse <FailureLevel>(levelText, out level))
                    {
                        // An illegal failure level '{0}' was returned running check '{1}' against '{2}'.
                        context.Logger.LogToolNotification(
                            Errors.CreateNotification(
                                context.TargetUri,
                                "ERR998.ValidatorReturnedIllegalResultLevel",
                                context.Rule.Id,
                                FailureLevel.Error,
                                exception: null,
                                persistExceptionStack: false,
                                messageFormat: SpamResources.ERR998_ValidatorReturnedIllegalResultLevel,
                                levelText,
                                context.Rule.Id,
                                context.TargetUri.GetFileName()));

                        // If we don't understand the failure level, elevate it to error.
                        level = FailureLevel.Error;
                    }

                    SetPropertiesBasedOnValidationState(state,
                                                        context,
                                                        ref level,
                                                        ref validationPrefix,
                                                        ref validationSuffix,
                                                        ref validatorMessage,
                                                        pluginSupportsDynamicValidation);

                    if (state == Validation.None ||
                        state == Validation.NoMatch ||
                        state == Validation.ValidatorReturnedIllegalValidationState)
                    {
                        continue;
                    }
                }

                // If we're matching against decoded contents, the region should
                // relate to the base64-encoded scan target content. We do use
                // the decoded content for the fingerprint, however.
                FlexMatch regionFlexMatch = binary64DecodedMatch ?? flexMatch;

                Region region = ConstructRegion(context, regionFlexMatch, refinedMatchedPattern);

                Dictionary <string, string> messageArguments = matchExpression.MessageArguments != null ?
                                                               new Dictionary <string, string>(matchExpression.MessageArguments) :
                                                               new Dictionary <string, string>();

                messageArguments["encoding"] = binary64DecodedMatch != null ?
                                               "base64-encoded" :
                                               string.Empty; // We don't bother to report a value for plaintext content

                messageArguments["validationPrefix"] = validationPrefix;
                messageArguments["validationSuffix"] = validationSuffix;

                IList <string> arguments = GetMessageArguments(match,
                                                               matchExpression.ArgumentNameToIndexMap,
                                                               filePath,
                                                               validatorMessage: NormalizeValidatorMessage(validatorMessage),
                                                               messageArguments);

                Result result = ConstructResult(context.TargetUri,
                                                reportingDescriptor.Id,
                                                level,
                                                region,
                                                flexMatch,
                                                fingerprint,
                                                matchExpression,
                                                arguments);

                // This skimmer instance mutates its reporting descriptor state,
                // for example, the sub-id may change for every match
                // expression. We will therefore generate a snapshot of
                // current ReportingDescriptor state when logging.
                context.Logger.Log(reportingDescriptor, result);
            }
        }
Beispiel #7
0
        public static string ParseExpression(IRegex regexEngine, string matchedPattern, string expression)
        {
            FlexMatch match = regexEngine.Match(matchedPattern, expression);

            return(match?.Success ?? false?ParseValue(match.Value) : null);
        }
Beispiel #8
0
        protected override string IsValidDynamicHelper(ref string fingerprintText,
                                                       ref string message)
        {
            var fingerprint = new Fingerprint(fingerprintText);

            string id  = fingerprint.Id;
            string key = fingerprint.Key;

            try
            {
                var iamClient = new AmazonIdentityManagementServiceClient(id, key);

                GetAccountAuthorizationDetailsRequest  request;
                GetAccountAuthorizationDetailsResponse response;

                request  = new GetAccountAuthorizationDetailsRequest();
                response = iamClient.GetAccountAuthorizationDetailsAsync(request).GetAwaiter().GetResult();

                message = BuildAuthorizedMessage(id, response);
            }
            catch (AmazonIdentityManagementServiceException e)
            {
                switch (e.ErrorCode)
                {
                case "AccessDenied":
                {
                    FlexMatch match = RegexEngine.Match(e.Message, AwsUserExpression);

                    // May return a message containing user id details such as:
                    // User: arn:aws:iam::123456123456:user/example.com@@dead1234dead1234dead1234 is not
                    // authorized to perform: iam:GetAccountAuthorizationDetails on resource: *

                    if (match.Success)
                    {
                        int    trimmedChars = "User: "******"is not authorized ".Length;
                        string iamUser      = match.Value.String.Substring("User: "******"the compromised AWS identity is '{iamUser}";
                    }

                    return(nameof(ValidationState.Authorized));
                }

                case "InvalidClientTokenId":
                case "SignatureDoesNotMatch":
                {
                    return(nameof(ValidationState.NoMatch));
                }
                }

                message = $"An unexpected exception was caught attempting to authenticate AWS id '{id}': {e.Message}";
                return(nameof(ValidationState.Unknown));
            }
            catch (Exception e)
            {
                message = $"An unexpected exception was caught attempting to authentic AWS id '{id}': {e.Message}";
                return(nameof(ValidationState.Unknown));
            }

            /*          var client = new HttpClient();
             *
             *          try
             *          {
             *              string uri = "https://iam.amazonaws.com/?Action=GetAccountAuthorizationDetails" +
             *                           "?X-Amz-Algorithm=AWS4-HMAC-SHA256" +
             *                          $"&X-Amz-Credential={id}";
             *
             *              HttpResponseMessage response = client.GetAsync(uri).GetAwaiter().GetResult();
             *
             *              switch (response.StatusCode)
             *              {
             *                  case HttpStatusCode.Forbidden:
             *                  {
             *                      message = $"for AWS credential id '{id}'.";
             *                      return nameof(ValidationState.Unauthorized);
             *                  }
             *              }
             *          }
             *          catch (Exception e)
             *          {
             *              message = $"An unexpected exception was caught attempting to authentic AWS id '{id}': {e.Message}";
             *              return nameof(ValidationState.Unknown);
             *          }
             */
            return(nameof(ValidationState.Authorized));
        }