Why does a script from PSGallery not have a Zone.Identifier stream?

Viewed 149

A NuGet repository, such as PSGallery, is clearly a remote system. Why do scripts installed from there not have a Zone.Identifier stream?

PS C:\> Find-Script -Repository PSGallery -Name Test-RPC | Install-Script -Scope CurrentUser

Untrusted repository
You are installing the scripts from an untrusted repository. If you trust this repository, change its InstallationPolicy value by running the
Set-PSRepository cmdlet. Are you sure you want to install the scripts from 'https://www.powershellgallery.com/api/v2'?
[Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend  [?] Help (default is "N"): Y

PS C:\> Get-Item -Path $Env:USERPROFILE\Documents\WindowsPowerShell\Scripts\Test-RPC.ps1 -Stream *

PSPath        : Microsoft.PowerShell.Core\FileSystem::C:\Users\lit\Documents\WindowsPowerShell\Scripts\Test-RPC.ps1::$DATA
PSParentPath  : Microsoft.PowerShell.Core\FileSystem::C:\Users\lit\Documents\WindowsPowerShell\Scripts
PSChildName   : Test-RPC.ps1::$DATA
PSDrive       : C
PSProvider    : Microsoft.PowerShell.Core\FileSystem
PSIsContainer : False
FileName      : C:\Users\lit\Documents\WindowsPowerShell\Scripts\Test-RPC.ps1
Stream        : :$DATA
Length        : 7771

The question is:

How can I ensure that users with ExecutionPolicy of RemoteSigned will need to use the signature? How will PowerShell know it is a remote file without a Zone.Identifier stream?

Is there any reason that package providers, especially untrusted ones, should not create a Zone.Identifier stream?

1 Answers

Continuing from my comment.

Clear-Host 

$Url          = 'https://www.powershellgallery.com/packages/Test-RPC/1.0/Content/Test-RPC.ps1'
$output       = 'C:\Temp\Test-RPC.ps1'
$ValidateFile = {
    Try {Get-Item -Path $output -Stream Zone.Identifier -ErrorAction Stop}
    Catch [System.Exception]
    {
        Write-Warning -Message 'Error'
        $PSItem.Exception.Message
    }
}


Remove-Item -Path $output -Force -ErrorAction SilentlyContinue

Invoke-WebRequest -Uri $url -OutFile $output

Remove-Item -Path $output -Force -ErrorAction SilentlyContinue

$wc = New-Object System.Net.WebClient
$wc.DownloadFile($url, $output)
& $ValidateFile

Remove-Item -Path $output -Force -ErrorAction SilentlyContinue
(New-Object System.Net.WebClient).DownloadFile($url, $output)
& $ValidateFile

Import-Module -Name BitsTransfer

Remove-Item -Path $output -Force -ErrorAction SilentlyContinue

Start-BitsTransfer -Source $url -Destination $output
& $ValidateFile

Remove-Item -Path $output -Force -ErrorAction SilentlyContinue
Start-BitsTransfer -Source $url -Destination $output -Asynchronous
& $ValidateFile
# Results
<#
WARNING: Error
Could not open the alternate data stream 'Zone.Identifier' of the file 'C:\Temp\Test-RPC.ps1'.
WARNING: Error
Could not open the alternate data stream 'Zone.Identifier' of the file 'C:\Temp\Test-RPC.ps1'.
WARNING: Error
Could not open the alternate data stream 'Zone.Identifier' of the file 'C:\Temp\Test-RPC.ps1'.

WARNING: Error
JobId                                DisplayName   TransferType JobState   OwnerAccount                      
-----                                -----------   ------------ --------   ------------                      
f5f04c93-4247-4095-8d9a-587b26d64d26 BITS Transfer Download     Connecting 570A5E12-BA93-4\WDAGUtilityAccount
Cannot find path 'C:\Temp\Test-RPC.ps1' because it does not exist.
#>

Doing the aforementioned download using real curl.exe also does not add the internet ADS tag. Manually download curl.exe via your browser.

https://curl.se/windows

Check the ADS data, note the internet tag is there.

The download using real curl.exe, in cmd.exe

curl.exe -O https://curl.se/windows/dl-7.76.0/curl-7.76.0-win64-mingw.zip

Check the ADS data, not the internet tag is not there.

Lastly, as for this ...

How can I ensure that users with ExecutionPolicy of RemoteSigned.

As documented and publically stated by MSFT, EP's are not a security boundary and that was never their design.

RemoteSigned ExecutionPolicy:

• Allows scripts to run

• Requires that all scripts ***downloaded from the Internet*** must be ***digitally signed by a publisher you specified as trusted***. This includes scripts received via email and instant messaging platforms.

• Will not require digital signing of scripts written on a local computer

• May allow running of malicious scripts from other sources

They are there to prevent accidental code runs. EP's can easily be bypassed and that too is fully documented/demo'd

15 Ways to Bypass the PowerShell Execution Policy: https://blog.netspi.com/15-ways-to-bypass-the-powershell-execution-policy

Detecting Offensive PowerShell Attack Tools: https://adsecurity.org/?p=2604

One can open any script in the ISE/VSCode, etc., select all, and hit run and the EP has no control over that. EP, is for running scripts by name, meaning, calling from the consolehost, scheduled task, etc.

Nothing stops a user from opening the script, removing the sigblock, and saving the script with a new name, and running it or creating a blank script, copy the content from the clocked script, saving and running.

PowerShell risk management/Security controls/mitigation are all the normal network/client stuff as well as all about full enterprise logging, auditing, and early alerting/effect response when strangeness is seen/discovered.

Related