private static SystemEnforcementMode GetAppLockerPolicy(string path, SafeHandle handle) { SaferPolicy result = SaferPolicy.Disallowed; // If path is NULL, we're looking for the system-wide lockdown policy. // Since there is no way to get that from AppLocker, we will test the policy // against a random non-existent script and module. If that is allowed, then there is // no AppLocker script policy. if (String.IsNullOrEmpty(path)) { if ((s_cachedSaferSystemPolicy != null) && (!InternalTestHooks.BypassAppLockerPolicyCaching)) { result = s_cachedSaferSystemPolicy.Value; } else { // // Temp path can sometimes be deleted. While many places in PowerShell depend on its existence, // this one can crash PowerShell. // A less sensitive implementation will be possible once AppLocker allows validation of files that // don't exist. // string testPathScript = null; string testPathModule = null; try { // Start with the current profile temp path. string tempPath = IO.Path.GetTempPath(); int iteration = 0; while (iteration++ < 2) { bool error = false; try { if (!IO.Directory.Exists(tempPath)) { IO.Directory.CreateDirectory(tempPath); } testPathScript = IO.Path.Combine(tempPath, AppLockerTestFileName + IO.Path.GetRandomFileName() + ".ps1"); testPathModule = IO.Path.Combine(tempPath, AppLockerTestFileName + IO.Path.GetRandomFileName() + ".psm1"); // AppLocker fails when you try to check a policy on a file // with no content. So create a scratch file and test on that. string dtAppLockerTestFileContents = AppLockerTestFileContents + DateTime.Now; IO.File.WriteAllText(testPathScript, dtAppLockerTestFileContents); IO.File.WriteAllText(testPathModule, dtAppLockerTestFileContents); } catch (System.IO.IOException) { if (iteration == 2) { throw; } error = true; } catch (System.UnauthorizedAccessException) { if (iteration == 2) { throw; } error = true; } catch (System.Security.SecurityException) { if (iteration == 2) { throw; } error = true; } if (!error) { break; } // Try again with the AppData\LocalLow\Temp path using known folder id: // https://msdn.microsoft.com/library/dd378457.aspx Guid AppDatalocalLowFolderId = new Guid("A520A1A4-1780-4FF6-BD18-167343C5AF16"); tempPath = GetKnownFolderPath(AppDatalocalLowFolderId) + @"\Temp"; } // Test policy. result = TestSaferPolicy(testPathScript, testPathModule); } catch (System.IO.IOException) { // If we fail to test the policy, assume the default. result = SaferPolicy.Disallowed; } catch (System.UnauthorizedAccessException) { // This can happen during thread impersonation if the profile temp paths are not accessible. // Allow policy if impersonated, otherwise disallow. result = (System.Security.Principal.WindowsIdentity.GetCurrent().ImpersonationLevel == System.Security.Principal.TokenImpersonationLevel.Impersonation) ? SaferPolicy.Allowed : SaferPolicy.Disallowed; } catch (ArgumentException) { // This is for IO.Path.GetTempPath() call when temp paths are not accessible. result = (System.Security.Principal.WindowsIdentity.GetCurrent().ImpersonationLevel == System.Security.Principal.TokenImpersonationLevel.Impersonation) ? SaferPolicy.Allowed : SaferPolicy.Disallowed; } finally { if (IO.File.Exists(testPathScript)) { IO.File.Delete(testPathScript); } if (IO.File.Exists(testPathModule)) { IO.File.Delete(testPathModule); } } s_cachedSaferSystemPolicy = result; } if (result == SaferPolicy.Disallowed) { return(SystemEnforcementMode.Enforce); } else { return(SystemEnforcementMode.None); } } else { // We got a path. Return the result for that path. result = SecuritySupport.GetSaferPolicy(path, handle); if (result == SaferPolicy.Disallowed) { return(SystemEnforcementMode.Enforce); } return(SystemEnforcementMode.None); } }
private bool CheckPolicy(ExternalScriptInfo script, PSHost host, out Exception reason) { string str2; bool flag = false; reason = null; string path = script.Path; if (Environment.OSVersion.Platform == PlatformID.Win32NT) { if (path.IndexOf('\\') < 0) { throw PSTraceSource.NewArgumentException("path"); } if (path.LastIndexOf('\\') == (path.Length - 1)) { throw PSTraceSource.NewArgumentException("path"); } } FileInfo info = new FileInfo(path); if (!info.Exists) { reason = new FileNotFoundException(path); return(false); } if (!IsSupportedExtension(info.Extension)) { return(true); } if (this.IsProductBinary(path)) { return(true); } this.executionPolicy = SecuritySupport.GetExecutionPolicy(this.shellId); if (this.executionPolicy == ExecutionPolicy.Bypass) { return(true); } SaferPolicy disallowed = SaferPolicy.Disallowed; int num = 0; bool flag2 = false; while (!flag2 && (num < 5)) { try { disallowed = SecuritySupport.GetSaferPolicy(path); flag2 = true; continue; } catch (Win32Exception) { if (num > 4) { throw; } num++; Thread.Sleep(100); continue; } } if (disallowed == SaferPolicy.Disallowed) { str2 = StringUtil.Format(Authenticode.Reason_DisallowedBySafer, path); reason = new UnauthorizedAccessException(str2); return(false); } if (this.executionPolicy != ExecutionPolicy.Unrestricted) { if (this.IsLocalFile(info.FullName) && (this.executionPolicy == ExecutionPolicy.RemoteSigned)) { return(true); } if ((this.executionPolicy == ExecutionPolicy.AllSigned) || (this.executionPolicy == ExecutionPolicy.RemoteSigned)) { if (string.IsNullOrEmpty(script.ScriptContents)) { str2 = StringUtil.Format(Authenticode.Reason_FileContentUnavailable, path); reason = new UnauthorizedAccessException(str2); return(false); } System.Management.Automation.Signature signature = this.GetSignatureWithEncodingRetry(path, script); if (signature.Status == SignatureStatus.Valid) { return(this.IsTrustedPublisher(signature, path) || this.SetPolicyFromAuthenticodePrompt(path, host, ref reason, signature)); } flag = false; if (signature.Status == SignatureStatus.NotTrusted) { reason = new UnauthorizedAccessException(StringUtil.Format(Authenticode.Reason_NotTrusted, path, signature.SignerCertificate.SubjectName.Name)); return(flag); } reason = new UnauthorizedAccessException(StringUtil.Format(Authenticode.Reason_Unknown, path, signature.StatusMessage)); return(flag); } flag = false; bool flag3 = false; if (string.Equals(info.Extension, ".ps1xml", StringComparison.OrdinalIgnoreCase)) { string[] strArray = new string[] { Environment.GetFolderPath(Environment.SpecialFolder.System), Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles) }; foreach (string str3 in strArray) { if (info.FullName.StartsWith(str3, StringComparison.OrdinalIgnoreCase)) { flag = true; } } if (!flag) { System.Management.Automation.Signature signature3 = this.GetSignatureWithEncodingRetry(path, script); if (signature3.Status == SignatureStatus.Valid) { if (this.IsTrustedPublisher(signature3, path)) { flag = true; } else { flag = this.SetPolicyFromAuthenticodePrompt(path, host, ref reason, signature3); flag3 = true; } } } } if (!flag && !flag3) { reason = new UnauthorizedAccessException(StringUtil.Format(Authenticode.Reason_RestrictedMode, path)); } return(flag); } if (this.IsLocalFile(info.FullName)) { return(true); } if (string.IsNullOrEmpty(script.ScriptContents)) { str2 = StringUtil.Format(Authenticode.Reason_FileContentUnavailable, path); reason = new UnauthorizedAccessException(str2); return(false); } System.Management.Automation.Signature signatureWithEncodingRetry = this.GetSignatureWithEncodingRetry(path, script); if ((signatureWithEncodingRetry.Status == SignatureStatus.Valid) && this.IsTrustedPublisher(signatureWithEncodingRetry, path)) { flag = true; } if (flag) { return(flag); } RunPromptDecision doNotRun = RunPromptDecision.DoNotRun; Label_0149: doNotRun = this.RemoteFilePrompt(path, host); if (doNotRun == RunPromptDecision.Suspend) { host.EnterNestedPrompt(); } switch (doNotRun) { case RunPromptDecision.RunOnce: return(true); case RunPromptDecision.Suspend: goto Label_0149; } flag = false; str2 = StringUtil.Format(Authenticode.Reason_DoNotRun, path); reason = new UnauthorizedAccessException(str2); return(flag); }
/// <summary> /// Sets the digital signature on the specified file. /// </summary> /// <param name="filePath"> /// The name of the file on which to perform the action. /// </param> /// <returns> /// The signature on the specified file. /// </returns> protected override Signature PerformAction(string filePath) { SigningOption option = GetSigningOption(IncludeChain); if (Certificate == null) { throw PSTraceSource.NewArgumentNullException("certificate"); } // // if the cert is not good for signing, we cannot // process any more files. Exit the command. // if (!SecuritySupport.CertIsGoodForSigning(Certificate)) { Exception e = PSTraceSource.NewArgumentException( "certificate", SignatureCommands.CertNotGoodForSigning); throw e; } if (!ShouldProcess(filePath)) { return(null); } FileInfo readOnlyFileInfo = null; try { if (this.Force) { try { // remove readonly attributes on the file FileInfo fInfo = new FileInfo(filePath); if (fInfo != null) { // Save some disk write time by checking whether file is readonly.. if ((fInfo.Attributes & FileAttributes.ReadOnly) == FileAttributes.ReadOnly) { // remember to reset the read-only attribute later readOnlyFileInfo = fInfo; //Make sure the file is not read only fInfo.Attributes &= ~(FileAttributes.ReadOnly); } } } // These are the known exceptions for File.Load and StreamWriter.ctor catch (ArgumentException e) { ErrorRecord er = new ErrorRecord( e, "ForceArgumentException", ErrorCategory.WriteError, filePath ); WriteError(er); return(null); } catch (IOException e) { ErrorRecord er = new ErrorRecord( e, "ForceIOException", ErrorCategory.WriteError, filePath ); WriteError(er); return(null); } catch (UnauthorizedAccessException e) { ErrorRecord er = new ErrorRecord( e, "ForceUnauthorizedAccessException", ErrorCategory.PermissionDenied, filePath ); WriteError(er); return(null); } catch (NotSupportedException e) { ErrorRecord er = new ErrorRecord( e, "ForceNotSupportedException", ErrorCategory.WriteError, filePath ); WriteError(er); return(null); } catch (System.Security.SecurityException e) { ErrorRecord er = new ErrorRecord( e, "ForceSecurityException", ErrorCategory.PermissionDenied, filePath ); WriteError(er); return(null); } } // // ProcessRecord() code in base class has already // ascertained that filePath really represents an existing // file. Thus we can safely call GetFileSize() below. // if (SecurityUtils.GetFileSize(filePath) < 4) { // Note that the message param comes first string message = String.Format( System.Globalization.CultureInfo.CurrentCulture, UtilsStrings.FileSmallerThan4Bytes, filePath); PSArgumentException e = new PSArgumentException(message, "filePath"); ErrorRecord er = SecurityUtils.CreateInvalidArgumentErrorRecord( e, "SignatureCommandsBaseFileSmallerThan4Bytes" ); WriteError(er); return(null); } return(SignatureHelper.SignFile(option, filePath, Certificate, TimestampServer, _hashAlgorithm)); } finally { // reset the read-only attribute if (null != readOnlyFileInfo) { readOnlyFileInfo.Attributes |= FileAttributes.ReadOnly; } } }
private bool CheckPolicy(ExternalScriptInfo script, PSHost host, out Exception reason) { bool policyCheckPassed = false; reason = null; string path = script.Path; string reasonMessage; // path is assumed to be fully qualified here if (path.IndexOf(System.IO.Path.DirectorySeparatorChar) < 0) { throw PSTraceSource.NewArgumentException("path"); } if (path.LastIndexOf(System.IO.Path.DirectorySeparatorChar) == (path.Length - 1)) { throw PSTraceSource.NewArgumentException("path"); } FileInfo fi = new FileInfo(path); // Return false if the file does not exist, so that // we don't introduce a race condition if (!fi.Exists) { reason = new FileNotFoundException(path); return(false); } // Quick exit if we don't support the file type if (!IsSupportedExtension(fi.Extension)) { return(true); } // Get the execution policy _executionPolicy = SecuritySupport.GetExecutionPolicy(_shellId); // Always check the SAFER APIs if code integrity isn't being handled system-wide through // WLDP or AppLocker. In those cases, the scripts will be run in ConstrainedLanguage. // Otherwise, block. // SAFER APIs are not on CSS or OneCore if (SystemPolicy.GetSystemLockdownPolicy() != SystemEnforcementMode.Enforce) { SaferPolicy saferPolicy = SaferPolicy.Disallowed; int saferAttempt = 0; bool gotSaferPolicy = false; // We need to put in a retry workaround, as the SAFER APIs fail when under stress. while ((!gotSaferPolicy) && (saferAttempt < 5)) { try { saferPolicy = SecuritySupport.GetSaferPolicy(path, null); gotSaferPolicy = true; } catch (System.ComponentModel.Win32Exception) { if (saferAttempt > 4) { throw; } saferAttempt++; System.Threading.Thread.Sleep(100); } } // If the script is disallowed via AppLocker, block the file // unless the system-wide lockdown policy is "Enforce" (where all PowerShell // scripts are in blocked). If the system policy is "Enforce", then the // script will be allowed (but ConstrainedLanguage will be applied). if (saferPolicy == SaferPolicy.Disallowed) { reasonMessage = StringUtil.Format(Authenticode.Reason_DisallowedBySafer, path); reason = new UnauthorizedAccessException(reasonMessage); return(false); } } // WLDP and Applocker takes priority over powershell exeuction policy. // See if they want to bypass the authorization manager if (_executionPolicy == ExecutionPolicy.Bypass) { return(true); } if (_executionPolicy == ExecutionPolicy.Unrestricted) { // Product binaries are always trusted // This avoids signature and security zone checks if (SecuritySupport.IsProductBinary(path)) { return(true); } // We need to give the "Remote File" warning // if the file originated from the internet if (!IsLocalFile(fi.FullName)) { // Get the signature of the file. if (string.IsNullOrEmpty(script.ScriptContents)) { reasonMessage = StringUtil.Format(Authenticode.Reason_FileContentUnavailable, path); reason = new UnauthorizedAccessException(reasonMessage); return(false); } Signature signature = GetSignatureWithEncodingRetry(path, script); // The file is signed, with a publisher that // we trust if (signature.Status == SignatureStatus.Valid) { // The file is signed by a trusted publisher if (IsTrustedPublisher(signature, path)) { policyCheckPassed = true; } } // We don't care about the signature. If you distrust them, // or the signature does not exist, we prompt you only // because it's remote. if (!policyCheckPassed) { RunPromptDecision decision = RunPromptDecision.DoNotRun; // Get their remote prompt answer, allowing them to // enter nested prompts, if wanted. do { decision = RemoteFilePrompt(path, host); if (decision == RunPromptDecision.Suspend) { host.EnterNestedPrompt(); } } while (decision == RunPromptDecision.Suspend); switch (decision) { case RunPromptDecision.RunOnce: policyCheckPassed = true; break; case RunPromptDecision.DoNotRun: default: policyCheckPassed = false; reasonMessage = StringUtil.Format(Authenticode.Reason_DoNotRun, path); reason = new UnauthorizedAccessException(reasonMessage); break; } } } else { policyCheckPassed = true; } } // Don't need to check the signature if the file is local // and we're in "RemoteSigned" mode else if ((IsLocalFile(fi.FullName)) && (_executionPolicy == ExecutionPolicy.RemoteSigned)) { policyCheckPassed = true; } else if ((_executionPolicy == ExecutionPolicy.AllSigned) || (_executionPolicy == ExecutionPolicy.RemoteSigned)) { // if policy requires signature verification, // make it so. // Get the signature of the file. if (string.IsNullOrEmpty(script.ScriptContents)) { reasonMessage = StringUtil.Format(Authenticode.Reason_FileContentUnavailable, path); reason = new UnauthorizedAccessException(reasonMessage); return(false); } Signature signature = GetSignatureWithEncodingRetry(path, script); // The file is signed. if (signature.Status == SignatureStatus.Valid) { // The file is signed by a trusted publisher if (IsTrustedPublisher(signature, path)) { policyCheckPassed = true; } // The file is signed by an unknown publisher, // So prompt. else { policyCheckPassed = SetPolicyFromAuthenticodePrompt(path, host, ref reason, signature); } } // The file is UnknownError, NotSigned, HashMismatch, // NotTrusted, NotSupportedFileFormat else { policyCheckPassed = false; if (signature.Status == SignatureStatus.NotTrusted) { reason = new UnauthorizedAccessException( StringUtil.Format(Authenticode.Reason_NotTrusted, path, signature.SignerCertificate.SubjectName.Name)); } else { reason = new UnauthorizedAccessException( StringUtil.Format(Authenticode.Reason_Unknown, path, signature.StatusMessage)); } } } else // if(executionPolicy == ExecutionPolicy.Restricted) { // Deny everything policyCheckPassed = false; // But accept mshxml files from publishers that we // trust, or files in the system protected directories bool reasonSet = false; if (string.Equals(fi.Extension, ".ps1xml", StringComparison.OrdinalIgnoreCase)) { string[] trustedDirectories = new string[] { Environment.GetFolderPath(Environment.SpecialFolder.System), Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles) }; foreach (string trustedDirectory in trustedDirectories) { if (fi.FullName.StartsWith(trustedDirectory, StringComparison.OrdinalIgnoreCase)) { policyCheckPassed = true; } } if (!policyCheckPassed) { // Get the signature of the file. Signature signature = GetSignatureWithEncodingRetry(path, script); // The file is signed by a trusted publisher if (signature.Status == SignatureStatus.Valid) { if (IsTrustedPublisher(signature, path)) { policyCheckPassed = true; } // The file is signed by an unknown publisher, // So prompt. else { policyCheckPassed = SetPolicyFromAuthenticodePrompt(path, host, ref reason, signature); reasonSet = true; } } } } if (!policyCheckPassed && !reasonSet) { reason = new UnauthorizedAccessException( StringUtil.Format(Authenticode.Reason_RestrictedMode, path)); } } return(policyCheckPassed); }
internal List <string> GenerateProxyModule(DirectoryInfo moduleRootDirectory, string fileNamePrefix, Encoding encoding, bool force, List <CommandMetadata> listOfCommandMetadata, Dictionary <string, string> alias2resolvedCommandName, List <ExtendedTypeDefinition> listOfFormatData, X509Certificate2 certificate) { List <string> list = new List <string>(); string str = Path.Combine(moduleRootDirectory.FullName, fileNamePrefix); FileMode mode = force ? FileMode.OpenOrCreate : FileMode.CreateNew; list.Add(str + ".psm1"); FileStream stream = new FileStream(str + ".psm1", mode, FileAccess.Write, FileShare.None); using (TextWriter writer = new StreamWriter(stream, encoding)) { if (listOfCommandMetadata == null) { listOfCommandMetadata = new List <CommandMetadata>(); } this.GenerateModuleHeader(writer); this.GenerateHelperFunctions(writer); this.GenerateCommandProxy(writer, listOfCommandMetadata); this.GenerateExportDeclaration(writer, listOfCommandMetadata); this.GenerateAliases(writer, alias2resolvedCommandName); stream.SetLength(stream.Position); } list.Add(str + ".format.ps1xml"); FileStream stream2 = new FileStream(str + ".format.ps1xml", mode, FileAccess.Write, FileShare.None); using (TextWriter writer2 = new StreamWriter(stream2, encoding)) { if (listOfFormatData == null) { listOfFormatData = new List <ExtendedTypeDefinition>(); } this.GenerateFormatFile(writer2, listOfFormatData); stream2.SetLength(stream2.Position); } switch (SecuritySupport.GetExecutionPolicy(Utils.DefaultPowerShellShellID)) { case ExecutionPolicy.Restricted: case ExecutionPolicy.AllSigned: { if (certificate == null) { throw new PSInvalidOperationException(ImplicitRemotingStrings.CertificateNeeded); } string fileName = str + ".psm1"; try { SignatureHelper.SignFile(SigningOption.AddFullCertificateChainExceptRoot, fileName, certificate, string.Empty, null); fileName = str + ".format.ps1xml"; SignatureHelper.SignFile(SigningOption.AddFullCertificateChainExceptRoot, fileName, certificate, string.Empty, null); } catch (Exception exception) { throw new PSInvalidOperationException(StringUtil.Format(ImplicitRemotingStrings.InvalidSigningOperation, fileName), exception); } break; } } list.Add(str + ".psd1"); FileInfo info = new FileInfo(str + ".psd1"); FileStream stream3 = new FileStream(info.FullName, mode, FileAccess.Write, FileShare.None); using (TextWriter writer3 = new StreamWriter(stream3, encoding)) { this.GenerateManifest(writer3, str + ".psm1", str + ".format.ps1xml"); stream3.SetLength(stream3.Position); } PSPrimitiveDictionary applicationArguments = this.GetApplicationArguments(); if (applicationArguments != null) { string item = Path.Combine(moduleRootDirectory.FullName, "ApplicationArguments.xml"); list.Add(item); using (XmlWriter writer4 = XmlWriter.Create(item)) { Serializer serializer = new Serializer(writer4); serializer.Serialize(applicationArguments); serializer.Done(); } } return(list); }