Repository: cowrie/cowrie

Issue:
builtins.AttributeError: 'HoneyPotSSHTransport' object has no attribute 'otherVersionString'
**Describe the bug**
I used the docker version of cowrie and got this error: `builtins.AttributeError: 'HoneyPotSSHTransport' object has no attribute 'otherVersionString'` when I tried SSH to the cowrie server.

**To Reproduce**
1. create a docker compose service file `compose.yaml`
```yaml
 services:
  2   cowrie:
  3     image: cowrie/cowrie:latest
  4     ports:
  5       - "22:2222"
 17     restart: always
```
2. start cowrie by executing `docker compose up` in the directory the `compose.yaml` file located
3. perform a SSH login attempt from otherwhere(e.g. from a windows PC): `ssh -p22 cowrie_server_ip`
4. get the `Connection closed by cowrie_server_ip port 22` error from your SSH client
5. check the cowrie's log and find the `builtins.AttributeError: 'HoneyPotSSHTransport' object has no attribute 'otherVersionString'` error

**Expected behavior**
cowrie should welcome the SSH login attempt correctly.

**Server (please complete the following information):**
 - OS: [5.15.0-58-generic # 64~20.04.1-**Ubuntu** SMP Fri Jan 6 16:42:31 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux]
 - Python: [3.8.10]

**Additional context**
### full log
```
cowrie-cowrie-1  | /cowrie/cowrie-env/lib/python3.9/site-packages/twisted/conch/ssh/transport.py:97: CryptographyDeprecationWarning: Blowfish has been deprecated
cowrie-cowrie-1  |   b"blowfish-cbc": (algorithms.Blowfish, 16, modes.CBC),
cowrie-cowrie-1  | /cowrie/cowrie-env/lib/python3.9/site-packages/twisted/conch/ssh/transport.py:101: CryptographyDeprecationWarning: CAST5 has been deprecated
cowrie-cowrie-1  |   b"cast128-cbc": (algorithms.CAST5, 16, modes.CBC),
cowrie-cowrie-1  | /cowrie/cowrie-env/lib/python3.9/site-packages/twisted/conch/ssh/transport.py:106: CryptographyDeprecationWarning: Blowfish has been deprecated
cowrie-cowrie-1  |   b"blowfish-ctr": (algorithms.Blowfish, 16, modes.CTR),
cowrie-cowrie-1  | /cowrie/cowrie-env/lib/python3.9/site-packages/twisted/conch/ssh/transport.py:107: CryptographyDeprecationWarning: CAST5 has been deprecated
cowrie-cowrie-1  |   b"cast128-ctr": (algorithms.CAST5, 16, modes.CTR),
cowrie-cowrie-1  | 2023-02-03T04:56:29+0000 [-] Python Version 3.9.2 (default, Feb 28 2021, 17:03:44) [GCC 10.2.1 20210110]
cowrie-cowrie-1  | 2023-02-03T04:56:29+0000 [-] Twisted Version 22.10.0
cowrie-cowrie-1  | 2023-02-03T04:56:29+0000 [-] Cowrie Version 2.5.0
cowrie-cowrie-1  | 2023-02-03T04:56:29+0000 [-] Loaded output engine: jsonlog
cowrie-cowrie-1  | 2023-02-03T04:56:29+0000 [-] Loaded output engine: textlog
cowrie-cowrie-1  | 2023-02-03T04:56:29+0000 [twisted.scripts._twistd_unix.UnixAppLogger#info] twistd 22.10.0 (/cowrie/cowrie-env/bin/python3 3.9.2) starting up.
cowrie-cowrie-1  | 2023-02-03T04:56:29+0000 [twisted.scripts._twistd_unix.UnixAppLogger#info] reactor class: twisted.internet.epollreactor.EPollReactor.
cowrie-cowrie-1  | 2023-02-03T04:56:29+0000 [-] CowrieSSHFactory starting on 2222
cowrie-cowrie-1  | 2023-02-03T04:56:29+0000 [cowrie.ssh.factory.CowrieSSHFactory#info] Starting factory <cowrie.ssh.factory.CowrieSSHFactory object at 0x7fdce7e47b50>
cowrie-cowrie-1  | 2023-02-03T04:56:29+0000 [-] Ready to accept SSH connections
cowrie-cowrie-1  | 2023-02-03T04:56:39+0000 [cowrie.ssh.factory.CowrieSSHFactory] No moduli, no diffie-hellman-group-exchange-sha1
cowrie-cowrie-1  | 2023-02-03T04:56:39+0000 [cowrie.ssh.factory.CowrieSSHFactory] No moduli, no diffie-hellman-group-exchange-sha256
cowrie-cowrie-1  | 2023-02-03T04:56:39+0000 [cowrie.ssh.factory.CowrieSSHFactory] New connection: 10.249.47.179:35369 (172.19.0.2:2222) [session: 6ebb4f6a7eca]
cowrie-cowrie-1  | 2023-02-03T04:56:39+0000 [HoneyPotSSHTransport,0,10.249.47.179] Remote SSH version: SSH-2.0-OpenSSH_for_Windows_8.1
cowrie-cowrie-1  | 2023-02-03T04:56:39+0000 [HoneyPotSSHTransport,0,10.249.47.179] SSH client hassh fingerprint: ec7378c1a92f5a8dde7e8b7a1ddf33d1
cowrie-cowrie-1  | 2023-02-03T04:56:39+0000 [cowrie.ssh.transport.HoneyPotSSHTransport#debug] kex alg=b'curve25519-sha256' key alg=b'ecdsa-sha2-nistp256'
cowrie-cowrie-1  | 2023-02-03T04:56:39+0000 [cowrie.ssh.transport.HoneyPotSSHTransport#debug] outgoing: b'aes128-ctr' b'hmac-sha2-512' b'none'
cowrie-cowrie-1  | 2023-02-03T04:56:39+0000 [cowrie.ssh.transport.HoneyPotSSHTransport#debug] incoming: b'aes128-ctr' b'hmac-sha2-512' b'none'
cowrie-cowrie-1  | 2023-02-03T04:56:39+0000 [HoneyPotSSHTransport,0,10.249.47.179] Unhandled Error
cowrie-cowrie-1  |      Traceback (most recent call last):
cowrie-cowrie-1  |        File "/cowrie/cowrie-env/lib/python3.9/site-packages/twisted/python/log.py", line 96, in callWithLogger
cowrie-cowrie-1  |          return callWithContext({"system": lp}, func, *args, **kw)
cowrie-cowrie-1  |        File "/cowrie/cowrie-env/lib/python3.9/site-packages/twisted/python/log.py", line 80, in callWithContext
cowrie-cowrie-1  |          return context.call({ILogContext: newCtx}, func, *args, **kw)
cowrie-cowrie-1  |        File "/cowrie/cowrie-env/lib/python3.9/site-packages/twisted/python/context.py", line 117, in callWithContext
cowrie-cowrie-1  |          return self.currentContext().callWithContext(ctx, func, *args, **kw)
cowrie-cowrie-1  |        File "/cowrie/cowrie-env/lib/python3.9/site-packages/twisted/python/context.py", line 82, in callWithContext
cowrie-cowrie-1  |          return func(*args, **kw)
cowrie-cowrie-1  |      --- <exception caught here> ---
cowrie-cowrie-1  |        File "/cowrie/cowrie-env/lib/python3.9/site-packages/twisted/internet/posixbase.py", line 487, in _doReadOrWrite
cowrie-cowrie-1  |          why = selectable.doRead()
cowrie-cowrie-1  |        File "/cowrie/cowrie-env/lib/python3.9/site-packages/twisted/internet/tcp.py", line 248, in doRead
cowrie-cowrie-1  |          return self._dataReceived(data)
cowrie-cowrie-1  |        File "/cowrie/cowrie-env/lib/python3.9/site-packages/twisted/internet/tcp.py", line 253, in _dataReceived
cowrie-cowrie-1  |          rval = self.protocol.dataReceived(data)
cowrie-cowrie-1  |        File "/cowrie/cowrie-git/src/cowrie/ssh/transport.py", line 144, in dataReceived
cowrie-cowrie-1  |          self.dispatchMessage(messageNum, packet[1:])
cowrie-cowrie-1  |        File "/cowrie/cowrie-git/src/cowrie/ssh/transport.py", line 148, in dispatchMessage
cowrie-cowrie-1  |          transport.SSHServerTransport.dispatchMessage(self, messageNum, payload)
cowrie-cowrie-1  |        File "/cowrie/cowrie-env/lib/python3.9/site-packages/twisted/conch/ssh/transport.py", line 781, in dispatchMessage
cowrie-cowrie-1  |          f(payload)
cowrie-cowrie-1  |        File "/cowrie/cowrie-env/lib/python3.9/site-packages/twisted/conch/ssh/transport.py", line 1618, in ssh_KEX_DH_GEX_REQUEST_OLD
cowrie-cowrie-1  |          return self._ssh_KEX_ECDH_INIT(packet)
cowrie-cowrie-1  |        File "/cowrie/cowrie-env/lib/python3.9/site-packages/twisted/conch/ssh/transport.py", line 1530, in _ssh_KEX_ECDH_INIT
cowrie-cowrie-1  |          h.update(NS(self.otherVersionString))
cowrie-cowrie-1  |      builtins.AttributeError: 'HoneyPotSSHTransport' object has no attribute 'otherVersionString'
cowrie-cowrie-1  |
cowrie-cowrie-1  | 2023-02-03T04:56:39+0000 [cowrie.ssh.transport.HoneyPotSSHTransport#info] connection lost
cowrie-cowrie-1  | 2023-02-03T04:56:39+0000 [HoneyPotSSHTransport,0,10.249.47.179] Connection lost after 0 seconds
```



Discussion:
Hi @HuengchI I was having the same, and ended up moving backwards from latest through the images.   and cowrie/cowrie:59f4ed7f worked for me.

https://hub.docker.com/r/cowrie/cowrie/tags
> I was having the same, and ended up moving backwards from latest through the images. and cowrie/cowrie:59f4ed7f worked for me.

@jquiros2 Thanks! I'll have a try.

It seems that the latest version has some bugs. The same error occurs even when I performed a 
["7-step standard installation"](https://cowrie.readthedocs.io/en/latest/INSTALL.html#installing-cowrie-in-seven-steps) following the document.
I have the same issue with the latest image.

2023-02-05T08:37:35+0000 [cowrie.ssh.factory.CowrieSSHFactory] No moduli, no diffie-hellman-group-exchange-sha1
2023-02-05T08:37:35+0000 [cowrie.ssh.factory.CowrieSSHFactory] No moduli, no diffie-hellman-group-exchange-sha256
2023-02-05T08:37:35+0000 [cowrie.ssh.factory.CowrieSSHFactory] New connection: 192.168.1.15:65199 (172.17.0.4:2222) [session: 55969b675696]
2023-02-05T08:37:35+0000 [HoneyPotSSHTransport,3,192.168.1.15] Remote SSH version: SSH-2.0-PuTTY_Release_0.76
2023-02-05T08:37:35+0000 [HoneyPotSSHTransport,3,192.168.1.15] SSH client hassh fingerprint: 5b7713a9ef2d162b16ea018fa8d40f02
2023-02-05T08:37:35+0000 [cowrie.ssh.transport.HoneyPotSSHTransport#debug] kex alg=b'curve25519-sha256' key alg=b'ssh-ed25519'
2023-02-05T08:37:35+0000 [cowrie.ssh.transport.HoneyPotSSHTransport#debug] outgoing: b'aes256-ctr' b'hmac-sha1' b'none'
2023-02-05T08:37:35+0000 [cowrie.ssh.transport.HoneyPotSSHTransport#debug] incoming: b'aes256-ctr' b'hmac-sha1' b'none'
2023-02-05T08:37:35+0000 [HoneyPotSSHTransport,3,192.168.1.15] Unhandled Error
	Traceback (most recent call last):
	  File "/cowrie/cowrie-env/lib/python3.9/site-packages/twisted/python/log.py", line 96, in callWithLogger
	    return callWithContext({"system": lp}, func, *args, **kw)
	  File "/cowrie/cowrie-env/lib/python3.9/site-packages/twisted/python/log.py", line 80, in callWithContext
	    return context.call({ILogContext: newCtx}, func, *args, **kw)
	  File "/cowrie/cowrie-env/lib/python3.9/site-packages/twisted/python/context.py", line 117, in callWithContext
	    return self.currentContext().callWithContext(ctx, func, *args, **kw)
	  File "/cowrie/cowrie-env/lib/python3.9/site-packages/twisted/python/context.py", line 82, in callWithContext
	    return func(*args, **kw)
	--- <exception caught here> ---
	  File "/cowrie/cowrie-env/lib/python3.9/site-packages/twisted/internet/posixbase.py", line 487, in _doReadOrWrite
	    why = selectable.doRead()
	  File "/cowrie/cowrie-env/lib/python3.9/site-packages/twisted/internet/tcp.py", line 248, in doRead
	    return self._dataReceived(data)
	  File "/cowrie/cowrie-env/lib/python3.9/site-packages/twisted/internet/tcp.py", line 253, in _dataReceived
	    rval = self.protocol.dataReceived(data)
	  File "/cowrie/cowrie-git/src/cowrie/ssh/transport.py", line 144, in dataReceived
	    self.dispatchMessage(messageNum, packet[1:])
	  File "/cowrie/cowrie-git/src/cowrie/ssh/transport.py", line 148, in dispatchMessage
	    transport.SSHServerTransport.dispatchMessage(self, messageNum, payload)
	  File "/cowrie/cowrie-env/lib/python3.9/site-packages/twisted/conch/ssh/transport.py", line 781, in dispatchMessage
	    f(payload)
	  File "/cowrie/cowrie-env/lib/python3.9/site-packages/twisted/conch/ssh/transport.py", line 1618, in ssh_KEX_DH_GEX_REQUEST_OLD
	    return self._ssh_KEX_ECDH_INIT(packet)
	  File "/cowrie/cowrie-env/lib/python3.9/site-packages/twisted/conch/ssh/transport.py", line 1530, in _ssh_KEX_ECDH_INIT
	    h.update(NS(self.otherVersionString))
	builtins.AttributeError: 'HoneyPotSSHTransport' object has no attribute 'otherVersionString'
	
2023-02-05T08:37:35+0000 [cowrie.ssh.transport.HoneyPotSSHTransport#info] connection lost
2023-02-05T08:37:35+0000 [HoneyPotSSHTransport,3,192.168.1.15] Connection lost after 0 seconds
Confirmed bug! Sorry about this! 
This shows the testing framework needs an integration test.

Resolving patch:
diff --git a/src/cowrie/ssh/transport.py b/src/cowrie/ssh/transport.py
--- a/src/cowrie/ssh/transport.py
+++ b/src/cowrie/ssh/transport.py
@@ -113,18 +113,18 @@ def dataReceived(self, data: bytes) -> None:
         if not self.gotVersion:
             if b"\n" not in self.buf:
                 return
-            otherVersion: bytes = self.buf.split(b"\n")[0].strip()
+            self.otherVersionString: bytes = self.buf.split(b"\n")[0].strip()
             log.msg(
                 eventid="cowrie.client.version",
-                version=otherVersion.decode(
+                version=self.otherVersionString.decode(
                     "utf-8", errors="backslashreplace"
                 ),
                 format="Remote SSH version: %(version)s",
             )
-            m = re.match(rb"SSH-(\d+.\d+)-(.*)", otherVersion)
+            m = re.match(rb"SSH-(\d+.\d+)-(.*)", self.otherVersionString)
             if m is None:
                 log.msg(
-                    f"Bad protocol version identification: {repr(otherVersion)}"
+                    f"Bad protocol version identification: {repr(self.otherVersionString)}"
                 )
                 # OpenSSH sending the same message
                 self.transport.write(b"Invalid SSH identification string.\n")
@@ -133,7 +133,7 @@ def dataReceived(self, data: bytes) -> None:
             self.gotVersion = True
             remote_version = m.group(1)
             if remote_version not in self.supportedVersions:
-                self._unsupportedVersionReceived(otherVersion)
+                self._unsupportedVersionReceived(self.otherVersionString)
                 return
             i = self.buf.index(b"\n")
             self.buf = self.buf[i + 1 :]
diff --git a/src/cowrie/ssh_proxy/server_transport.py b/src/cowrie/ssh_proxy/server_transport.py
--- a/src/cowrie/ssh_proxy/server_transport.py
+++ b/src/cowrie/ssh_proxy/server_transport.py
@@ -211,18 +211,18 @@ def dataReceived(self, data: bytes) -> None:
         if not self.gotVersion:
             if b"\n" not in self.buf:
                 return
-            otherVersion = self.buf.split(b"\n")[0].strip()
+            self.otherVersionString = self.buf.split(b"\n")[0].strip()
             log.msg(
                 eventid="cowrie.client.version",
-                version=otherVersion.decode(
+                version=self.otherVersionString.decode(
                     "utf-8", errors="backslashreplace"
                 ),
                 format="Remote SSH version: %(version)s",
             )
-            m = re.match(rb"SSH-(\d+.\d+)-(.*)", otherVersion)
+            m = re.match(rb"SSH-(\d+.\d+)-(.*)", self.otherVersionString)
             if m is None:
                 log.msg(
-                    f"Bad protocol version identification: {repr(otherVersion)}"
+                    f"Bad protocol version identification: {repr(self.otherVersionString)}"
                 )
                 if self.transport:
                     self.transport.write(b"Protocol mismatch.\n")


Test patch: