【发布时间】:2019-08-06 15:09:02
【问题描述】:
我可以通过 CreateProcessAsUser 从我在这里找到的代码中创建一个新进程: https://odetocode.com/blogs/scott/archive/2004/10/28/createprocessasuser.aspx
它工作正常,但新进程不包含由 IIS Asp.net Impersonation 模拟的新用户的 Kerberos 票证。我知道 IIS 有 Kerberos 票证,我只是不知道如何以编程方式将它从父工作进程获取到我生成的调用 OpenSSH 的新进程。
编辑:使用 @Steve 提到的 DupliateHandlers 函数更新了 Impersonation 块
var CurrentIdentity = ((WindowsIdentity)User.Identity).Token;
IntPtr parentHandle = IntPtr.Zero;
QuerySecurityContextToken(ref CurrentIdentity, out parentHandle);
using (WindowsImpersonationContext impersonationContext = ((System.Security.Principal.WindowsIdentity)User.Identity).Impersonate())
{
IntPtr childHandle = CreateProcessAsUser();
IntPtr lpTargetHandle = IntPtr.Zero;
if (CloneParentProcessToken.DuplicateHandle(parentHandle, null, childHandle, out lpTargetHandle,
null, true, DuplicateOptions.DUPLICATE_SAME_ACCESS, ) > 0)
{
if(ImpersonateLoggedOnUser(lpTargetHandle))
{
}
}
impersonationContext.Undo();
}
private void CreateProcessAsUser()
{
IntPtr hToken = WindowsIdentity.GetCurrent().Token;
IntPtr hDupedToken = IntPtr.Zero;
ProcessUtility.PROCESS_INFORMATION pi = new ProcessUtility.PROCESS_INFORMATION();
try
{
ProcessUtility.SECURITY_ATTRIBUTES sa = new ProcessUtility.SECURITY_ATTRIBUTES();
sa.Length = Marshal.SizeOf(sa);
bool result = ProcessUtility.DuplicateTokenEx(
hToken,
ProcessUtility.GENERIC_ALL_ACCESS,
ref sa,
(int)ProcessUtility.SECURITY_IMPERSONATION_LEVEL.SecurityIdentification,
(int)ProcessUtility.TOKEN_TYPE.TokenPrimary,
ref hDupedToken
);
if (!result)
{
throw new ApplicationException("DuplicateTokenEx failed");
}
ProcessUtility.STARTUPINFO si = new ProcessUtility.STARTUPINFO();
si.cb = Marshal.SizeOf(si);
si.lpDesktop = String.Empty;
result = ProcessUtility.CreateProcessAsUser(
hDupedToken,
null,
"powershell.exe -Command SSHCommand.ps1",
ref sa, ref sa,
true, 0, IntPtr.Zero,
@"C:\", ref si, ref pi
);
if (!result)
{
int error = Marshal.GetLastWin32Error();
string message = String.Format("CreateProcessAsUser Error: {0}", error);
throw new ApplicationException(message);
}
}
finally
{
if (pi.hProcess != IntPtr.Zero)
ProcessUtility.CloseHandle(pi.hProcess);
if (pi.hThread != IntPtr.Zero)
ProcessUtility.CloseHandle(pi.hThread);
if (hDupedToken != IntPtr.Zero)
ProcessUtility.CloseHandle(hDupedToken);
}
}
}
public class ProcessUtility
{
[StructLayout(LayoutKind.Sequential)]
public struct STARTUPINFO
{
public Int32 cb;
public string lpReserved;
public string lpDesktop;
public string lpTitle;
public Int32 dwX;
public Int32 dwY;
public Int32 dwXSize;
public Int32 dwXCountChars;
public Int32 dwYCountChars;
public Int32 dwFillAttribute;
public Int32 dwFlags;
public Int16 wShowWindow;
public Int16 cbReserved2;
public IntPtr lpReserved2;
public IntPtr hStdInput;
public IntPtr hStdOutput;
public IntPtr hStdError;
}
[StructLayout(LayoutKind.Sequential)]
public struct PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public Int32 dwProcessID;
public Int32 dwThreadID;
}
[StructLayout(LayoutKind.Sequential)]
public struct SECURITY_ATTRIBUTES
{
public Int32 Length;
public IntPtr lpSecurityDescriptor;
public bool bInheritHandle;
}
public enum SECURITY_IMPERSONATION_LEVEL
{
SecurityAnonymous,
SecurityIdentification,
SecurityImpersonation,
SecurityDelegation
}
public enum TOKEN_TYPE
{
TokenPrimary = 1,
TokenImpersonation
}
public const int GENERIC_ALL_ACCESS = 0x10000000;
public const int TOKEN_ASSIGN_PRIMARY = 0x0001;
[
DllImport("kernel32.dll",
EntryPoint = "CloseHandle", SetLastError = true,
CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)
]
public static extern bool CloseHandle(IntPtr handle);
[
DllImport("advapi32.dll",
EntryPoint = "CreateProcessAsUser", SetLastError = true,
CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)
]
public static extern bool
CreateProcessAsUser(IntPtr hToken, string lpApplicationName, string lpCommandLine,
ref SECURITY_ATTRIBUTES lpProcessAttributes, ref SECURITY_ATTRIBUTES lpThreadAttributes,
bool bInheritHandle, Int32 dwCreationFlags, IntPtr lpEnvrionment,
string lpCurrentDirectory, ref STARTUPINFO lpStartupInfo,
ref PROCESS_INFORMATION lpProcessInformation);
[
DllImport("advapi32.dll",
EntryPoint = "DuplicateTokenEx")
]
public static extern bool
DuplicateTokenEx(IntPtr hExistingToken, Int32 dwDesiredAccess,
ref SECURITY_ATTRIBUTES lpThreadAttributes,
Int32 ImpersonationLevel, Int32 dwTokenType,
ref IntPtr phNewToken);
}
【问题讨论】:
-
您似乎在复制令牌并且只要求提供身份证明。根据您在子进程中执行的操作,您需要模拟或可能委托。
-
@Steve 感谢您的回复。我确实尝试了模拟和委托,但得到了这个错误:调用 API LsaCallAuthenticationPackage 时出错(ShowTickets 子状态):1312 klist 失败,出现 0xc000005f/-1073741729:指定的登录会话不存在。它可能已经被终止了。
-
您是否将 klist 称为委托应用程序?重新阅读一下,我认为您可能会在这里遇到问题,因为我认为新应用程序也需要知道模拟。 stackoverflow.com/questions/51735041/…
-
@Steve 谢谢。是否可以在新进程中仅找到 krb5cache 位置并将其设置为 env var KRB5CCNAME?
-
不,出于安全原因,Windows 不是这样工作的。
标签: c# asp.net kerberos createprocessasuser