为什么在响应 kex-neogitation 时有来自 openssh 服务器的一些随机字节?
Why there are some random bytes from the openssh server while responding kex-neogitation?
我正在 python 中按照指定的规范 here 编写一个简单的 ssh 客户端。在解析首选 kex_algorithms 列表时,列表开头有一些随机字节,不应该存在?
我正在按照 here 上定义的结构来解析服务器响应。
这是我正在讨论的客户端的 python 代码。
import os
import socket
import io
import struct
HOST = 'localhost'
PORT = 22
MSG_KEXINIT = 20
_preferred_ciphers = (
"aes128-ctr-random-str",
"aes192-ctr-random-str",
"aes256-ctr-random-str",
"aes128-cbc-random-str",
"aes192-cbc-random-str",
"aes256-cbc-random-str",
"blowfish-cbc-random-str",
"3des-cbc-random-str",
)
_preferred_macs = (
"hmac-sha2-256",
"hmac-sha2-512",
"hmac-sha1",
"hmac-md5",
"hmac-sha1-96",
"hmac-md5-96",
)
_preferred_keys = (
"ssh-ed25519",
"ecdsa-sha2-nistp256",
"ecdsa-sha2-nistp384",
"ecdsa-sha2-nistp521",
"ssh-rsa",
"ssh-dss",
)
_preferred_kex = (
"ecdh-sha2-nistp256",
"ecdh-sha2-nistp384",
"ecdh-sha2-nistp521",
"diffie-hellman-group-exchange-sha256",
"diffie-hellman-group-exchange-sha1",
"diffie-hellman-group14-sha1",
"diffie-hellman-group1-sha1",
)
_preferred_compression = ("none",)
def to_name_list(namelist):
namelist_bytes = ",".join(namelist).encode('utf-8')
namelist_size = struct.pack(">I", len(namelist_bytes))
return namelist_size + namelist_bytes
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((HOST, PORT))
# Version exchange
local_version = b'SSH-2.0-MYSSH\r\n'
sock.sendall(local_version)
print("SENT : {}".format(local_version))
data = sock.recv(1024)
print("RECEIVED : {}".format(data))
print("-"*20)
# Key negotiation
kex_msg = io.BytesIO()
kex_msg.write(struct.pack("B", MSG_KEXINIT))
kex_msg.write(os.urandom(16))
kex_msg.write(to_name_list(_preferred_kex))
kex_msg.write(to_name_list(_preferred_keys))
kex_msg.write(to_name_list(_preferred_ciphers))
kex_msg.write(to_name_list(_preferred_ciphers))
kex_msg.write(to_name_list(_preferred_macs))
kex_msg.write(to_name_list(_preferred_macs))
kex_msg.write(to_name_list(_preferred_compression))
kex_msg.write(to_name_list(_preferred_compression))
kex_msg.write(bytes())
kex_msg.write(bytes())
kex_msg.write(struct.pack("B", 0))
kex_msg.write(struct.pack(">I", 0))
sock.sendall(kex_msg.getvalue())
print("SENT : {}".format(kex_msg.getvalue()))
data = sock.recv(1024*4)
print("RECEIVED : {}".format(data))
server_kex_bytes = io.BytesIO(data)
print("Parsing server response")
flag = struct.unpack(">B", server_kex_bytes.read(1))[0]
print("flag : {}".format(flag))
cookie = server_kex_bytes.read(16)
print("cookie : {}".format(cookie))
kex_algo_list_len = struct.unpack(">I", server_kex_bytes.read(4))[0]
print("length of kex algo list: {}".format(kex_algo_list_len))
kex_algo_list = server_kex_bytes.read(kex_algo_list_len)
print("kex_algo_list: {}".format(kex_algo_list))
上述代码生成以下输出。
SENT : b'SSH-2.0-MYSSH\r\n'
RECEIVED : b'SSH-2.0-OpenSSH_8.0\r\n'
--------------------
SENT : b'\x14\xc6\xff\x10r/W2c+\xf3\x15w\x93`\x92\xf5\x00\x00\x00\xb7ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group-exchange-sha1,diffie-hellman-group14-sha1,diffie-hellman-group1-sha1\x00\x00\x00Wssh-ed25519,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,ssh-rsa,ssh-dss\x00\x00\x00\xafaes128-ctr-random-str,aes192-ctr-random-str,aes256-ctr-random-str,aes128-cbc-random-str,aes192-cbc-random-str,aes256-cbc-random-str,blowfish-cbc-random-str,3des-cbc-random-str\x00\x00\x00\xafaes128-ctr-random-str,aes192-ctr-random-str,aes256-ctr-random-str,aes128-cbc-random-str,aes192-cbc-random-str,aes256-cbc-random-str,blowfish-cbc-random-str,3des-cbc-random-str\x00\x00\x00Ghmac-sha2-256,hmac-sha2-512,hmac-sha1,hmac-md5,hmac-sha1-96,hmac-md5-96\x00\x00\x00Ghmac-sha2-256,hmac-sha2-512,hmac-sha1,hmac-md5,hmac-sha1-96,hmac-md5-96\x00\x00\x00\x04none\x00\x00\x00\x04none\x00\x00\x00\x00\x00'
RECEIVED : b'\x00\x00\x044\x06\x14\x18!\xfa\xea\xc4Vv\xd2\xe6\xe5pg\xbc\x08\x8a\xa3\x00\x00\x01\x02curve25519-sha256,curve25519-sha256@libssh.org,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group14-sha256,diffie-hellman-group14-sha1\x00\x00\x00Arsa-sha2-512,rsa-sha2-256,ssh-rsa,ecdsa-sha2-nistp256,ssh-ed25519\x00\x00\x00lchacha20-poly1305@openssh.com,aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,aes256-gcm@openssh.com\x00\x00\x00lchacha20-poly1305@openssh.com,aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,aes256-gcm@openssh.com\x00\x00\x00\xd5umac-64-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha1-etm@openssh.com,umac-64@openssh.com,umac-128@openssh.com,hmac-sha2-256,hmac-sha2-512,hmac-sha1\x00\x00\x00\xd5umac-64-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha1-etm@openssh.com,umac-64@openssh.com,umac-128@openssh.com,hmac-sha2-256,hmac-sha2-512,hmac-sha1\x00\x00\x00\x15none,zlib@openssh.com\x00\x00\x00\x15none,zlib@openssh.com\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
Parsing server response
flag : 0
cookie : b'\x00\x044\x06\x14\x18!\xfa\xea\xc4Vv\xd2\xe6\xe5p'
length of kex algo list: 1740376202
kex_algo_list: b'\xa3\x00\x00\x01\x02curve25519-sha256,curve25519-sha256@libssh.org,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group14-sha256,diffie-hellman-group14-sha1\x00\x00\x00Arsa-sha2-512,rsa-sha2-256,ssh-rsa,ecdsa-sha2-nistp256,ssh-ed25519\x00\x00\x00lchacha20-poly1305@openssh.com,aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,aes256-gcm@openssh.com\x00\x00\x00lchacha20-poly1305@openssh.com,aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,aes256-gcm@openssh.com\x00\x00\x00\xd5umac-64-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha1-etm@openssh.com,umac-64@openssh.com,umac-128@openssh.com,hmac-sha2-256,hmac-sha2-512,hmac-sha1\x00\x00\x00\xd5umac-64-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha1-etm@openssh.com,umac-64@openssh.com,umac-128@openssh.com,hmac-sha2-256,hmac-sha2-512,hmac-sha1\x00\x00\x00\x15none,zlib@openssh.com\x00\x00\x00\x15none,zlib@openssh.com\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
为什么在 kex-list 的开头有一些额外的字节 \xa3\x00\x00\x01\x02
?
是服务器泄露了那些额外的字节还是我理解协议有误?
看起来这个解析跳过了一些字段并对其他字段重新排序。
\x00\x044\x06
看起来像 binary packet 字段:
uint32 packet_length
byte padding_length
(我认为像 [=24=]\x044 这样的序列使它成为一个很难计算字节数的表示。)
cookie 内容以这个和包含 \xa3\x00\x00\x01\x02
的 kex message number which I think is \x14
where they should be the 16 bytes after the message type right up to the name-lists 结尾。此外,解析后的大小看起来高得不可思议。
我正在 python 中按照指定的规范 here 编写一个简单的 ssh 客户端。在解析首选 kex_algorithms 列表时,列表开头有一些随机字节,不应该存在?
我正在按照 here 上定义的结构来解析服务器响应。
这是我正在讨论的客户端的 python 代码。
import os
import socket
import io
import struct
HOST = 'localhost'
PORT = 22
MSG_KEXINIT = 20
_preferred_ciphers = (
"aes128-ctr-random-str",
"aes192-ctr-random-str",
"aes256-ctr-random-str",
"aes128-cbc-random-str",
"aes192-cbc-random-str",
"aes256-cbc-random-str",
"blowfish-cbc-random-str",
"3des-cbc-random-str",
)
_preferred_macs = (
"hmac-sha2-256",
"hmac-sha2-512",
"hmac-sha1",
"hmac-md5",
"hmac-sha1-96",
"hmac-md5-96",
)
_preferred_keys = (
"ssh-ed25519",
"ecdsa-sha2-nistp256",
"ecdsa-sha2-nistp384",
"ecdsa-sha2-nistp521",
"ssh-rsa",
"ssh-dss",
)
_preferred_kex = (
"ecdh-sha2-nistp256",
"ecdh-sha2-nistp384",
"ecdh-sha2-nistp521",
"diffie-hellman-group-exchange-sha256",
"diffie-hellman-group-exchange-sha1",
"diffie-hellman-group14-sha1",
"diffie-hellman-group1-sha1",
)
_preferred_compression = ("none",)
def to_name_list(namelist):
namelist_bytes = ",".join(namelist).encode('utf-8')
namelist_size = struct.pack(">I", len(namelist_bytes))
return namelist_size + namelist_bytes
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((HOST, PORT))
# Version exchange
local_version = b'SSH-2.0-MYSSH\r\n'
sock.sendall(local_version)
print("SENT : {}".format(local_version))
data = sock.recv(1024)
print("RECEIVED : {}".format(data))
print("-"*20)
# Key negotiation
kex_msg = io.BytesIO()
kex_msg.write(struct.pack("B", MSG_KEXINIT))
kex_msg.write(os.urandom(16))
kex_msg.write(to_name_list(_preferred_kex))
kex_msg.write(to_name_list(_preferred_keys))
kex_msg.write(to_name_list(_preferred_ciphers))
kex_msg.write(to_name_list(_preferred_ciphers))
kex_msg.write(to_name_list(_preferred_macs))
kex_msg.write(to_name_list(_preferred_macs))
kex_msg.write(to_name_list(_preferred_compression))
kex_msg.write(to_name_list(_preferred_compression))
kex_msg.write(bytes())
kex_msg.write(bytes())
kex_msg.write(struct.pack("B", 0))
kex_msg.write(struct.pack(">I", 0))
sock.sendall(kex_msg.getvalue())
print("SENT : {}".format(kex_msg.getvalue()))
data = sock.recv(1024*4)
print("RECEIVED : {}".format(data))
server_kex_bytes = io.BytesIO(data)
print("Parsing server response")
flag = struct.unpack(">B", server_kex_bytes.read(1))[0]
print("flag : {}".format(flag))
cookie = server_kex_bytes.read(16)
print("cookie : {}".format(cookie))
kex_algo_list_len = struct.unpack(">I", server_kex_bytes.read(4))[0]
print("length of kex algo list: {}".format(kex_algo_list_len))
kex_algo_list = server_kex_bytes.read(kex_algo_list_len)
print("kex_algo_list: {}".format(kex_algo_list))
上述代码生成以下输出。
SENT : b'SSH-2.0-MYSSH\r\n'
RECEIVED : b'SSH-2.0-OpenSSH_8.0\r\n'
--------------------
SENT : b'\x14\xc6\xff\x10r/W2c+\xf3\x15w\x93`\x92\xf5\x00\x00\x00\xb7ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group-exchange-sha1,diffie-hellman-group14-sha1,diffie-hellman-group1-sha1\x00\x00\x00Wssh-ed25519,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,ssh-rsa,ssh-dss\x00\x00\x00\xafaes128-ctr-random-str,aes192-ctr-random-str,aes256-ctr-random-str,aes128-cbc-random-str,aes192-cbc-random-str,aes256-cbc-random-str,blowfish-cbc-random-str,3des-cbc-random-str\x00\x00\x00\xafaes128-ctr-random-str,aes192-ctr-random-str,aes256-ctr-random-str,aes128-cbc-random-str,aes192-cbc-random-str,aes256-cbc-random-str,blowfish-cbc-random-str,3des-cbc-random-str\x00\x00\x00Ghmac-sha2-256,hmac-sha2-512,hmac-sha1,hmac-md5,hmac-sha1-96,hmac-md5-96\x00\x00\x00Ghmac-sha2-256,hmac-sha2-512,hmac-sha1,hmac-md5,hmac-sha1-96,hmac-md5-96\x00\x00\x00\x04none\x00\x00\x00\x04none\x00\x00\x00\x00\x00'
RECEIVED : b'\x00\x00\x044\x06\x14\x18!\xfa\xea\xc4Vv\xd2\xe6\xe5pg\xbc\x08\x8a\xa3\x00\x00\x01\x02curve25519-sha256,curve25519-sha256@libssh.org,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group14-sha256,diffie-hellman-group14-sha1\x00\x00\x00Arsa-sha2-512,rsa-sha2-256,ssh-rsa,ecdsa-sha2-nistp256,ssh-ed25519\x00\x00\x00lchacha20-poly1305@openssh.com,aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,aes256-gcm@openssh.com\x00\x00\x00lchacha20-poly1305@openssh.com,aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,aes256-gcm@openssh.com\x00\x00\x00\xd5umac-64-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha1-etm@openssh.com,umac-64@openssh.com,umac-128@openssh.com,hmac-sha2-256,hmac-sha2-512,hmac-sha1\x00\x00\x00\xd5umac-64-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha1-etm@openssh.com,umac-64@openssh.com,umac-128@openssh.com,hmac-sha2-256,hmac-sha2-512,hmac-sha1\x00\x00\x00\x15none,zlib@openssh.com\x00\x00\x00\x15none,zlib@openssh.com\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
Parsing server response
flag : 0
cookie : b'\x00\x044\x06\x14\x18!\xfa\xea\xc4Vv\xd2\xe6\xe5p'
length of kex algo list: 1740376202
kex_algo_list: b'\xa3\x00\x00\x01\x02curve25519-sha256,curve25519-sha256@libssh.org,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group14-sha256,diffie-hellman-group14-sha1\x00\x00\x00Arsa-sha2-512,rsa-sha2-256,ssh-rsa,ecdsa-sha2-nistp256,ssh-ed25519\x00\x00\x00lchacha20-poly1305@openssh.com,aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,aes256-gcm@openssh.com\x00\x00\x00lchacha20-poly1305@openssh.com,aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,aes256-gcm@openssh.com\x00\x00\x00\xd5umac-64-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha1-etm@openssh.com,umac-64@openssh.com,umac-128@openssh.com,hmac-sha2-256,hmac-sha2-512,hmac-sha1\x00\x00\x00\xd5umac-64-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha1-etm@openssh.com,umac-64@openssh.com,umac-128@openssh.com,hmac-sha2-256,hmac-sha2-512,hmac-sha1\x00\x00\x00\x15none,zlib@openssh.com\x00\x00\x00\x15none,zlib@openssh.com\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
为什么在 kex-list 的开头有一些额外的字节 \xa3\x00\x00\x01\x02
?
是服务器泄露了那些额外的字节还是我理解协议有误?
看起来这个解析跳过了一些字段并对其他字段重新排序。
\x00\x044\x06
看起来像 binary packet 字段:
uint32 packet_length
byte padding_length
(我认为像 [=24=]\x044 这样的序列使它成为一个很难计算字节数的表示。)
cookie 内容以这个和包含 \xa3\x00\x00\x01\x02
的 kex message number which I think is \x14
where they should be the 16 bytes after the message type right up to the name-lists 结尾。此外,解析后的大小看起来高得不可思议。