Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ignore data of SSH_MSG_IGNORE when its specified length is greater than the actual available bytes #41

Closed
rhegner opened this issue Jul 15, 2016 · 2 comments
Assignees

Comments

@rhegner
Copy link

rhegner commented Jul 15, 2016

I'm getting an ArgumentOutOfRangeException from within SshDataStream.ReadBytes when I execute the following code:

using (var ssh = new SshClient("ip", 22, "usr", "pwd"))
{
    ssh.Connect();
    IDictionary<Renci.SshNet.Common.TerminalModes, uint> termkvp = new Dictionary<Renci.SshNet.Common.TerminalModes, uint>();
    termkvp.Add(Renci.SshNet.Common.TerminalModes.ECHO, 53);

    using (var stream = ssh.CreateShellStream("xterm", 80, 24, 800, 600, 1024, termkvp))
    using (var sr = new StreamReader(stream))
    {

        // wait for command promt
        var ln = ReadLine(sr, ">");
        while ((ln == null) || !ln.EndsWith(">"))
            ln = ReadLine(sr, ">");

        // send enable
        stream.WriteLine("enable");

        // wait for password promt
        ln = ReadLine(sr, "Password: ");
        while ((ln == null) || !ln.Equals("Password: "))
            ln = ReadLine(sr, "Password: ");

        // send password
        stream.WriteLine("enable-pwd");

        // wait for command promt
        ln = ReadLine(sr, "#");
        while ((ln == null) || !ln.EndsWith("#"))
            ln = ReadLine(sr, "#");
        var commandPromt = ln;
    }

    ssh.Disconnect();
}

Background: This code is for connecting to a Cisco router. I need privileged access to the router so I send the "enable" command. The router then promts for a password. The router does not echo the password. And I think that's exactly what confuses SshDataStream.ReadBytes. The problem occurs only after sending the (hidden) password to the router.

Here is the stack trace from the exception:

Renci.SshNet.dll!Renci.SshNet.Common.SshDataStream.ReadBytes(int length) Line 222
Renci.SshNet.dll!Renci.SshNet.Common.SshDataStream.ReadUInt32() Line 173
Renci.SshNet.dll!Renci.SshNet.Common.SshDataStream.ReadString(System.Text.Encoding encoding) Line 198
Renci.SshNet.dll!Renci.SshNet.Common.SshData.ReadString(System.Text.Encoding encoding) Line 267
Renci.SshNet.dll!Renci.SshNet.Common.SshData.ReadNamesList() Line 289
Renci.SshNet.dll!Renci.SshNet.Messages.Transport.KeyExchangeInitMessage.LoadData() Line 146
Renci.SshNet.dll!Renci.SshNet.Common.SshData.Load(byte[] value, int offset) Line 126
Renci.SshNet.dll!Renci.SshNet.Session.LoadMessage(byte[] data, int offset) Line 1642
Renci.SshNet.dll!Renci.SshNet.Session.ReceiveMessage() Line 954
Renci.SshNet.dll!Renci.SshNet.Session.MessageListener() Line 1791
Renci.SshNet.dll!Renci.SshNet.Abstractions.ThreadAbstraction.ExecuteThread.AnonymousMethod__0(object o) Line 32
mscorlib.dll!System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(object state)
mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx)
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx)
mscorlib.dll!System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
mscorlib.dll!System.Threading.ThreadPoolWorkQueue.Dispatch()
mscorlib.dll!System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()

When I remove the check which causes the exception to be thrown

    if (bytesRead < length)
        throw new ArgumentOutOfRangeException("length");

from SshDataStream.ReadBytes, everything works fine.

So I'm wondering: Am I doing something wrong or is this a bug in SSH.NET? Could you remove that check from SshDataStream.ReadBytes? If not, is there something else you can do to not getting messed up by such a hidden password use-case?

Note that the ReadLine method I'm using above is a custom one which basically reads from the underlying stream byte by byte. But the problem described above also occured when I experimented with ShellStream.Expect or ShellStream.ReadLine. Nevertheless, here is the code of my ReadLine method, just for reference:

private static string ReadLine(StreamReader stream, params string[] acceptedLineEndings)
{
    var ret = "";
    var eol = false;
    while (!eol)
    {
        var b = stream.Read();
        if (b >= 0)
        {
            var c = (char)b;
            if (c == '\r')
            {

            }
            else if (c == '\n')
            {
                eol = true;
            }
            else
            {
                ret += (char)b;
            }
        }
        else
        {
            // if no more data and received data ends with a promt char, we return as well
            foreach (var le in acceptedLineEndings)
            {
                if (ret.EndsWith(le))
                {
                    eol = true;
                    break;
                }
            }
        }
    }
    return ret;
}
@rhegner
Copy link
Author

rhegner commented Aug 8, 2016

I can also reproduce this issue with latest version 2016.0.0

drieseng added a commit that referenced this issue Sep 2, 2016
@drieseng drieseng added this to the 2016.1.0 milestone Sep 11, 2016
@drieseng drieseng self-assigned this Sep 11, 2016
@drieseng drieseng changed the title ArgumentOutOfRangeException with hidden password Ignore data of SSH_MSG_IGNORE when its specified length is greater than the actual available bytes Dec 7, 2016
@drieseng
Copy link
Member

drieseng commented Dec 7, 2016

Note that this a hardening fix where we protect the client from a malformed SSH server request.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants