從Windows 10 SSH-Agent中提取SSH私鑰
背景
在這個周末我安裝了Windows 10 Spring Update,最令我期待的就是它的內置OpenSSH工具,這意味著Windows管理員不再需要使用Putty和PPK格式的密鑰了。隨後,我花了些時間來探索並了解該版本所支持的特性。最終沒有令我失望,我驚喜地看到ssh-agent.exe也被包含在內。在MSDN的一篇關於使用新Windows ssh-agent文章的以下部分,引起了我的注意:
過去我曾有過劫持ssh-agent.的相關經驗,並嘗試過一些有趣的測試,所以我決定開始查看Windows是如何「安全地」用這個新的服務來存儲您的私鑰的。我將在這篇文章中概述我的方法和步驟,這是一個非常有趣的過程。好了,話不多說讓我們開始我們的旅程吧!
私鑰由DPAPI保護並存儲在HKCU註冊表hive中。我在這裡發布了一些PoC代碼,從註冊表中提取並重構RSA私鑰。
在Windows 10中使用OpenSSH
測試要做的第一件事就是使用OpenSSH生成幾個密鑰對並將它們添加到ssh-agent中。
首先,我使用ssh-keygen.exe生成了一些受密碼保護的測試密鑰對:
然後確保新的ssh-agent服務正在運行,並使用ssh-add將私鑰對添加到正在運行的agent中:
運行ssh-add.exe -L顯示當前由SSH agent管理的密鑰。
最後,在將公鑰添加到Ubuntu box之後,我驗證了我可以從Windows 10進入SSH,而不需要解密我的私鑰(因為ssh-agent正在為我處理):
監控SSH Agent
為了了解SSH代理是如何存儲和讀取我的私鑰,我開始靜態檢查ssh-agent.exe。然而,我的靜態分析技能很弱,所以我放棄了,並最終決定採用動態跟蹤這個過程的方式,看看它在做什麼。
我使用了Sysinternals的procmon.exe,並為包含「ssh」的任意進程名稱添加了一個過濾器。
隨著procmon捕獲事件,我再次進入我的Ubuntu機器。查看所有的事件,我看到ssh.exe打開了一個TCP連接到Ubuntu,以及ssh-agent.exe進入並從Registry中讀取了一些值:
這裡有兩個非常重要的點:
進程ssh-agent.exe讀取來自HKCUSoftwareOpenSSHAgentKeys的鍵值
讀取這些值後,立即打開了dpapi.dll。
正因為如此,我現在知道某種受保護的數據被存儲在註冊表中並從註冊表中被讀取,ssh-agent正在使用微軟的數據保護API.aspx)。
測試註冊表值
果然,在註冊表中,可以看到我使用ssh-add添加的兩個鍵項。密鑰名稱是公開密鑰的指紋,並且存在一些二進位blobs:
我能夠pull註冊表值並操作它們。「注釋」欄位只是ASCII編碼文本,是我添加的密鑰的名稱:
(默認值)只是一個位元組數組,沒有解碼出任何有意義的東西。我有一個預感,這是「加密」私鑰,那麼我是否能pull並解密它呢。我把位元組pull到了一個Powershell變數:
解除密鑰保護
雖然我知道很多後利用工具可以濫用它來取出憑據,但我對DPAPI並不太熟悉,因此我也知道其他人可能已經實現了一個wrapper。通過Google搜索,我找到了一個簡單的單線程wrapper。
我仍然不知道這是否可行,但我試圖使用DPAPI去解除位元組數組的保護。Base64編碼結果如下:
返回的Base64看起來不像是私鑰,但我只是為了好玩而解碼它,然而對於裡面出現的「ssh-rsa」字元串我感到非常的驚喜。
找出二進位格式
這部分是我花時間最長的一部分。我知道我有某種鍵的二進位表示,但我無法找出格式或如何使用它。
我用openssl,puttygen和ssh-keygen來生成各種RSA密鑰,但從來沒有得到類似於我擁有的二進位文件的任何東西。
最後,在大量的Google之後,我從NetSPI找到了一篇關於從Linux上的ssh-agent的內存轉儲中取出OpenSSH私鑰的文章:https://blog.netspi.com/stealing-unencrypted-ssh-agent-keys-from-memory/
難道是二進位格式相同嗎?我從博客中獲取了Python腳本,並為它提供了我從Windows註冊表中獲得的不受保護的base64 blob:
可以正常工作了!我不知道原作者soleblaze是如何找出二進位數據的正確格式的,但在這裡我要特別感謝他所做的以及他的分享!
在證明可以從註冊表中提取私鑰後,我將PoC分享到了GitHub。
GitHub Repo
第一個是Powershell腳本(extract_ssh_keys.ps1),用於查詢註冊表中被ssh-agent保存的任何密鑰。然後使用DPAPI與當前用戶上下文來解除二進位保護,並將其保存在Base64中。由於我不知道如何在Powershell中解析二進位數據,所以我把所有的密鑰保存到了一個JSON文件中,然後我可以在Python中導入。Powershell腳本只有幾行:
我大量借用了parse_mem_python.py中的代碼,並將其更新為Python 3,用於下一個腳本:extractPrivateKeys.py。從Powershell腳本生成的JSON將輸出所有的RSA私鑰:
這些RSA私鑰是未加密的。雖然我創建它們時,添加了一個密碼,但它們使用ssh-agent未加密存儲,所以我不再需要密碼。
為了驗證,我將密鑰複製回了Kali linux box中驗證了指紋,並將其應用到了SSH中!
結語
很顯然,我的PowerShell功底非常的薄弱,我發布的代碼更多的是PoC。我也希望我的PoC最終能被武器化,並被添加到後利用的框架中。希望大家也能積極地探索,如果你也有新的發現和玩法,那麼歡迎你在第一時間與我分享!
*參考來源:ropnop,FB小編 secist 編譯,轉載請註明來自FreeBuf.COM


※機器學習之垃圾信息過濾
※Facebook醜聞反思 | 大數據環境下的隱形黑手
TAG:FreeBuf |