gpt4 book ai didi

c# - CreateProcessAsUser : Service gets "5: Access Denied" trying to access network share

转载 作者:太空宇宙 更新时间:2023-11-03 13:48:30 24 4
gpt4 key购买 nike

我使用 Windows 服务中的 CreateProcessAsUser 为当前事件用户启动应用程序。到目前为止,它适用于本地驱动器上的应用程序。

但是如果可执行文件存在于网络共享上,当我使用完整的服务器名称 (\myserver\path\app.exe) 时,服务会生成 5: ERROR_ACCESS_DENIED。如果我改用映射驱动器 (P:\path\app.exe),我还可以生成 2: ERROR_FILE_NOT_FOUND。

我可以从资源管理器中正常启动应用程序。听起来我确实无法获得正确的 token 副本,因为该服务无法在服务器上正确地模拟我。

我从各种帖子中尝试了 CreateProcessAsUser 的几种不同实现,但无济于事。这对我来说是全新的(迷幻的)东西,坦率地说,我迫不及待地想回到 .NET :) 我猜这里有问题:

DuplicateTokenEx(
hUserToken,
(Int32)MAXIMUM_ALLOWED,
ref sa,
(Int32)SECURITY_IMPERSONATION_LEVEL.SecurityIdentification,
(Int32)TOKEN_TYPE.TokenPrimary,
ref hUserTokenDup);

CreateEnvironmentBlock(ref pEnv, hUserTokenDup, true);

Int32 dwCreationFlags = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE | CREATE_UNICODE_ENVIRONMENT;

PROCESS_INFORMATION pi;
STARTUPINFO si = new STARTUPINFO();
si.cb = Marshal.SizeOf(si);
si.lpDesktop = "winsta0\\default";

CreateProcessAsUser(hUserTokenDup, // client's access token
null, // file to execute
commandLine, // command line
ref sa, // pointer to process SECURITY_ATTRIBUTES
ref sa, // pointer to thread SECURITY_ATTRIBUTES
false, // handles are not inheritable
dwCreationFlags, // creation flags
pEnv, // pointer to new environment block
workingDirectory, // name of current directory
ref si, // pointer to STARTUPINFO structure
out pi); // receives information about new process

这是完整的示例代码,我想它可能会有用:

using System;
using System.Text;
using System.Security;
using System.Management;
using System.Diagnostics;
using System.Runtime.InteropServices;

namespace Win32
{
public class Win32API
{
[StructLayout(LayoutKind.Sequential)]
struct SECURITY_ATTRIBUTES
{
public Int32 Length;
public IntPtr lpSecurityDescriptor;
public Boolean bInheritHandle;
}

enum TOKEN_TYPE
{
TokenPrimary = 1,
TokenImpersonation = 2
}

[StructLayout(LayoutKind.Sequential)]
struct STARTUPINFO
{
public Int32 cb;
public String lpReserved;
public String lpDesktop;
public String lpTitle;
public UInt32 dwX;
public UInt32 dwY;
public UInt32 dwXSize;
public UInt32 dwYSize;
public UInt32 dwXCountChars;
public UInt32 dwYCountChars;
public UInt32 dwFillAttribute;
public UInt32 dwFlags;
public short wShowWindow;
public short cbReserved2;
public IntPtr lpReserved2;
public IntPtr hStdInput;
public IntPtr hStdOutput;
public IntPtr hStdError;
}

[StructLayout(LayoutKind.Sequential)]
struct PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public UInt32 dwProcessId;
public UInt32 dwThreadId;
}

enum SECURITY_IMPERSONATION_LEVEL
{
SecurityAnonymous = 0,
SecurityIdentification = 1,
SecurityImpersonation = 2,
SecurityDelegation = 3,
}

const UInt32 MAXIMUM_ALLOWED = 0x2000000;
const Int32 CREATE_UNICODE_ENVIRONMENT = 0x00000400;
const Int32 NORMAL_PRIORITY_CLASS = 0x20;
const Int32 CREATE_NEW_CONSOLE = 0x00000010;

[DllImport("kernel32.dll", SetLastError = true)]
static extern Boolean CloseHandle(IntPtr hSnapshot);

[DllImport("kernel32.dll")]
public static extern UInt32 WTSGetActiveConsoleSessionId();

[DllImport("Wtsapi32.dll")]
static extern UInt32 WTSQueryUserToken(UInt32 SessionId, ref IntPtr phToken);

[DllImport("advapi32.dll", EntryPoint = "CreateProcessAsUser", SetLastError = true, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
extern static Boolean CreateProcessAsUser(
IntPtr hToken,
String lpApplicationName,
String lpCommandLine,
ref SECURITY_ATTRIBUTES lpProcessAttributes,
ref SECURITY_ATTRIBUTES lpThreadAttributes,
Boolean bInheritHandle,
Int32 dwCreationFlags,
IntPtr lpEnvironment,
String lpCurrentDirectory,
ref STARTUPINFO lpStartupInfo,
out PROCESS_INFORMATION lpProcessInformation);

[DllImport("advapi32.dll", EntryPoint = "DuplicateTokenEx")]
extern static Boolean DuplicateTokenEx(
IntPtr ExistingTokenHandle,
UInt32 dwDesiredAccess,
ref SECURITY_ATTRIBUTES lpThreadAttributes,
Int32 TokenType,
Int32 ImpersonationLevel,
ref IntPtr DuplicateTokenHandle);

[DllImport("userenv.dll", SetLastError = true)]
static extern Boolean CreateEnvironmentBlock(
ref IntPtr lpEnvironment,
IntPtr hToken,
Boolean bInherit);

[DllImport("userenv.dll", SetLastError = true)]
static extern Boolean DestroyEnvironmentBlock(IntPtr lpEnvironment);

/// <summary>
/// Creates the process in the interactive desktop with credentials of the logged in user.
/// </summary>
public static Boolean CreateProcessAsUser(String commandLine, String workingDirectory, out StringBuilder output)
{
Boolean processStarted = false;
output = new StringBuilder();

try
{
UInt32 dwSessionId = WTSGetActiveConsoleSessionId();
output.AppendLine(String.Format("Active console session Id: {0}", dwSessionId));

IntPtr hUserToken = IntPtr.Zero;
WTSQueryUserToken(dwSessionId, ref hUserToken);

SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES();
sa.Length = Marshal.SizeOf(sa);

IntPtr hUserTokenDup = IntPtr.Zero;
DuplicateTokenEx(
hUserToken,
(Int32)MAXIMUM_ALLOWED,
ref sa,
(Int32)SECURITY_IMPERSONATION_LEVEL.SecurityIdentification,
(Int32)TOKEN_TYPE.TokenPrimary,
ref hUserTokenDup);


if (hUserTokenDup != IntPtr.Zero)
{
output.AppendLine(String.Format("DuplicateTokenEx() OK (hToken: {0})", hUserTokenDup));

Int32 dwCreationFlags = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE;

IntPtr pEnv = IntPtr.Zero;
if (CreateEnvironmentBlock(ref pEnv, hUserTokenDup, true))
{
dwCreationFlags |= CREATE_UNICODE_ENVIRONMENT;
output.AppendLine(String.Format("CreateEnvironmentBlock() success."));
}
else
{
output.AppendLine(String.Format("CreateEnvironmentBlock() FAILED (Last Error: {0})", Marshal.GetLastWin32Error()));
pEnv = IntPtr.Zero;
}

// Launch the process in the client's logon session.
PROCESS_INFORMATION pi;

STARTUPINFO si = new STARTUPINFO();
si.cb = Marshal.SizeOf(si);
si.lpDesktop = "winsta0\\default";

output.AppendLine(String.Format("CreateProcess (Path:{0}, CurrDir:{1})", commandLine, workingDirectory));

if (CreateProcessAsUser(hUserTokenDup, // client's access token
null, // file to execute
commandLine, // command line
ref sa, // pointer to process SECURITY_ATTRIBUTES
ref sa, // pointer to thread SECURITY_ATTRIBUTES
false, // handles are not inheritable
dwCreationFlags, // creation flags
pEnv, // pointer to new environment block
workingDirectory, // name of current directory
ref si, // pointer to STARTUPINFO structure
out pi // receives information about new process
))
{
processStarted = true;
output.AppendLine(String.Format("CreateProcessAsUser() OK (PID: {0})", pi.dwProcessId));
}
else
{
output.AppendLine(String.Format("CreateProcessAsUser() failed (Last Error: {0})", Marshal.GetLastWin32Error()));
}

if (DestroyEnvironmentBlock(pEnv))
{
output.AppendLine("DestroyEnvironmentBlock: Success");
}
else
{
output.AppendLine(String.Format("DestroyEnvironmentBlock() failed (Last Error: {0})", Marshal.GetLastWin32Error()));
}
}
else
{
output.AppendLine(String.Format("DuplicateTokenEx() failed (Last Error: {0})", Marshal.GetLastWin32Error()));
}
CloseHandle(hUserTokenDup);
CloseHandle(hUserToken);
}
catch (Exception ex)
{
output.AppendLine("Exception occurred: " + ex.Message);
}
return processStarted;
}
}
}

它非常适合像这样的本地可执行文件:

StringBuilder result = new StringBuilder();
Win32API.CreateProcessAsUser(@"C:\Windows\notepad.exe", @"C:\Windows\", out result);

我的问题:需要调整什么才能使用重复 token 正确访问网络共享?

最佳答案

当您将此命令用于允许 guest 访问的共享(即无用户名/密码)时,该命令可以正常工作,但是当您将它用于需要身份验证才能使用的共享时,它不起作用。

UI 调用涉及重定向器,它自动建立与执行所需的远程服务器的连接。

请注意,一个解决方法,但不是真正的解决方案是使用基于 cmd 的中继来获取可执行文件,因此对于命令行,您可以将其设置为:

CreateProcessAsUser(@"cmd /c ""start \\server\share\binary.exe""", @"C:\Windows", out result);

然后将 startupinfo 更改为 SW_HIDE cmd 窗口使用:

si.cb = Marshal.SizeOf(si);
si.lpDesktop = "winsta0\\default";
si.dwFlags = 0x1; // STARTF_USESHOWWINDOW
si.wShowWindow = 0; // SW_HIDE

cmd 调用是在启动命令之前完全进入用户环境的一些垫片 - 这将利用所有凭据来访问服务器。

请注意,您可能需要一些逻辑来防止直接调用的应用程序出现 SW_HIDE(例如,在命令行字符串的开头检查 cmd?)

关于c# - CreateProcessAsUser : Service gets "5: Access Denied" trying to access network share,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14463556/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com