diff --git a/kippo/core/connection.py b/kippo/core/connection.py new file mode 100644 index 0000000..13c8cb5 --- /dev/null +++ b/kippo/core/connection.py @@ -0,0 +1,59 @@ +# Copyright (c) 2015 Michel Oosterhof +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. The names of the author(s) may not be used to endorse or promote +# products derived from this software without specific prior written +# permission. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. + +import struct + +from twisted.conch.ssh import connection, common +from twisted.python import log +from twisted.internet import defer + +MSG_CHANNEL_SUCCESS = 99 + +class KippoSSHConnection(connection.SSHConnection): + """ + Subclass this for a workaround for the Granados SSH library. + Channel request for openshell needs to return success immediatly + """ + + def ssh_CHANNEL_REQUEST(self, packet): + localChannel = struct.unpack('>L', packet[:4])[0] + requestType, rest = common.getNS(packet[4:]) + wantReply = ord(rest[0]) + channel = self.channels[localChannel] + + if requestType == 'shell': + wantReply = 0 + self.transport.sendPacket(MSG_CHANNEL_SUCCESS, struct.pack('>L', self.localToRemoteChannel[localChannel])) + + d = defer.maybeDeferred(log.callWithLogger, channel, + channel.requestReceived, requestType, rest[1:]) + if wantReply: + d.addCallback(self._cbChannelRequest, localChannel) + d.addErrback(self._ebChannelRequest, localChannel) + return d + diff --git a/kippo/core/ssh.py b/kippo/core/ssh.py index 6d7b352..39dbda2 100644 --- a/kippo/core/ssh.py +++ b/kippo/core/ssh.py @@ -12,7 +12,7 @@ from zope.interface import implementer import twisted from twisted.cred import portal from twisted.conch import avatar, interfaces as conchinterfaces -from twisted.conch.ssh import factory, userauth, connection, keys, session, transport, filetransfer, forwarding +from twisted.conch.ssh import factory, userauth, keys, session, transport, filetransfer, forwarding from twisted.conch.ssh.filetransfer import FXF_READ, FXF_WRITE, FXF_APPEND, FXF_CREAT, FXF_TRUNC, FXF_EXCL import twisted.conch.ls from twisted.python import log, components @@ -24,6 +24,7 @@ import ConfigParser import fs import sshserver import auth +import connection import honeypot import ssh import protocol @@ -79,7 +80,7 @@ class HoneyPotSSHUserAuthServer(userauth.SSHUserAuthServer): class HoneyPotSSHFactory(factory.SSHFactory): services = { 'ssh-userauth': HoneyPotSSHUserAuthServer, - 'ssh-connection': connection.SSHConnection, + 'ssh-connection': connection.KippoSSHConnection, } # Special delivery to the loggers to avoid scope problems @@ -267,13 +268,6 @@ class HoneyPotSSHSession(session.SSHSession): log.msg( eventid='KIPP0013', format='request_env: %(name)s=%(value)s', name=name, value=value ) return 0 - def request_shell(self, data): - # workaround specifically for Granados SSH library. - # It needs the channel request reply as the first packet after request - # Send the request success immediatly - self.conn.transport.sendPacket(connection.MSG_CHANNEL_SUCCESS, struct.pack('>L', self.conn.localToRemoteChannel[self.id])) - return session.SSHSession.request_shell(self, data) - def request_agent(self, data): log.msg('request_agent: %s' % repr(data) ) return 0