AD域权限提升是渗透测试中很重要的一部分。比较常用的提升域权限是围绕着收集你登录系统的纯文本身份认证信息或令牌,这种方式主要是用Mimikatz实现的。通常情况是在你已获取到的机器上发现域管理员的登录信息,然后就可以直接收集域管的身份认证信息,拿着这些去登录主系统。
但是,如果你处于一个更加复杂的环境,你此刻并没有获取到这台机器的管理员权限,那么,域管理员信息在哪里呢?你可能需要一个个去试,使你离域管理员越来越远,最后需要做大量错误尝试才能找到。
在最近的一个渗透测试中,我们一开始只获得了域用户权限,而这个渗透环境是有成百上千个工作站和服务器,同时有好几个不同的域相互管理。而我们的目的是不断扩大权限,可能的话最后拿到企业管理员权限。幸运的是,我们得到了网络拓扑图;但域中的机器都严格的遵循最小化权限的原则,几乎是零失误。经过不懈的战斗之后,我们最后终于还是拿到一个服务器的管理员帐号,我们先称之为:“Steve-Admin”。
“Steve-Admin”是这台服务器的本地管理员,我们找出哪些用户登录过这些服务器。在这个时候,我们需要决定接下来我们要渗透哪些目标。但我们登录的用户没有可以得到域管权限,也无法抓去域管的登录信息,我们只能随机选一个账户。
我们发现这是一个有系统管理员权限的帐号,于是我们列举了所有登录过这台机器的用户,直到我们找到正确的途径。在一个大型的网络中,这个方法可能要花费好几天甚至好几个礼拜。
在下面的文章中,我将会描述并展示这个自动化的流程。
前期准备
这个概念的证明依赖现有的工具和一群勤奋的人类,工具如下:
Schroeder (@harmj0y) 做的PowerView –https://github.com/PowerShellMafia/PowerSploit/blob/master/Recon/PowerView.ps1
Justin Warner(@sixdub)到处本地管理员–http://www.sixdub.net/?p=591
Jim Truher (@jwtruher)的Dijkstra算法的PowerShell实现– https://jtruher3.wordpress.com/2006/10/16/dijkstra/
Emmanuel Gras 和 Lucas Bouillot负责AD控制器的路径 – https://github.com/ANSSI-FR/AD-control-paths
Justin Warner (@sixdub)负责域节点的分析 – http://www.sixdub.net/?p=285
图论
想象一下,我们不是在考虑从”Steve-Admin”账户一步步提升到企业管理员的路径,而是在思考一条从华盛顿的西雅图到俄勒冈的波特兰的路。对人类而言,看着地图就能很容易看出5号州际公路就是我们需要的。但是,对电脑来说,必须通过数学计算来计算出西雅图到波特兰的路径(类比于“Steve-Admin”账户到企业管理员的路径,前提是这条路径存在)。
PowerView可以把我们给的大多数的数据转化成从“Steve-Admin”到企业管理员的路径。其余部分来自18世纪的欧拉提出的一个数学的分支–图论。欧拉就是通过图论证明了柯尼斯堡七桥问题是无解的。这个方法包括:
顶点——顶点(或者节点)代表一个系统中的单个元素,你可以理解成地图上的城市。
边界——边界用来连接节点,可以是有向的,也可以是无向的。
路径——路径是一组边界和节点的集合,节点间要相互连接
邻接——共享同一个边的节点互称为邻接。
图形设计
针对这个问题提出来的想法的证明目的只有一个 —— 自动化的找出攻陷域管理员的最短路径。 当然,这个图的设计可能并不适合其他的问题。
这个图最开始的时候我先设计成一个非常简单的并且可能充满错误,随着不断的添加机器,最终设计成:
每一个用户和机器都是一个节点
所有边都是无权重的有向线
从用户到机器的有向边代表本地管理员权限
从机器到用户的有向边代表登录过该机器的用户
想象一个只有两台电脑和两个用户组成的非常基础的网络结构。其中,”Administrator”用户有两台机器的管理员权限。其中一台机器有一个用户“mnelson”用户登录。用可视化表示,如下图:
上图中每个用户和电脑都是一个节点。橘色的线表示Administrator账户拥有两台电脑的系统管理员权限。蓝色的线表示“mnelson”用户登录过HR-WS-002。在这个设计中,边的方向意味着源节点可以攻陷目标节点 —— Administrator可能攻陷电脑HR-WS-002,HR-WS-002可能攻陷mnleson用户。
图的构建
找到图的节点并不简单,因为我们需要把每一个用户和电脑处理成节点,最简单的处理方法是使用两个PowerView命令集Get-NetUser和 Get-NetComputer:
这个图的可视化可能是下面这个样子:
在计算Dijkstra算法前,我们先给这几个节点定义以下的属性:
名字 —— 节点的名字。例如:‘mnelson’ 或者 ‘HR-WS-002’
边界 —— 节点的边界数组。初始值为 $null
距离 —— 从源节点到目标节点的跳数。初始设置为无限远。注意这是一个未加权图。
已访问 —— 到该节点的最短距离是否已经确定。初始化设置为 $False
前驱 —— 路径中源顶点到该顶点的第一个节点的名字。初始化为$False
接下来我们再次用PowerView命令集,不过这次我们用Get-NetSession 。这个命令集可以在我们访问了的一台电脑后返回sessions信息,这可以让我们知道哪些账户在这台电脑上有留下会话信息,并且知道这些账户是属于哪些机器上的,而这些都不需要很高的权限。通过这些信息,我们可以扩大我们的图,丰富我们的图。接下来,我们有了每台电脑的登录信息,逐个递归得列举每台机器的用户信息。这些信息又能继续丰富我们图的边和节点。
在我们的测试环境中完成得到以下图结构:
如上图,user –> computer代表的是管理权限,computer -> user则代表的是已登录用户。
很明显,“Administrator”账户是三台电脑的管理员,’mnelson’用户可以管理OPS-WS-002电脑。用户’jwarner’可以管理IT-STV-002。
HR-WS-002有一个用户登录:mnelson。OPS-WS-002有一个用户:jwarner。IT-SRV-002有三个登录用户:rwinchester,,jfrank,和 Administrator。用户jdimmock既不是管理者也不是登录者。
现在我们就开始用我们已拥有的信息找到最短的路径。
回到之前我们提到的那个案例。从‘Steve-Admin’开始,我们可以得到很多电脑和目标用户,但是这些用户里面并没有能立即找到域管理员的。为了不必要花费好几天去一个个分析(更糟糕的是如果我们用试错法将会花费更大代价),我们使用一种算法计算出最短的路径。
Dijkstra算法
越深入的学习Dijkstra算法,我就越觉得这个算法是那么迷人。Dijkstra算法可以在我们提供的节点中算出图中每个节点间的最短的路径,而这些只需要做n次循环计算,这个n表示顶点的数量。以下是Dijkstra算法的工作流程:
1. 选取一个源节点,把距离值设置成0,与其他的节点距离值先假设为无穷远。
2. 选取最近距离的未访问节点,把它标记为当前节点。
3. 比较当前节点的所有边。比较所有与当前节点相邻的节点到当前节点的距离,把距离值加1,比较计算出来的距离值和当前值,如果小于则更新这个距离值,并且把相邻节点的值更新到当前节点中来。
4. 回到第二步,知道所有节点遍历。
算法完成后,从每一个节点距离的值就可以知道这个节点是否可以到达源节点,需要多少跳才能到达,都可以知道。此外,找到这条最小路径的流程如下:
1. 把目标节点的名字添加到我们的路径数组中。
2. 把最近距离节点添加到数组中,并且找到他的上一跳。把上一跳添加进数组。
3. 循环执行这两步,知道没有上一跳。这个时候,我们就到达源节点了
结论
这里介绍的一些方法都很浅显,通过图论技术(或者其他的数学技术)来进行AD攻击和防护其实还有很多令人心奋的手法:比如这篇文章(https://cr0n1c.wordpress.com/2016/01/27/using-sccm-to-violate-best-practices/)。例如,通过反转图中的边的方向并且使用管理权限获得更多的用户信息,我们甚至可以用Administrator用户作为源节点进行算法计算,通过迭代AD中的用户,就可以算出Administrator账户。
大家可以从这里得到验证的脚本:https://github.com/andyrobbins/PowerPath