預備知識:
SSH認證流程:
SSH的登錄過程會分為5個階段進行,首先是版本號協商階段,服務器端監聽22端口,客戶端與服務端建立TCP連接,並且進行SSH版本協商,如果協商成功就進入密鑰和算法協商階段,否則就斷開TCP連接。
在密鑰算法協商階段,服務器首先將自己的公鑰和會話ID發送給客戶端,客戶端將ID及會話密鑰Key進行異或操作,用公鑰將異或后的結果加密,發送給服務端。
服務端進行反向操作,利用自己的密鑰和客戶端的公鑰解密,得到Key值,接下來的傳輸都是以密鑰的形式進行加解密。
在口令或密鑰認證階段,首先是客戶端利用自己的私鑰和Key進行加密,然后傳輸到服務器端,服務器端利用自己的私鑰和Key進行解密,判斷解密后的口令,
如果口令錯誤,發送失敗報文和認證列表,客戶端收到后重新選擇認證,如果認證成功則進入交互界面,如果認證失敗則一直循環,直到達到服務器端認證的次數上限,服務器端主動關閉本次TCP連接。
libssh版本0.6及更高版本在服務端代碼中具有身份驗證繞過漏洞。
實驗環境:
libssh0.7.5
Ubuntu 192.168.100.160/24
python3
docker & docker-compose
漏洞復現:
創建source目錄,復制libssh到source

解壓並進入目錄
tar xvJf libssh-0.7.5.tar.xz
cd libssh-0.7.5
看到解壓出來的文件

編譯並安裝
mkdir build && cd build
cmake -DCMAKE_install_prefix=/usr -DCMAKE_BUILD_TYPE=Debug ..
make


修改src目錄下的auth.c源文件。
找到ssh_userauth_password函數並將SSH2_MSG_USERAUTH_REQUEST替換為SSH2_MSG_USERAUTH_SUCCESS
vim ../src/auth.c

修改后 ./examples/samplessh就會成為驗證該漏洞的PoC。
找到SSH_AUTH_STATE_NONE和SSH_PENDING_CALL_AUTH_OFFER_PUBKEY
替換為SSH_AUTH_STATE_SUCCESS和SSH_PENDING_CALL_CONNECT

修改兩處登錄狀態源代碼,./examples/samplessh就會成為驗證該漏洞的PoC。
保存退出輸入make再次編譯

輸入 ssh-keygen創建私鑰和公鑰
ssh-keygen生成過程中會詢問多個配置信息,全部點擊回車,使用默認設置即可。

啟動服務並測試
examples/ssh_server_fork -p 7777 127.0.0.1 -v -k /root/.ssh/id_rsa
同時啟動新終端窗口,使用SSH客戶端連接服務端:
進入build目錄 輸入代碼 ./examples/samplessh -p 7777 root@127.0.0.1 ,連接成功

在服務器輸出的調試信息中可以找到包類型的分派處理程序(ssh_packet_process)

根據服務端輸出的調試信息,篩掉無用的日志信息,找到ssh_pack_process,
分析可以看出該漏洞的利用點就是發送SSH2_MSG_USERAUTH_SUCCESS請求,從而進入ssh_packet_userauth_success函數。
cd 進入 libssh-0.7.5/examples/
在ssh_server_fork.c文件找到ssh_server_callbacks_struct函數,發現服務端設Demo中進行了設置

在ssh_server_fork.c文件中找到auth_password函數

認證成功后的路徑:
ssh_message_auth_reply_success ->ssh_auth_reply_success:
從源代碼可以看出,在正常情況下,在SSH登錄成功后,libssh給Session設置了認證成功的狀態。
結束服務端和客戶端程序
退出到source目錄,並刪除剛才解壓的目錄
rm -rf libssh-0.7.5
通過程序發送SSH2_MSG_USERAUTH_SUCCESS消息,觸發漏洞
創建docker-compose.yml 輸入如下代碼

docker-compose up -d 啟動環境
創建python文件libssh_poc.py並輸入代碼

輸入命令利用poc
python3 libssh_poc.py

成功執行id命令
