「安全研究」从mimikatz学习万能密码——下

续上篇文章
我这里测了一下skeleton攻击并抓取了流量包,客户端发送的AS-REQ请求存在AES加密
「安全研究」从mimikatz学习万能密码——下_第1张图片

但是域控的响应中却没有AES加密同时确实是报错STATUS_NOT_SUPPORTED

「安全研究」从mimikatz学习万能密码——下_第2张图片
我们继续看下kdcsvc.dll的流程在域控通过kdcgetuserskey函数接收到用户的密码后不单单是会走
SamIRetrieveMultiplePrimaryCredentials函数同时会将密码传递给kerbhashpassword函数最终调用cryptdll.dll的导出函数CDLocateCSystem选择对应的加密系统对用户传入的凭据进行处理
「安全研究」从mimikatz学习万能密码——下_第3张图片
接下来就可以看到mimikatz继续利用
kull_m_process_getVeryBasicModuleInformationsForName函数也是通过pebldr从lsass进程中获取cryptdll.dll的模块信息,同时获取了该dll的句柄保存在localaddr中
「安全研究」从mimikatz学习万能密码——下_第4张图片
然后通过CDLocateCSystem函数找到RC4类型的加密系统存储在pCrypt结构体中,可以看到该加密类型的一系列函数存储在结构体中
「安全研究」从mimikatz学习万能密码——下_第5张图片
接下来给最开始定义的extensions赋值,将cryptdll.dll!rc4HmacInitialize,cryptdll.dll!rc4HmacDecrypt函数地址传入
「安全研究」从mimikatz学习万能密码——下_第6张图片
接下来
kull_m_remotelib_CreateRemoteCodeWitthPatternReplace函数中传入了几个函数名其实是传入函数的地址
「安全研究」从mimikatz学习万能密码——下_第7张图片
「安全研究」从mimikatz学习万能密码——下_第8张图片
第一个参数是lsass进程的内存属性,第二个是rc4_init函数的地址,第三个参数rc4_end函数地址-rc4_init函数地址代表的是rc4_init到rc4_end之间的内存内容其实这块空间包含了init函数decrypt两块函数内容,第四个参数是存储extensions的结构体指针,第五个参数是lsass进程的指针
「安全研究」从mimikatz学习万能密码——下_第9张图片
跟进后首先通过
kull_m_remotelib_GetProcAddressMultipleModules函数这个函数主要也是调用kull_m_process_getVeryBasicModuleInformations函数通过PEBldr获取模块信息,给RemoteExt结构体也就是extensions结构体数组填充对应的值
「安全研究」从mimikatz学习万能密码——下_第10张图片
可以看到被填充后的数据如下
「安全研究」从mimikatz学习万能密码——下_第11张图片
这里是新创了个空间aLocalAddr大小跟rc4_end-rc4_init函数地址相距的大小一致,并把rc4_end-rc4_init函数地址内存的内容拷贝到新空间中,并将extensions[j].ToReplace的值在该空间中查找其对应的位置,后续用extensions[j].Point的值替换该值
「安全研究」从mimikatz学习万能密码——下_第12张图片
我们可以看到rc4_init函数到rc4_end函数内存空间中还有rc4_init_decrypt函数其中rc4_init函数与rc4_decrypt函数中有很多函数不过名字为0x4a4a这种一串奇怪的数字,同时我们前面被填充好的extensions结构体数组也存在这些奇怪的数字并且存在正常的模块名称及其对应的函数名以及函数对应的地址,就是通过内存搜索这些特殊字符然后进行对应的替换。
「安全研究」从mimikatz学习万能密码——下_第13张图片
「安全研究」从mimikatz学习万能密码——下_第14张图片
替换后这些函数内容应该是这样的
「安全研究」从mimikatz学习万能密码——下_第15张图片
该空间内存内容替换为正常的函数内容后使用kull_m_memory_alloc函数在lsass进程中开辟了一块可读可写可执行的内存空间并且大小也是函数rc4_int到函数rc4_end内存空间的大小并通过kull_m_memory_copy函数将该内容拷贝lsass进程中拷贝到新开辟的空间中
「安全研究」从mimikatz学习万能密码——下_第16张图片
可以看到下图左边是lsass进程中新开辟的内存空间的内容与我们之前函数空间的内容一致。新开辟的地址是000001f3`d4fb0000
「安全研究」从mimikatz学习万能密码——下_第17张图片
所以函数
kull_m_remotelib_CreateRemoteCodeWitthPatternReplace主要的目的就是将rc4_int,rc4_decrypt函数修复后将代码注入到lsass空间中,后续通过kull_M_memory_copy函数将原地址7ffa3cabf628指向的是cryptdll!rc4HmacInitialize函数的指针替换为了0xc79bcdfd88地址中存储的8字节的值也就是01f3d4fb0000,这块地址指向的我们自己定义的kuhl_misc_skeleton_rc4_init函数的地址也就是hook了原始的rc4HmacInitialize函数
「安全研究」从mimikatz学习万能密码——下_第18张图片
从下图可以看到该地址处替换前地址是00007ffa3cab84c0,右侧为替换后
「安全研究」从mimikatz学习万能密码——下_第19张图片
「安全研究」从mimikatz学习万能密码——下_第20张图片
原始的RC4_init函数被hook后,后续又开始计算自己定义的rc4_decrypt函数相较于rc4_init函数的偏移,然后ptrValue加上偏移就是指向我们自定义rc4_decrypt函数的地址指针,aLsass.address也通过偏移计算得到lsass进程中原始的rc4_decrypt函数的地址的指针,然后通过kull_m_memory_copy函数将我们的rc4_decrypt函数替换掉原始的
「安全研究」从mimikatz学习万能密码——下_第21张图片
可以看到又是调用WriteProcessMemory函数将原地址7ffa3cabf638指向的是cryptdll!rc4HmacDecrypt函数的指针替换为了0xc79bcdfc20地址中存储的8字节的值也就是01f3d4fb016c,这块地址指向的我们自己定义的
kuhl_misc_skeleton_rc4_init_decrypt函数的地址也就是hook了原始的rc4HmacDecrypt函数
「安全研究」从mimikatz学习万能密码——下_第22张图片
从下图我们可以看到hook前的情况7ffa3cabf638存的是原始的rc4HmacDecrypt函数
「安全研究」从mimikatz学习万能密码——下_第23张图片
到这里skeleton模块函数已经全部分析完,接下来我们来分析一下我们自定义的rc4初始化函数,在rc4init函数中首先有个kiwiKey数组我们的认证都是传输的hash这个数组正好也是32位很有可能就是skeleton的默认密码mimikatz的hash 通过计算mimikatz的hash发现这里确实就是存的skeleton的密码hash

「安全研究」从mimikatz学习万能密码——下_第24张图片
「安全研究」从mimikatz学习万能密码——下_第25张图片
通过LocalAlloc分配了内存指向pContext,将Key(用户的输入的原始密码hash的地址)传入rc4HmacInitialize函数中生成原始密码的秘钥流完成后续的rc4加密解密的操作,将生成的秘钥流拷贝到开始分配的空间中大小为16字节,接着将kiwiKey(mimikatz字符串的hash)传入rc4HmacInitialize函数中生成mimikatz的秘钥流,接着又继续拷贝到开始分配的空间中大小为16字节,最后将原始的密码hash地址Key也拷贝到pContext空间中
「安全研究」从mimikatz学习万能密码——下_第26张图片
我们给rc4HmacInitialize函数下断点域控输入net use \win2016\c$/user:“test.com\administrator” “mimikatz”,断下来后我们执行完*(LPCVOID *) ((PBYTE) *pContext + 32)= Key这段代码就可以看到pContext存储的内容了也就是上图反汇编中rax指向的地址,我们查看dq rax 第一排是原始密码生成的秘钥流,第二排是mimikatz生成的秘钥流,第三排前8字节是我们输入的原始密码hash的地址查看该地址的内容发现就是mimikatz的hash,这里由于我们的原始密码输入的就是mimikatz所以第一排第二排的秘钥流一致。
「安全研究」从mimikatz学习万能密码——下_第27张图片
由于rc4的对称算法加密与解密是一致的都是用上面的秘钥流,解密函数中传入了开始init函数中的pContext以及被加密的数据,首先函数里面也是先分配了一段空间buffer,将待解密的数据拷贝到buffer中,将buffer以及pContext传入rc4HmacDecrypt函数中进行解密,这里是利用第一次的秘钥流解密如果解密成功的话就返回了,如果解密失败会再次调用rc4HmacDecrypt函数使用第二次我们设置的mimikatz生成的秘钥流解密如果成功就会改变pContext存在的原始Key改成我们设置的kiwikey的值,这样的方式就保证了我们无论是输入正确的密码还是我们设置的kiwikey来走rc4初始化加密解密流程都是可以通过的。
「安全研究」从mimikatz学习万能密码——下_第28张图片
「安全研究」从mimikatz学习万能密码——下_第29张图片
自定义kiwikey:zhuzhuxiaoba重新编译后认证成功,不过当前的mimikatz的skeleton万能密码只支持kerberos流程,其实在ntlm认证流程中也是可以实现万能钥shi的早期的万能钥shi的恶意样本就是这样操作的。通过在MSV1_0.dll中定位函数MsvpSamValidate,MsvpSamValidate函数中有一个对MsvpPasswordValidate函数的调用,通过hook该函数,同样的可以实现万能密码的功能。github上有个类似的利用笔者在win10系统上测了一下确实可以利用,不过在server上未能复现「安全研究」从mimikatz学习万能密码——下_第30张图片

3.防御方案

由于该攻击是对lsass进程进行了注入, 从Windows 8.1(和Server 2012 R2)开始,Microsoft引入了一项称为LSA保护的功能。此功能基于PPL技术,它是一种纵深防御的安全功能,旨在“防止非管理员非PPL进程通过打开进程之类的函数串改PPL进程的代码和数据”。防止对进程lsass.exe 的代码注入,这样一来就无法使用 mimikatz 对 lsass.exe 进行注入,相关操作也会失败。在注册表HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa

添加RunAsPPL=dword:00000001,重启就可以开启了PPL保护了
「安全研究」从mimikatz学习万能密码——下_第31张图片
开启后mimikatz注入lsass进程的行为将会失败,虽然mimikatz后面又增加了一个mimidrv.sys驱动来绕过PPL保护,但是加载驱动这一行为已经有明显的日志可以供我们进行检测。

windows日志4697记录了mimidrv.sys驱动的安装
「安全研究」从mimikatz学习万能密码——下_第32张图片
sysmon日志13可以很明显看到mimidrv服务以及对应的驱动程序
「安全研究」从mimikatz学习万能密码——下_第33张图片
我们可以使用zBang 工具扫描当前的域控环境是否已经被注入了万能密码。

https://github.com/cyberark/zBang),因为Skeleton Key 是注入恶意代码到 lsass.exe 进程的,所以它只存在于内存中,如果域控制器重启,注入的 Skeleton Key 将会失效。

「安全研究」从mimikatz学习万能密码——下_第34张图片
这就是整篇文章已发出了,

关注我,持续更新文章

查看【网络安全学习资料·攻略

你可能感兴趣的:(程序员,安全,网络,1024程序员节,网络安全,安全,web)