Можно ли обмануть этот код 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
). Справедливо. Совершенство убивает. Я просто не хочу оставлять двери открытыми, как тот, который Дамиан любезно продемонстрировал. Если бы я выпустил систему и ее легко взломали в поле, я бы смутился по этому поводу.: -)
Ответы
Ответ 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) Я верю и допускаю все эти хакеры.
Подводя итог: если он работает на моей машине, я могу взломать его (если у меня нет физического доступа к моей машине).