def request_env(self, data): name, rest = getNS(data) value, rest = getNS(rest) if rest: raise ValueError("Bad data given in env request") log.msg(eventid='KIPP0013', format='request_env: %(name)s=%(value)s', name=name, value=value) return 0
def auth_publickey(self, packet): # This is copied and pasted from twisted/conch/ssh/userauth.py in # Twisted 8.0.1. We do this so we can customize how the credentials # are built and pass a mind to self.portal.login. hasSig = ord(packet[0]) algName, blob, rest = getNS(packet[1:], 2) pubKey = keys.Key.fromString(blob).keyObject signature = hasSig and getNS(rest)[0] or None if hasSig: b = ( NS(self.transport.sessionID) + chr(userauth.MSG_USERAUTH_REQUEST) + NS(self.user) + NS(self.nextService) + NS("publickey") + chr(hasSig) + NS(keys.objectType(pubKey)) + NS(blob) ) # The next three lines are different from the original. c = self.makePublicKeyCredentials(self.user, algName, blob, b, signature) return self.portal.login(c, self.getMind(), IConchUser) else: # The next four lines are different from the original. c = self.makePublicKeyCredentials(self.user, algName, blob, None, None) return self.portal.login(c, self.getMind(), IConchUser).addErrback(self._ebCheckKey, packet[1:])
def auth_publickey(self, packet): """ Public key authentication. Payload:: byte has signature string algorithm name string key blob [string signature] (if has signature is True) Create a SSHPublicKey credential and verify it using our portal. """ hasSig = ord(packet[0:1]) algName, blob, rest = getNS(packet[1:], 2) try: pubKey = keys.Key.fromString(blob) except keys.BadKeyError: error = "Unsupported key type %s or bad key" % ( algName.decode('ascii'),) log.msg(error) return defer.fail(UnauthorizedLogin(error)) signature = hasSig and getNS(rest)[0] or None if hasSig: b = (NS(self.transport.sessionID) + chr(MSG_USERAUTH_REQUEST) + NS(self.user) + NS(self.nextService) + NS(b'publickey') + chr(hasSig) + NS(pubKey.sshType()) + NS(blob)) c = credentials.SSHPrivateKey(self.user, algName, blob, b, signature) return self.portal.login(c, None, interfaces.IConchUser) else: c = credentials.SSHPrivateKey(self.user, algName, blob, None, None) return self.portal.login(c, None, interfaces.IConchUser).addErrback(self._ebCheckKey, packet[1:])
def _parseAttributes(self, data): flags ,= struct.unpack('!L', data[:4]) attrs = {} data = data[4:] if flags & FILEXFER_ATTR_SIZE == FILEXFER_ATTR_SIZE: size ,= struct.unpack('!Q', data[:8]) attrs['size'] = size data = data[8:] if flags & FILEXFER_ATTR_OWNERGROUP == FILEXFER_ATTR_OWNERGROUP: uid, gid = struct.unpack('!2L', data[:8]) attrs['uid'] = uid attrs['gid'] = gid data = data[8:] if flags & FILEXFER_ATTR_PERMISSIONS == FILEXFER_ATTR_PERMISSIONS: perms ,= struct.unpack('!L', data[:4]) attrs['permissions'] = perms data = data[4:] if flags & FILEXFER_ATTR_ACMODTIME == FILEXFER_ATTR_ACMODTIME: atime, mtime = struct.unpack('!2L', data[:8]) attrs['atime'] = atime attrs['mtime'] = mtime data = data[8:] if flags & FILEXFER_ATTR_EXTENDED == FILEXFER_ATTR_EXTENDED: extended_count ,= struct.unpack('!L', data[:4]) data = data[4:] for i in xrange(extended_count): extended_type, data = getNS(data) extended_data, data = getNS(data) attrs['ext_%s' % extended_type] = extended_data return attrs, data
def ssh_USERAUTH_PK_OK(self, packet): if self.lastAuth == 'publickey': # this is ok publicKey = self.lastPublicKey keyType = getNS(publicKey)[0] b = NS(self.transport.sessionID) + chr(MSG_USERAUTH_REQUEST) + \ NS(self.user) + NS(self.instance.name) + NS('publickey') + '\xff' +\ NS(keyType) + NS(publicKey) d = self.signData(publicKey, b) if not d: self.askForAuth('none', '') # this will fail, we'll move on return d.addCallback(self._cbSignedData) d.addErrback(self._ebAuth) elif self.lastAuth == 'password': prompt, language, rest = getNS(packet, 2) self._oldPass = self._newPass = None self.getPassword('Old Password: '******'keyboard-interactive': name, instruction, lang, data = getNS(packet, 3) numPrompts = struct.unpack('!L', data[:4])[0] data = data[4:] prompts = [] for i in range(numPrompts): prompt, data = getNS(data) echo = bool(ord(data[0])) data = data[1:] prompts.append((prompt, echo)) d = self.getGenericAnswers(name, instruction, prompts) d.addCallback(self._cbGenericAnswers) d.addErrback(self._ebAuth)
def verify(self, signature, data): """ Returns true if the signature for data is valid for this Key. @type signature: C{str} @type data: C{str} @rtype: C{bool} """ if len(signature) == 40: # DSA key with no padding signatureType, signature = 'ssh-dss', common.NS(signature) else: signatureType, signature = common.getNS(signature) if signatureType != self.sshType(): return False if self.type() == 'RSA': numbers = common.getMP(signature) digest = pkcs1Digest(data, self.keyObject.size() / 8) elif self.type() == 'DSA': signature = common.getNS(signature)[0] numbers = [ Util.number.bytes_to_long(n) for n in (signature[:20], signature[20:]) ] digest = sha1(data).digest() return self.keyObject.verify(digest, numbers)
def auth_publickey(self, packet): """ Public key authentication. Payload:: byte has signature string algorithm name string key blob [string signature] (if has signature is True) Create a SSHPublicKey credential and verify it using our portal. """ hasSig = ord(packet[0]) algName, blob, rest = getNS(packet[1:], 2) pubKey = keys.Key.fromString(blob) signature = hasSig and getNS(rest)[0] or None if hasSig: b = (NS(self.transport.sessionID) + chr(MSG_USERAUTH_REQUEST) + NS(self.user) + NS(self.nextService) + NS('publickey') + chr(hasSig) + NS(pubKey.sshType()) + NS(blob)) c = credentials.SSHPrivateKey(self.user, algName, blob, b, signature) return self.portal.login(c, None, interfaces.IConchUser) else: c = credentials.SSHPrivateKey(self.user, algName, blob, None, None) return self.portal.login(c, None, interfaces.IConchUser).addErrback(self._ebCheckKey, packet[1:])
def request_env(self, data): name, rest = getNS(data) value, rest = getNS(rest) if rest: raise ValueError("Bad data given in env request") log.msg('request_env: %s=%s' % (name, value) ) return 0
def auth_publickey(self, packet): try: #extract the public key blob from the SSH packet key_blob = getNS(getNS(packet[1:])[1])[0] except: key_blob = "No public key found." try: #convert blob into openssh key format key = keys.Key.fromString(key_blob).toString('openssh') except: key = "Invalid SSH Public Key Submitted: {key_blob}".format(key_blob=key_blob.encode('hex')) for keytype in ['ecdsa-sha2-nistp256','ecdsa-sha2-nistp384','ecdsa-sha2-nistp521','ssh-ed25519']: if keytype in key_blob: key = '{keytype} {keydata}'.format( keytype=keytype, keydata=base64.b64encode(key_blob)) print 'Key was {key}'.format(key=key) c = credentials.SSHPrivateKey(None,None,None,None,None) #self.log(key=key) return self.portal.login(c, None, conchinterfaces.IConchUser).addErrback( self._ebPassword)
def packet_SYMLINK(self, data): requestId = data[:4] data = data[4:] linkPath, data = getNS(data) targetPath, data = getNS(data) d = defer.maybeDeferred(self.client.makeLink, linkPath, targetPath) d.addCallback(self._cbStatus, requestId, 'symlink succeeded') d.addErrback(self._ebStatus, requestId, 'symlink failed')
def unpackOpen_direct_tcpip(data): """Unpack the data to a usable format. """ connHost, rest = common.getNS(data) connPort = int(struct.unpack('>L', rest[:4])[0]) origHost, rest = common.getNS(rest[4:]) origPort = int(struct.unpack('>L', rest[:4])[0]) return (connHost, connPort), (origHost, origPort)
def packet_RENAME(self, data): requestId = data[:4] data = data[4:] oldPath, data = getNS(data) newPath, data = getNS(data) assert data == '', 'still have data in RENAME: %s' % repr(data) d = defer.maybeDeferred(self.client.renameFile, oldPath, newPath) d.addCallback(self._cbStatus, requestId, "rename succeeded") d.addErrback(self._ebStatus, requestId, "rename failed")
def packet_HANDLE(self, data): d, data = self._parseRequest(data) isFile, name = self.wasAFile.pop(d) if isFile: cb = ClientFile(self, getNS(data)[0]) else: cb = ClientDirectory(self, getNS(data)[0]) cb.name = name d.callback(cb)
def request_env(self, data): name, rest = getNS(data) value, rest = getNS(rest) if rest: raise ValueError("Bad data given in env request") log.msg(eventid='cowrie.client.var', format='request_env: %(name)s=%(value)s', name=name, value=value) # FIXME: This only works for shell, not for exec command # if self.session: # self.session.environ[name] = value return 0
def packet_VERSION(self, data): version, = struct.unpack('!L', data[:4]) data = data[4:] d = {} while data: k, data = getNS(data) v, data = getNS(data) d[k]=v self.version = version self.gotServerVersion(version, d)
def parseRequest_pty_req(data): """Parse the data from a pty-req request into usable data. @returns: a tuple of (terminal type, (rows, cols, xpixel, ypixel), modes) """ term, rest = common.getNS(data) cols, rows, xpixel, ypixel = struct.unpack('>4L', rest[: 16]) modes, ignored= common.getNS(rest[16:]) winSize = (rows, cols, xpixel, ypixel) modes = [(ord(modes[i]), struct.unpack('>L', modes[i+1: i+5])[0]) for i in range(0, len(modes)-1, 5)] return term, winSize, modes
def packet_NAME(self, data): d, data = self._parseRequest(data) count, = struct.unpack('!L', data[:4]) data = data[4:] files = [] for i in range(count): filename, data = getNS(data) longname, data = getNS(data) attrs, data = self._parseAttributes(data) files.append((filename, longname, attrs)) d.callback(files)
def unpackOpen_direct_tcpip(data): """Unpack the data to a usable format. """ connHost, rest = common.getNS(data) if _PY3 and isinstance(connHost, bytes): connHost = connHost.decode("utf-8") connPort = int(struct.unpack('>L', rest[:4])[0]) origHost, rest = common.getNS(rest[4:]) if _PY3 and isinstance(origHost, bytes): origHost = origHost.decode("utf-8") origPort = int(struct.unpack('>L', rest[:4])[0]) return (connHost, connPort), (origHost, origPort)
def agentc_SIGN_REQUEST(self, data): """ Data is a structure with a reference to an already added key object and some data that the clients wants signed with that key. If the key object wasn't loaded, return AGENT_FAILURE, else return the signature. """ blob, data = getNS(data) if blob not in self.factory.keys: return self.sendResponse(AGENT_FAILURE, '') signData, data = getNS(data) assert data == '\000\000\000\000' self.sendResponse(AGENT_SIGN_RESPONSE, NS(self.factory.keys[blob][0].sign(signData)))
def request_env(self, data): """ """ name, rest = getNS(data) value, rest = getNS(rest) if rest: raise ValueError("Bad data given in env request") log.msg(eventid='KIPP0013', format='request_env: %(name)s=%(value)s', name=name, value=value) # Environment variables come after shell or before exec command if self.session: self.session.environ[name] = value return 0
def verify(self, signature, data): """ Verify a signature using this key. @type signature: L{bytes} @param signature: The signature to verify. @type data: L{bytes} @param data: The signed data. @rtype: L{bool} @return: C{True} if the signature is valid. """ if len(signature) == 40: # DSA key with no padding signatureType, signature = b'ssh-dss', common.NS(signature) else: signatureType, signature = common.getNS(signature) if signatureType != self.sshType(): return False if self.type() == 'RSA': k = self._keyObject if not self.isPublic(): k = k.public_key() verifier = k.verifier( common.getNS(signature)[0], padding.PKCS1v15(), hashes.SHA1(), ) elif self.type() == 'DSA': concatenatedSignature = common.getNS(signature)[0] r = int_from_bytes(concatenatedSignature[:20], 'big') s = int_from_bytes(concatenatedSignature[20:], 'big') signature = encode_dss_signature(r, s) k = self._keyObject if not self.isPublic(): k = k.public_key() verifier = k.verifier( signature, hashes.SHA1()) else: raise BadKeyError("unknown key type %s" % (self.type(),)) verifier.update(data) try: verifier.verify() except InvalidSignature: return False else: return True
def packet_INIT(self, data): version ,= struct.unpack('!L', data[:4]) self.version = min(list(self.versions) + [version]) data = data[4:] ext = {} while data: ext_name, data = getNS(data) ext_data, data = getNS(data) ext[ext_name] = ext_data our_ext = self.client.gotVersion(version, ext) our_ext_data = "" for (k,v) in our_ext.items(): our_ext_data += NS(k) + NS(v) self.sendPacket(FXP_VERSION, struct.pack('!L', self.version) + \ our_ext_data)
def packet_WRITE(self, data): requestId = data[:4] data = data[4:] handle, data = getNS(data) offset, = struct.unpack('!Q', data[:8]) data = data[8:] writeData, data = getNS(data) assert data == '', 'still have data in WRITE: %s' % repr(data) if handle not in self.openFiles: self._ebWrite(failure.Failure(KeyError()), requestId) else: fileObj = self.openFiles[handle] d = defer.maybeDeferred(fileObj.writeChunk, offset, writeData) d.addCallback(self._cbStatus, requestId, "write succeeded") d.addErrback(self._ebStatus, requestId, "write failed")
def _cbRequestIdentities(self, data): """ Unpack a collection of identities into a list of tuples comprised of public key blobs and comments. """ if ord(data[0]) != AGENT_IDENTITIES_ANSWER: raise ConchError('unexpected response: %i' % ord(data[0])) numKeys = struct.unpack('!L', data[1:5])[0] keys = [] data = data[5:] for i in range(numKeys): blob, data = getNS(data) comment, data = getNS(data) keys.append((blob, comment)) return keys
def ssh_USERAUTH_REQUEST(self, packet): """ The client has requested authentication. Payload:: string user string next service string method <authentication specific data> @type packet: C{str} """ user, nextService, method, rest = getNS(packet, 3) if user != self.user or nextService != self.nextService: self.authenticatedWith = [] # clear auth state self.user = user self.nextService = nextService self.method = method d = self.tryAuth(method, user, rest) if not d: self._ebBadAuth( failure.Failure(error.ConchError('auth returned none'))) return d.addCallback(self._cbFinishedAuth) d.addErrback(self._ebMaybeBadAuth) d.addErrback(self._ebBadAuth) return d
def isInKnownHosts(self, host, pubKey): """checks to see if host is in the known_hosts file for the user. returns 0 if it isn't, 1 if it is and is the same, 2 if it's changed. """ keyType = common.getNS(pubKey)[0] retVal = 0 try: known_hosts = open(os.path.expanduser('~/.ssh/known_hosts')) except IOError: return 0 for line in known_hosts.xreadlines(): split = line.split() if len(split) != 3: # old 4-field known_hosts entry (ssh1?) continue hosts, hostKeyType, encodedKey = split if not host in hosts.split(','): # incorrect host continue if not hostKeyType == keyType: # incorrect type of key continue try: decodedKey = base64.decodestring(encodedKey) except: continue if decodedKey == pubKey: return 1 else: retVal = 2 return retVal
def ssh_USERAUTH_INFO_RESPONSE(self, packet): """ The user has responded with answers to PAMs authentication questions. Parse the packet into a PAM response and callback self._pamDeferred. Payload:: uint32 numer of responses string response 1 ... string response n """ d, self._pamDeferred = self._pamDeferred, None try: resp = [] numResps = struct.unpack('>L', packet[:4])[0] packet = packet[4:] while len(resp) < numResps: response, packet = getNS(packet) resp.append((response, 0)) if packet: raise error.ConchError("%i bytes of extra data" % len(packet)) except: d.errback(failure.Failure()) else: d.callback(resp)
def verifyHostKey(self, pubKey, fingerprint): goodKey = self.isInKnownHosts(options['host'], pubKey) if goodKey == 1: # good key return defer.succeed(1) elif goodKey == 2: # AAHHHHH changed return defer.fail(ConchError('changed host key')) else: oldout, oldin = sys.stdout, sys.stdin sys.stdin = sys.stdout = open('/dev/tty','r+') if options['host'] == self.transport.getPeer()[1]: host = options['host'] khHost = options['host'] else: host = '%s (%s)' % (options['host'], self.transport.getPeer()[1]) khHost = '%s,%s' % (options['host'], self.transport.getPeer()[1]) keyType = common.getNS(pubKey)[0] print """The authenticity of host '%s' can't be extablished. %s key fingerprint is %s.""" % (host, {'ssh-dss':'DSA', 'ssh-rsa':'RSA'}[keyType], fingerprint) ans = raw_input('Are you sure you want to continue connecting (yes/no)? ') while ans.lower() not in ('yes', 'no'): ans = raw_input("Please type 'yes' or 'no': ") sys.stdout,sys.stdin=oldout,oldin if ans == 'no': print 'Host key verification failed.' return defer.fail(ConchError('bad host key')) print "Warning: Permanently added '%s' (%s) to the list of known hosts." % (khHost, {'ssh-dss':'DSA', 'ssh-rsa':'RSA'}[keyType]) known_hosts = open(os.path.expanduser('~/.ssh/known_hosts'), 'a') encodedKey = base64.encodestring(pubKey).replace('\n', '') known_hosts.write('\n%s %s %s' % (khHost, keyType, encodedKey)) known_hosts.close() return defer.succeed(1)
def ssh_CHANNEL_EXTENDED_DATA(self, packet): """ The other side is sending us exteneded data. Payload:: uint32 local channel number uint32 type code string data Check to make sure the other side hasn't sent too much data (more than what's in the window, or or than the maximum packet size). If they have, close the channel. Otherwise, decrease the available window and pass the data and type code to the channel's extReceived(). """ localChannel, typeCode, dataLength = struct.unpack('>3L', packet[:12]) channel = self.channels[localChannel] if (dataLength > channel.localWindowLeft or dataLength > channel.localMaxPacket): log.callWithLogger(channel, log.msg, 'too much extdata') self.sendClose(channel) return data = common.getNS(packet[8:])[0] channel.localWindowLeft -= dataLength if channel.localWindowLeft < channel.localWindowSize / 2: self.adjustWindow(channel, channel.localWindowSize - channel.localWindowLeft) log.callWithLogger(channel, channel.extReceived, typeCode, data)
def packet_EXTENDED(self, data): requestId = data[:4] data = data[4:] extName, extData = getNS(data) d = defer.maybeDeferred(self.client.extendedRequest, extName, extData) d.addCallback(self._cbExtended, requestId) d.addErrback(self._ebStatus, requestId, 'extended %s failed' % extName)
def ssh_KEXINIT(self, packet): k = getNS(packet[16:], 10) strings, rest = k[:-1], k[-1] (kexAlgs, keyAlgs, encCS, encSC, macCS, macSC, compCS, compSC, langCS, langSC) = [s.split(',') for s in strings] log.msg('KEXINIT: client supported key exchange: %s' % kexAlgs) log.msg('KEXINIT: client supported public keys: %s' % keyAlgs) log.msg('KEXINIT: client supported encryption: %s' % encCS) log.msg('KEXINIT: client supported MAC: %s' % macCS) log.msg('KEXINIT: client supported compression: %s' % compCS) log.msg('KEXINIT: client supported lang: %s' % langCS) log.msg(eventid='KIPP0009', version=self.otherVersionString, kexAlgs=kexAlgs, keyAlgs=keyAlgs, encCS=encCS, macCS=macCS, compCS=compCS, format='Remote SSH version: %(version)s') return sshserver.CowrieSSHServerTransport.ssh_KEXINIT(self, packet)
def _fromString_PRIVATE_BLOB(cls, blob): """ Return a private key object corresponding to this private key blob. The blob formats are as follows: RSA keys:: string 'ssh-rsa' integer n integer e integer d integer u integer p integer q DSA keys:: string 'ssh-dss' integer p integer q integer g integer y integer x @type blob: L{bytes} @param blob: The key data. @return: A new key. @rtype: L{twisted.conch.ssh.keys.Key} @raises BadKeyError: if the key type (the first string) is unknown. """ keyType, rest = common.getNS(blob) if keyType == b'ssh-rsa': n, e, d, u, p, q, rest = common.getMP(rest, 6) return cls._fromRSAComponents(n=n, e=e, d=d, p=p, q=q) elif keyType == b'ssh-dss': p, q, g, y, x, rest = common.getMP(rest, 5) return cls._fromDSAComponents(y=y, g=g, p=p, q=q, x=x) else: raise BadKeyError('unknown blob type: %s' % (keyType, ))
def ssh_CHANNEL_REQUEST(self, packet): """ The other side is sending a request to a channel. Payload:: uint32 local channel number string request name bool want reply <request specific data> Pass the message to the channel's requestReceived method. If the other side wants a reply, add callbacks which will send the reply. """ localChannel = struct.unpack('>L', packet[:4])[0] requestType, rest = common.getNS(packet[4:]) wantReply = ord(rest[0:1]) channel = self.channels[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
def _fromString_PRIVATE_BLOB(Class, blob): """ Return a private key object corresponding to this private key blob. The blob formats are as follows: RSA keys:: string 'ssh-rsa' integer n integer e integer d integer u integer p integer q DSA keys:: string 'ssh-dss' integer p integer q integer g integer y integer x @type blob: C{str} @return: a C{Crypto.PublicKey.pubkey.pubkey} object @raises BadKeyError: if the key type (the first string) is unknown. """ keyType, rest = common.getNS(blob) if keyType == 'ssh-rsa': n, e, d, u, p, q, rest = common.getMP(rest, 6) rsakey = Class(RSA.construct((n, e, d, p, q, u))) return rsakey elif keyType == 'ssh-dss': p, q, g, y, x, rest = common.getMP(rest, 5) dsakey = Class(DSA.construct((y, g, p, q, x))) return dsakey else: raise BadKeyError('unknown blob type: %s' % keyType)
def isInKnownHosts(host, pubKey, options): """ Checks to see if host is in the known_hosts file for the user. @return: 0 if it isn't, 1 if it is and is the same, 2 if it's changed. @rtype: L{int} """ keyType = common.getNS(pubKey)[0] retVal = 0 if not options['known-hosts'] and not os.path.exists( os.path.expanduser('~/.ssh/')): print('Creating ~/.ssh directory...') os.mkdir(os.path.expanduser('~/.ssh')) kh_file = options['known-hosts'] or _KNOWN_HOSTS try: known_hosts = open(os.path.expanduser(kh_file), 'rb') except IOError: return 0 with known_hosts: for line in known_hosts.readlines(): split = line.split() if len(split) < 3: continue hosts, hostKeyType, encodedKey = split[:3] if host not in hosts.split(b','): # incorrect host continue if hostKeyType != keyType: # incorrect type of key continue try: decodedKey = decodebytes(encodedKey) except: continue if decodedKey == pubKey: return 1 else: retVal = 2 return retVal
def ssh_KEXINIT(self, packet): """ """ cookie = packet[:16] log.msg("EXPERIMENTAL KEXINIT cookie %s" % (cookie.encode('hex'), )) k = getNS(packet[16:], 10) strings, rest = k[:-1], k[-1] (kexAlgs, keyAlgs, encCS, encSC, macCS, macSC, compCS, compSC, langCS, langSC) = [s.split(',') for s in strings] log.msg("EXPERIMENTAL KEXINIT langCS langSC %s %s" % ( langCS, langSC, )) log.msg(eventid='COW0009', version=self.otherVersionString, kexAlgs=kexAlgs, keyAlgs=keyAlgs, encCS=encCS, macCS=macCS, compCS=compCS, format='Remote SSH version: %(version)s') return transport.SSHServerTransport.ssh_KEXINIT(self, packet)
def _guessStringType(Class, data): """ Guess the type of key in data. The types map to _fromString_* methods. """ if data.startswith('ssh-'): return 'public_openssh' elif data.startswith('-----BEGIN'): return 'private_openssh' elif data.startswith('{'): return 'public_lsh' elif data.startswith('('): return 'private_lsh' elif data.startswith('\x00\x00\x00\x07ssh-'): ignored, rest = common.getNS(data) count = 0 while rest: count += 1 ignored, rest = common.getMP(rest) if count > 4: return 'agentv3' else: return 'blob'
def _fromString_BLOB(cls, blob): """ Return a public key object corresponding to this public key blob. The format of a RSA public key blob is:: string 'ssh-rsa' integer e integer n The format of a DSA public key blob is:: string 'ssh-dss' integer p integer q integer g integer y @type blob: L{bytes} @param blob: The key data. @return: A new key. @rtype: L{twisted.conch.ssh.keys.Key} @raises BadKeyError: if the key type (the first string) is unknown. """ keyType, rest = common.getNS(blob) if keyType == b'ssh-rsa': e, n, rest = common.getMP(rest, 2) return cls( rsa.RSAPublicNumbers(e, n).public_key(default_backend())) elif keyType == b'ssh-dss': p, q, g, y, rest = common.getMP(rest, 4) return cls( dsa.DSAPublicNumbers(y=y, parameter_numbers=dsa.DSAParameterNumbers( p=p, q=q, g=g)).public_key(default_backend())) else: raise BadKeyError('unknown blob type: %s' % (keyType, ))
def ssh_USERAUTH_REQUEST(self, packet): """ The client has requested authentication. Payload:: string user string next service string method <authentication specific data> @type packet: L{bytes} """ user, nextService, method, rest = getNS(packet, 3) if user != self.user or nextService != self.nextService: self.authenticatedWith = [] # clear auth state self.user = user self.nextService = nextService self.method = method d = self.tryAuth(method, user, rest) if not d: self._ebBadAuth(failure.Failure(error.ConchError("auth returned none"))) return d.addCallback(self._cbFinishedAuth) d.addErrback(self._ebMaybeBadAuth) d.addErrback(self._ebBadAuth) return d
def ssh_KEXINIT(self, packet): """ Called when we receive a MSG_KEXINIT message. Payload:: bytes[16] cookie string keyExchangeAlgorithms string keyAlgorithms string incomingEncryptions string outgoingEncryptions string incomingAuthentications string outgoingAuthentications string incomingCompressions string outgoingCompressions string incomingLanguages string outgoingLanguages bool firstPacketFollows unit32 0 (reserved) Starts setting up the key exchange, keys, encryptions, and authentications. Extended by ssh_KEXINIT in SSHServerTransport and SSHClientTransport. """ self.otherKexInitPayload = chr(MSG_KEXINIT) + packet #cookie = packet[: 16] # taking this is useless k = getNS(packet[16:], 10) strings, rest = k[:-1], k[-1] (kexAlgs, keyAlgs, encCS, encSC, macCS, macSC, compCS, compSC, langCS, langSC) = [s.split(',') for s in strings] # these are the server directions outs = [encSC, macSC, compSC] ins = [encCS, macSC, compCS] if self.isClient: outs, ins = ins, outs # switch directions server = (self.supportedKeyExchanges, self.supportedPublicKeys, self.supportedCiphers, self.supportedCiphers, self.supportedMACs, self.supportedMACs, self.supportedCompressions, self.supportedCompressions) client = (kexAlgs, keyAlgs, outs[0], ins[0], outs[1], ins[1], outs[2], ins[2]) if self.isClient: server, client = client, server self.kexAlg = ffs(client[0], server[0]) self.keyAlg = ffs(client[1], server[1]) self.nextEncryptions = SSHCiphers(ffs(client[2], server[2]), ffs(client[3], server[3]), ffs(client[4], server[4]), ffs(client[5], server[5])) self.outgoingCompressionType = ffs(client[6], server[6]) self.incomingCompressionType = ffs(client[7], server[7]) if None in (self.kexAlg, self.keyAlg, self.outgoingCompressionType, self.incomingCompressionType): self.sendDisconnect(DISCONNECT_KEY_EXCHANGE_FAILED, "couldn't match all kex parts") return if None in self.nextEncryptions.__dict__.values(): self.sendDisconnect(DISCONNECT_KEY_EXCHANGE_FAILED, "couldn't match all kex parts") return log.msg('kex alg, key alg: %s %s' % (self.kexAlg, self.keyAlg)) log.msg( 'outgoing: %s %s %s' % (self.nextEncryptions.outCipType, self.nextEncryptions.outMACType, self.outgoingCompressionType)) log.msg('incoming: %s %s %s' % (self.nextEncryptions.inCipType, self.nextEncryptions.inMACType, self.incomingCompressionType)) return kexAlgs, keyAlgs, rest # for SSHServerTransport to use
def request_env(self, data): name, rest = getNS(data) value, rest = getNS(rest) print 'request_env: %s=%s' % (name, value)
def request_subsystem(self, data): subsystem, _ = common.getNS(data) log.msg('asking for subsystem "{}"'.format(subsystem)) return 0
def packet_DATA(self, data): d, data = self._parseRequest(data) d.callback(getNS(data)[0])
def packet_HANDLE(self, data): d, data = self._parseRequest(data) handle, _ = getNS(data) d.callback(handle)
def unpackGlobal_tcpip_forward(data): host, rest = common.getNS(data) port = int(struct.unpack('>L', rest[:4])[0]) return host, port
def auth_password(self, packet): password = getNS(packet[1:])[0] src_ip = self.transport.transport.getPeer().host c = credentials.UsernamePasswordIP(self.user, password, src_ip) return self.portal.login( c, src_ip, conchinterfaces.IConchUser).addErrback(self._ebPassword)
def _cbSignData(self, data): if ord(data[0]) != AGENT_SIGN_RESPONSE: raise ConchError('unexpected data: %i' % ord(data[0])) signature = getNS(data[1:])[0] return signature
def unpackGlobal_tcpip_forward(data): host, rest = common.getNS(data) if _PY3 and isinstance(host, bytes): host = host.decode("utf-8") port = int(struct.unpack('>L', rest[:4])[0]) return host, port
def verify(self, signature, data): """ Verify a signature using this key. @type signature: L{bytes} @param signature: The signature to verify. @type data: L{bytes} @param data: The signed data. @rtype: L{bool} @return: C{True} if the signature is valid. """ if len(signature) == 40: # DSA key with no padding signatureType, signature = b'ssh-dss', common.NS(signature) else: signatureType, signature = common.getNS(signature) if signatureType != self.sshType(): return False keyType = self.type() if keyType == 'RSA': k = self._keyObject if not self.isPublic(): k = k.public_key() args = ( common.getNS(signature)[0], data, padding.PKCS1v15(), hashes.SHA1(), ) elif keyType == 'DSA': concatenatedSignature = common.getNS(signature)[0] r = int_from_bytes(concatenatedSignature[:20], 'big') s = int_from_bytes(concatenatedSignature[20:], 'big') signature = encode_dss_signature(r, s) k = self._keyObject if not self.isPublic(): k = k.public_key() args = (signature, data, hashes.SHA1()) elif keyType == 'EC': # Pragma: no branch concatenatedSignature = common.getNS(signature)[0] rstr, sstr, rest = common.getNS(concatenatedSignature, 2) r = int_from_bytes(rstr, 'big') s = int_from_bytes(sstr, 'big') signature = encode_dss_signature(r, s) k = self._keyObject if not self.isPublic(): k = k.public_key() keySize = self.size() if keySize <= 256: # Hash size depends on key size hashSize = hashes.SHA256() elif keySize <= 384: hashSize = hashes.SHA384() else: hashSize = hashes.SHA512() args = (signature, data, ec.ECDSA(hashSize)) try: k.verify(*args) except InvalidSignature: return False else: return True
def auth_password(self, packet): password = getNS(packet[1:])[0] host = self.transport.transport.getPeer().host self.transport.factory.updatePot(self.user, password, host) return None
def request_exit_signal(self, data): signame, rest = getNS(data) core_dumped = struct.unpack('>?', rest[0])[0] msg, lang, rest = getNS(rest[1:], 2) self._protocol.commandExited( Failure(ProcessTerminated(signal=signame, status=msg)))
class SSHFactory(factory.SSHFactory): publicKeys = {common.getNS(pubkey)[0]: pubkey} privateKeys = {keys.objectType(privkey): privkey}
def request_env(self, data): (key, value, _) = getNS(data, count=2) self.env[key] = value return True