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世紀的歐拉提出的一個數學的分支–圖論。歐拉就是通過圖論證明了柯尼斯堡七橋問題是無解的。這個方法包括:
頂點——頂點(或者節點)代表一個系統中的單個元素,你可以理解成地圖上的城市。
邊界——邊界用來連接節點,可以是有向的,也可以是無向的。
路徑——路徑是一組邊界和節點的集合,節點間要相互連接
鄰接——共享同一個邊的節點互稱為鄰接。
圖形設計
針對這個問題提出來的想法的證明目的只有一個 ——自動化的找出攻陷域管理員的最短路徑。 當然,這個圖的設計可能并不適合其他的問題。
這個圖最開始的時候我先設計成一個非常簡單的并且可能充滿錯誤,隨著不斷的添加機器,最終設計成:
每一個用戶和機器都是一個節點
所有邊都是無權重的有向線
從用戶到機器的有向邊代表本地管理員權限
從機器到用戶的有向邊代表登錄過該機器的用戶
想象一個只有兩臺電腦和兩個用戶組成的非?;A的網絡結構。其中,”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