Ian*_*oyd 18 security winapi ntlm kerberos
在调用时InitializeSecurityContext
,我传递给TargetName
参数的值是多少?
我正在调用这个函数InitializeSecurityContext
:
InitializeSecurityContextA(
@pAS.hcred, //[in] credentials
phContext, //[in] optional] Context handle structure
pszTargetName, //[in, optional] Target name
0, //[in] context requirements
0, //[in] reserved1, must be zero
SECURITY_NATIVE_DREP, //[in] target data representation
pInput, //[in] optional] SecBufferDescription
0, //[in] reserved2, must be zero
@pAS.hctxt, //[in, out] pointer to context handle structure
@OutBuffDesc, //[in, out] pointer to SecBufferDesc
ContextAttributes, //[out] context attributes
@lifetime); //[out] expiration timestamp
Run Code Online (Sandbox Code Playgroud)
我传递给pszTargetName
谁?
我试过了
null
: InitializeSecurityContextA(@pAS.hcred, phContext, null, ...);
""
: InitializeSecurityContextA(@pAS.hcred, phContext, "", ...);
"spn/HOSTNAME"
: InitializeSecurityContextA(@pAS.hcred, phContext, "spn/HOSTNAME", ...);
spn/HOSTNAME.DOMAIN.COM
: InitializeSecurityContextA(@pAS.hcred, phContext, "spn/HOSTNAME.DOMAIN.COM", ...);
"cargocult/PROGRAMMING"
: InitializeSecurityContextA(@pAS.hcred, phContext, "cargocult/PROGRAMMING", ...);
"http/TFS.DOMAIN.COM"
: InitializeSecurityContextA(@pAS.hcred, phContext, "http/TFS.DOMAIN.COM", ...);
"http/HOSTNAME"
: InitializeSecurityContextA(@pAS.hcred, phContext, "http/HOSTNAME", ...);
"qwertyasdf"
: InitializeSecurityContextA(@pAS.hcred, phContext, "qwertyasdf", ...);
"AuthSamp"
: InitializeSecurityContextA(@pAS.hcred, phContext, "AuthSamp", ...);
他们都要么失败,要么降级到NTLM.
注意:我的计算机已加入域,但域名未命名domain.com
,甚至hostname.domain.com
甚至没有qwertyasdf
.所以我对这些尝试失败并不感到惊讶.但人们说尝试的东西http/HOSTNAME
,所以我投入http/HOSTNAME
.
的InitializeSecurityContext
(协商)函数具有一个可选 TargetName
参数:
pszTargetName [in,optional]
指向以null结尾的字符串的指针,该字符串指示服务主体名称(SPN)或目标服务器的安全上下文.
应用程序必须提供有效的SPN以帮助缓解重放攻击.
这应该是什么?
我正在尝试验证一组用户的凭据,例如:
Boolean ValidateCredentials(String username, String password, String domain)
{
...
}
Run Code Online (Sandbox Code Playgroud)
验证一组用户凭据需要使用SSPI API.第一个要调用的函数是InitializeSecurityContext
.其中一个参数InitializeSecurityContext
是"TargetName"字符串.
我尝试将其保留为null,但Application Verifier触发断点,写出错误:
VERIFIER STOP 00005003:pid 0xF08:
InitializeSecurityContext对Kerberos服务使用NULL目标或格式错误的目标.
请参阅pszTargetName获取目标值.
00000000:未使用.
00000000:没有
在这一点上,记住Negotiate
提供者将尝试使用Kerberos
,但回退到将有所帮助NTLM
.在的情况下Negotiate
,Kerberos
或者NTLM
,所述TargetName
的参数被记录为:
但那我应该通过什么?
我尝试过做SSPI知识库文章的内容,没有任何内容(即通过NULL
):
如何在Microsoft操作系统上验证用户凭据
Run Code Online (Sandbox Code Playgroud)ss = _InitializeSecurityContext( &pAS->hcred, pAS->fInitialized ? &pAS->hctxt : NULL, NULL, //<-------pszTargetName 0, 0, SECURITY_NATIVE_DREP, pAS->fInitialized ? &sbdIn : NULL, 0, &pAS->hctxt, &sbdOut, &fContextAttr, &tsExpiry);
但没有(ie NULL
)不起作用.
注意:知识库文章在2007年大规模改写.在其最初的1999年版本中,它们"AuthSamp"
作为目标传递,但也失败了.
服务主体名称
(SPN)客户端唯一标识服务实例的名称.如果在整个林中的计算机上安装多个服务实例,则每个实例都必须具有自己的SPN.如果客户端可能使用多个名称进行身份验证,则给定的服务实例可以具有多个SPN安全上下文
当前有效的安全属性或规则.例如,当前用户登录到计算机或智能卡用户输入的个人识别码.对于SSPI,安全上下文是不透明的数据结构,其包含与连接相关的安全数据,例如会话密钥或会话持续时间的指示.
从应用程序验证程序文档:
Verifier插件检测到以下错误:
在调用AcquireCredentialsHandle(或更高级别的包装器API)时直接指定NTLM包.
InitializeSecurityContext调用中的目标名称为NULL.
调用InitializeSecurityContext时的目标名称不是正确形成的SPN,UPN或NetBIOS样式的域名.
后两种情况将迫使Negotiate直接(第一种情况)或间接地回退到NTLM(在第二种情况下,域控制器将返回"未找到主体"错误,导致Negotiate回退).
插件在检测到降级到NTLM时也会记录警告; 例如,域控制器找不到SPN时.这些仅作为警告记录,因为它们通常是合法的情况 - 例如,在对未加入域的系统进行身份验证时.
在我的情况下,我对验证域是null
(因为我不知道机器的域名,或者即使有是一个域).但是如果硬编码我的开发机器的域名,结果是一样的.
更新3
pszTargetName的值,它触发AppVerifier错误,但登录成功:
null
""
"AuthSamp"
"qwertyasdf"
"avatopia.com"
)"avatopia.com"
)"avatopia.com"
)pszTargetName的值不会触发AppVerifier错误,但登录失败:
"http/HOSTNAME"
"http/TFS.DOMAIN.COM"
"frob/GROBBER"
"cargocult/PROGRAMMING"
"spn/HOSTNAME"
"spn/HOSTNAME.DOMAIN.COM"
pszTargetname的值不会触发AppVerifier错误,并且登录成功:
更新4
我想做的是:弄清楚用户名/密码是否有效.
"ian"
"pass1"
现在,该帐户ian
可能是本地帐户或域帐户的进一步皱纹.ian
在您提出要求之前,您需要决定是否是本地或域帐户.这是因为ian
可以有两个帐户:
ian
在域上 stackoverflow.com
ian
在本地机器上所以我需要指定是否我想:
stackoverflow.com
),或"."
)现在我们可以提出一个交叉参考:
Username Password Domain Machine on domain? Validate as
======== ======== ================= ================== ==============
iboyd pass1 . No Local account
iboyd pass1 (empty) No Local account
iboyd pass1 stackoverflow.com No Domain account
iboyd pass1 . Yes Local account
iboyd pass1 (empty) Yes Domain account
iboyd pass1 stackoverflow.com Yes Domain account
Run Code Online (Sandbox Code Playgroud)
更新5
它可能有助于解释我正在尝试做什么,然后也许如何做它将变得更容易.让我说我走进市中心随意的办公大楼,走进一个随机的小隔间,输入一个随机的用户名和密码:
我打算尝试登录域名TURBOENCABULATOR
.我指定我想尝试TURBOENCABULATOR
通过为我的用户名添加前缀来对域进行身份验证:
TURBOENCABULATOR\ian
Run Code Online (Sandbox Code Playgroud)
注意:我非常怀疑该网络有一个名为turboencabulator的域名,因为该名称本身仅来自罗克韦尔自动化.登录尝试几乎肯定会失败.但Windows如何检查它们?
Windows如何尝试验证这些凭据?Windows如何验证凭据:
Windows是否使用安全支持包界面?假设 Windows使用Negotiate或Kerberos进行身份验证,Windows传递的pszTarget
参数是什么?几乎可以肯定,我输入的凭证将无效.Windows将如何确定它们是否有效?Windows将调用哪些API 来验证凭证?
Windows能够验证凭证.我还要验证凭据.
也许我没有尝试连接到TURBOENCABULATOR
域,而是尝试通过将turboencabulator.com
域名添加到我的用户名来连接到域turboencabulator.com\ian
:
同样的问题适用.Windows如何验证凭据?我想做Windows所做的事情.假设Windows使用kerberos进行授权,那么Windows pszTargetName
在SSPI中作为参数传递了什么?
也许turboencabulator.com
我尝试连接到域,而不是尝试连接到turboencabulator.net
域:
请注意,在此示例中,我已将域名附加到我的用户名,而不是在其前面添加.
也许我没有尝试连接到turboencabulator.net
域,而是尝试通过在我的用户名前加上.\
as 来验证用户是否为本地(机器)帐户:
Windows如何根据本地帐户数据库验证用户名和密码?它是否将SSPI与Negotiate包一起使用?如果是这样,它通过什么价值pszTargetName
呢?
人们在谈论Web服务器,http,团队基础服务器.我真的不知道他们从哪里得到的.或者他们谈论在活动目录中编辑用户以确保存在某些东西 - 我不明白为什么我需要编辑任何东西:Windows不编辑任何东西.
TargetName
在调用InitializeSecurityContext
以验证一组凭据时我使用了什么?
以下是Application Verifier文档中的一章,说明如果有人错误地使用NTLM,他们为什么要进行测试:
为什么需要NTLM插件
NTLM是一种过时的身份验证协议,其缺陷可能会危及应用程序和操作系统的安全性.最重要的缺点是缺乏服务器身份验证,这可能允许攻击者诱骗用户连接到欺骗性服务器.作为缺少服务器身份验证的必然结果,使用NTLM的应用程序也可能容易受到一种称为"反射"攻击的攻击.后者允许攻击者将用户的身份验证会话劫持到合法服务器,并使用它来验证攻击者对用户计算机的身份.NTLM的漏洞和利用它们的方式是增加安全社区研究活动的目标.
虽然Kerberos已经存在多年,但仍然编写许多应用程序以仅使用NTLM.这不必要地降低了应用程序的安全性.但是,Kerberos无法在所有场景中替换NTLM - 主要是客户端需要对未加入域的系统(家庭网络可能是其中最常见的)进行身份验证的场景.Negotiate安全包允许尽可能使用Kerberos的向后兼容折衷,并且在没有其他选项时仅恢复为NTLM.切换代码以使用Negotiate而不是NTLM将显着提高我们客户的安全性,同时引入很少或没有应用程序兼容性.谈判本身并不是一个灵丹妙药 - 有些情况下,攻击者可以强制降级到NTLM,但这些更难以利用.但是,立即改进的是,为正确使用Negotiate而编写的应用程序自动免受NTLM反射攻击.
通过对使用NTLM的最后警告:在Windows的未来版本中,可以在操作系统中禁用NTLM.如果应用程序对NTLM具有硬依赖性,则在禁用NTLM时,它们将无法进行身份验证.
插件如何工作
Verifier插件检测到以下错误:
在调用AcquireCredentialsHandle(或更高级别的包装器API)时直接指定NTLM包.
InitializeSecurityContext调用中的目标名称为NULL.
调用InitializeSecurityContext时的目标名称不是正确形成的SPN,UPN或NetBIOS样式的域名.
后两种情况将迫使Negotiate直接(第一种情况)或间接地回退到NTLM(在第二种情况下,域控制器将返回"未找到主体"错误,导致Negotiate回退).
插件在检测到降级到NTLM时也会记录警告; 例如,域控制器找不到SPN时.这些仅作为警告记录,因为它们通常是合法的情况 - 例如,在对未加入域的系统进行身份验证时.
NTLM停止
5000 - 应用程序已明确选择NTLM程序包
严重性 - 错误
应用程序或子系统在调用AcquireCredentialsHandle时显式选择NTLM而不是Negotiate.尽管客户端和服务器可能使用Kerberos进行身份验证,但这可以通过显式选择NTLM来防止.
如何解决此错误
此错误的修复是选择Negotiate包代替NTLM.如何完成此操作取决于客户端或服务器使用的特定网络子系统.下面给出一些例子.您应该查阅您正在使用的特定库或API集的文档.
Run Code Online (Sandbox Code Playgroud)APIs(parameter) Used by Application Incorrect Value Correct Value ===================================== =============== ======================== AcquireCredentialsHandle (pszPackage) “NTLM” NEGOSSP_NAME “Negotiate”
伊恩,我想我们仍然不明白你要做什么.为了帮助您向我们提供有关您尝试执行的操作的更多信息,这里有一些关于SSPI的背景知识.您可能已经知道这一点,但只是为了确保我们在同一页面上.
SSPI通常用于通过网络验证用户.客户端调用AcquireCredentialsHandle
获取凭证句柄,然后通过调用创建安全上下文InitializeSecurityContext
.将安全缓冲区传递给服务器.请注意,SSPI并未规定如何通过安全缓冲区.您可以随意使用http,tcp,命名管道.一旦服务器收到安全缓冲区.同样,它称之为第AcquireCredentialsHandle
一个.然后它将收到的安全缓冲区传递到AcceptSecurityContext
并生成新的安全缓冲区.在某些情况下,新生成的安全缓冲区需要发送回客户端,客户端将其传递给InitializeSecurityContext并再次生成另一个新的安全上下文.这SSPI握手过程一直持续到InitializeSecurityContext
与AcceptSecurityContext
这两个回报SEC_E_OK
尽管SSPI设计用于通过网络进行身份验证,但许多应用程序实际上正在进行环回SSPI握手,这意味着客户端和服务器都在同一个盒子上.这实际上只是网络身份验证的一个特例.环回SSPI握手的最终结果是经过身份验证的SSPI安全上下文.有了这个经过身份验证的SSPI,应用程序可以做QueryContextAttributes
和ImpersonateSecurityContext
.既然你似乎不知道是什么targetName
意思,我猜你正试图做回环握手.我可能错了,但你需要告诉我们你想做什么.
要了解targetName
Kerberos中需要的原因而不是NTLM中的原因,您需要了解更多底层实现.
获取凭证句柄有两种不同的方法.通常,人们指定使用当前的安全上下文.(即您用于登录计算机的帐户).您还可以提供另一组用户名/密码.不同的安全包对术语有不同的含义credentials
.NTLM意味着它将保存密码的哈希值.Kerberos意味着它将保存票证授予票证(TGT).对于SSPI程序员,您无需担心这一点.
现在,当客户端将获取的凭证句柄传入时InitializeSecurityContext
,同样地,不同的安全包将执行不同的操作.NTLM将在第一次InitializeSecurityContext
调用时生成NEGOTIATE数据包.在生成NEGOTITATE数据包的过程中没有涉及其他机器.Kerberos包非常不同.它将与KDC交谈以请求所请求服务的服务票证.该服务由Kerberos中的服务主体名称(SPN)标识.我不能在这里详述所有细节.净网络是针对NTLM的服务请求是无目标的,同时针对Kerberos的服务请求.您可以使用NTLM身份验证方法将相同的NTLM NEGOTIATE数据包用于不同的服务.但是,您需要使用Kerberos身份验证方法为不同的服务使用不同的Kerberos服务票证.这就是为什么在调用InitializeSecurityContext
Kerberos/Negotiate时,你需要提供targetName
.
当KDC收到服务票证的请求时,它会搜索其LDAP数据库并找出与指定帐户关联的帐户servicePrincipalName
.该帐户可以是AD用户帐户或AD计算机帐户.KDC将使用目标服务帐户的主密钥(由帐户密码生成)来加密会话密钥.此加密的会话密钥稍后将从客户端传递到服务器.
现在,记得我说服务器也需要做AcquireCredentialsHandle
,我说有两种主要的方法来获取凭证?我想你正在使用第一种方法来获取凭证句柄.这意味着它将使用当前的安全上下文.在正常的网络认证情况下,这可以通过以下示例来说明.如果您的服务器是HTTP服务器,它将是您的IIS服务器的服务帐户.IIS服务器将使用其服务帐户主密钥来解密加密的会话密钥.一旦获得会话密钥,客户端和服务器就使用会话密钥继续通信以进行加密和解密.
如果它是一个环回SSPI场景,那就更棘手了.如果您正在运行domain\jane
并自行循环.您需要为domain\jane指定SPN.什么是域\ jane的SPN.如果检查AD用户对象,则默认情况下没有.您需要手动修复它.
曾经有一件事对我有用,但它没有记载.您可以将用户的UPN(即jane@domain.com)指定为SPN.这适合我.你可以尝试一下.
如果这不起作用,另一种解决方法是使用第二种方法来执行服务器部分AcquireCredentialsHandle
.domain\jane
您可以指定其他服务帐户凭据,而不是使用凭据句柄.您可以确保服务帐户具有正确的SPN集.然后,您可以在您的服务帐户中使用该服务帐户的SPN InitializeSecurityContext
.当然,这也意味着您需要在代码中对服务帐户的密码进行硬编码.您需要小心并确保完全锁定此服务帐户,以便即使密码被盗,您的AD环境也不会有很大的风险.
该的TargetName是,用户名“服务器”代码将被运行的。
ian@stackoverflow.com
steve@stackoverflow.com
steve@stackoverflow.com
该Negotiate
验证包将尝试使用Kerberos
。如果不能,它将尝试回退到NTLM
.
Kerberos
.Kerberos
你必须提供一个TargetNameKerberos
根本无法实现功能考虑到所有相关方,问题变成了:
我指定什么TargetName?
这是了解TargetName对 Kerberos 意味着什么很重要的地方:
steve@stackoverflow.local
steve@stackoverflow.local
是唯一能够解密它的人steve@stackoverflow.local
因为我steve@stackoverflow.local
在TargetName 中指定这就是史蒂夫如何知道 blob 是有效的,它是加密的,所以只有他才能解密。
我必须告诉 Kerberos我会将加密的 blob 提供给谁,以便域控制器知道为谁加密。
所以在上面的可能名称列表中,三个值起作用:
InitializeSecurityContext(credHandle, context, "steve@stackoverflow.local", ...);
InitializeSecurityContext(credHandle, context, "stackoverflow.local\steve", ...);
InitializeSecurityContext(credHandle, context, "steve", ...); //if we're in the same forest
Run Code Online (Sandbox Code Playgroud)
所以你可以看到为什么我之前尝试调用InitializeSecurityContext都失败了:
InitializeSecurityContextA(credHandle, context, null, ...);
InitializeSecurityContextA(credHandle, context, "", ...);
InitializeSecurityContextA(credHandle, context, "spn/HOSTNAME", ...);
InitializeSecurityContextA(credHandle, context, "spn/HOSTNAME.DOMAIN.COM", ...);
InitializeSecurityContextA(credHandle, context, "cargocult/PROGRAMMING", ...);
InitializeSecurityContextA(credHandle, context, "http/TFS.DOMAIN.COM", ...);
InitializeSecurityContextA(credHandle, context, "http/HOSTNAME", ...);
InitializeSecurityContextA(credHandle, context, "qwertyasdf", ...);
InitializeSecurityContextA(credHandle, context, "AuthSamp", ...);
Run Code Online (Sandbox Code Playgroud)
因为我没有将Steve指定为TargetName;我在指定一些毫无意义的东西:
spn/HOSTNAME
Run Code Online (Sandbox Code Playgroud)
公平地说,人们确实一直告诉我通过"spn/HOSTNAME"
。
在上述情况下,我必须知道“服务器”代码将作为steve@stackoverflow.local
.
那是一种痛苦。我的意思是,当我知道是史蒂夫时就好了。但是如果我正在与远程机器交谈,我必须找出代码运行的用户帐户?
iisagent@stackoverflow.local
?sqldaemon@stackoverflow.local
?幸运的是(?),Kerberos 创建了别名(称为服务原则名称- 或 SPN):
http://bugtracker.stackoverflow.local
iisagent@stackoverflow.local
iisagent@stackoverflow.local
HTTP/bugtracker.stackoverflow.local
HTTP/bugtracker.stackoverflow.local
? iisagent@stackoverflow.local
如果您希望将其用作TargetName ,则所有这些都要求您知道 SPN 。各种标准 Microsoft 产品在安装时都会注册 SPN:
HTTP/[servername]
MSSQLSvc/[servername]:1433
SMTPSVC/[servername]
HOST/[servername]
这些都是无证的,如果配置不正确,会让你的生活陷入困境。
但绝非必须提供SPN。SPN 只是一个别名,旨在让您的生活更轻松更困难。
这大致相当于尝试指定"stackoverflow.com",而不是简单地使用"35.186.238.101"。
SSPI 被设计为围绕不同安全算法的通用包装器。使用 API 的方法非常简单:
InitializeSecurityContext
并获得一个 blobAcceptSecurityContext(blob)
,并返回一个 blobInitializeSecurityContext(blob)
,并返回一个 blobAcceptSecurityContext(blob)
,并返回一个 blob双方不断来回,直到函数停止返回需要发送到另一方的 blob:
因此,使用 SSPI,您可以来回进行这种乒乓操作,直到您被告知停止为止。因此,他们能够将每个身份验证方案硬塞进那个乒乓直到被告知停止的高级抽象。
您可以通过您使用的任何通信渠道传输 blob。
如果您通过 TCP/IP 与远程服务器通话,那么您可能会使用它:
// Open connection to server
sockConnect(162.210.196.166, 1433);
blob = null;
Boolean bContinue = InitializeSecurityContext(ref blob);
while (bContinue)
{
sockWrite(blob); //send the blob to the server
blob = sockRead(); //wait for the server to return a blob
bContinue = InitializeSecurityContext(ref blob);
}
Run Code Online (Sandbox Code Playgroud)
如果您通过 http 进行操作:
blob = null;
Boolean bContinue = InitializeSecurityContext(ref blob);
while (bContinue)
{
http = new HttpRequest("http://4chan.org/default.aspx");
http.AddHeader("X-SSPI-Blob", blob.ToBase64());
http.Send();
blob = http.ReasponseHeader["X-SSPI-Blob"];
if (blob.IsEmpty())
break;
bContinue = InitializeSecurityContext(ref blob);
}
Run Code Online (Sandbox Code Playgroud)
SSPI API 不关心您来回传输 blob - 只是您必须来回传输它。
如果您愿意,您甚至可以使用运营商 pidgeon、Skype 或电子邮件。
归档时间: |
|
查看次数: |
6897 次 |
最近记录: |