Skip to content

Commit

Permalink
Avoid SecureString disclosure
Browse files Browse the repository at this point in the history
  • Loading branch information
iRon7 authored May 1, 2024
1 parent b04b04d commit b3cc93d
Show file tree
Hide file tree
Showing 2 changed files with 106 additions and 0 deletions.
39 changes: 39 additions & 0 deletions AvoidSecureStringDisclosure.Tests.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#Requires -Modules @{ModuleName="Pester"; ModuleVersion="5.0.0"}

Describe 'AvoidSecureStringDisclosure' {

Context 'Positives' {
It 'ConvertFrom-SecureString' {
$Expression = {
$SecureString = ConvertTo-SecureString 'P@ssW0rd' -AsPlainText
$Null = $SecureString | ConvertFrom-SecureString -AsPlainText
}.ToString()
$Results = Invoke-ScriptAnalyzer -ScriptDefinition $Expression -CustomRulePath .\AvoidSecureStringDisclosure.psm1
$Results | Should -not -BeNullOrEmpty
$Results.RuleName | Should -Be 'PSAvoidSecureStringDisclosure'
$Results.RuleSuppressionID | Should -Be 'ConvertFrom-SecureString'
}
It 'SecureStringToBSTR' {
$Expression = {
$SecureString = ConvertTo-SecureString 'P@ssW0rd' -AsPlainText
$BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($SecureString)
$Null = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)
[Runtime.InteropServices.Marshal]::ZeroFreeBSTR($BSTR)
}.ToString()
$Results = Invoke-ScriptAnalyzer -ScriptDefinition $Expression -CustomRulePath .\AvoidSecureStringDisclosure.psm1
$Results | Should -not -BeNullOrEmpty
$Results.RuleName | Should -Be 'PSAvoidSecureStringDisclosure'
$Results.RuleSuppressionID | Should -Be 'SecureStringToBSTR'
}
It 'GetNetworkCredential' {
$Expression = {
$SecureString = ConvertTo-SecureString 'P@ssW0rd' -AsPlainText
$Null = (New-Object PSCredential 0, $SecureString).GetNetworkCredential().Password
}.ToString()
$Results = Invoke-ScriptAnalyzer -ScriptDefinition $Expression -CustomRulePath .\AvoidSecureStringDisclosure.psm1
$Results | Should -not -BeNullOrEmpty
$Results.RuleName | Should -Be 'PSAvoidSecureStringDisclosure'
$Results.RuleSuppressionID | Should -Be 'GetNetworkCredential'
}
}
}
67 changes: 67 additions & 0 deletions AvoidSecureStringDisclosure.psm1
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#Requires -Version 3.0

using namespace System.Management.Automation.Language

function Measure-AvoidSecureStringDisclosure {
<#
.SYNOPSIS
Avoid SecureString disclosure.
.DESCRIPTION
For better security, it should be avoided to retrieve a PlainText passwords from a SecureString
as it might leave memory trials (or even logging trails).
The general approach of dealing with credentials is to avoid them and instead rely on other means
to authenticate, such as certificates or Windows authentication.
.INPUTS
[System.Management.Automation.Language.ScriptBlockAst]
.OUTPUTS
[Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord]
.LINK
https://github.com/dotnet/platform-compat/blob/master/docs/DE0001.md
#>

[CmdletBinding()]
[OutputType([Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord])]
Param (
[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[ScriptBlockAst]
$ScriptBlockAst
)
Process {
[ScriptBlock]$Predicate = {
Param ([Ast]$Ast)
(
$Ast -is [CommandAst] -and
$Ast.CommandElements[0].Value -eq 'ConvertFrom-SecureString' -and
$Ast.CommandElements.where{ $_ -is [CommandParameterAst] -and $_.ParameterName -eq 'AsPlainText' }
) -or
(
$Ast -is [InvokeMemberExpressionAst] -and
$Ast.Member.Value -eq 'SecureStringToBSTR'
) -or
(
$Ast -is [MemberExpressionAst] -and
$Ast.Expression -is [InvokeMemberExpressionAst] -and
$Ast.Member.Value -eq 'Password' -and
$Ast.Expression.Member.Value -eq 'GetNetworkCredential'
)
}
$Violations = $ScriptBlockAst.FindAll($Predicate, $False)
Foreach ($Violation in $Violations) {
$Extent = $Violation.Extent
[Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord]@{
Message = "Avoid SecureString disclosure: $Extent"
Extent = $Extent
RuleName = 'PSAvoidSecureStringDisclosure'
Severity = 'Warning'
RuleSuppressionID = [Regex]::Match($Extent.Text, 'ConvertFrom-SecureString|SecureStringToBSTR|GetNetworkCredential').Value
}
}
}
}
Export-ModuleMember -Function Measure-*

0 comments on commit b3cc93d

Please sign in to comment.