sshopenssh

Unexpected Server Response During SSH Connection Protocol


I am implementing a rudimentary ssh client capable of securely sending a single command to an OpenSSH server. My client is currently able to handle everything up to sending service requests to the server (ie. I have derived keys from a Diffie-Hellman exchange). My goal is to send a single command (ie. whoami) to the server.

Once key exchange has been completed successfully, I am sending these packets in the following order in accordance with binary packet protocol. Each message has been unencrypted, and I've bolded the message IDs for each of the messages.

#1: Authentication service request
      byte      SSH_MSG_SERVICE_REQUEST
      string    “ssh-userauth”

Packet sent: 00 00 00 1c 0a 05 00 00 00 0c 73 73 68 2d 75 73 65 72 61 75 74 68 31 89 4b 1f 27 2f 02 98 f0 0d

Server response: 00 00 00 1c 0a 06 00 00 00 0c 73 73 68 2d 75 73 65 72 61 75 74 68 89 da 3a a3 b3 63 8e 8d c5 40

#2: Authentication information
      byte      SSH_MSG_USERAUTH_REQUEST
      string    user name
      string    “ssh-connection”
      string    "password"
      boolean   FALSE
      string    plaintext password

Packet sent: 00 00 00 3c 0b 32 00 00 00 04 XX XX XX XX 00 00 00 0e 73 73 68 2d 63 6f 6e 6e 65 63 74 69 6f 6e 00 00 00 08 70 61 73 73 77 6f 72 64 00 00 00 00 04 XX XX XX XX 31 89 4b 1f 27 2f 02 98 f0 0d 25

(omitted username and password)

Server’s response: 00 00 00 0c 0a 34 de f3 3b 8c 20 ca 6b 0f 69 43

This indicates that I am authenticating successfully and the server is ready for the client to open channels.

I are getting responses I expect up until this point, so I'm assuming server auth has been completed successfully, so I move on to opening a session channel:

Expected #4: Open session channel
      byte      SSH_MSG_CHANNEL_OPEN
      string    "session"
      uint32    sender channel
      uint32    initial window size
      uint32    maximum packet size

Packet sent: 00 00 00 1c 03 5a 00 00 00 07 73 65 73 73 69 6f 6e 00 00 00 01 00 00 04 00 00 00 04 00 06 c4 3d

Server’s response: 00 00 00 1c 0a 5b 00 00 00 00 00 00 00 00 00 00 00 00 00 00 80 00 c6 ee 88 13 f7 78 ba a0 1d ea

The server responds with a 5b code (SSH_MSG_CHANNEL_OPEN_CONFIRMATION), so the channel open request seems to have been carried out correctly as well; however, I don't understand why the window size is set to 0 (may be relevant later).

I now want to request execution of a command: "whoami". So I send a message channel request:

Expected #5: Send command to server
      byte      SSH_MSG_CHANNEL_REQUEST
      uint32    recipient channel
      string    "exec"
      boolean   want reply
      string    “whoami”

Packet sent: 00 00 00 2c 13 62 00 00 00 00 00 00 00 04 65 78 65 63 01 00 00 00 06 77 68 6f 61 6d 69 ad de 4d 6c dd b7 8e 19 3f 68 7a 8e 5a 63 10 99 2e dd 54

Here's where I get confused, packet received: 00 00 00 1c 12 5d 00 00 00 00 00 20 00 00 fd fa 83 ae 1d 50 ca 25 7c 42 6b 71 a7 ea dc 9f 9a 41 12 8d ff 45 f6 84 c0 36 a0 10 12 f8 01 c5 11 80 49 4c 95 9c be ec b2 b2 49 70 3e e3 d8 1e 3c 68 78 79 c5 b9

The server sends back a SSH_MSG_CHANNEL_WINDOW_ADJUST packet which is unexpected since I'm just requesting the results of "whoami," but I suspect it has to do with the fact that in the server's channel open confirmation message, the server sent that the window size is 0. Also, from reading RFC 4254 it doesn't seem like the server wants a response to this window adjust message.

What I'm even more confused about is how this packet seems to deviate from the binary packet protocol. The length is 1c, but the number of bytes the client is sent is much more than that, and the padding length is 12, but even after the 12 bytes of padding, there is more to the message.

Any insight into what this extra information is in the packet?

Am I missing a step in the connection or messing up a step?


Solution

  • The issue was that I didn't realize that the server was sending multiple messages within a single packet.

    My client was correctly decrypting the first message, but not the second.

    The server response looks something like this:

    (encrypted packet 1 || MAC 1 || encrypted packet 2 || MAC 2 ...)

    But I was expecting it to looks like this:

    (encrypted packet 1 || MAC 1)