Skip to content

Commit

Permalink
Expand RabbitMQ validator to check loose credentials expressions. (#788)
Browse files Browse the repository at this point in the history
* Expand RabbitMQ validator to check loose credentials expressions.

* update release history

* Remove if statement checking the required regex group

---------

Co-authored-by: Yong Yan <v-yongyan@microsoft.com>
  • Loading branch information
yongyan-gh and Yong Yan committed Jul 18, 2023
1 parent b43be56 commit c0e4df8
Show file tree
Hide file tree
Showing 8 changed files with 161 additions and 11 deletions.
2 changes: 2 additions & 0 deletions ReleaseHistory.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@

## v4.5.8 UNRELEASED
- 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)
- FNC: Update `SEC101/041.RabbitMqCredentials` in `Security` to check loose credential combinations. [#788](https://github.com/microsoft/sarif-pattern-matcher/pull/788)
- 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)

## v4.5.7 6/28/2023
Expand Down
12 changes: 12 additions & 0 deletions Src/Plugins/Security/SEC101.SecurePlaintextSecrets.json
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,18 @@
"ContentsRegex": "$SEC101/041.RabbitMqCredentials",
"MessageArguments": { "secretKind": "RabbitMq credential" }
},
{
"Id": "SEC101/041",
"Name": "RabbitMqCredentials",
"IntrafileRegexes": [
"$SEC101/041.RabbitMqCredentialsHost",
"?SEC101/041.RabbitMqCredentialsPort",
"$SEC101/041.RabbitMqCredentialsUser",
"$SEC101/041.RabbitMqCredentialsPassword",
"?SEC101/041.RabbitMqCredentialsVirtualHost"
],
"MessageArguments": { "secretKind": "RabbitMq credential" }
},
{
"Id": "SEC101/042",
"Name": "DynatraceToken",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,13 @@ public class RabbitMqCredentialsValidator : 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) ||
!groups.TryGetNonEmptyValue("resource", out FlexMatch resource))
groups.TryGetValue("id", out FlexMatch id);
groups.TryGetValue("host", out FlexMatch host);
groups.TryGetValue("secret", out FlexMatch secret);
groups.TryGetValue("resource", out FlexMatch resource);
groups.TryGetValue("port", out FlexMatch port);

if (FilteringHelpers.PasswordIsInCommonVariableContext(secret.Value))
{
return ValidationResult.CreateNoMatch();
}
Expand All @@ -32,8 +35,9 @@ protected override IEnumerable<ValidationResult> IsValidStaticHelper(IDictionary
{
Id = id.Value,
Host = hostValue,
Port = port?.Value,
Secret = secret.Value,
Resource = resource.Value,
Resource = resource?.Value,
},
};

Expand All @@ -46,6 +50,7 @@ protected override ValidationState IsValidDynamicHelper(ref Fingerprint fingerpr
ref ResultLevelKind resultLevelKind)
{
string host = fingerprint.Host;
string port = fingerprint.Port;
string account = fingerprint.Id;
string password = fingerprint.Secret;
string resource = fingerprint.Resource;
Expand All @@ -55,6 +60,8 @@ protected override ValidationState IsValidDynamicHelper(ref Fingerprint fingerpr
return ValidationState.Unknown;
}

host += string.IsNullOrWhiteSpace(port) ? string.Empty : $":{port}";

try
{
var factory = new ConnectionFactory
Expand Down
9 changes: 7 additions & 2 deletions Src/Plugins/Security/Security.SharedStrings.txt
Original file line number Diff line number Diff line change
Expand Up @@ -129,9 +129,14 @@
$SEC101/038.PostgreSqlCredentialsAdoSecret=(?i)(?:password|pwd)\s*=\s*(?P<secret>[^,;"'<\s]{8,128})(?:[,;"'<\s]|$)
$SEC101/038.PostgreSqlCredentialsAdoResource=(?i)(?:database|db|dbname)\s*=\s*(?P<resource>[^,;"'=|&\]\[><\s]+)(?:[,;"'=|&\]\[><\s]|$)

$SEC101/041.RabbitMqCredentials=(?i)amqps?:\/\/(?P<id>[^:"]+):(?P<secret>[^@\s]+)@(?P<host>[\w_\-\:]+)\/(?P<resource>[\w]+)(?:[^0-9a-z]|$)
$SEC101/041.RabbitMqCredentials=(?i)amqps?:\/\/(?P<id>[^:"]+):(?P<secret>[^@\s]+)@(?P<host>[\w_-]+)(?::?(?P<port>[0-9]{4,5}))?\/(?P<resource>[\w]+)?(?:[^0-9a-z]|$)
$SEC101/041.RabbitMqCredentialsHost=(?i)rabbitmq[-_\s]?host[\s,:='"]+(?:value?[\s,:='"]+)?(?P<host>[.\w_-]+)
$SEC101/041.RabbitMqCredentialsPort=(?i)rabbitmq[-_\s]?port[\s,:='"]+(?:value?[\s,:='"]+)?(?P<port>[0-9]{4,5})(?:[^0-9]|$)
$SEC101/041.RabbitMqCredentialsUser=(?i)rabbitmq[-_\s]?user(?:name)?[\s,:='"]+(?:value?[\s,:='"]+)?(?P<id>[0-9a-z._-]+)(?:[^0-9a-z._-]|$)
$SEC101/041.RabbitMqCredentialsPassword=(?i)rabbitmq[-_\s]?password[\s,:='"]+(?:value?[\s,:='"]+)?(?P<secret>[^,:='"]+)(?:[,:='"]|$)
$SEC101/041.RabbitMqCredentialsVirtualHost=(?i)rabbitmq[-_\s]?v(irtual)?host[\s,:='"]+(?:value?[\s,:='"]+)?(?P<resource>[^;,"<'\s]+)(?:[;,"<'\s]|$)
$SEC101/043.NuGetPackageSourceCredentialsXml=(?i)(?P<host><\s*packageSources\s*>(?s).{0,500}?(?-s)<\\?\/packageSources\s*>)(?s).{0,200}?(?-s)[^\/](?P<secret><\s*packageSourceCredentials\s*>(?s).{0,500}?(?-s)<\\?\/packageSourceCredentials\s*>)

$SEC101/044.NpmCredentialsRegistry=(?i)(registry\s*=\s*|-r\s+)https:\/\/(?P<host>\S+)(?:\s|$)
$SEC101/044.NpmCredentialsAuth=(?i)_auth(Token)?\s*=\s*(?P<secret>[0-9A-Za-z\/+]+[=]{0,2})(?:[^0-9A-Za-z\/+]|$)
$SEC101/044.NpmCredentialsUser=(?i)(?:(?:email|user(name)?)\s*=\s*|-u\s+)(?-i)(?P<id>\S+)(?:\s|$)
Expand Down
2 changes: 1 addition & 1 deletion Src/Plugins/Security/Security.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
<PackageReference Include="Microsoft.Security.Utilities" Version="1.4.0" />
<PackageReference Include="MySqlConnector" Version="1.2.1" />
<PackageReference Include="Npgsql" Version="5.0.3" />
<PackageReference Include="RabbitMQ.Client" Version="6.2.1" />
<PackageReference Include="RabbitMQ.Client" Version="6.5.0" />
<PackageReference Include="System.Data.SqlClient" Version="4.8.5" />
<PackageReference Include="System.Net.Http" Version="4.3.4" />
<PackageReference Include="System.Text.Json" Version="5.0.1" />
Expand Down
19 changes: 19 additions & 0 deletions Src/Plugins/Security/Utilities/FilteringHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,5 +48,24 @@ public static bool LikelyPowershellVariable(string input)

return true;
}

public static bool PasswordIsInCommonVariableContext(string secret)
{
var passwordContextList = new List<Tuple<string, string>>
{
new Tuple<string, string>("{", "}"),
new Tuple<string, string>("$(", ")"),
};

foreach (Tuple<string, string> tuplePair in passwordContextList)
{
if (secret.StartsWith(tuplePair.Item1))
{
return secret.EndsWith(tuplePair.Item2);
}
}

return false;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -245,12 +245,110 @@
],
"fingerprints": {
"secretHashSha256/v0": "8ee3280c2b16572db6de68a544e1359b024e02f0883855579a2ad30377342476",
"assetFingerprint/v0": "{\"host\":\"host:1234\",\"id\":\"user\",\"resource\":\"database4\"}",
"validationFingerprintHashSha256/v0": "ae3c9e40e7e50921fa67195289b1cb2be76a61b4504a6554fdb1339749ec4949",
"assetFingerprint/v0": "{\"host\":\"host\",\"id\":\"user\",\"resource\":\"database4\"}",
"validationFingerprintHashSha256/v0": "b072b04dc20528de96afa27d61ec069f4100f631d3417d29266767821935e9e6",
"secretFingerprint/v0": "{\"secret\":\"password\"}",
"validationFingerprint/v0": "{\"host\":\"host:1234\",\"id\":\"user\",\"resource\":\"database4\",\"secret\":\"password\"}"
"validationFingerprint/v0": "{\"host\":\"host\",\"id\":\"user\",\"port\":\"1234\",\"resource\":\"database4\",\"secret\":\"password\"}"
},
"rank": 39.29
},
{
"rule": {
"id": "SEC101/041",
"index": 0,
"toolComponent": {
"index": 0
}
},
"message": {
"id": "Default",
"arguments": [
"…ssword",
"an apparent ",
"",
"RabbitMq credential",
"",
" (no validation occurred as it was not enabled. Pass '--dynamic-validation' on the command-line to validate this match)"
]
},
"locations": [
{
"physicalLocation": {
"artifactLocation": {
"uri": "src/Plugins/Tests.Security/TestData/SecurePlaintextSecrets/Inputs/SEC101_041.RabbitMqCredentials.ps1",
"uriBaseId": "SRC_ROOT"
},
"region": {
"startLine": 14,
"startColumn": 15,
"endLine": 14,
"endColumn": 23,
"charOffset": 319,
"charLength": 8,
"snippet": {
"text": "password"
}
}
}
}
],
"fingerprints": {
"secretHashSha256/v0": "8ee3280c2b16572db6de68a544e1359b024e02f0883855579a2ad30377342476",
"assetFingerprint/v0": "{\"host\":\"host\",\"id\":\"user\"}",
"validationFingerprintHashSha256/v0": "d95f5afa621b3965946933ad24d5c7dfddf04f79f9a84c770044c71b14f43b0b",
"secretFingerprint/v0": "{\"secret\":\"password\"}",
"validationFingerprint/v0": "{\"host\":\"host\",\"id\":\"user\",\"port\":\"1234\",\"secret\":\"password\"}"
},
"rank": 39.29
},
{
"rule": {
"id": "SEC101/041",
"index": 0,
"toolComponent": {
"index": 0
}
},
"message": {
"id": "Default",
"arguments": [
"…s@word",
"an apparent ",
"",
"RabbitMq credential",
"",
" (no validation occurred as it was not enabled. Pass '--dynamic-validation' on the command-line to validate this match)"
]
},
"locations": [
{
"physicalLocation": {
"artifactLocation": {
"uri": "src/Plugins/Tests.Security/TestData/SecurePlaintextSecrets/Inputs/SEC101_041.RabbitMqCredentials.ps1",
"uriBaseId": "SRC_ROOT"
},
"region": {
"startLine": 17,
"startColumn": 95,
"endLine": 17,
"endColumn": 104,
"charOffset": 457,
"charLength": 9,
"snippet": {
"text": "pass@word"
}
}
}
}
],
"fingerprints": {
"secretHashSha256/v0": "80cd575b97ae03b1a21b78bb7f69ad2afa6f3d2830b24bd07ce040090c8146a6",
"assetFingerprint/v0": "{\"host\":\"12.23.45.78\",\"id\":\"guest\"}",
"validationFingerprintHashSha256/v0": "8adb2e5e9ac8ca6c4c30426aaba4b3136af298520fb074839ecd42b0bd89ee33",
"secretFingerprint/v0": "{\"secret\":\"pass@word\"}",
"validationFingerprint/v0": "{\"host\":\"12.23.45.78\",\"id\":\"guest\",\"port\":\"5672\",\"secret\":\"pass@word\"}"
},
"rank": 42.11
}
],
"columnKind": "utf16CodeUnits"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,14 @@ amqp://user:password@host/database1
# Simple string with port
amqp://user:password@host:1234/database4

# Simple string with default vhost
"amqps://user:password@host:1234/"

# Name/value pairs
{ "name": "RABBITMQ_HOST", "value": "12.23.45.78" }, { "name": "RABBITMQ_PASSWORD", "value": "pass@word" }, { "name": "RABBITMQ_PORT", "value": "5672" }, { "name": "RABBITMQ_USERNAME", "value": "guest" },

# This is invalid and should not be captured
amqp://user:{{rabbitmq_password}}@host:1234/database4
amqp://user:password@host:1234 /database5
amqp://user:password@host:1234
amqp://id:secret @host/resource
Expand Down

0 comments on commit c0e4df8

Please sign in to comment.