Подтвердить что ты не робот

Можно ли обмануть этот код WindowsIdentity с использованием неправильного пользователя?

TL; DR Может ли пользовательский токен, содержащийся в свойстве WindowsIdentity Token (например, someIdentity.Token), подделываться так, что:

var validated = new WindowsIdentity(someIdentity.Token);

... вернет экземпляр, который утверждает, что представляет пользователя, который на самом деле не был аутентифицирован, но имеет IsAuthenticated установить true, допустимые .Name и .User свойства и т.д.?

Ниже я наложил несколько ограничений на это; это, по-видимому, невозможно для полностью ложного доказательства.


Полная история:

В этот ответ, Damien_The_Unbeliever ловко продемонстрировал, что какой-то мой код можно обмануть, полагая, что он действительный аутентифицированный пользователь в экземпляре WindowsIdentity, когда он этого не сделал. Короче говоря, мой код предполагал, что если Thread.CurrentPrincipal.Identity был экземпляром WindowsIdentity, а IsAuthorized был true, он представлял аутентифицированного пользователя, и я мог полагаться на SID в .User:

WindowsIdentity identity = Thread.CurrentPrincipal == null
    ? null
    : Thread.CurrentPrincipal.Identity as WindowsIdentity;

if (identity != null && identity.IsAuthenticated && !identity.IsAnonymous) {
    // ...use and trust the SID in identity.User, the
    // username in identity.Name, etc....
}

(Есть причина, по которой этот код использует поток, а не WindowsIdentity.GetCurrent().)

Его код, чтобы обмануть (слегка измененный):

var ident = WindowsIdentity.GetCurrent();
Thread.CurrentPrincipal = new WindowsPrincipal(ident);
var fakeSid = new SecurityIdentifier("S-1-3-0"/* E.g., some SID you want to trick me into believing is the real user */);
typeof(WindowsIdentity).GetField("m_user", BindingFlags.Instance | BindingFlags.NonPublic)
    .SetValue(ident, fakeSid);

И конечно, если вы это сделаете, тогда позвоните моему коду выше, мой код обманут. Кудос Дэмиен.

Итак, в настоящей моде гонки гонок, здесь мой пересмотренный код, который ловит пародию и отрицает ее:

WindowsIdentity identity = Thread.CurrentPrincipal == null
    ? null
    : Thread.CurrentPrincipal.Identity as WindowsIdentity;

if (identity != null && identity.IsAuthenticated && !identity.IsAnonymous) {
    var validated = new WindowsIdentity(identity.Token);
    if (!validated.User.Equals(identity.User) || !validated.IsAuthenticated || validated.IsAnonymous) {
        // Something fishy is going on, don't trust it
    } else {
        // Good! Use the validated one
        identity = validated;
        // ...use and trust the SID in identity.User, the
        // username in identity.Name, etc....
    }
}

Как вы можете видеть, он принимает Token из предоставленного идентификатора и создает новый экземпляр WindowsIdentity, используя этот токен. Если идентификаторы идентификаторов идентификаторов совпадают, мы продолжаем, доверяя проверке. (Документация для WindowsIdentity(IntPtr token) говорит, что начальное значение IsAuthenticated будет false, но это просто неправильно в моих тестах, предполагающих Я создал его с действующим токеном пользователя.)

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


Границы

Я должен отметить, что я просто стреляю в разумную степень безопасности единого входа здесь, делая все возможное. Если вредоносное приложение успешно начало перехватывать системные вызовы/скомпрометированные ОС Windows, ну, просто не так много, что я смогу сделать с этим. Как заметил Дэмиен в комментариях к этому другому вопросу, он мог бы создать контейнер-контейнер, который полностью игнорировал бы сильное именование (и, таким образом, мог бы дать мне совершенно поддельный тип WindowsIdentity). Справедливо. Совершенство убивает. Я просто не хочу оставлять двери открытыми, как тот, который Дамиан любезно продемонстрировал. Если бы я выпустил систему и ее легко взломали в поле, я бы смутился по этому поводу.: -)

4b9b3361

Ответ 1

Чтобы продемонстрировать это выполнимо, давайте рассмотрим классный аддон Visual Studio с именем " Microsoft Fakes" (само название означает много..).

Фейки привязаны к тестовым функциям Visual Studio, но это докажет суть. Вы можете следовать стандартным учебникам для настройки проекта и добавить сборку подделок для системы (на самом деле mscorlib + system)

Это ваш код в проекте библиотеки (я использовал исключение везде, потому что это проще в условиях тестирования...).

namespace ClassLibrary1
{
    public class Class1
    {
        public static void MyCheck()
        {
            WindowsIdentity identity = Thread.CurrentPrincipal == null
                ? null
                : Thread.CurrentPrincipal.Identity as WindowsIdentity;

            if (identity != null && identity.IsAuthenticated && !identity.IsAnonymous)
            {
                var validated = new WindowsIdentity(identity.Token);
                if (!validated.User.Equals(identity.User) || !validated.IsAuthenticated || validated.IsAnonymous)
                    throw new Exception("Something fishy is going on, don't trust it");
                else
                    throw new Exception("Good! Use the validated one. name is:" + validated.Name);
            }
            else
                throw new Exception("not in");
        }
    }
}

Это тестовый код в тестовом проекте:

namespace UnitTestProject1
{
    [TestClass]
    public class UnitTest1
    {
        [TestMethod]
        public void TestMethod1()
        {
            using (ShimsContext.Create())
            {
                System.Security.Principal.Fakes.ShimWindowsIdentity.AllInstances.NameGet = (i) =>
                {
                    return "Simon the hacker";
                };

                WindowsIdentity wi = WindowsIdentity.GetCurrent(); // this is the real one "Simon".
                Thread.CurrentPrincipal = new WindowsPrincipal(wi);

                Class1.MyCheck();
            }
        }
    }
}

Это макет проекта в Visual Studio:

введите описание изображения здесь

Также убедитесь, что вы изменили файл mscorlib.fakes, который был автоматически сгенерирован следующим образом:

<Fakes xmlns="http://schemas.microsoft.com/fakes/2011/" Diagnostic="true" TargetFrameworkVersion="v4.6">
  <Assembly Name="mscorlib" />
  <ShimGeneration>
    <Clear />
    <Add Namespace="System.Security.Principal" />
  </ShimGeneration>
</Fakes>

Это означает, что я хочу, чтобы целое пространство имен System.Security.Principal было подкрашено, и я предлагаю вам использовать фреймворк 4.6 для обоих проектов и добавить соответствующий атрибут TargetFrameworkVersion.

Теперь, когда вы запускаете тест, это то, что вы увидите:

введите описание изображения здесь

Хорошо, в вашем конкретном сценарии я не могу использовать подделки, но базовая технология, на которую он опирается, только перенаправляет все API (она ниже, чем .NET, на самом деле она называется Detours) Я верю и допускаю все эти хакеры.

Подводя итог: если он работает на моей машине, я могу взломать его (если у меня нет физического доступа к моей машине).