Hi,
When I download a script using Invoke-WebRequest or WebClient.DownloadFile, it seems like the script is not marked as “downloaded” (not blocked), and it’s signature is not verified (in case the execution policy is RemoteSigned). Is there a way to download the file so it will be marked as downloaded? I’ve searched for solutions but everything I found was how to unblock the script or bypass the execution policy, I want the opposite
And an extra question - if I don’t want to save the downloaded script to disk, just run it immediately from the web response, I can pipe the response to Invoke-Expression. I tried that and it worked, but following the previous question, is there a way to enforce execution policy in this case? It’s not really treated as a script in this case so I don’t think so but worth asking…
Thanks!
Gabriel
Are you looking at this from a security standpoint? The execution policy is not really a security control and can easily be bypassed:
PowerShell Execution Policy Explained (thinkpowershell.com)
Typically, the methods you are mentioning are how malicious actors execute code on machines. Go to your favorite video platform and do some searching for powershell cyber security and watch the webinars. There are guides on best practices on locking down Powershell, although to have more control and tracking with active blocking, you may need to have 3rd party software to mitigate risk.
Intel Insights: How to Secure PowerShell (cisecurity.org)
2 Likes
The mechanism used to identify a file as downloaded from the internet is “Alternate Data Stream”
More specifically the Zone.Identifier stream. Find a file that shows the option to unblock it, and inspect with Get-Item/Get-Content or other stream supporting cmdlets
Get-Item C:\users\Doug\Downloads\PSFolderSize-master.zip -Stream *
PSPath : Microsoft.PowerShell.Core\FileSystem::C:\users\Doug\Downloads\PSFolderSize-master.zip::$DATA
PSParentPath : Microsoft.PowerShell.Core\FileSystem::C:\users\Doug\Downloads
PSChildName : PSFolderSize-master.zip::$DATA
PSDrive : C
PSProvider : Microsoft.PowerShell.Core\FileSystem
PSIsContainer : False
FileName : C:\users\Doug\Downloads\PSFolderSize-master.zip
Stream : :$DATA
Length : 33667
PSPath : Microsoft.PowerShell.Core\FileSystem::C:\users\Doug\Downloads\PSFolderSize-master.zip:Zone.Identifier
PSParentPath : Microsoft.PowerShell.Core\FileSystem::C:\users\Doug\Downloads
PSChildName : PSFolderSize-master.zip:Zone.Identifier
PSDrive : C
PSProvider : Microsoft.PowerShell.Core\FileSystem
PSIsContainer : False
FileName : C:\users\Doug\Downloads\PSFolderSize-master.zip
Stream : Zone.Identifier
Length : 163
Get-Content C:\users\Doug\Downloads\PSFolderSize-master.zip -Stream Zone.Identifier
[ZoneTransfer]
ZoneId=3
ReferrerUrl=https://github.com/gngrninja/PSFolderSize
HostUrl=https://codeload.github.com/gngrninja/PSFolderSize/zip/refs/heads/master
All Unblock-File does is clear/remove this stream. You can achieve the same result by running
Set-Content C:\users\Doug\Downloads\PSFolderSize-master.zip -Stream Zone.Identifier -Value ""
or
Clear-Content C:\Users\Doug\Downloads\PSFolderSize-master.zip -Stream Zone.Identifier
Conversely, you can set the value of this data stream (as well as create any number of other alternate data streams) - it accepts an array of strings. The minimum requirement from my testing is to add these two lines.
'[ZoneTransfer]'
'ZoneId=3'
Here is an example
Set-Content C:\users\Doug\Downloads\PSFolderSize-master.zip -Stream Zone.Identifier -Value @(
'[ZoneTransfer]'
'ZoneId=3'
)
Now when you view the properties it should show blocked, and I believe this is what you are trying to do.
1 Like
Hi, thanks for you response!
I am looking at this from security perspective, I understand the execution policies can be easily bypassed if you are already on the machine, but I’m referring to something else - I have a trusted script that downloads another script from the internet and executes it, and I want to verify the second script is legit/was not tampered/the web server was not spoofed. I understand that if an attacker can change the first script they can change the way it executes the second script so the policy will be ignored, but that’s a different attack vector.
Thanks,
Gabriel
Thanks!
Do you know why downloading with Powershell does not set this stream while downloading from the browser does? I understand that Invoke-WebRequest uses IE components under the hood so I would assume that it should behave the same.