Paul Fiterau
2021-Oct-15 13:23 UTC
Report on findings after testing OpenSSH server implementations
Hello! I am part of a testing research group at Uppsala University. We have recently applied our model-based testing technique to OpenSSH servers and would like to share our findings in terms of potential issues found and receive feedback of course. The version we tested is 8.8p1, which was running on a Ubuntu 20.04 machine. For each issue, we give an input/output sequence that exposes it, and relevant quotes for the RFC. We can also provide reproduction material if asked. None of the issues appear to have any security implications. Before going over the issues, we wanted to first ask you about one behavior which we struggle to understand. We notice that OpenSSH buffers higher-layer messages received during part of the key re-exchange process. Is this really necessary given that a client should not generate these messages, according to RFC 4253 (see quote below). Wouldn't it be easier to simply discard/reject these messages (like Dropbear does, which would solve Issues 1 and 2)? What we want to know, concretely, is, if there is a practical reason for this behavior/design choice. RFC 4253, page 19: "? After the SSH_MSG_KEXINIT message exchange, the key exchange algorithm is run. It may involve several packet exchanges, as specified by the key exchange method. Once a party has sent a SSH_MSG_KEXINIT message for key exchange or re-exchange, until it has sent a SSH_MSG_NEWKEYS message (Section 7.3), it MUST NOT send any messages other than: o Transport layer generic messages (1 to 19) (but SSH_MSG_SERVICE_REQUEST and SSH_MSG_SERVICE_ACCEPT MUST NOT be sent); o Algorithm negotiation messages (20 to 29) (but further SSH_MSG_KEXINIT messages MUST NOT be sent); o Specific key exchange method messages (30 to 49)." Now onto the issues. Issue 1. Processing upper-layer data before key re-exchange is complete. When performing key re-exchange (rekeying), OpenSSH does not wait for the client NEWKEYS before processing higher-layer messages. Concretely, it processes higher-layer messages (secured with old keys) received between sending NEWKEYS to the client and receiving NEWKEYS from the client. Technically, the RFC does not explicitly mention that servers should wait for NEWKEYS from the client before processing messages. But intuitively, a key re-exchange (like the initial key exchange) is only complete once keys are renewed and deployed in both directions. Before that, it seems to us that higher-layer messages should not be processed, as is the case for the initial key exchange (which key re-exchange is supposed to be similar with). Not to mention that a client is not supposed to send any higher-layer messages before sending NEWKEYS. Sequence: KEXINIT/KEXINIT KEX30/KEX31+NEWKEYS NEWKEYS/NO_RESPONSE SERVICE_REQUEST(ssh-userauth)/SERVICE_ACCEPT USERAUTH_REQUEST/USERAUTH_SUCCESS+GLOBAL_REQUEST KEXINIT/KEXINIT KEX30/KEX31+NEWKEYS CHANNEL_OPEN/CHANNEL_OPEN_SUCCESS Issue 2. Non-conforming response to CHANNEL_CLOSE. The presence of Issue 1 leads to Issue 2. The RFC says that on receiving a CHANNEL_CLOSE to close a channel, implementations SHOULD reply with CHANNEL_CLOSE. OpenSSH does not always follow this requirement. In particular, when receiving CHANNEL_CLOSE during key exchange, it silently consumes this message and only generates CHANNEL_CLOSE response after receiving NEWKEYS from the client. What is interesting is that, during that same key re-exchange, OpenSSH processes CHANNEL_OPEN and generates CHANNEL_OPEN_SUCCESS before NEWKEYS is received. RFC 4254, page 9: "? When either party wishes to terminate the channel, it sends SSH_MSG_CHANNEL_CLOSE. Upon receiving this message, a party MUST send back an SSH_MSG_CHANNEL_CLOSE unless it has already sent this message for the channel. " Sequence: KEXINIT/KEXINIT KEX30/KEX31+NEWKEYS NEWKEYS/NO_RESPONSE SERVICE_REQUEST(ssh-userauth)/SERVICE_ACCEPT USERAUTH/USERAUTH_SUCCESS+GLOBAL_REQUEST KEXINIT/KEXINIT KEX30/KEX31+NEWKEYS CHANNEL_OPEN/CHANNEL_OPEN_SUCCESS CHANNEL_CLOSE/NO_RESPONSE CHANNEL_OPEN/CHANNEL_OPEN_SUCCESS CHANNEL_CLOSE/NO_RESPONSE NEWKEYS / CHANNEL_CLOSE + CHANNEL_CLOSE Issue 3. Rekey not supported pre-authentication. We found that rekey is not supported after key exchange is complete but before the user authenticates. Sequence: KEXINIT/KEXINIT KEX30/KEX31+NEWKEYS NEWKEYS/NO_RESPONSE SERVICE_REQUEST(ssh-userauth)/SERVICE_ACCEPT KEXINIT/UNIMPLEMENTED Issue 4. Use of UNIMPLEMENTED when the RFC says otherwise (very minor but might as well mention it). RFC 4253, page 24: "? If the server rejects the service request, it SHOULD send an appropriate SSH_MSG_DISCONNECT message and MUST disconnect." Sequence: KEXINIT/KEXINIT SERVICE_REQUEST(ssh-userauth)/UNIMPLEMENTED RFC 4252, page 6: "? SSH_MSG_USERAUTH_SUCCESS MUST be sent only once. When SSH_MSG_USERAUTH_SUCCESS has been sent, any further authentication requests received after that SHOULD be silently ignored." Sequence: KEXINIT/KEXINIT KEX30/KEX31+NEWKEYS NEWKEYS/NO_RESPONSE SERVICE_REQUEST(ssh-userauth)/SERVICE_ACCEPT USERAUTH/USERAUTH_SUCCESS+GLOBAL_REQUEST USERAUTH/UNIMPLEMENTED Thanks for any feedback, particularly on Issue 1 and buffering! Paul. N?r du har kontakt med oss p? Uppsala universitet med e-post s? inneb?r det att vi behandlar dina personuppgifter. F?r att l?sa mer om hur vi g?r det kan du l?sa h?r: http://www.uu.se/om-uu/dataskydd-personuppgifter/ E-mailing Uppsala University means that we will process your personal data. For more information on how this is performed, please read here: http://www.uu.se/en/about-uu/data-protection-policy