这次真实客户授权测试的目标,是识别承载敏感文档的检索系统,取得对应嵌入向量,并判断敏感信息能否从向量中恢复。最终得到的候选值通过了独立验证,但到达结果的过程远比“导出向量,运行反演脚本”复杂。多数时间消耗在真实资产识别、Windows 权限判断、跨主机认证和失败结果的解释上。
本文按有证据支持的推进关系重建全过程。每一阶段说明已有条件、实际检查、观察结果、失败分支,以及下一步为何成立。后半部分集中分析 AI 辅助执行中的错误:基础知识不足首先造成判断失准,缺少结果核验又让错误判断继续支配后续动作。
客户名称、真实网段、账户、凭据、密钥、文档名称和最终敏感值均已替换。DC-A、WIN-A、LINUX-A 分别代表域控、Windows 成员服务器和 Linux 主机;SERVICE_USER、LOCAL_ADMIN_A、DOMAIN_ADMIN 为角色占位符。代码包含脱敏后的命令摘录,以及为解释检查方法整理的示例;数组回读、文件摘要核对和异常处理等示例不代表原始记录逐字包含了这些步骤。尖括号中的内容均为占位符。输出块是脱敏后的关键字段摘录,省略了原始日志中的身份信息。
一、初始条件与任务拆分
最初可见三台主机,已有线索是一组来自前序授权测试的低权限凭据。Linux 主机没有可直接使用的登录凭据。目标提示指向 RAG 和嵌入向量,但没有指出哪台机器是真实数据载体。另有一个约一万条候选的词表可用于后续验证。
任务拆成五个可独立验证的问题:真实检索系统在哪里;什么身份能进入该系统;敏感内容是否以明文属性保存;若只有向量,编码模型和候选范围是否足够明确;得到候选后如何确认正确。顺序不能倒过来:如果没有确认真实数据面,后面的反演方法选择再精细也没有对象。
| 主机代号 | 初始观察 | 需要回答的问题 |
|---|---|---|
| DC-A | 域目录、文件共享、远程桌面及标准域服务 | 已知身份能读什么,不能执行什么 |
| WIN-A | 研究门户、Qdrant、MongoDB、Windows 管理接口 | 门户是否连接真实数据,是否存在可验证的本地权限路径 |
| LINUX-A | 外部主要看到 SSH | 是否承载仅本机可达的服务,以及可用认证方式是什么 |
初始网络探测出现了一个误导:大范围存活探测把大量地址标为在线,但后续端口探测并没有发现相应主机服务。初步分析将此归因于网关代答;现有证据只能确认“存活标记不能用来证明真实资产数量”,缺少抓包证据时不把具体代答机制写成定论。这类端口与服务核对对应 [ATT&CK T1046:网络服务发现](https://attack.mitre.org/techniques/T1046/)。
ip route
nmap -Pn -sT -p 22,53,88,135,139,389,445,464,636,3389,5985,5986 <HOST>这里关注的是同一地址能否返回稳定、可解释的服务响应。端口拒绝、超时、认证失败和应用层报错分别属于不同层,不能全部压成一个“通”或“不通”。
二、先测身份边界,再谈远程执行
已知身份在不同主机和协议上的能力并不相同。WIN-A 的文件共享和远程桌面可用;DC-A 的域共享和部分目录查询可读,但管理共享、WMI 和远程管理接口拒绝访问。SSH 也没有因为 Windows 侧密码有效就自动接受同一组凭据。使用现有身份对应 [T1078:有效账户](https://attack.mitre.org/techniques/T1078/),实际建立 RDP 会话对应 [T1021.001](https://attack.mitre.org/techniques/T1021/001/);被拒绝的域控登录不能计入成功路径。
| 验证面 | 观察结果 | 能支持的结论 |
|---|---|---|
| WIN-A SMB 与 RDP | 可认证并访问相应资源 | 已建立成员服务器访问入口 |
| DC-A 普通域共享 | 可读 | 存在受限文件读取能力 |
| DC-A 管理共享 | 拒绝 | 不能据此声明管理权限 |
| DC-A LDAP | 可做部分只读查询 | 可以收集目录信息 |
| DC-A RDP | 探测标记积极,但实际登录报权限不足 | 凭据有效与远程登录权必须分开 |
| WinRM、WMI | 对初始身份拒绝 | 没有获得相应执行通道 |
| SSH | 拒绝 | 需要继续区分账户、密钥、认证方式与授权配置 |
whoami
whoami /groups
whoami /priv
net localgroup Administrators
net localgroup "Remote Desktop Users"
net localgroup "OpenSSH Users"这一步原本应该成为后续行动的边界,实际却出现严重误判。DC-A 的 RDP 探测工具给出积极标记,客户端日志也出现 framebuffer 初始化,于是连接被当成了命令会话。会话持续几十秒,又被拿来解释成某条等待命令执行结束。
真正的反证来自登录界面:
To sign in remotely you need the right to sign in
through Remote Desktop Services.此前看到的是登录错误画面存活到超时,没有证据证明进入了可执行命令的用户会话。建立在这一假设上的命名管道、回传脚本和输出通道设计都失去了前提。判断应当退回到已经验证的边界:初始身份对域控主要只有只读访问,远程执行尚未成立。
这不是偶然看错一条日志。基础知识缺口在于没有分清四个状态:网络可达、身份认证、登录授权、目标执行。只有前两项成立时,不能把后两项补出来。
三、研究门户看起来像 RAG,数据层却不支持
WIN-A 上的门户具备研究资料列表、仪表盘、登录入口和活动区。介绍页写明依赖 Qdrant 做嵌入检索,MongoDB 保存元数据,活动区还有更新嵌入的记录。这些界面元素很容易形成“目标已经找到”的判断。
第一轮核对从 Qdrant 的只读接口开始:
curl -sS http://<WIN_A>:6333/collections
curl -sS http://<WIN_A>:6333/telemetry关键观察为集合为空,遥测没有显示与门户声称的数据活动相匹配的写入。查询记录主要对应测试期间发起的读取。单靠这个结果还不能排除权限、加载时机或错误实例,因此又继续检查门户程序和元数据服务。
Qdrant:
collections = []
没有与门户活动对应的写入证据
MongoDB:
admin
config
local
Portal:
Qdrant / MongoDB 引用出现在介绍文案
未发现对应的实际后端调用证据门户程序的可见模板与页面路由基本对应,关于数据库的字符串出现在介绍内容中。MongoDB 则只显示系统库,没有承载页面所宣称的研究资料。对本机常见向量及模型数据扩展名的查找,也没有得到支持真实数据管道存在的结果。
这些证据的组合比“页面写了 RAG”更可靠:空向量集合、缺少业务元数据、程序未见对应调用,互相指向同一个问题。结论收敛为“这套门户不是当前目标数据的有效入口”。这不等于证明任何时候都没有外部后端,更不能仅凭字符串扫描宣布彻底逆向完成。
门户登录也走过失败分支。多个已知身份与候选口令组合返回相同错误,表单响应没有提供新的状态差异。继续扩大尝试不能补上后端数据缺失的问题,因此该方向被降级。后续精力转向主机内部和另一台 Linux 机器。
为什么还要从内网再看一次
外部只见 LINUX-A 的 SSH,不足以排除“服务对内网来源开放”。因此又从 WIN-A 的已有访问位置检查域控和 Linux 主机的关键端口,比较外部视角与内部视角是否存在差异。
Test-NetConnection <LINUX_A> -Port 22
Test-NetConnection <LINUX_A> -Port <CANDIDATE_PORT>
Test-NetConnection <DC_A> -Port <CANDIDATE_PORT>两种视角都没有发现可直接访问的真实 RAG 接口。这个结果排除了若干来源地址差异假设,但没有证明服务不存在。服务仍可能只监听 Linux 本机回环地址;只有取得主机内访问后,才能检查这个假设。
DNS 中另有指向旧网段的记录。区传送被拒,反向查询和部分目录查询也失败。旧网段未通过实际服务验证,因此不能把 DNS 返回的地址直接当成新增攻击目标。这些记录具有陈旧迹象,但 DNS 枚举没有完成,仍有未验证部分。
四、Windows 枚举经历了哪些否定结果
在 WIN-A 取得低权限访问后,winPEAS 两次未能提供有效报告。输出文件很小,内容是可执行文件不存在或无法运行。记录显示文件落地受到终端防护影响;这只能说明工具交付或运行受阻,不能用来证明主机没有提权面。
于是改为逐项检查原生系统状态。每个检查都对应明确假设,保留失败结果,是为了避免后面在相同条件下重复尝试。
whoami /priv
sc.exe query state= all
schtasks.exe /query /fo LIST /v
cmdkey.exe /list
Get-Volume| 检查方向 | 本次记录 | 决策 |
|---|---|---|
| 令牌权限 | 初始身份未见关键模拟权限 | 不继续把依赖该权限的路线当作默认选项 |
| 安装策略 | 未发现已启用的高权限安装组合 | 暂不沿该配置路线推进 |
| 服务权限与文件 ACL | 被检查服务未见低权限可写入口 | 未证明服务替换或路径劫持可行 |
| 已缓存凭据 | 常用凭据管理位置未得到有效线索 | 转向部署与初始化文件 |
| 计划任务、启动项 | 未找到与目标进程对应的启动项 | 仅记录启动来源尚未查明 |
| 用户配置目录 | 部分管理用户目录无法读取 | 标记为权限受限,等待权限变化后重查 |
| 安装与初始化残留 | 出现历史口令和配置介质线索 | 继续判断当前有效性及清理状态 |
初步分析曾从“常见启动位置没有命中”推导出进程必由宿主平台拉起。这一步超出了证据。没有找到计划任务、服务或启动项,只能说明这些位置未解释进程来源;缺少完整父进程链和宿主日志时,不能把启动者写死。
漏洞库搜索同样没有直接带来入口。检索结果中有不同版本、不同操作系统、不同虚拟化前提或只造成拒绝服务的条目。产品名一致不是适用性证明。未使用条件不匹配的漏洞,也不把“未检索到现成漏洞”写成软件绝对安全。
终端和脚本本身制造了假阴性
多次枚举失败来自执行通道。复杂 PowerShell 表达式穿过终端、cmd 和 PowerShell 后,引号、变量及管道含义发生变化,最终表现成空输出或语法错误。另有服务列表被终端缓冲区截断,视觉上像是已经列举完成。
修正办法是把复杂逻辑写进脚本,在目标上明确调用,并把标准输出和错误一起保存。下面是这一处理方式的示意,不是原始输出全文:
powershell.exe -NoProfile -File .\inventory.ps1 *> .\inventory.log
Get-Item .\inventory.log | Select-Object Length, LastWriteTime
Get-Content .\inventory.log对目录遍历也需要保留失败路径。只在异常后继续循环而不记录,会把“没有权限”“路径不可读”和“没有目标文件”混成同一个零结果。
try {
Get-ChildItem -LiteralPath $CandidatePath -Force -ErrorAction Stop
}
catch {
Write-Warning ("Enumeration failed: " + $CandidatePath)
Write-Warning $_.Exception.Message
}这类错误直接影响后续判断。若输出没有完整采集,任何“排除该路线”的结论都应暂停。
原生枚举具体查了什么
服务检查不仅列名字,还核对运行身份、二进制路径、服务 DACL 与目录 ACL。MongoDB 以 NetworkService 运行,其路径带引号;已检查的程序目录对普通用户只开放读和执行,没有发现可直接替换程序的写权限。初始令牌仅见有限的普通权限,没有观察到 SeImpersonatePrivilege,因此依赖该前提的路线没有继续推进。
sc.exe qc MongoDB
sc.exe sdshow MongoDB
sc.exe sdshow sshd
icacls "C:\<APPLICATION_DIRECTORY>"
reg.exe query HKLM\SOFTWARE\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevated
reg.exe query HKCU\SOFTWARE\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevated启动来源检查覆盖计划任务、Run/RunOnce、启动目录、Winlogon、Active Setup 以及 WMI 永久事件订阅。任务清单没有命中目标进程名称,其他检查也未解释启动来源。这里仍然只能保留“来源未查明”,不能因为检查项目多就把猜测升级成事实。
凭据侧检查了凭据管理器、用户 Credentials/Protect 目录、浏览器配置及 Windows 诊断日志。部分位置为空,部分位置未得到可用内容。VSS 查询返回权限不足,这一项没有完成。安装残留中,Panther 下的应答文件提供了旧口令线索,另一份 Sysprep 应答文件主要是设备配置,没有提供新凭据。每项的失败原因不同,下一步才会收敛到初始化流程,而不是继续无差别地搜密码。
漏洞检索也按产品逐项展开:MongoDB 的旧版本条目、QEMU Guest Agent 的拒绝服务条目,以及依赖特定虚拟化接口的 Windows 提权条目,都没有与当时主机的版本和运行前提对齐。这一轮没有得到可直接使用的已知漏洞,因此配置残留和身份关系成为优先方向。
五、从历史口令到仍可读取的配置介质
安装应答文件先暴露了一条旧口令。第一反应是把它当作当前管理员凭据,但针对不同身份范围的验证均失败。后续凭据记录又显示它属于历史状态,因此不能把明文出现本身等同于当前可用。
这条失败线索仍然有价值:文件内容指向自动初始化和口令轮换过程,于是检查从“还有哪些密码”转向“初始化系统如何取得并清理新密码”。清理脚本声称卸载配置介质,系统卷信息却仍能看到对应介质。
初始化组件是 cloudbase-init,配置介质带有 configdrive 的典型标识。检查把安装应答文件、初始化脚本与卷状态连起来:应答文件保存的是旧值,初始化流程负责设置另一组值,而配置介质可能仍保留输入元数据。旧口令验证失败没有让这条线索终止,反而说明需要追踪轮换后的来源。
Get-Volume |
Select-Object DriveLetter, FileSystemLabel, DriveType, HealthStatus, Size
Get-CimInstance Win32_Volume |
Select-Object DeviceID, DriveLetter, Label关键不是发现一个盘符,而是确认“卸载盘符”和“数据不可再读”并非同一件事。该实例中,普通 dir 调用没有正确处理卷 GUID 路径,改用 PowerShell 的 Get-ChildItem -LiteralPath 后才能列出初始化内容。问题出在路径传递和解释方式,不能把第一次列举失败当成卷已不可读。路径与元数据字段摘录如下:
\\?\Volume{REDACTED-VOLUME-ID}\openstack\latest\meta_data.json
{
"machine_name": "<WIN_A>",
"admin_pass": "<REDACTED_BOOTSTRAP_SECRET>"
}这里可以确认初始化秘密残留并可读。不能进一步声称执行某个卸载选项就等于安全擦除:清理必须覆盖介质本身、后端挂载和秘密轮换,并从实际可读性验证结果。对应 [T1552.001:文件中的凭据](https://attack.mitre.org/techniques/T1552/001/)。这里读的是配置介质文件,不是云实例元数据 API,不能仅因字段属于元数据就标为 T1552.005。
清理逻辑中的 mountvol /D 主要移除挂载点。卷仍能经 GUID 路径读取,是本次关键证据。把它简单改成另一条卸载命令,也不能自动证明元数据已经销毁;这一区别关系到修复是否真正阻断了同一路径。
密码正确,但账户状态阻止登录
这组残留秘密并没有直接打开管理共享。针对本地管理账户验证时,出现了明确状态码:
STATUS_PASSWORD_MUST_CHANGE
0xc0000224这一状态不同于密码错误。多种远程登录和改密尝试受到限制,改变传入格式或改用同一密码的哈希表示也没有解决账户状态。继续把问题当作密码编码错误,方向就错了。
实际成功路径是调整 RDP 的认证协商:此前的 NLA 登录返回 ERRCONNECT_PASSWORD_MUST_CHANGE,没有进入可完成改密的交互界面,改用该实例支持的 TLS 连接方式后,进入交互式强制改密流程。完成密码修改后,再验证新的本地管理身份。这里记录的是本次实例中走通的方法;此前几个协议尝试失败,不能推广为“所有协议都无解”或“任何环境都只有这一条路”。
完成后核对的是目标侧可观察状态:新凭据可以认证,管理共享可访问,令牌和账户关系符合预期。至此才能把“残留秘密”提升为“本地管理权限已确认”。
注意此处身份是 LOCAL_ADMIN_A。下一阶段提取的内置管理员凭据属于另一个身份,不能把两者混写,否则会出现“同一口令既改了又没改”的逻辑冲突。
六、本地权限如何进一步关联到域权限
取得本地管理权限后,首先尝试常规远程凭据审计。工具输出停在读取本地凭据的位置,退出状态没有报出足够明确的错误,却没有生成预期结果文件。第二次仍无有效产物。该结果应记作“未成功取得凭据材料”,而不是因为退出码为零就记成功。
后续在获授权的本机执行通道中继续检查。不同通道的令牌、完整性级别和可访问注册表范围不同:一种通道对受保护位置返回拒绝访问,另一种临时结果读取又出现文件不存在。UAC、终端防护和时序都曾被列为可能原因,但并非每个解释都被独立验证,不能把这些猜测当成已查明的原因。
具体使用了 mimikatz 检查不同凭据来源。文件上传先遇到两个接口用法问题:SMBConnection.putFile 需要可调用的读取回调,直接传字节对象报错;另一种客户端的 put 参数被当成一个路径处理,目标命名写法不符合该版本语法。调整后核对远端文件存在且长度一致,才进入执行阶段。上传成功、程序执行和取得凭据是三个独立检查点。
WMI 通道读 SECURITY 时返回 0x00000005;计划任务通道第一次读取临时输出又遇到 STATUS_OBJECT_NAME_NOT_FOUND。改用能完整回收标准输出的调用方式后,才获得可分析的结果。记录同时涉及令牌、防护状态和输出回收方式变化,无法仅凭最终成功把前两次失败归于唯一因素。
privilege::debug
返回权限启用成功
sekurlsa::logonpasswords
日志会话读取失败
lsadump::sam
返回本地账户材料
lsadump::secrets
返回部分 LSA secrets最终取得了本机账户凭据材料和部分本地秘密。LSASS 内存读取没有成功,不妨碍另外的本地账户存储读取已经得到结果;“凭据提取”不是一个只有成功或失败两种状态的整体动作。分别对应 [T1003.002:SAM](https://attack.mitre.org/techniques/T1003/002/)与 [T1003.004:LSA Secrets](https://attack.mitre.org/techniques/T1003/004/);[T1003.001:LSASS Memory](https://attack.mitre.org/techniques/T1003/001/)在本次仅是失败尝试。
LOCAL_ADMIN_A:
当前凭据状态与前一步改密一致
BUILTIN_LOCAL_ADMIN:
获得可核对的本地账户凭据材料
Historical secret:
与先前安装文件中的旧口令线索对应
LSASS memory extraction:
未获得成功结果随后按身份逐项验证,避免把任意一个本地哈希都当成域凭据。真正的转折是:本机内置管理员的材料可以作为域管理员身份通过认证,其他候选组合并没有同样成功。
这说明至少存在有效的跨身份凭据复用。仅凭相同哈希本身不能推断两个账户拥有相同授权;本次域端验证与后续权限确认,才证明影响已经跨出本机。使用已有 NT 哈希进行认证对应 [T1550.002:Pass the Hash](https://attack.mitre.org/techniques/T1550/002/);凭据复用是扩大影响的环境条件,不等于所有本地哈希都能用于域身份。
授权范围内的目录凭据审计随后获得了域账户材料,并与前述身份关系交叉核对。该阶段的命令形式如下,执行目标、账户和哈希均已替换:
impacket-secretsdump \
-just-dc \
-hashes :<REDACTED_NT_HASH> \
'<DOMAIN>/<DOMAIN_ADMIN>@<DC_A>' \
-outputfile <AUTHORIZED_OUTPUT_PREFIX>结果文件按用途分别保存,检查是否存在、是否包含预期类型的记录,以及相同身份在不同来源的材料能否对上。公开文章不包含这些文件或任何真实凭据。
域侧导出产生了 NTLM、Kerberos 密钥及其他账户材料对应的结果文件。本机机器账户材料与域侧相应记录也做了交叉核对。最初一次调用还受到 Network unreachable 影响,恢复网络后重试才完成;网络失败不能用来判断凭据无效。结合文中的目录复制工具模式和结果,可映射 [T1003.006:DCSync](https://attack.mitre.org/techniques/T1003/006/);这是行为归类,不额外声称保留了复制协议抓包。
本地输出中的历史秘密与安装应答文件旧值相符,LOCAL_ADMIN_A 的当前与历史材料则对应本次改密前后状态。这些关系解释了为何同一机器里会出现多个不同阶段的秘密。模板或部署流程可能是复用来源,但没有构建流水线证据,不能直接把具体设置过程写成已查明事实。
之后曾把已有词表用于部分域口令候选核对,没有得到命中。这个结果只说明受测候选没有匹配,不能说明口令无法恢复。更重要的是,域权限并没有自动带来 LINUX-A 的 SSH 登录;Windows 域身份与 Linux 的账户和认证配置需要单独验证。该方向对应 [T1110.002:Password Cracking](https://attack.mitre.org/techniques/T1110/002/),状态是未命中;后文嵌入模板匹配并非密码哈希破解。
七、Kerberos、时钟和无效服务线索
域侧还走过 Kerberos、服务主体、无需预认证账户以及托管秘密等方向。过程中出现时钟偏差错误,校时又与本机自动授时和 VPN 稳定性相互影响。
KRB_AP_ERR_SKEW
KDC_ERR_ETYPE_NOSUPP
Network unreachable三个错误属于不同问题:时钟容差、加密类型协商以及网络路径。把它们都叫“Kerberos 不通”,会导致在网络已经中断时继续换认证参数。校时后应先确认隧道和目标可达,再确认绝对时间,最后处理认证协商。
date -u
systemctl is-active systemd-timesyncd chrony ntp
ip route初步分析曾把两个不同显示时区的时间直接相减,夸大了表面时差。正确比较应统一时区或比较时间戳。VPN 在校时后发生中断是观察到的顺序,具体握手为何失败则需要 VPN 日志支持,不能仅凭先后关系锁定原因。
服务主体枚举还出现一个数据库服务标记,但目标没有对应监听、没有对应服务,也没有运行实例。该标记未能支持新的服务入口。AS-REP 查询未得到符合条件的账户,LAPS 与 gMSA 查询也未取得相应对象。这些都是本次检查的否定结果,不代表整个域不存在其他问题。
对 LINUX-A 尝试域认证时,先遇到了客户端能力和选项问题:一条客户端路径无法使用所需 GSSAPI 功能,另一条路径拒绝相关选项。这些本地失败都不能说明服务器是否接受域认证。换到能够发起该方式的客户端后,才得到服务器实际仅接受公钥和密码的响应:
allowed authentication methods:
publickey
password因此,当前 SSH 入口不支持所尝试的 GSSAPI 路径。不能从这个接口的响应进一步推导“Linux 绝不可能加入域”;只能停止在该端点继续投入不匹配的方法。
八、Linux 突破的关键是密钥与身份同时匹配
LINUX-A 是最难推进的一段。多组已有口令、常见账户、域账户格式和部分词表尝试均被拒绝。持续扩大密码尝试没有增加有效信息,但公钥认证本来就是服务器已声明支持的方式。
检查先落在 Windows OpenSSH 的服务配置和主机密钥位置。这里发现的是 sshd 的配置与主机身份密钥。主机密钥用于服务器证明自身身份,并不自动等于能够登录另一台机器的用户私钥。将两者混淆,会在“找到很多 key 文件”的表象下继续走错方向。
C:\ProgramData\ssh 中可见 RSA、ECDSA、Ed25519 主机密钥及 sshd_config,未在该位置找到预期的用户授权文件。配置同时区分普通用户和管理员的授权文件路径,并限制允许登录的组:
AuthorizedKeysFile .ssh/authorized_keys
AllowGroups administrators "openssh users"
Match Group administrators
AuthorizedKeysFile __PROGRAMDATA__/ssh/administrators_authorized_keys本机 OpenSSH Users 组为空,初始身份也不在管理员组中。这与该身份无法登录 WIN-A 的 SSH 相符,却不能替代 LINUX-A 的配置检查。两台主机的 sshd 是不同认证边界,不能把 Windows 上读到的规则套到 Linux。
随后检查用户资料目录。低权限阶段某些管理用户目录不可读;取得管理权限后的第一次遍历,又因为脚本吞掉异常得到零命中。两次错误叠加,使同一处文件连续被遗漏。最终重新直接核对受限目录,才找到用户 SSH 私钥与公钥。目录查找与私钥发现分别对应 [T1083:文件与目录发现](https://attack.mitre.org/techniques/T1083/)和 [T1552.004:Private Keys](https://attack.mitre.org/techniques/T1552/004/)。
Get-ChildItem -LiteralPath "C:\Users\<PROFILE>\.ssh" -Force |
Select-Object Name, Length, LastWriteTime发现私钥后,仍不能宣布“Linux 已拿下”。需要确认文件格式、是否需要口令短语、对应公钥,以及远端哪一个账户接受该公钥。公钥注释只能提供线索,不能替代远端授权验证。
ssh-keygen -y -f <USER_PRIVATE_KEY> > <DERIVED_PUBLIC_KEY>
ssh-keygen -lf <DERIVED_PUBLIC_KEY>本次私钥没有口令短语,最初搭配几个常见 Linux 用户名依然被拒绝。之后把前序 Windows 测试中出现过的服务身份放回候选,公钥认证才成功。此前错误地把“Windows 域用户名”和“Linux 用户名”当成互不相交的集合,导致最有线索依据的身份排在后面。
ssh \
-i <USER_PRIVATE_KEY> \
-o IdentitiesOnly=yes \
-o PreferredAuthentications=publickey \
<SERVICE_USER>@<LINUX_A>拒绝响应不能单独区分密钥不被信任、账户不存在、账户被限制等原因。成功时则核对实际用户名与主机身份,再进行本机服务观察。
whoami
hostname
ss -lntp至此形成的跨主机关系是:WIN-A 的用户私钥,对应 LINUX-A 某账户信任的公钥。此前取得域权限有助于扩大调查,但真正跨到 Linux 的直接认证依据是这组密钥与账户的组合。这一步对应 [T1021.004:SSH](https://attack.mitre.org/techniques/T1021/004/),成立依据是已验证的远端会话。
九、回环地址上才出现真实向量库
登录后观察到 SSH 以外还有多个仅回环监听的服务。它们分别涉及向量接口及本地模型相关服务,解释了外部扫描为何主要只见 SSH。端口号只能产生候选指纹,必须继续看协议响应。
curl -sS http://127.0.0.1:<VECTOR_PORT>/
curl -sS http://127.0.0.1:<VECTOR_PORT>/v1/schema响应路径、服务元信息与 Schema 共同指向 Weaviate。几个按其他产品习惯猜测的路径返回 404,并不代表服务故障;改按实际 API 路由请求后,Schema 正常返回。
在当前访问范围内,读取 Schema 和目标对象没有要求 API 凭据。这证明相应读取缺少独立认证。初步分析据此进一步断言“所有数据均可任意读写”,范围过大。本次没有保留写入验证证据,能够确认的是目标对象可读,任意写权限尚未得到证明。数据收集可参照 [ATT&CK T1213](https://attack.mitre.org/techniques/T1213/);向量数据面的访问控制风险直接对应 [OWASP LLM08:2025](https://genai.owasp.org/llmrisk/llm082025-vector-and-embedding-weaknesses/)。这不构成提示注入或 RAG 投毒的证据。
| 对象类别 | 对象数 | 可见属性 | 对本次目标的意义 |
|---|---|---|---|
| ResearchRecords | 3 | 标题、正文及来源等 | 背景资料 |
| InternalRecords | 2 | 标题、正文、类别及来源等 | 系统与管道背景 |
| SensitivePolicy | 1 | 标题、来源和摘要标识,无正文属性 | 敏感目标向量 |
表中的类名已替换。目标对象缺少明文正文,但仍保留向量。Schema 中的 vectorizer 设置还表明向量由外部生成后写入,而非当前库内自动编码。没有看到量化启用,也不能直接宣称“反演一定成功”,只能把它视为影响恢复方法选择的一个条件。
十、向量导出必须按实际 Schema 查询
第一次导出把同一组字段套在三个类别上,其中一个类别有 category 字段,另外两个没有。GraphQL 校验直接拒绝不合法查询。这个错误来自不了解类型边界,和网络、认证或向量数据不存在都无关。
Cannot query field "category" on type "<CLASS_WITHOUT_CATEGORY>"修正是先按 Schema 确认字段,再按类别分别请求。下面是替换类名后的目标对象查询结构:
{
Get {
SensitivePolicy {
title
_additional {
id
vector
}
}
}
}响应中的业务字段、对象标识和向量分别保存。导出后先检查响应是否含 errors,再核对返回对象数与向量长度,避免把错误 JSON 当成数据文件继续送入反演程序。
import json
from pathlib import Path
payload = json.loads(Path("target-response.json").read_text())
if payload.get("errors"):
raise RuntimeError("GraphQL export failed")
records = payload["data"]["Get"]["SensitivePolicy"]
assert len(records) == 1
vector = records[0]["_additional"]["vector"]
assert len(vector) == 384
assert all(isinstance(value, (int, float)) for value in vector)三个类别共得到六个向量,目标对象对应一个 384 维向量。随后转换为反演程序使用的数组格式,保留原始响应以便回查。
import numpy as np
matrix = np.asarray([vector], dtype=np.float32)
assert matrix.shape == (1, 384)
assert np.isfinite(matrix).all()
np.save("target-vector.npy", matrix)
loaded = np.load("target-vector.npy", allow_pickle=False)
assert loaded.shape == matrix.shape
assert np.array_equal(loaded, matrix)数组形状、数值类型、文件回读和有限值检查,比仅凭文件大小判断格式更可靠。数组文件还包含格式头,不能只用简化的字节数公式判断完整性;加载后的结构和数值核对更直接。
384 维、归一化特征和距离度量可以帮助缩小编码器范围,但不能唯一识别模型。测试采用 all-MiniLM-L6-v2 作为候选编码器,还参考了环境线索和后续匹配结果。维度指纹本身不能作为编码器身份的确定证据。
其余模型服务没有继续深入,因为当前目标向量已经取得,反演路径也不依赖在线聊天接口。观察到某个 gRPC 端口,不足以把服务直接命名为某个推理框架。
十一、反演环境、方法选择与文件传输
向量导出后转到专用分析环境执行恢复计算。备选方法和工具包括模板候选匹配、束搜索以及需要专门模型或训练准备的方案。实际选择的是准备条件与当前证据最匹配的模板方法。
分析环境具备 T4 GPU 和 Python 虚拟环境,也已有 ALGEN、Vec2Text 相关目录,但缺少本次要用的零样本脚本。随后补齐 generate_templates.py、emb_fin.py、zero2text_impl.py,以及候选词表和导出的数组。准备工作先核对依赖与输入,再启动计算;目录里有某个工具,不等于其模型和运行条件已经准备完成。
| 备选路径 | 本次取舍 | 结论边界 |
|---|---|---|
| emb_fin.py 模板候选匹配 | 目标语境、编码器线索和词表均已具备,优先使用 | 只搜索当前模板和候选空间 |
| zero2text_impl.py 束搜索 | 作为模板结果不足时的后备,没有实际运行 | 未对它在本目标上的效果下结论 |
| ALGEN 相关方案 | 当时未准备完整的数据与接口条件 | 不把单个实验配置概括为方法的必要条件 |
| Vec2Text 相关方案 | 没有准备对应模型或训练流程 | 不把固定训练时长套用于所有实现 |
计算安排在专用分析环境,前端测试机负责导出与传输。这个分工是本次执行约束,与模板法能否在 CPU 上运行是两回事。
选择依据包括:已经有目标向量,编码器候选范围较小,文本领域接近密码重置通知,而且有明确候选词表。此时可以把问题收窄为“在给定上下文中,哪一个候选最能解释目标向量”。这不等于对任意未知文本进行通用恢复。
没有采用其他方法,并不意味着其他方法普遍要求固定的训练时长或写权限。不同实现的前提不同。本次取舍仅说明当时未准备好对应模型、训练资源或接口条件。Vec2Text 的原始研究见 [Morris 等,Text Embeddings Reveal (Almost) As Much As Text,EMNLP 2023](https://aclanthology.org/2023.emnlp-main.765/)。本文没有运行该路线,也不将模板法结果当作该论文的复现。
传输也出现一次配置错误:SSH 设置了 BatchMode=yes,却仍期望密码交互完成。该选项适合已经配置好非交互认证的情形,不能在需要输入密码时随意加上。取消不符合当前认证流程的选项后完成了文件传输,并核对文件内容。
sha256sum target-vector.npy
scp target-vector.npy <ANALYSIS_USER>@<ANALYSIS_HOST>:<WORK_DIRECTORY>/
ssh <ANALYSIS_USER>@<ANALYSIS_HOST> \
'sha256sum <WORK_DIRECTORY>/target-vector.npy'这段代码展示的是文件完整性核对方式。两端摘要一致证明传输未改变文件,不证明向量来源、模型选择或恢复算法正确。
十二、模板匹配如何产生候选
分析脚本首先判断目标向量更接近哪类企业文本。密码重置语境获得较高匹配,随后围绕通知句式、上下文顺序和语言变体生成约两万个模板。模板保留密码和链接等槽位,避免把一个候选孤立地与整段文档向量比较。
The default password after resetting is {PASSWORD}.
Please open {URL} and update the password after signing in.
Your account has been reset.
Use {PASSWORD} to sign in at {URL}.恢复过程先选出得分较高的模板,再去除高度相似的模板,避免五条近乎重复的句子制造虚假的“五票一致”。候选词表约一万条,先做粗筛,再对缩小后的候选集用多条模板比较。
记录中的参数过程更具体:先对约两万条模板评分,取前 50 条,再通过成对余弦相似度去重选出 5 条模板。候选粗筛保留约 200 个值,随后进行多模板比较。去重能减少近似句式重复计票,但不意味着这五条模板在统计意义上相互独立。
模板生成从企业文本领域识别开始,在约 20 个领域中,密码重置相关语境得分突出。生成器由 7 条基础模板,通过模式、语言、结构和上下文变体扩展。模板与目标文档的句式接近,是本次方法奏效的重要条件;不能把这种有领域约束的恢复包装成“只给任意向量就能找回任意秘密”。
1. 模板匹配与排序
2. 高分模板去重
3. 候选粗筛
4. 多模板交叉比较
5. 输出候选及分数
6. 进行独立核验原始工具调用的脱敏形式如下。这里的文件名和参数属于该次使用的脚本接口,不应被当成所有向量反演工具的通用参数。
python3 generate_templates.py \
--output templates.json \
target-vector.npy \
--count 20000
python3 emb_fin.py \
target-vector.npy \
--chunk 0 \
--templates templates.json \
--wordlist candidates.txt \
--slots PASSWORD最终有五条经去重的模板支持同一个候选。工具报告较高相似度及 Strong 标签。其含义是当前模板、候选集和评分策略下,某个候选占优;它不是正确概率,也不能证明原文被逐字还原。
运行过程中先出现约 71.6% 的模板匹配,汇总输出的最佳值为 75.6%。工具没有报告亚军,并将分离比显示为无穷大;这只是该输出规则下缺少可比较的第二名,不能直接解释成候选与所有其他答案存在无限差距。当时依据较高匹配分数及 Strong 标签,没有继续运行束搜索;这只是执行阶段的停止决定。随后获得的独立确认才支持最终正确性结论,不能倒过来把后来的确认写成当时作出决定的原因。
Candidate: <REDACTED_VALUE>
Template agreement: 5 / 5
Best template match: 75.6%
Runner-up: not reported
Tool label: Strong
Independent validation: confirmed独立验证确认了最终敏感值。公开文章保留验证结论,不披露敏感值本身、原始向量或可重建客户敏感资料的产物。结果的机密性影响对应 [OWASP LLM02:2025](https://genai.owasp.org/llmrisk/llm022025-sensitive-information-disclosure/),实际机制更直接对应 LLM08 的嵌入反演。ATLAS 的 Invert AI Model 可作概念参考:[官方 v2026.10 更新](https://github.com/mitre-atlas/atlas-data/commit/f56c1468731d6428e5bf875263b4643b46d67437)将旧编号 AML.T0024.001 迁至 AML.T0137.002;但该分类涉及训练数据信息,本文恢复的是外部文档的嵌入候选,不能直接等同为训练集反演。
十三、已知文本校验失败为何必须单独分析
成功结果旁边还有一个很重要的失败实验:构造一段包含已知值的文本,编码成向量,再交给同一套恢复脚本。如果管线与候选条件合适,应该找回已知值;实际却返回了另一个候选,而且仍显示高置信标签。
这个失败意味着不能把工具标签直接当证明。需要逐项检查:候选词表是否包含已知值,大小写及预处理是否一致,编码器是否相同,模板中的链接和上下文是否匹配,以及粗筛是否提前丢掉了正确候选。
实际核对在候选文件中找到了已知值的小写形式,因此“词表里完全没有它”不是充分解释。构造句采用了不同大小写;即使编码器的分词处理会折叠大小写,恢复脚本的候选处理与输出比较仍需单独检查。已知值是否在粗筛时被剔除,没有保留完整排名证据,也不能凭猜测确认。
对照检查发现构造句使用了一个具体链接,而恢复运行没有对齐该链接槽位。这是明确的实验条件差异,但未记录修复后重跑成功,因此不能断言它就是失败的唯一原因。链接槽位不一致应列为待验证原因,只有对齐条件后的复测才能检验这一解释。
known_text = (
"The default password after resetting is <KNOWN_VALUE>. "
"Please sign in at <CONTROL_URL>."
)
control_settings = {
"encoder": "<SAME_ENCODER_AND_PREPROCESSING>",
"candidate_list": "<SAME_CANDIDATE_LIST>",
"url_slot": "<CONTROL_URL>",
"template_strategy": "<MATCHED_TEMPLATE_STRATEGY>",
}合理的对照应尽量保持编码、上下文、候选集和模板条件一致,只改变待验证值。还可以加入多个不同语义类别的已知值,观察是否总有某类候选反复胜出。两次不同实验得到同一语义类别的候选,只能提示可能存在偏置,不能凭两个点就确认系统性机制。
最终目标候选已经独立确认,不等于整套恢复管线在任意文本上都可靠。控制实验失败仍然是方法有效性上的限制,应该与客户目标结果一并保留。
十四、环境波动与失败路线如何收束
测试期间多次出现服务不可达、RDP 握手失败、VPN 中断和 SMB 工具超时。部分事件恰好发生在测试请求之后,最容易被写成“某次请求导致服务崩溃”。服务恢复、目录时间戳变化和其他工具可达性提供了更多线索,但没有宿主和服务端日志就无法完全归因。
因此将异常按四项记下:发生时间、当时操作、目标侧观测、独立复测结果。时间相邻只能说明相关,不能直接说明因果。某个 SMB 客户端超时、另一个直连方式成功,优先提示客户端路径或协议差异,不应立即宣布目标宕机。
其中一次,门户、Qdrant 和 MongoDB 同时不可达,数小时后恢复,存储目录时间戳也发生变化。中断前恰好进行过集合接口测试,但没有服务端日志证明该请求造成故障;时间戳变化同样不足以证明虚拟机一定经历了快照恢复。
另一次 RDP 客户端报 ERRCONNECT_TLS_CONNECT_FAILED,同一时段端口仍开放,独立 TLS 检查能完成握手,重连后恢复。它支持“客户端或会话路径的短暂故障”这一方向,但没有精确定位触发点。SMB 的 NETBIOS 超时也与其他客户端能直连的结果并存,因此后续切换客户端并继续核对目标状态,没有把单一工具超时当作全机失联。
终端防护状态在测试期间发生过调整。早期 winPEAS 落地失败、后续某些凭据读取成功,不能据此拼成“所有失败都由防护造成”的单一故事:中间还同时改变了权限、执行方式和输出读取方式。复盘必须保留这些变量,才能分清观察到的阻断与尚未证实的推断。
| 已检查路线 | 记录中的否定或限制 | 是否可推广 |
|---|---|---|
| WIN-A 门户即真实 RAG | 集合、元数据与程序调用不支持 | 仅针对观察到的实例 |
| Linux 密码认证 | 已测试组合均被拒 | 不代表所有账户密码无效 |
| Linux GSSAPI | 当前 SSH 端点未接受该方式 | 不代表 Linux 不能加入域 |
| 域数据库服务标记 | 未找到实际实例与监听 | 不能用 SPN 证明服务正在运行 |
| 自动提权工具 | 文件交付或执行受阻 | 不能证明没有提权路径 |
| 若干本地提权配置 | 未满足被检查方法的前提 | 不能证明主机无其他弱点 |
| 管理用户资料目录 | 低权限读取失败 | 权限提升后必须重查 |
| DC-A 低权限远程执行 | 登录权不足或缺少目标侧结果 | 不能继续基于假通道设计回传 |
| 已知文本反演对照 | 返回错误候选,条件未完全对齐 | 不能宣称管线已普遍验证 |
否定表的价值在于明确每条路线在哪些条件下未走通,而不是宣称“其他所有门都关死了”。后续权限、网络或环境状态一旦变化,部分否定结果需要重新检查。
十五、AI 十类错误与对应的知识缺口
1. 把连接和认证当成登录授权
RDP 客户端完成部分连接步骤,不代表目标允许当前身份远程登录。错误画面存活几十秒也不能证明命令执行了几十秒。缺口是 Windows 登录权、认证阶段和会话状态的基础知识,纠正必须落到真实界面或目标侧事件。
2. 把工具积极标记当成执行结果
远程管理工具显示“Executed”后,目标没有预期产物,直接操作又返回拒绝访问。初步分析还试图据此解释工具内部完成了哪个 API 阶段,但缺少对应版本源码或调用记录,这一解释无法确认。可以确认的只有:积极回显没有被目标效果支持。
3. 把输出截断当成枚举结束
终端缓存不足、旧输出混入以及只读取尾部,都让完整性失去保障。错误根源是不了解观测通道的限制,表现出来却像“没有服务”“没有文件”。采集状态与目标状态必须分开验证。
4. 把多层转义当作机械拼接
脚本跨越多个解释器时,每层都有自己的引号、转义和变量规则。继续修改一串越来越复杂的内联命令,增加的是不可见差异。把复杂逻辑固化到脚本,保存错误输出,再核对实际执行内容,才能确认失败来自目标还是来自命令自身。
5. 错用 SSH 交互控制
密码传输时禁用交互导致失败,公钥测试时又可能被其他认证方式干扰。选项是否正确取决于要验证的认证方式。不了解 BatchMode、IdentitiesOnly 与认证偏好之间的作用,就无法解释拒绝响应。
6. 把密码作为唯一搜索方向
服务器已经说明支持公钥,却仍在密码组合上持续投入。应尽早把密码、用户密钥、账户范围和授权限制列成独立假设,按证据排序。更多候选不是更完整的思路。
7. 权限改变后沿用旧的“零结果”
低权限下不可读的目录,在获得管理权限后可能包含关键材料。遍历异常再被静默吞掉,会形成第二层假阴性。错误不仅是少查一个目录,更是把“在某个身份下的观察”误当成环境不变事实。
8. 把查询方法失败当成对象不存在
区传送拒绝、PTR 超时和目录查询中断都只说明对应方法没有给出结果。本次并未完成所有 DNS 路径,相关检查仍有缺口。把未完成检查写成排除结论,会制造虚假的搜索收敛。
9. 忽略反演对照实验的变量控制
已知值恢复失败却仍有高置信标签,说明标签与真实性不能画等号。对照条件不同又使失败难以解释。领域知识不足不仅影响渗透操作,也影响对机器学习实验的设计、评分解释和可推广性判断。
10. 把成功日志当成交付物
报告脚本显示已保存,文件却未在回读时找到。原因未完全查明,但交付不成立是可确定的事实。存在性、可读性、内容完整性和最终路径都必须核对,不能只引用写文件函数的返回值。
这十类错误的共同根源,是对当前安全领域、协议细节和实验方法的知识不足。证据检查缺失又放大了这些知识缺口,使错误前提不断生成后续动作。增加调用次数、让执行持续更久,无法自行补上概念上的错误。
十六、按证据重建完整路径
原始操作中存在并行、回头检查和多次重试,下面给出依赖关系顺序,便于理解哪些步骤必须成立后才能推进。它不是把所有尝试伪装成一次顺利完成的线性过程。
已有低权限身份
→ 验证成员服务器入口与域侧只读范围
→ 核对门户、Qdrant、MongoDB,排除错误目标
→ 双视角网络检查,保留回环服务假设
→ 原生枚举与部署残留检查
→ 旧口令失效,继续追踪初始化与轮换过程
→ 配置介质仍可读,发现另一组本地管理凭据
→ 处理必须改密状态,确认本地管理权限
→ 检查本机凭据,区分不同本地管理员身份
→ 域端验证发现凭据复用,确认域级影响
→ 权限变化后重查用户资料,发现 SSH 私钥
→ 私钥与对应 Linux 账户匹配,确认主机访问
→ 本机监听和 API 核对,定位 Weaviate
→ 按 Schema 导出目标向量,验证数据格式
→ 在分析环境完成模板候选比较
→ 目标候选独立核验成立
→ 已知文本对照失败作为方法限制单独保留两条主线到这里才真正连接:环境突破提供了向量访问条件;反演方法在明确模型线索、文本领域和候选空间后提供了敏感值候选。任何一段缺少独立证据,最终结论都应停在相应层级。
十七、客户环境暴露出的改进点
部署初始化的秘密应当有完整生命周期。删除盘符、隐藏路径或只打印清理成功日志,都不足以证明介质和元数据不可读取。应验证实际挂载状态、数据可达性和秘密是否已轮换。
本地管理账户、内置管理员、域管理身份以及服务身份应分别管理秘密。复用让单机凭据泄露扩大为域级影响;跨主机复用 SSH 私钥又打开了另一条访问路径。密钥口令短语、用途限制与使用审计都需要结合部署方式设计,不能只检查文件是否存在。
向量库应有独立认证与最小权限。回环监听有助于减少网络暴露,但主机访问、代理或转发一旦成立,缺少认证的数据面仍可被读取。敏感文档进入检索管道前需要分类和必要性审查,移除正文属性不等于嵌入已经脱敏。这一风险也有原始研究依据:[Song 与 Raghunathan,Information Leakage in Embedding Models(2020)](https://arxiv.org/abs/2004.00053)。论文说明表示中的信息泄漏风险,不替代本次测试证据,也不提供本次方法的成功率。
日志应能支持进程来源、权限变化和数据访问的回溯。没有常见启动项,不证明进程来自某个宿主动作;没有记录到某次读取,也不证明读取没有发生。每个调查结论都要说明日志覆盖范围。
自动化测试需要同时具备领域知识和验证机制。对身份、协议和实验方法理解不准确时,流程会反复把“可以连接”“凭据有效”“工具说成功”写成“已经执行并验证”。这次测试真正需要保留的,是这些混淆如何发生、如何被证据否定,以及每次纠正如何让路径重新成立。