Skip to content

Commit

Permalink
Re-enable MongoDbCredentials dynamic validator (#789)
Browse files Browse the repository at this point in the history
* Re-enable MongoDbCredentials dynamic validator

* Update release record

* Update option capture group name

* Use Fingerprint.QueryString for connection string options.

* order release records

* Address review feedbacks

* Upgrade System.Drawing.Common from 4.7.0 to 4.7.2 to fix the vulnerability.

---------

Co-authored-by: Yong Yan <v-yongyan@microsoft.com>
Co-authored-by: Michael C. Fanning <mikefan@microsoft.com>
  • Loading branch information
3 people committed Aug 2, 2023
1 parent 79a6b56 commit 8bd50cc
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 59 deletions.
2 changes: 2 additions & 0 deletions ReleaseHistory.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@
## v4.6.0 7/27/2023
- DEP: Update SARIF SDK submodule from [7e8def7 to dd3741f(https://github.com/microsoft/sarif-sdk/compare/7e8def7..dd3741f). [Full SARIF SDK release history](https://github.com/microsoft/sarif-sdk/blob/dd3741f/ReleaseHistory.md).
- DEP: Upgrade `Microsoft.Security.Utilities` from 6.2.1 to 6.5.0. [#788](https://github.com/microsoft/sarif-pattern-matcher/pull/788)
- DEP: Add package `MongoDB.Driver` 2.20.0. [#789](https://github.com/microsoft/sarif-pattern-matcher/pull/789)
- BRK: Replaced `MatchLengthToDecode` property of `MatchExpression` with new `Base64EncodingMatch` class to support detecting Base64 string from strings of specific length range. [#790](https://github.com/microsoft/sarif-pattern-matcher/pull/790)
- BRK: Re-enable `SEC101/033.MongoDbCredentials` in `Security`. [#789](https://github.com/microsoft/sarif-pattern-matcher/pull/789)
- FNC: Update `SEC101/041.RabbitMqCredentials` in `Security` to check loose credential combinations. [#788](https://github.com/microsoft/sarif-pattern-matcher/pull/788)
- FND: Remove the secret format assumption that it must contain both digits and letters in static validation for rule `SEC101/044.NpmCredentials` in `Security`. [#799](https://github.com/microsoft/sarif-pattern-matcher/pull/799)
- FPD: Removed dynamic analysis entirely for `SEC101/047.CratesApiKey` rule due to outdated validation always returning status code 200 to all tokens. No API endpoint seems to return different status codes to distinguish between valid and invalid API keys. [#786](https://github.com/microsoft/sarif-pattern-matcher/pull/786)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,27 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Collections.Generic;
using System.Linq;

using Microsoft.CodeAnalysis.Sarif.PatternMatcher.Sdk;
using Microsoft.RE2.Managed;

using MongoDB.Driver;

namespace Microsoft.CodeAnalysis.Sarif.PatternMatcher.Plugins.Security
{
[ValidatorDescriptor("SEC101/033")]
public class MongoDbCredentialsValidator : StaticValidatorBase
public class MongoDbCredentialsValidator : DynamicValidatorBase
{
protected override IEnumerable<ValidationResult> IsValidStaticHelper(IDictionary<string, FlexMatch> groups)
{
if (!groups.TryGetNonEmptyValue("id", out FlexMatch id) ||
!groups.TryGetNonEmptyValue("host", out FlexMatch host) ||
!groups.TryGetNonEmptyValue("secret", out FlexMatch secret))
{
return ValidationResult.CreateNoMatch();
}
FlexMatch id = groups["id"];
FlexMatch host = groups["host"];
FlexMatch secret = groups["secret"];
FlexMatch protocol = groups["protocol"];
groups.TryGetValue("options", out FlexMatch options);

var validationResult = new ValidationResult
{
Expand All @@ -27,38 +30,55 @@ protected override IEnumerable<ValidationResult> IsValidStaticHelper(IDictionary
Id = id.Value,
Host = host.Value,
Secret = secret.Value,
Scheme = protocol.Value,
QueryString = options?.Value,
},
};

return new[] { validationResult };
}

// protected override ValidationState IsValidDynamicHelper(ref Fingerprint fingerprint,
// ref string message,
// IDictionary<string, string> options,
// ref ResultLevelKind resultLevelKind)
// {
// string id = fingerprint.Id;
// string host = fingerprint.Host;
// string password = fingerprint.Secret;
// try
// {
// var dbClient = new MongoClient($"mongodb+srv://{id}:{password}@{host}/?connectTimeoutMS=3000");
// List<BsonDocument> databases = dbClient.ListDatabases().ToList();
// message = $"The following databases are compromised: {string.Join(",", databases.Select(q => $"'{q["name"].AsString}'"))}";
// return ValidationState.Authorized;
// }
// catch (Exception e)
// {
// if (e is MongoAuthenticationException mae)
// {
// if (e.Message.StartsWith("Unable to authenticate"))
// {
// return ReturnUnauthorizedAccess(ref message, asset: host);
// }
// }
// return ReturnUnhandledException(ref message, e, asset: host);
// }
// }
protected override ValidationState IsValidDynamicHelper(ref Fingerprint fingerprint,
ref string message,
IDictionary<string, string> options,
ref ResultLevelKind resultLevelKind)
{
string id = fingerprint.Id;
string host = fingerprint.Host;
string password = fingerprint.Secret;
string protocol = fingerprint.Scheme;
string queryString = fingerprint.QueryString;

try
{
string connectionString = $"{protocol}://{id}:{password}@{host}";

string timeoutOption = "serverSelectionTimeoutMS=3000&connectTimeoutMS=3000&socketTimeoutMS=3000";

connectionString += string.IsNullOrEmpty(queryString) ?
$"/?{timeoutOption}" :
$"{queryString}&{timeoutOption}";

var dbClient = new MongoClient(connectionString);

var databases = dbClient.ListDatabases().ToList();

message = $"The following databases are compromised: {string.Join(",", databases.Select(q => $"'{q["name"].AsString}'"))}";

return ValidationState.Authorized;
}
catch (Exception e)
{
if (e is MongoAuthenticationException mae)
{
if (e.Message.StartsWith("Unable to authenticate"))
{
return ReturnUnauthorizedAccess(ref message, asset: host);
}
}

return ReturnUnhandledException(ref message, e, asset: host);
}
}
}
}
2 changes: 1 addition & 1 deletion src/Plugins/Security/Security.SharedStrings.txt
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@
$SEC101/027.MailChimpApiKey=(?:[^0-9a-f]|^)(?P<secret>[0-9a-f]{32}-us[0-9]{12})
$SEC101/029.AlibabaCloudAccessKey=(?:^|[^0-9A-Za-z])(?P<id>LTAI([0-9A-Za-z]{12}|[0-9A-Za-z]{20}))(?:[^0-9A-Za-z]|$)
$SEC101/029.AlibabaCloudSecretKey=(?:^|[^0-9A-Za-z\-~_+/%\\])(?P<secret>[0-9A-Za-z]{30})(?:[^0-9A-Za-z\-~_+/=%\\]|$)
$SEC101/033.MongoDbCredentials=(?i)mongodb(?:[^:]{0,50})?:\/\/(?P<id>[0-9a-z]+):(?P<secret>[^@\s]{1,200})@(?P<host>[^\/;"<\s,]+)
$SEC101/033.MongoDbCredentials=(?i)(?P<protocol>mongodb|mongodb\+srv):\/\/(?P<id>[0-9a-z_-]+):(?P<secret>[^@\s]{1,200})@(?P<host>[^\/;"<\s,]+)(?P<options>/[0-9a-z?&@=_-]+)?
$SEC101/035.CloudantCredentialsPython=(?si)cloudant\s*\(\s*"(?P<id>[\w-]+)"\s*\,\s*"(?P<secret>[\w]{64})"\s*\,\s*.{0,200}url=\s*"https:\/\/(?P<resource>[\w.-]+)\.(?P<host>cloudantnosqldb\.appdomain\.cloud|cloudant\.com)
$SEC101/035.CloudantCredentialsJson=(?si)apiKey"[^"]+"(?P<secret>[\w-]+)".{1,100}[^0-9a-z\.-](?P<id>[0-9a-z\.-]{32,44})\.(?P<host>cloudantnosqldb\.appdomain\.cloud|cloudant\.com)
$SEC101/035.CloudantCredentialsUrl=(?i)https:\/\/(?P<id>[^:]+):(?P<secret>[\w]{64}|[a-z]{24})@[\w-]+\.(?P<host>cloudantnosqldb\.appdomain\.cloud|cloudant\.com)
Expand Down
1 change: 1 addition & 0 deletions src/Plugins/Security/Security.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
<ItemGroup>
<PackageReference Include="BouncyCastle.Cryptography" Version="2.2.1" />
<PackageReference Include="Microsoft.Security.Utilities" Version="1.4.0" />
<PackageReference Include="MongoDB.Driver" Version="2.20.0" />
<PackageReference Include="MySqlConnector" Version="1.2.1" />
<PackageReference Include="Npgsql" Version="5.0.3" />
<PackageReference Include="RabbitMQ.Client" Version="6.2.1" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@
"",
"MongoDb credential",
"",
""
" (no validation occurred as it was not enabled. Pass '--dynamic-validation' on the command-line to validate this match)"
]
},
"locations": [
Expand All @@ -98,10 +98,10 @@
],
"fingerprints": {
"secretHashSha256/v0": "24987d958329be51a1b59d52b078f2d1d719918d7e6ef92b976092967ac9c2c9",
"assetFingerprint/v0": "{\"host\":\"database.com:10250\",\"id\":\"dbuser1\"}",
"validationFingerprintHashSha256/v0": "2b7726361acf7b6f4557e99f7e640aad24737ee9dbf8435bb24df793b4349f9f",
"assetFingerprint/v0": "{\"host\":\"database.com:10250\",\"id\":\"dbuser1\",\"queryString\":\"/database\",\"scheme\":\"mongodb\"}",
"validationFingerprintHashSha256/v0": "d13acdc9725494f089ba1d90e8dc7f43fde2e8d5793c8f970efca81c9abf1c89",
"secretFingerprint/v0": "{\"secret\":\"<password>\"}",
"validationFingerprint/v0": "{\"host\":\"database.com:10250\",\"id\":\"dbuser1\",\"secret\":\"<password>\"}"
"validationFingerprint/v0": "{\"host\":\"database.com:10250\",\"id\":\"dbuser1\",\"queryString\":\"/database\",\"scheme\":\"mongodb\",\"secret\":\"<password>\"}"
},
"rank": 44.6
},
Expand All @@ -121,7 +121,7 @@
"",
"MongoDb credential",
"",
""
" (no validation occurred as it was not enabled. Pass '--dynamic-validation' on the command-line to validate this match)"
]
},
"locations": [
Expand All @@ -147,10 +147,10 @@
],
"fingerprints": {
"secretHashSha256/v0": "24987d958329be51a1b59d52b078f2d1d719918d7e6ef92b976092967ac9c2c9",
"assetFingerprint/v0": "{\"host\":\"database.com\",\"id\":\"dbuser2\"}",
"validationFingerprintHashSha256/v0": "5054ad0052f5ca4f870f137a2fded3946d9da6bc9bbc003225a4e0d5baa4561e",
"assetFingerprint/v0": "{\"host\":\"database.com\",\"id\":\"dbuser2\",\"scheme\":\"mongodb+srv\"}",
"validationFingerprintHashSha256/v0": "276623334bbbed676aa336b1d2052921ab4a3cbb2bff0c1ffabf1fe69a246ddf",
"secretFingerprint/v0": "{\"secret\":\"<password>\"}",
"validationFingerprint/v0": "{\"host\":\"database.com\",\"id\":\"dbuser2\",\"secret\":\"<password>\"}"
"validationFingerprint/v0": "{\"host\":\"database.com\",\"id\":\"dbuser2\",\"scheme\":\"mongodb+srv\",\"secret\":\"<password>\"}"
},
"rank": 44.6
},
Expand All @@ -170,7 +170,7 @@
"",
"MongoDb credential",
"",
""
" (no validation occurred as it was not enabled. Pass '--dynamic-validation' on the command-line to validate this match)"
]
},
"locations": [
Expand All @@ -196,10 +196,10 @@
],
"fingerprints": {
"secretHashSha256/v0": "24987d958329be51a1b59d52b078f2d1d719918d7e6ef92b976092967ac9c2c9",
"assetFingerprint/v0": "{\"host\":\"database.com\",\"id\":\"dbuser3\"}",
"validationFingerprintHashSha256/v0": "5ec3eb9e4e62504f7a0cb3f27062e318acb6cf4ce628d0bf70e657f8ba609858",
"assetFingerprint/v0": "{\"host\":\"database.com\",\"id\":\"dbuser3\",\"scheme\":\"mongodb+srv\"}",
"validationFingerprintHashSha256/v0": "8d04042a7aa98479de18845270c6d3f7cc841fa1d08a35eb7ece017d9437d497",
"secretFingerprint/v0": "{\"secret\":\"<password>\"}",
"validationFingerprint/v0": "{\"host\":\"database.com\",\"id\":\"dbuser3\",\"secret\":\"<password>\"}"
"validationFingerprint/v0": "{\"host\":\"database.com\",\"id\":\"dbuser3\",\"scheme\":\"mongodb+srv\",\"secret\":\"<password>\"}"
},
"rank": 44.6
},
Expand All @@ -219,7 +219,7 @@
"",
"MongoDb credential",
"",
""
" (no validation occurred as it was not enabled. Pass '--dynamic-validation' on the command-line to validate this match)"
]
},
"locations": [
Expand All @@ -245,10 +245,10 @@
],
"fingerprints": {
"secretHashSha256/v0": "24987d958329be51a1b59d52b078f2d1d719918d7e6ef92b976092967ac9c2c9",
"assetFingerprint/v0": "{\"host\":\"database.com\",\"id\":\"dbuser4\"}",
"validationFingerprintHashSha256/v0": "be9a255ca20f181fa32a493b9f7418aa116df8e87b2cc2c5e206df2792689164",
"assetFingerprint/v0": "{\"host\":\"database.com\",\"id\":\"dbuser4\",\"scheme\":\"mongodb+srv\"}",
"validationFingerprintHashSha256/v0": "418aeb9dc55399784f397ca1eb55688b69736f789783390512cc29f30eb87145",
"secretFingerprint/v0": "{\"secret\":\"<password>\"}",
"validationFingerprint/v0": "{\"host\":\"database.com\",\"id\":\"dbuser4\",\"secret\":\"<password>\"}"
"validationFingerprint/v0": "{\"host\":\"database.com\",\"id\":\"dbuser4\",\"scheme\":\"mongodb+srv\",\"secret\":\"<password>\"}"
},
"rank": 44.6
},
Expand All @@ -268,7 +268,7 @@
"",
"MongoDb credential",
"",
""
" (no validation occurred as it was not enabled. Pass '--dynamic-validation' on the command-line to validate this match)"
]
},
"locations": [
Expand All @@ -294,10 +294,10 @@
],
"fingerprints": {
"secretHashSha256/v0": "8ee3280c2b16572db6de68a544e1359b024e02f0883855579a2ad30377342476",
"assetFingerprint/v0": "{\"host\":\"localhost:55555\",\"id\":\"dbuser5\"}",
"validationFingerprintHashSha256/v0": "94065eb91a048f1fd7a7fc117ea3841dfc2a5ddf307268b9f965e2df78403476",
"assetFingerprint/v0": "{\"host\":\"localhost:55555\",\"id\":\"dbuser5\",\"scheme\":\"mongodb\"}",
"validationFingerprintHashSha256/v0": "a7510d37f706c4897da810adf651a60bf8285144b629b7670e16fa4ebe0b8ad4",
"secretFingerprint/v0": "{\"secret\":\"password\"}",
"validationFingerprint/v0": "{\"host\":\"localhost:55555\",\"id\":\"dbuser5\",\"secret\":\"password\"}"
"validationFingerprint/v0": "{\"host\":\"localhost:55555\",\"id\":\"dbuser5\",\"scheme\":\"mongodb\",\"secret\":\"password\"}"
},
"rank": 39.29
},
Expand All @@ -317,7 +317,7 @@
"",
"MongoDb credential",
"",
""
" (no validation occurred as it was not enabled. Pass '--dynamic-validation' on the command-line to validate this match)"
]
},
"locations": [
Expand All @@ -343,10 +343,10 @@
],
"fingerprints": {
"secretHashSha256/v0": "8ee3280c2b16572db6de68a544e1359b024e02f0883855579a2ad30377342476",
"assetFingerprint/v0": "{\"host\":\"localhost:66666\",\"id\":\"dbuser6\"}",
"validationFingerprintHashSha256/v0": "b41667ffee48a881da9e8d951d3ffa05738ffabd3fca2ee2ee55622f649d1318",
"assetFingerprint/v0": "{\"host\":\"localhost:66666\",\"id\":\"dbuser6\",\"scheme\":\"mongodb\"}",
"validationFingerprintHashSha256/v0": "3d9635b5d6061fa39239c3b4bee76e9223a6f740962c57c54b29bd4d3a571a3e",
"secretFingerprint/v0": "{\"secret\":\"password\"}",
"validationFingerprint/v0": "{\"host\":\"localhost:66666\",\"id\":\"dbuser6\",\"secret\":\"password\"}"
"validationFingerprint/v0": "{\"host\":\"localhost:66666\",\"id\":\"dbuser6\",\"scheme\":\"mongodb\",\"secret\":\"password\"}"
},
"rank": 39.29
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
<ItemGroup>
<PackageReference Include="FluentAssertions" Version="6.9.0" />
<PackageReference Include="Moq" Version="4.18.4" />
<PackageReference Include="System.Drawing.Common" Version="4.7.2" />
</ItemGroup>

<ItemGroup>
Expand Down

0 comments on commit 8bd50cc

Please sign in to comment.