Для симуляции различных ошибок проверки сертификатов, существует прекрасный сайт — https://badssl.com/ , который предоставляет отличный набор тестов. В PowerShell 6.0 у командлетов Invoke-WebRequest/Invoke-RestMethod появился параметр –SkipCertificateCheck . Версия PowerShell v2.0 — Windows PowerShell 2.0 Deprecation. В PowerShell v3-5.1 — отсутствуют параметры для игнорирования ошибок связанных с сертификатами, поэтому воспользуемся сторонними методами.
Быстрый поиск в Google по теме игнорирование ошибок связанный с сертификатами дает большое количество различный способов.
Все примеры для PowerShell v5.1 и https://expired.badssl.com/
1 – 2 – не работают
3 – работает частично
4 – 5 – работают
Первоначальная ошибка:
1. [Net.ServicePointManager]::ServerCertificateValidationCallback = { $true }
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = { $true } Invoke-RestMethod https://expired.badssl.com/ Invoke-RestMethod : The underlying connection was closed: An unexpected error occurred on a send. At line:1 char:1 + Invoke-RestMethod https://expired.badssl.com/ + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand 2. https://blogs.technet.microsoft.com/bshukla/2010/04/12/ignoring-ssl-trust-in-powershell-system-net-webclient/
$netAssembly = [Reflection.Assembly]::GetAssembly([System.Net.Configuration.SettingsSection]) if($netAssembly) { $bindingFlags = [Reflection.BindingFlags] "Static,GetProperty,NonPublic" $settingsType = $netAssembly.GetType("System.Net.Configuration.SettingsSectionInternal") $instance = $settingsType.InvokeMember("Section", $bindingFlags, $null, $null, @()) if($instance) { $bindingFlags = "NonPublic","Instance" $useUnsafeHeaderParsingField = $settingsType.GetField("useUnsafeHeaderParsing", $bindingFlags) if($useUnsafeHeaderParsingField) { $useUnsafeHeaderParsingField.SetValue($instance, $true) } } } Invoke-RestMethod : The underlying connection was closed: An unexpected error occurred on a send. At line:1 char:1 + Invoke-RestMethod https://expired.badssl.com/ + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
3. [Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy
Тут странности у меня – в 90% случаев отрабатывает, 10% – после перезапуска сессии, уже не отрабатывало. Проверяйте.
add-type @" using System.Net; using System.Security.Cryptography.X509Certificates; public class TrustAllCertsPolicy : ICertificatePolicy { public bool CheckValidationResult( ServicePoint srvPoint, X509Certificate certificate, WebRequest request, int certificateProblem) { return true; } } "@ [System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy Invoke-RestMethod https://expired.badssl.com/
С ошибкой:
Без ошибки:
4. https://stackoverflow.com/questions/36456104/invoke-restmethod-ignore-self-signed-certs
if (-not("dummy" -as [type])) { add-type -TypeDefinition @" using System; using System.Net; using System.Net.Security; using System.Security.Cryptography.X509Certificates; public static class Dummy { public static bool ReturnTrue(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; } public static RemoteCertificateValidationCallback GetDelegate() { return new RemoteCertificateValidationCallback(Dummy.ReturnTrue); } } "@ } [System.Net.ServicePointManager]::ServerCertificateValidationCallback = [dummy]::GetDelegate() Invoke-RestMethod https://expired.badssl.com/
При использовании Add-Type создается dll с случайным именем, а после удаляется. У тех, кто использует SRP/Aplocker — потребуются дополнительные действия для администратора. Утилита ProcMon – покажет, какие действия с файловой системой производит Add-Type. Сохраним вывод ProcMon в csv формате.
PS > Import-Csv AddType.CSV | Where Path -match "Temp" | Format-Table -Auto Operation,Path,Detail
Operation Path Detail
--------- ---- ------
CreateFile C:\Users\user\AppData\Local\Temp\ucp2kjeg.tmp Desired Access: Generic Write, Read Attri
CloseFile C:\Users\user\AppData\Local\Temp\ucp2kjeg.tmp
CreateFile C:\Users\user\AppData\Local\Temp\ucp2kjeg.0.cs Desired Access: Generic Write, Read Attri
WriteFile C:\Users\user\AppData\Local\Temp\ucp2kjeg.0.cs Offset: 0, Length: 465, Priority: Normal
CloseFile C:\Users\user\AppData\Local\Temp\ucp2kjeg.0.cs
CreateFile C:\Users\user\AppData\Local\Temp\ucp2kjeg.dll Desired Access: Generic Read/Write, Dispo
CloseFile C:\Users\user\AppData\Local\Temp\ucp2kjeg.dll
CreateFile C:\Users\user\AppData\Local\Temp\ucp2kjeg.cmdline Desired Access: Generic Write, Read Attri
WriteFile C:\Users\user\AppData\Local\Temp\ucp2kjeg.cmdline Offset: 0, Length: 357, Priority: Normal
CloseFile C:\Users\user\AppData\Local\Temp\ucp2kjeg.cmdline
CreateFile C:\Users\user\AppData\Local\Temp\ucp2kjeg.out Desired Access: Generic Write, Read Attri
CreateFile C:\Users\user\AppData\Local\Temp\ucp2kjeg.err Desired Access: Generic Write, Read Attri
WriteFile C:\Users\user\AppData\Local\Temp\ucp2kjeg.out Offset: 0, Length: 440, Priority: Normal
CreateFile C:\Users\user\AppData\Local\Temp\ucp2kjeg.dll Desired Access: Generic Read, Disposition
QueryStandardInformationFile C:\Users\user\AppData\Local\Temp\ucp2kjeg.dll AllocationSize: 4 096, EndOfFile: 3 584,
ReadFile C:\Users\user\AppData\Local\Temp\ucp2kjeg.dll Offset: 0, Length: 3 584, Priority: Norma
CloseFile C:\Users\user\AppData\Local\Temp\ucp2kjeg.dll
CreateFile C:\Users\user\AppData\Local\Temp\ucp2kjeg.pdb Desired Access: Read Attributes, Disposit
CreateFile C:\Users\user\AppData\Local\Temp\ucp2kjeg.out Desired Access: Read Attributes, Delete,
QueryAttributeTagFile C:\Users\user\AppData\Local\Temp\ucp2kjeg.out Attributes: A, ReparseTag: 0x0
SetDispositionInformationFile C:\Users\user\AppData\Local\Temp\ucp2kjeg.out Delete: True
CloseFile C:\Users\user\AppData\Local\Temp\ucp2kjeg.out
CreateFile C:\Users\user\AppData\Local\Temp\ucp2kjeg.0.cs Desired Access: Read Attributes, Delete,
QueryAttributeTagFile C:\Users\user\AppData\Local\Temp\ucp2kjeg.0.cs Attributes: A, ReparseTag: 0x0
SetDispositionInformationFile C:\Users\user\AppData\Local\Temp\ucp2kjeg.0.cs Delete: True
CloseFile C:\Users\user\AppData\Local\Temp\ucp2kjeg.0.cs
CreateFile C:\Users\user\AppData\Local\Temp\ucp2kjeg.tmp Desired Access: Read Attributes, Delete,
QueryAttributeTagFile C:\Users\user\AppData\Local\Temp\ucp2kjeg.tmp Attributes: A, ReparseTag: 0x0
SetDispositionInformationFile C:\Users\user\AppData\Local\Temp\ucp2kjeg.tmp Delete: True
CloseFile C:\Users\user\AppData\Local\Temp\ucp2kjeg.tmp
CreateFile C:\Users\user\AppData\Local\Temp\ucp2kjeg.pdb Desired Access: Read Attributes, Delete,
CreateFile C:\Users\user\AppData\Local\Temp\ucp2kjeg.err Desired Access: Read Attributes, Delete,
QueryAttributeTagFile C:\Users\user\AppData\Local\Temp\ucp2kjeg.err Attributes: A, ReparseTag: 0x0
SetDispositionInformationFile C:\Users\user\AppData\Local\Temp\ucp2kjeg.err Delete: True
CloseFile C:\Users\user\AppData\Local\Temp\ucp2kjeg.err
CreateFile C:\Users\user\AppData\Local\Temp\ucp2kjeg.cmdline Desired Access: Read Attributes, Delete,
QueryAttributeTagFile C:\Users\user\AppData\Local\Temp\ucp2kjeg.cmdline Attributes: A, ReparseTag: 0x0
SetDispositionInformationFile C:\Users\user\AppData\Local\Temp\ucp2kjeg.cmdline Delete: True
CloseFile C:\Users\user\AppData\Local\Temp\ucp2kjeg.cmdline
CreateFile C:\Users\user\AppData\Local\Temp\ucp2kjeg.dll Desired Access: Read Attributes, Delete,
QueryAttributeTagFile C:\Users\user\AppData\Local\Temp\ucp2kjeg.dll Attributes: A, ReparseTag: 0x0
SetDispositionInformationFile C:\Users\user\AppData\Local\Temp\ucp2kjeg.dll Delete: True
CloseFile C:\Users\user\AppData\Local\Temp\ucp2kjeg.dll
Попробуем сгенерировать динамический код в памяти не используя промежуточный файл. Для этого сначала создадим dll и получим IL код.
Add-Type $code -OutputAssembly cert.dll
Для получение IL-кода — воспользуемся бесплатным продуктом dotPeek (существует большого количество декомпиляторов на любой вкус – ildasm, .Net Reflector, ILSpy и т.д.)
dotPeek – Load — Windows — IL Viewer
Получим код:
Создадим динамический модуль:
https://blogs.technet.microsoft.com/heyscriptingguy/2013/06/25/use-powershell-to-interact-with-the-windows-api-part-1/
https://blogs.technet.microsoft.com/heyscriptingguy/2013/06/26/use-powershell-to-interact-with-the-windows-api-part-2/
https://blogs.technet.microsoft.com/heyscriptingguy/2013/06/27/use-powershell-to-interact-with-the-windows-api-part-3/
# Module Builder
$Domain = [AppDomain]::CurrentDomain
$DynAssembly = New-Object System.Reflection.AssemblyName('Win32IC')
# Запускать в памяти [System.Reflection.Emit.AssemblyBuilderAccess]::Run
$AssemblyBuilder = $Domain.DefineDynamicAssembly(
$DynAssembly,
[System.Reflection.Emit.AssemblyBuilderAccess]::Run
)
$ModuleBuilder = $AssemblyBuilder.DefineDynamicModule('Win32IC', $False)
# [Dummy]::GetDelegate()
$TypeBuilder = $ModuleBuilder.DefineType('Dummy', 'Public, Class')
# Определим ReturnTrue метод
$ReturnTrue = $TypeBuilder.DefineMethod(
# Название метода
'ReturnTrue',
# Атрибуты класса
[Reflection.MethodAttributes] 'Public, Static',
# Тип возврата
[bool],
# Тип параметров
[Type[]] @(
[object],
[System.Security.Cryptography.X509Certificates.X509Certificate],
[System.Security.Cryptography.X509Certificates.X509Chain],
[System.Net.Security.SslPolicyErrors]
)
)
$ilReturnTrue = $ReturnTrue.GetILGenerator()
$ilReturnTrue.Emit([Reflection.Emit.OpCodes]::Ldc_I4_1)
$ilReturnTrue.Emit([Reflection.Emit.OpCodes]::Ret)
# Определим GetDelegate метод
$GetDelegate = $TypeBuilder.DefineMethod(
'GetDelegate',
[Reflection.MethodAttributes] 'Public, Static',
[System.Net.Security.RemoteCertificateValidationCallback],
$null
)
$ctor = [System.Net.Security.RemoteCertificateValidationCallback].GetConstructor(
[type[]]@([object],[intptr])
)
$ilGetDelegate = $GetDelegate.GetILGenerator()
$ilGetDelegate.Emit([Reflection.Emit.OpCodes]::Ldnull)
$ilGetDelegate.Emit([Reflection.Emit.OpCodes]::Ldftn,$ReturnTrue)
$ilGetDelegate.Emit([Reflection.Emit.OpCodes]::Newobj,$ctor)
$ilGetDelegate.Emit([Reflection.Emit.OpCodes]::Ret)
# Создание типа и вызов метода
$Dummy = $TypeBuilder.CreateType()
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = $Dummy::GetDelegate()
# Выполнияем запрос к сайту
Invoke-RestMethod https://expired.badssl.com/
5. Использование модуля Tunable-SSL-Validator
Описание проблемы — http://huddledmasses.org/blog/validating-self-signed-certificates-properly-from-powershell/
Скачать модуль — https://github.com/Jaykul/Tunable-SSL-Validator/archive/master.zip
В данной модуле Invoke-WebRequest/Invoke-RestMethod – переопределены в виде proxy function и добавляют дополнительную диагностическую информацию.
Get-Command -Module TunableSSLValidator -Verb Invoke CommandType Name Version Source ----------- ---- ------- ------ Function Invoke-RestMethod 0.0 TunableSSLValidator Function Invoke-WebRequest 0.0 TunableSSLValidator
Дополнительная диагностическая информация:

Добавим сертификат в исключение:
Add-SessionTrustedCertificate -LastFailed
# Удалим сертификат
Get-SessionTrustedCertificate | Remove-SessionTrustedCertificate
# Отключим проверку
Disable-SSLChainValidation
Invoke-RestMethod https://expired.badssl.com/
PS. Пример динамического кода из 4 пункта –RemoteCertificateValidationCallback .
Добавить комментарий