是否有可能欺骗此WindowsIdentity代码使用错误的用户?

T.J*_*der 23 .net c# authentication

TL; DR可以包含在用户令牌WindowsIdentityToken属性(比如someIdentity.Token)被欺骗这样的:

var validated = new WindowsIdentity(someIdentity.Token);
Run Code Online (Sandbox Code Playgroud)

...将返回一个声称代表用户的实例,该用户实际上尚未经过身份验证,但具有IsAuthenticated设置true,有效.Name.User属性等?

下面我对此进行了一些界定; 它可能不可能完全欺骗.


全文:

这个答案中,Damien_The_Unbeliever巧妙地证明了我的一些代码可能会被欺骗,因为它认为它在WindowsIdentity实例中没有有效的身份验证用户.长话短说,我的代码假设if Thread.CurrentPrincipal.Identity是一个实例,WindowsIdentity并且IsAuthorizedtrue,它代表一个经过身份验证的用户,我可以依赖于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....
}
Run Code Online (Sandbox Code Playgroud)

(这个代码使用线程而不是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);
Run Code Online (Sandbox Code Playgroud)

果然,如果你这样做然后调用上面的代码,我的代码就会被愚弄.Kudos Damien.

因此,在真正的军备竞赛方式中,这是我的修改后的代码,它可以捕获欺骗并拒绝它:

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....
    }
}
Run Code Online (Sandbox Code Playgroud)

如您所见,它Token从提供的标识中获取并使用该标记创建 WindowsIdentity实例.如果身份的SID匹配,我们继续,信任经过验证的身份.(本为文档WindowsIdentity(IntPtr token)说的初始值IsAuthenticatedfalse,但这是在我的测试假设我已经有一个有效的用户令牌创建它完全错误的.)

我可以看到可以欺骗的唯一方法是使用欺骗性的用户令牌,但仍然通过Windows对其进行的验证.这对我来说似乎不太可能.但是,这对我来说是一个无知的领域.


边界:

我应该注意到,我只是在这里拍摄合理程度的单点登录安全性,尽我所能.如果恶意应用程序已经成功开始拦截系统调用/受到威胁的Windows本身,那么,我将无法做很多事情.正如Damien在对其他问题的评论中指出的那样,他可能会构建一个完全忽略强命名的主机容器(因此可能会给我一个完全假的WindowsIdentity类型).很公平.完美杀死.我只是不想像Damien亲切地展示的那样打开门.如果我发布了一个系统,并且很容易在现场进行黑客入侵,那我就很尴尬.:-)

Sim*_*ier 7

为了证明这是可行的,让我们使用名为" Microsoft Fakes " 的酷炫Visual Studio插件(名称本身意味着很多......).

伪造本身与Visual Studio的测试功能有关,但它将证明这一点.您可以按照标准教程设置项目,并为System添加一个fakes程序集(实际上是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");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这是测试项目中的测试代码:

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();
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这是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>
Run Code Online (Sandbox Code Playgroud)

这意味着我想要整个System.Security.Principal命名空间,我建议你为两个项目使用框架4.6并添加相应的TargetFrameworkVersion属性.

现在,当您运行测试时,您将看到:

在此输入图像描述

好吧,在你的特定场景中,我可能无法使用假货,但它所依赖的底层技术只是重新路由所有API(实际上它比.NET低,它叫做Detours)我相信并且允许所有这些hackery.

总结一下:如果它在我的机器上运行,我可以破解它(除非我没有物理访问我的机器).