Как правильно использовать LogonUser для олицетворения пользователя домена из клиента рабочей группы

ASP.NET: выдача себя за домен в VMWare

Я задаю этот вопрос, но в ответе не содержится подробностей о том, как получен _token. Кажется, используется только WindowsIdentity.GetCurrent().Token, поэтому не происходит выдачи себя за другое лицо.

Могу ли я выдать себя за пользователя на другой домен Active Directory в .NET?

На следующий вопрос есть противоречивые ответы, а в принятом есть комментарий «Я начинаю подозревать, что моя проблема в другом». Не полезно.

LogonUser работает только для моего домена

Следующий вопрос, похоже, подразумевает, что это невозможно, но он касается двух доменов, поэтому я не уверен, актуален ли он.

Мой настоящий вопрос:

  • Возможно ли это? И если да,
  • Как? или Где я ошибся?

Пока что я пробовал использовать код из http://msdn.microsoft.com/en-us/library/chf6fbt4%28v=VS.80%29.aspx

bool returnValue = LogonUser(user, domain, password,
            LOGON32_LOGON_NETWORK, LOGON32_PROVIDER_DEFAULT,
            ref tokenHandle);
// after this point, returnValue = false

Ошибка Win32

Ошибка входа в систему: неизвестное имя пользователя или неверный пароль


person RichardTheKiwi    schedule 16.02.2011    source источник


Ответы (6)


Очень немногие сообщения предлагают использовать LOGON_TYPE_NEW_CREDENTIALS вместо LOGON_TYPE_NETWORK или LOGON_TYPE_INTERACTIVE. У меня была проблема с олицетворением, когда одна машина была подключена к домену, а другая - нет, и это устранило ее. Последний фрагмент кода в этом сообщении предполагает, что выдача себя за другое лицо в лесу действительно работает, но не конкретно сказать что-нибудь о создаваемом доверии. Так что, возможно, стоит попробовать:

const int LOGON_TYPE_NEW_CREDENTIALS = 9;
const int LOGON32_PROVIDER_WINNT50 = 3;
bool returnValue = LogonUser(user, domain, password,
            LOGON_TYPE_NEW_CREDENTIALS, LOGON32_PROVIDER_WINNT50,
            ref tokenHandle);

MSDN сообщает, что LOGON_TYPE_NEW_CREDENTIALS работает только при использовании LOGON32_PROVIDER_WINNT50.

person takrl    schedule 12.03.2012
comment
Имейте в виду, что LOGON_TYPE_NEW_CREDENTIALS, похоже, не проверяет учетные данные до тех пор, пока они не будут использоваться для доступа к сетевому ресурсу, поэтому его нельзя использовать для аутентификации так, как LOGON_TYPE_NETWORK. - person Nicholas Blumhardt; 22.01.2014
comment
У меня была такая же проблема, когда я выдавал себя за другой домен, отличный от того, в котором работало мое приложение. Другой домен также не имел доверия. Я бы получил бессмысленную ошибку. Система не может найти указанный файл. Изменение 0,2 на 9,3, как вы предложили выше, сработало! Теперь я могу читать файлы из общей папки в другом домене. Спасибо, чувак, ты избавил меня от сильной боли! - person MikeTeeVee; 31.07.2014
comment
Спасибо, работает, но тем не менее проблема в целом странная. Я пытался аутентифицироваться, чтобы выдать себя за другое лицо в той же сети, и всегда получал сообщение «Неизвестное имя пользователя или неверный пароль» при использовании LOGON32_LOGON_INTERACTIVE. На моей машине dev все работало нормально. Я хотел бы проследить причину до самого низа, но с чего мне начать? - person Daniel; 24.04.2017
comment
@ Дэниел Хороший вопрос. Я нашел это, только экспериментируя с параметрами, приведенными в документации, а не потому, что я знал, как и почему это работает ;-) - person takrl; 25.04.2017

это работает для меня, полный рабочий пример (я бы хотел, чтобы больше людей делали это):

//logon impersonation
using System.Runtime.InteropServices; // DllImport
using System.Security.Principal; // WindowsImpersonationContext
using System.Security.Permissions; // PermissionSetAttribute

...

class Program {

    // obtains user token
    [DllImport("advapi32.dll", SetLastError = true)]
    public static extern bool LogonUser(string pszUsername, string pszDomain, string pszPassword,
        int dwLogonType, int dwLogonProvider, ref IntPtr phToken);

    // closes open handes returned by LogonUser
    [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
    public extern static bool CloseHandle(IntPtr handle);

    public void DoWorkUnderImpersonation() {
        //elevate privileges before doing file copy to handle domain security
        WindowsImpersonationContext impersonationContext = null;
        IntPtr userHandle = IntPtr.Zero;
        const int LOGON32_PROVIDER_DEFAULT = 0;
        const int LOGON32_LOGON_INTERACTIVE = 2;
        string domain = ConfigurationManager.AppSettings["ImpersonationDomain"];
        string user = ConfigurationManager.AppSettings["ImpersonationUser"];
        string password = ConfigurationManager.AppSettings["ImpersonationPassword"];

        try {
            Console.WriteLine("windows identify before impersonation: " + WindowsIdentity.GetCurrent().Name);

            // if domain name was blank, assume local machine
            if (domain == "")
                domain = System.Environment.MachineName;

            // Call LogonUser to get a token for the user
            bool loggedOn = LogonUser(user,
                                        domain,
                                        password,
                                        LOGON32_LOGON_INTERACTIVE,
                                        LOGON32_PROVIDER_DEFAULT,
                                        ref userHandle);

            if (!loggedOn) {
                Console.WriteLine("Exception impersonating user, error code: " + Marshal.GetLastWin32Error());
                return;
            }

            // Begin impersonating the user
            impersonationContext = WindowsIdentity.Impersonate(userHandle);

            Console.WriteLine("Main() windows identify after impersonation: " + WindowsIdentity.GetCurrent().Name);

            //run the program with elevated privileges (like file copying from a domain server)
            DoWork();

        } catch (Exception ex) {
            Console.WriteLine("Exception impersonating user: " + ex.Message);
        } finally {
            // Clean up
            if (impersonationContext != null) {
                impersonationContext.Undo();
            }

            if (userHandle != IntPtr.Zero) {
                CloseHandle(userHandle);
            }
        }
    }


    private void DoWork() {
        //everything in here has elevated privileges

        //example access files on a network share through e$ 
        string[] files = System.IO.Directory.GetFiles(@"\\domainserver\e$\images", "*.jpg");
    }
}
person JJ_Coder4Hire    schedule 20.06.2013
comment
Как предотвратить утечку содержимого password через дампы памяти или подключенные отладчики в скомпрометированной системе? Я заметил, что вы оставили это в памяти. - person Justin Skiles; 03.06.2014
comment
эти API такие разборчивые. Я получил почти такое же решение, но оно не удалось из-за неправильной комбинации logonprovider и logontype. интерактивный в связи со значением по умолчанию - это нормально, в то время как newcredentials работает только с winnt50 ... при таком подходе Environment.Username действительно возвращает олицетворенную учетную запись, если это то, что вам нужно, используйте это решение. - person Cee McSharpface; 01.08.2017

У меня была такая же проблема. Не знаю, решили вы это или нет, но на самом деле я пытался получить доступ к общему сетевому ресурсу с учетными данными AD. WNetAddConnection2() - это то, что вам нужно использовать в этом случае.

person Conrad    schedule 07.10.2011

Мне удалось выдать себя за пользователей в другом домене, но только с установкой доверия между двумя доменами.

var token = IntPtr.Zero;
var result = LogonUser(userID, domain, password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, ref token);
if (result)
{
    return WindowsIdentity.Impersonate(token);
}
person Jason    schedule 01.12.2011

Лучше использовать SecureString:

var password = new SecureString();
var phPassword phPassword = Marshal.SecureStringToGlobalAllocUnicode(password);
IntPtr phUserToken;
LogonUser(username, domain, phPassword, LOGON32_LOGON_INTERACTIVE,  LOGON32_PROVIDER_DEFAULT, out phUserToken);

И:

Marshal.ZeroFreeGlobalAllocUnicode(phPassword);
password.Dispose();

Определение функции:

private static extern bool LogonUser(
  string pszUserName,
  string pszDomain,
  IntPtr pszPassword,
  int dwLogonType,
  int dwLogonProvider,
  out IntPtr phToken);
person Tovich    schedule 11.08.2017
comment
Да, документ базового winapi довольно ясен в этом. Цитата Когда вы закончите использовать пароль, удалите пароль из памяти, вызвав функцию SecureZeroMemory. Дополнительные сведения о защите паролей см. В разделе Обработка паролей. - person David Burg; 16.10.2019

Неверный логин / пароль также может быть связан с проблемами на вашем DNS-сервере - это то, что случилось со мной и стоило мне добрых 5 часов моей жизни. Посмотрите, можете ли вы указать IP-адрес вместо имени домена.

person Dan    schedule 20.03.2014
comment
Итак, в чем была проблема с DNS. Я думаю, что у меня есть эта проблема на одном из наших сайтов - person Zaid Amir; 29.04.2016