Smartcards und runas in Powershell
Achtung: Expertenfrage
Achtung, habe was korrigieren müssen
Servus Kollegen,
das ist ein seltenes und wie ich denke schwieriges Anliegen:
ich habe eine SmartCard zur Windowsanmeldung mit PIN. Ich kann per Rechtsklick "ausführen als" auch wunderbar damit arbeiten.
Ich möchte nun dieses Rechtsgeklicke loswerden und in einem Skript eben diesen Dialog anfordern.
Ich habe sogar ein Skript dazu, welches auch mit SmartCards, die die PC-Tastatur zur PIN-Eingabe nutzen, funktioniert - z.B. mit einem Yubikey 5.
Mit einem SmartCardreader mit eigener Tastatur funktioniert es leider nicht, weder wird die Tastatur des Readers selbst wird nicht angesteuert , noch kann ich die PC-Tastatur nutzen.
Was muss an folgendem Skript geändert werden, damit das geht?
(dieses Skript startet nach PIN-Eingabe cmd.exe als anderer Nutzer)
PS: mir ist bewusst, dass es auf der ollen Kommandozeile per runas /smartcard sehr wohl auch geht, jedoch hat das noch gravierendere Nachteile: es kommt nicht mit mehreren Credentials pro SmartCard klar.
Achtung, habe was korrigieren müssen
Servus Kollegen,
das ist ein seltenes und wie ich denke schwieriges Anliegen:
ich habe eine SmartCard zur Windowsanmeldung mit PIN. Ich kann per Rechtsklick "ausführen als" auch wunderbar damit arbeiten.
Ich möchte nun dieses Rechtsgeklicke loswerden und in einem Skript eben diesen Dialog anfordern.
Ich habe sogar ein Skript dazu, welches auch mit SmartCards, die die PC-Tastatur zur PIN-Eingabe nutzen, funktioniert - z.B. mit einem Yubikey 5.
Mit einem SmartCardreader mit eigener Tastatur funktioniert es leider nicht,
Was muss an folgendem Skript geändert werden, damit das geht?
Function Get-SmartCardCred{
<#
.SYNOPSIS
Get certificate credentials from the user's certificate store.
.DESCRIPTION
Returns a PSCredential object of the user's selected certificate.
.EXAMPLE
Get-SmartCardCred
UserName Password
-------- --------
@@BVkEYkWiqJgd2d9xz3-5BiHs1cAN System.Security.SecureString
.EXAMPLE
$Cred = Get-SmartCardCred
.OUTPUTS
[System.Management.Automation.PSCredential]
.NOTES
Author: Joshua Chase
Last Modified: 01 August 2018
C# code used from https://github.com/bongiovimatthew-microsoft/pscredentialWithCert
#>
[cmdletbinding()]
param()
$SmartCardCode = @"
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Management.Automation;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Cryptography.X509Certificates;
namespace SmartCardLogon{
static class NativeMethods
{
public enum CRED_MARSHAL_TYPE
{
CertCredential = 1,
UsernameTargetCredential
}
[StructLayout(LayoutKind.Sequential)]
internal struct CERT_CREDENTIAL_INFO
{
public uint cbSize;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
public byte rgbHashOfCert;
}
[DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern bool CredMarshalCredential(
CRED_MARSHAL_TYPE CredType,
IntPtr Credential,
out IntPtr MarshaledCredential
);
[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool CredFree([In] IntPtr buffer);
}
public class Certificate
{
public static PSCredential MarshalFlow(string thumbprint, SecureString pin)
{
//
// Set up the data struct
//
NativeMethods.CERT_CREDENTIAL_INFO certInfo = new NativeMethods.CERT_CREDENTIAL_INFO();
certInfo.cbSize = (uint)Marshal.SizeOf(typeof(NativeMethods.CERT_CREDENTIAL_INFO));
//
// Locate the certificate in the certificate store
//
X509Certificate2 certCredential = new X509Certificate2();
X509Store userMyStore = new X509Store(StoreName.My, StoreLocation.CurrentUser);
userMyStore.Open(OpenFlags.ReadOnly);
X509Certificate2Collection certsReturned = userMyStore.Certificates.Find(X509FindType.FindByThumbprint, thumbprint, false);
userMyStore.Close();
if (certsReturned.Count == 0)
{
throw new Exception("Unable to find the specified certificate.");
}
//
// Marshal the certificate
//
certCredential = certsReturned;
certInfo.rgbHashOfCert = certCredential.GetCertHash();
int size = Marshal.SizeOf(certInfo);
IntPtr pCertInfo = Marshal.AllocHGlobal(size);
Marshal.StructureToPtr(certInfo, pCertInfo, false);
IntPtr marshaledCredential = IntPtr.Zero;
bool result = NativeMethods.CredMarshalCredential(NativeMethods.CRED_MARSHAL_TYPE.CertCredential, pCertInfo, out marshaledCredential);
string certBlobForUsername = null;
PSCredential psCreds = null;
if (result)
{
certBlobForUsername = Marshal.PtrToStringUni(marshaledCredential);
psCreds = new PSCredential(certBlobForUsername, pin);
}
Marshal.FreeHGlobal(pCertInfo);
if (marshaledCredential != IntPtr.Zero)
{
NativeMethods.CredFree(marshaledCredential);
}
return psCreds;
}
}
}
"@
Add-Type -TypeDefinition $SmartCardCode -Language CSharp
Add-Type -AssemblyName System.Security
$ValidCerts = [System.Security.Cryptography.X509Certificates.X509Certificate2[]](Get-ChildItem 'Cert:\CurrentUser\My')
$Cert = [System.Security.Cryptography.X509Certificates.X509Certificate2UI]::SelectFromCollection($ValidCerts, 'Choose a certificate', 'Choose a certificate', 0)
$Pin = Read-Host "Enter your PIN: " -AsSecureString
Write-Output ([SmartCardLogon.Certificate]::MarshalFlow($Cert.Thumbprint, $Pin))
}
$cred=Get-SmartCardCred
$StartInfo = New-Object System.Diagnostics.ProcessStartInfo
$StartInfo.FileName = 'cmd.exe'
$StartInfo.UseShellExecute = $false
$StartInfo.UserName = $Cred.Username
$StartInfo.Password = $Cred.Password
$StartInfo.WorkingDirectory = $env:windir
$Process = New-Object System.Diagnostics.Process
$Process.StartInfo = $StartInfo
$Process.Start()
$Cred = $null
(dieses Skript startet nach PIN-Eingabe cmd.exe als anderer Nutzer)
PS: mir ist bewusst, dass es auf der ollen Kommandozeile per runas /smartcard sehr wohl auch geht, jedoch hat das noch gravierendere Nachteile: es kommt nicht mit mehreren Credentials pro SmartCard klar.
Bitte markiere auch die Kommentare, die zur Lösung des Beitrags beigetragen haben
Content-ID: 2434101143
Url: https://administrator.de/contentid/2434101143
Ausgedruckt am: 19.12.2024 um 12:12 Uhr
3 Kommentare
Neuester Kommentar
Hallo,
ich weiß nicht ob das hilft, aber des normale Vorgehen bei Smartcard Credentials mit dem Yubikey wäre ja folgendes:
Wobei nach Zeile 1 der Auswahldialog kommt und erst beim ausführen von Zeile 2 der Yubikey blinkt und nach Tastendruck die Kryptographieberechnung erfolgt. Vielleicht funktioniert mit Deinem Skript bzw. Reader dieses „asynchrone“ Verhalten nicht.
Grüße
lcer
ich weiß nicht ob das hilft, aber des normale Vorgehen bei Smartcard Credentials mit dem Yubikey wäre ja folgendes:
$cred = get-Credential
Mache-irgendwas -Credential $cred
Wobei nach Zeile 1 der Auswahldialog kommt und erst beim ausführen von Zeile 2 der Yubikey blinkt und nach Tastendruck die Kryptographieberechnung erfolgt. Vielleicht funktioniert mit Deinem Skript bzw. Reader dieses „asynchrone“ Verhalten nicht.
Grüße
lcer