首页 时政热点 科技头条 智能AI 安全攻防 数码硬件 开发者生态 归档 标签 关于

红队实战复盘:四档探针测 EDR 水位,非 SYSTEM 取 SAM

摘要

01 前言 去年底的一次红队演练,入口机是台 linux webshell,从配置文件翻到了一个服务账号的明文口令信息,巧合的是可以通过 3389 远连到几台一样的 win 主机,均隶属于管理员组但非 system 权限,这个被加进本地组不是镜像带来的而是人手动做的,推测管理员凭据都是一样但我没明文,在主机的 SAM 里。主机不在域内,进程里有个杂牌的 EDR ,其规则对落地文件和读 SAM 都会...

SAM return case EDR Hop ntlm system const char ERROR_ACCESS_DENIED
2026-11-09 1 阅读 约9分钟阅读 先知社区
分享:
字号:
01 前言 去年底的一次红队演练,入口机是台 linux webshell,从配置文件翻到了一个服务账号的明文口令信息,巧合的是可以通过 3389 远连到几台一样的 win 主机,均隶属于管理员组但非 system 权限,这个被加进本地组不是镜像带来的而是人手动做的,推测管理员凭据都是一样但我没明文,在主机的 SAM 里。主机不在域内,进程里有个杂牌的 EDR ,其规则对落地文件和读 SAM 都会有覆盖。当前 EDR 环境下,你是否能做到不依赖 mimikatz、secretsdump、不调用任何现成的 SAM 解析库、不碰活注册表、不硬要提权 NTsystem 来拿 NTLM 。 02 当前场景 1、多台win主机,镜像部署,服务账号凭据,均隶属于管理员组但非 system 权限,无域环境 2、防护为杂牌 EDR 3、可通的网段有多个 4、可访问的端口、服务、文件,未发现可进一步利用的 03 思路梳理 1、明确任务,要的只是扩大采样面。 从主机的文件判断这多台主机均为镜像部署,所以一个 ntlm 就等于多台机器。服务账号的可接管的范围就到这几台win主机。对于横向的那批主机,这个服务账号均不存在,入口是用服务账号的明文进的,要想扩大成果只能用 ntlm。 2、铺垫的是后续拿域内主机。 这个主机没有域,拿 ntlm 意义在于拿到更多位置和痕迹,域身份总得先找到域。所以拿到多台机器的目的不在于多几个立足点,而在于其他机器 lsass 是否会有域会话,我要的域身份只能从那里拿。 3、明确目标,取哈希。 这笔投入成立的前提为内置管理员凭据得相同,拿手上这个哈希去打第二台,成功说明前提成。如果失败,那应该是去翻凭据管理器和浏览器历史。目标具体化操作就能明确到我要把 RID 500 的内置管理员 ntlm 提出来横向。 4、整体方向。 SAM 提供本地管理员账户,用它 PTH 到同镜像、同口令的机器,在那台机器的 lsass 里,才拿得到域用户的哈希。 04 读注册表 1)程序 RegOpenKeyEx.cpp 单纯只 RegOpenKeyEx 打开 HKLM\SAM\SAM\Domains\Account\Users 不去做后续读取枚举 #include #include static const char *ErrName(LONG rc) { switch (rc) { case ERROR_SUCCESS: return "ERROR_SUCCESS"; case ERROR_FILE_NOT_FOUND: return "ERROR_FILE_NOT_FOUND"; case ERROR_PATH_NOT_FOUND: return "ERROR_PATH_NOT_FOUND"; case ERROR_ACCESS_DENIED: return "ERROR_ACCESS_DENIED"; case ERROR_INVALID_PARAMETER: return "ERROR_INVALID_PARAMETER"; case ERROR_SHARING_VIOLATION: return "ERROR_SHARING_VIOLATION"; default: return "(other)"; } } static void Hop(const char *tag, const char *sub) { HKEY h = NULL; LONG rc = RegOpenKeyExA(HKEY_LOCAL_MACHINE, sub, 0, KEY_READ, &h); printf("%-5s HKLM\\%-45s rc=%-2ld 0x%08lX %s\n", tag, sub, rc, (DWORD)rc, ErrName(rc)); if (h) RegCloseKey(h); } int main() { Hop("[1]", "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"); Hop("[2]", "SAM"); Hop("[3]", "SAM\\SAM"); Hop("[4]", "SAM\\SAM\\Domains\\Account\\Users"); return 0; } 2)结果未出现告警未拦截,返回 ERROR_ACCESS_DENIED 。 拒绝访问并不意外,默认 system 才有读权限。有价值的点在于侦察水位。可能只被记录为一次事件甚至根本没被看见。之前说过这是个杂牌 EDR ,在现代 EDR 环境高权限进程执行这个动作必告警。 3)这里可以总结出几个点: 1、对方在打开 SAM 健上没有阻断。 2、edr 可能没看见,可能看见了只记录未拦截,或者规则命中了却只记录。所以复盘时我能写的是"主机侧没有可见后果" 3、这个玩法没做任何后续读取,所以万一被拦,原因只可能是打开的意图,不可能是读了什么。动作的粒度越细,归因才越准。 05 思路梳理 此时最顺的思路是提权 system,最后直接是放弃了。原因是同时间同个进程开 SYSTEM 进程、复制令牌启用新进程无疑是会压在 EDR 遥测最密的那一层,每一层操作必然命中的遥感规则。关键的是即便拿到 SYSTEM,读 hive 还要面对独占锁和 REGF 解析两件事。所以我要的从来不是 SYSTEM 这个身份,是一份没被锁住的只读副本。 我的路只剩两条: 1、改权限(动对象),操作为改 dacl。 2、或者改数据来源(不动对象),做卷影复制。 不动权限,先判定卷影这条路在这台机器上到底通不通?那么就先先写一版试试。 07 实践 第一档、测绘防护栈 枚举出vss服务相关信息,均为管理员日常会敲的命令 //目标:以获取 “普通 CIM 服务查询” 基准,看是否告警或拦截。 Get-CimInstance Win32_Service -Filter "Name='vss'" //目标:单独查询存储池,看是否告警或拦截。 Get-CimInstance Win32_ShadowStorage //目标:单独枚举快照,看是否告警或拦截。 Get-CimInstance Win32_ShadowCopy 或直接一次跑只显示有价值信息。 $vss = Get-CimInstance Win32_Service -Filter "Name='vss'" $sh = @(Get-CimInstance Win32_ShadowCopy) $st = Get-CimInstance Win32_ShadowStorage $maxGB = if ($st) { [math]::Round((($st | Measure-Object MaxSpace -Sum).Sum)/1GB, 1) } else { 'n/a' } $usedGB = if ($st) { [math]::Round((($st | Measure-Object UsedSpace -Sum).Sum)/1GB, 1) } else { 'n/a' } [pscustomob
这篇文章对您有帮助吗?

订阅66必读

每日精选科技资讯,直达你的邮箱