Получение расширенных данных с помощью ssh с использованием twisted.conch в качестве клиента - PullRequest
3 голосов
/ 29 октября 2011

Я сейчас нахожусь в процессе изучения ssh с помощью грубой силы / просто продолжаю взламывать, пока не пойму, как он подходит.После некоторых проб и ошибок я смог успешно отправить «pty-req», за которым последовал запрос «shell», я могу получить преамбулу входа в систему, отправить команды и получить стандартный вывод, но я не совсем уверен, как сказатьСлужба SSH Я хочу получать stderr и сообщения о состоянии.Прочтение других реализаций SSH (paramiko, Net :: SSH) на данный момент не очень помогает.

Тем не менее, глядя на один из RFC для SSH, я считаю, что, возможно, один изперечисленные запросы могут быть тем, что я ищу: http://tools.ietf.org/html/rfc4250#section-4.9.3

#!/usr/bin/env python


from twisted.conch.ssh import transport
from twisted.conch.ssh import userauth
from twisted.conch.ssh import connection
from twisted.conch.ssh import common
from twisted.conch.ssh.common import NS
from twisted.conch.ssh import keys
from twisted.conch.ssh import channel
from twisted.conch.ssh import session
from twisted.internet import defer

from twisted.internet import defer, protocol, reactor
from twisted.python import log
import struct, sys, getpass, os
log.startLogging(sys.stdout)


USER = 'dward'  
HOST = '192.168.0.19' # pristine.local
PASSWD = "password"
PRIVATE_KEY = "~/id_rsa"

class SimpleTransport(transport.SSHClientTransport):
    def verifyHostKey(self, hostKey, fingerprint):
        print 'host key fingerprint: %s' % fingerprint
        return defer.succeed(1) 

    def connectionSecure(self):
        self.requestService(
            SimpleUserAuth(USER,
                SimpleConnection()))

class SimpleUserAuth(userauth.SSHUserAuthClient):
    def getPassword(self):
        return defer.succeed(PASSWD)

    def getGenericAnswers(self, name, instruction, questions):
        print name
        print instruction
        answers = []
        for prompt, echo in questions:
            if echo:
                answer = raw_input(prompt)
            else:
                answer = getpass.getpass(prompt)
            answers.append(answer)
        return defer.succeed(answers)

    def getPublicKey(self):
        path = os.path.expanduser(PRIVATE_KEY) 
        # this works with rsa too
        # just change the name here and in getPrivateKey
        if not os.path.exists(path) or self.lastPublicKey:
            # the file doesn't exist, or we've tried a public key
            return
        return keys.Key.fromFile(filename=path+'.pub').blob()

    def getPrivateKey(self):
        path = os.path.expanduser(PRIVATE_KEY)
        return defer.succeed(keys.Key.fromFile(path).keyObject)



class SimpleConnection(connection.SSHConnection):
    def serviceStarted(self):
        self.openChannel(SmartChannel(2**16, 2**15, self))        




class SmartChannel(channel.SSHChannel):
    name = "session"


    def getResponse(self, timeout = 10):
        self.onData = defer.Deferred()
        self.timeout = reactor.callLater( timeout, self.onData.errback, Exception("Timeout") )
        return self.onData

    def openFailed(self, reason):
        print "Failed", reason

    @defer.inlineCallbacks    
    def channelOpen(self, ignoredData):
        self.data = ''
        self.oldData = ''
        self.onData = None
        self.timeout = None
        term = os.environ.get('TERM', 'xterm')
        #winsz = fcntl.ioctl(fd, tty.TIOCGWINSZ, '12345678')
        winSize = (25,80,0,0) #struct.unpack('4H', winsz)
        ptyReqData = session.packRequest_pty_req(term, winSize, '')

        try:
            result = yield self.conn.sendRequest(self, 'pty-req', ptyReqData, wantReply = 1 )
        except Exception as e:
            print "Failed with ", e

        try:
            result = yield self.conn.sendRequest(self, "shell", '', wantReply = 1)
        except Exception as e:
            print "Failed shell with ", e


        #fetch preample    
        data = yield self.getResponse()
        """
        Welcome to Ubuntu 11.04 (GNU/Linux 2.6.38-8-server x86_64)

            * Documentation:  http://www.ubuntu.com/server/doc

             System information as of Sat Oct 29 13:09:50 MDT 2011

             System load:  0.0               Processes:           111
             Usage of /:   48.0% of 6.62GB   Users logged in:     1
             Memory usage: 39%               IP address for eth1: 192.168.0.19
             Swap usage:   3%

             Graph this data and manage this system at https://landscape.canonical.com/
           New release 'oneiric' available.
           Run 'do-release-upgrade' to upgrade to it.

           Last login: Sat Oct 29 01:23:16 2011 from 192.168.0.17
        """
        print data
        while data != "" and data.strip().endswith("~$") == False:
            try:
                data = yield self.getResponse()
                print repr(data)
                """
                \x1B]0;dward@pristine: ~\x07dward@pristine:~$ 
                """
            except Exception as e:
                print e
                break

        self.write("false\n")
        #fetch response
        try:
            data = yield self.getResponse()
        except Exception as e:
            print "Failed to catch response?", e
        else:
            print data
            """
                false
                \x1B]0;dward@pristine: ~\x07dward@pristine:~$ 
            """

        self.write("true\n")
        #fetch response
        try:
            data = yield self.getResponse()
        except Exception as e:
            print "Failed to catch response?", e
        else:
            print data
            """
            true
            \x1B]0;dward@pristine: ~\x07dward@pristine:~$ 
            """

        self.write("echo Hello World\n\x00")
        try:
            data = yield self.getResponse()
        except Exception as e:
            print "Failed to catch response?", e
        else:            
            print data
            """
            echo Hello World
            Hello World
            \x1B]0;dward@pristine: ~\x07dward@pristine:~$ 
            """

        #Close up shop
        self.loseConnection()
        dbgp = 1


    def request_exit_status(self, data):
        status = struct.unpack('>L', data)[0]
        print 'status was: %s' % status    

    def dataReceived(self, data):
        self.data += data
        if self.onData is not None:
            if self.timeout and self.timeout.active():
                self.timeout.cancel()
            if self.onData.called == False:                
                self.onData.callback(data)

    def extReceived(self, dataType, data):
        dbgp = 1
        print "Extended Data recieved! dataType = %s , data = %s " % ( dataType, data, )
        self.extendData = data

    def closed(self):
        print 'got data : %s' % self.data.replace("\\r\\n","\r\n")
        self.loseConnection()
        reactor.stop()



protocol.ClientCreator(reactor, SimpleTransport).connectTCP(HOST, 22)
reactor.run()

Кроме того, я попытался добавить явно удаленную команду к удаленной оболочке:

    self.write("ls -alF badPathHere\n\x00")
    try:
        data = yield self.getResponse()
    except Exception as e:
        print "Failed to catch response?", e
    else:            
        print data
        """
        ls -alF badPathHere
        ls: cannot access badPathHere: No such file or directory
        \x1B]0;dward@pristine: ~\x07dward@pristine:~$ 
        """

И это выглядит как stderrсмешивается в stderr

1 Ответ

0 голосов
/ 30 октября 2011

Копая исходный код OpenSSH, логика сеанса канала обрабатывается в session.c в строке Функция 2227 -> session_input_channel_req, которая, если задан pty-req, тогда запрос «shell» приводит к do_exec_pty, что в конечном итоге приводит к вызову session_set_fds (s, ptyfd, fdout, -1, 1, 1). Четвертый аргумент обычно является файловым дескриптором, отвечающим за обработку stderr, но, поскольку ни один из них не предоставлен, расширенных данных для stderr не будет.

В конечном счете, даже если я изменил openssh для предоставления FD stderr, проблема связана с оболочкой. На этом этапе полная работа по предположению, но я полагаю, что, подобно входу в службу ssh через терминал, такой как xterm или putty, эти stderr и stdout отправляются вместе, если только они не перенаправлены явно через что-то вроде «2> someFile», что выходит за рамки Поставщик услуг SSH.

...