linux 服务器基本信息:

bash
1
2
3
4
5
6
7
8
root@tom-server:~/ssh-test# uname -a
Linux tom-server 5.4.0-200-generic #220-Ubuntu SMP Fri Sep 27 13:19:16 UTC 2024 x86_64 x86_64 x86_64 GNU/Linux
root@tom-server:~/ssh-test# ssh -V
OpenSSH_8.2p1 Ubuntu-4ubuntu0.12, OpenSSL 1.1.1f 31 Mar 2020
root@tom-server:~/ssh-test# python3 -V
Python 3.8.10
root@tom-server:~/ssh-test# python2 -V
Python 2.7.18

获取SSH会话解密因子和流量包

使用 tcpdump 在 linux 服务端抓取 SSH 22 端口的流量包

bash
1
sudo tcpdump -i any port 22 -w ssh_traffic.pcap

客户端通过 SSH 连接服务器,并执行一些简单的命令做测试,如 lspwd等,方便解密流量后观察

bash
1
ssh root@server-ip

使用 OpenSSH-Session-Key-Recovery 对 SSH 内存抓取会话解密因子

bash
1
python3 OpenSSH-Session-Key-Recovery/pip-package/openssh_session_keys/keys.py

抓取前可以先测试一遍,以判断哪一对是新增的解密因子

  • 通过脚本抓取到的解密因子
    • pid:ssh客户端的进程号为4039879
    • sshenc_addr:sshenc结构体内存地址为93860335628000
    • cipher_name:对称加密算法为aes256-gcm@openssh.com
    • key:会话密钥
    • iv:初始化向量
    • sshenc:sshenc结构体
    • network_connections:tcp连接情况,10.181.11.90的22端口向远程10.181.11.92的22端口建立了TCP连接
json
1
2
{"pid": 4039879, "proc_name": "sshd", "sshenc_addr": 93860335628000, "cipher_name": "aes256-gcm@openssh.com", "key": "a9ac0ed591a68dd8752e625c44ec3333ec9bdcf074f9474f09068d036955c1b8", "iv": "f8520a9d17d34d6c9b0d25f6", "sshenc": {"name": 93860335680080, "cipher": 93860080389480, "enabled": 0, "key_len": 32, "iv_len": 12, "block_size": 16, "key": 93860335615632, "iv": 93860335670560}, "network_connections": [{"family": 2, "fd": 4, "laddr": ["10.181.11.92", 22], "raddr": ["10.181.11.90", 50623], "status": "ESTABLISHED", "type": 1}]}
{"pid": 4039879, "proc_name": "sshd", "sshenc_addr": 93860335703504, "cipher_name": "aes256-gcm@openssh.com", "key": "7ca58c5b5e67f34043069d53fb13ebc2b82fb7c10138dbf4e8921a84aa371c97", "iv": "5c20bc2f6ffe9f81516ca2a0", "sshenc": {"name": 93860335523952, "cipher": 93860080389480, "enabled": 0, "key_len": 32, "iv_len": 12, "block_size": 16, "key": 93860335701296, "iv": 93860335680048}, "network_connections": [{"family": 2, "fd": 4, "laddr": ["10.181.11.92", 22], "raddr": ["10.181.11.90", 50623], "status": "ESTABLISHED", "type": 1}]}
  • 参考下面模板,替换对应内容,并保存为 json 文件解密使用
json
1
2
{"task_name": "sshd", "sshenc_addr": 93860335628000, "cipher_name": "aes256-gcm@openssh.com", "key": "a9ac0ed591a68dd8752e625c44ec3333ec9bdcf074f9474f09068d036955c1b8", "iv": "f8520a9d17d34d6c9b0d25f6"}
{"task_name": "sshd", "sshenc_addr": 93860335703504, "cipher_name": "aes256-gcm@openssh.com", "key": "7ca58c5b5e67f34043069d53fb13ebc2b82fb7c10138dbf4e8921a84aa371c97", "iv": "5c20bc2f6ffe9f81516ca2a0"}

解密 SSH 流量

前置条件:

bash
1
python2.7 -m openssh_network_parser.tools.network_parser -p ../ssh_traffic.pcap --proto=ssh --popt keyfile=../ssh-keys.json -o outssh -s
  • -p:载入pcap流量包路径
  • --proto:解析协议
  • --popt:载入密钥文件
  • -o:运行过程中一些统计信息输出路径
  • -s:打印到标准输出而不是日志文件

可以看到脚本成功执行后,客户端向服务器传输的命令以及服务器的响应都解密还原成功

解决 dissect 依赖报错

运行命令先查看当前 pip2 查看当前环境安装包信息

rust
1
pip2 list -v | grep dissect

可以发现dissect.cstruct 的版本是 2.0

而我们需要的环境是 1.0.0

重新安装

rust
1
2
pip2 uninstall dissect.cstruct
pip2 install dissect.cstruct==1.0.0

参考

https://blog.fox-it.com/2020/11/11/decrypting-openssh-sessions-for-fun-and-profit/

https://github.com/fox-it/OpenSSH-Session-Key-Recovery

https://github.com/fox-it/OpenSSH-Network-Parser