From 581c78469c93bf6cb0a1e69ed1013f20c4e02fad Mon Sep 17 00:00:00 2001 From: Warren Date: Mon, 15 Jun 2026 01:42:28 +0800 Subject: [PATCH] =?UTF-8?q?OpenSSH=20client=E6=BA=90=E7=A0=81=E9=AA=8C?= =?UTF-8?q?=E8=AF=81=EF=BC=9A=E5=8F=91=E7=8E=B0padding=20bytes=E5=B7=AE?= =?UTF-8?q?=E5=BC=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 深度分析OpenSSH packet processing: 关键发现: ✅ ssh_packet_read_poll2_mux(): incoming_packet存储padding_length + type + payload + padding ✅ sshbuf_get_u8()消耗padding_length和type后,剩余payload + padding ✅ kex_input_kexinit(): sshpkt_ptr()返回payload + padding(从cookie开始) ✅ kex->peer存储:payload fields + padding(不包括type byte) 差异: - OpenSSH kex->peer包括padding bytes - 我们client_kexinit_payload不包括padding bytes 测试padding fix: ❌ 加padding后:签名验证失败(说明exchange hash计算方式不同) ✅ 不加padding:签名成功但MAC失败(说明不是padding问题) 结论: OpenSSH exchange hash calculation可能不包括padding bytes 需要进一步验证OpenSSH如何计算exchange hash 下一步建议: 1. 检查OpenSSH exchange hash calculation是否重新构建packet(包括padding) 2. 或验证OpenSSH kex->my是否也包括padding 3. 或使用OpenSSH server对比测试(手动启动) --- data/auth.sqlite | Bin 73728 -> 73728 bytes markbase-core/src/ssh_server/kex_complete.rs | 16 ++++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/data/auth.sqlite b/data/auth.sqlite index 3e7f0cd050714fa68299d891050830909010ee4b..afccceb5748d1d1c01259690e7af3d49337717c5 100644 GIT binary patch delta 171 zcmZoTz|wGlWr8&0%84@0j4L-Lw97CWO+F~4FquR44%@>UO&q-@n_tPYF#_3*b-l)u zzsdb!dU#{=7y0M>lAC#%WtnpGb5rw5iYnQ*a59TBrKINOvu)b^MgIf8z-CrvPA0Z3 q3=Aw_22j)k{fuLWtnpGb5rw5iYnPQax#lDrKINOv#sC!MgIf8zy?-kPA0aE q3=Aw_22j)peer存储的是:incoming_packet剩余内容(payload fields + padding) + /// - kex->my存储的是:prop2buf()结果(payload fields,不包括padding) + /// + /// **但exchange hash必须使用相同的I_C/I_S!** + /// + /// 疑问:OpenSSH如何确保client和server使用相同的padding? + /// 可能答案:OpenSSH在计算exchange hash时,不包括padding? + /// + /// 暂时保持不包括padding(因为签名验证之前成功) pub fn save_kexinit_payloads( &mut self, client_kexinit: &SshPacket, server_kexinit: &SshPacket, ) { + // Only save payload (without padding) for now self.client_kexinit_payload = client_kexinit.payload.clone(); self.server_kexinit_payload = server_kexinit.payload.clone(); + + info!("Saved KEXINIT payloads (payload only, no padding)"); + info!(" client payload: {} bytes", self.client_kexinit_payload.len()); + info!(" server payload: {} bytes", self.server_kexinit_payload.len()); } /// 计算Exchange Hash(参考OpenSSH kex.c: kex_hash())