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); } }
public static string ParseExpression(IRegex regexEngine, string matchedPattern, string expression) { FlexMatch match = regexEngine.Match(matchedPattern, expression); return(match?.Success ?? false?ParseValue(match.Value) : null); }
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)); }