Proposal Details
I propose a new ssh.Channel function to read a single SSH packet.
This is required in to inter-opt with some channel types in use by OpenSSH.
For example to inter-opt with the tun@openssh.com channel type defined in section 2.3 of the openssh protocol standard:
283: Once established the client and server may exchange packet or frames
284: over the tunnel channel by encapsulating them in SSH protocol strings
285: and sending them as channel data. This ensures that packet boundaries
286: are kept intact. Specifically, packets are transmitted using normal
287: SSH_MSG_CHANNEL_DATA packets:
It is required that you are able to read each individual SSH packet as it defines the length of each Network packet.
Currently the Read(...) function defined by the ssh.Channel interface reads all buffered SSH packets.
This requires the implementer of tun@openssh.com and other similar channel types to attempt to determine SSH packet size (and thus network packet size) from the data that is returned from Read(...).
This is error prone and in some cases not feasible.
The following are two snippets to show how this may be implemented.
Example addition to ssh.buffer:
func (b *buffer) ReadSingle() ([]byte, error) {
sb.Cond.L.Lock()
defer sb.Cond.L.Unlock()
if sb.closed {
return nil, io.EOF
}
if len(sb.head.buf) == 0 && sb.head == sb.tail {
// If we have no messages right now, just wait until we do
sb.Cond.Wait()
if sb.closed {
return nil, io.EOF
}
}
result := make([]byte, len(sb.head.buf))
n := copy(result, sb.head.buf)
sb.head.buf = sb.head.buf[n:]
if sb.head != sb.tail {
sb.head = sb.head.next
}
return result, nil
}
Example addition to ssh.channel (and thus the ssh.Channel interface):
func (c *channel) ReadSSHPacket() ([]byte, error) {
buff, err := m.pending.ReadSingle()
if err != nil {
return nil, err
}
if len(buff) > 0 {
err = c.adjustWindow(uint32(len(buff)))
if len(buff) > 0 && err == io.EOF {
err = nil
}
}
return buff, err
}
Additionally, here is a working example of how this must currently be done which uses incredibly brittle reflections.
https://github.com/NHAS/reverse_ssh/blob/f5d2a6cd8562e5f5ff33551aa37285651b90a309/internal/client/handlers/tun.go#L356
Proposal Details
I propose a new
ssh.Channelfunction to read a single SSH packet.This is required in to inter-opt with some channel types in use by OpenSSH.
For example to inter-opt with the
tun@openssh.comchannel type defined in section 2.3 of the openssh protocol standard:It is required that you are able to read each individual SSH packet as it defines the length of each Network packet.
Currently the
Read(...)function defined by thessh.Channelinterface reads all buffered SSH packets.This requires the implementer of
tun@openssh.comand other similar channel types to attempt to determine SSH packet size (and thus network packet size) from the data that is returned fromRead(...).This is error prone and in some cases not feasible.
The following are two snippets to show how this may be implemented.
Example addition to
ssh.buffer:Example addition to
ssh.channel(and thus thessh.Channelinterface):Additionally, here is a working example of how this must currently be done which uses incredibly brittle reflections.
https://github.com/NHAS/reverse_ssh/blob/f5d2a6cd8562e5f5ff33551aa37285651b90a309/internal/client/handlers/tun.go#L356