Repository: cowrie/cowrie

Issue:
Unable to curl or wget URL with hostname
If you try to download anything via curl or wget and url contains hostname not ip address it crashes.

I am pretty sure it is because of https://github.com/cowrie/cowrie/pull/1557/commits/0b3b257e0ecf10b5b4d381d724cf4c3e23f0ed81 and https://github.com/cowrie/cowrie/pull/1557/commits/ff6bfdcdb75fefbc35ac19fad7c98c0f69da48b7

Line:         # TODO: need to do full name resolution.


Example:

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
root@czbrqobpvmssd01:~# wget notino.czConnection to czbrqobpvmssd01 closed by remote host.
Connection to czbrqobpvmssd01 closed.




2021-05-28T14:13:00.312387Z [HoneyPotSSHTransport,9,172.16.23.9] Unhandled Error
	Traceback (most recent call last):
	  File "/home/cowrie/cowrie/cowrie-env/lib64/python3.6/site-packages/twisted/python/log.py", line 101, in callWithLogger
	    return callWithContext({"system": lp}, func, *args, **kw)
	  File "/home/cowrie/cowrie/cowrie-env/lib64/python3.6/site-packages/twisted/python/log.py", line 85, in callWithContext
	    return context.call({ILogContext: newCtx}, func, *args, **kw)
	  File "/home/cowrie/cowrie/cowrie-env/lib64/python3.6/site-packages/twisted/python/context.py", line 118, in callWithContext
	    return self.currentContext().callWithContext(ctx, func, *args, **kw)
	  File "/home/cowrie/cowrie/cowrie-env/lib64/python3.6/site-packages/twisted/python/context.py", line 83, in callWithContext
	    return func(*args, **kw)
	--- <exception caught here> ---
	  File "/home/cowrie/cowrie/cowrie-env/lib64/python3.6/site-packages/twisted/internet/posixbase.py", line 687, in _doReadOrWrite
	    why = selectable.doRead()
	  File "/home/cowrie/cowrie/cowrie-env/lib64/python3.6/site-packages/twisted/internet/tcp.py", line 246, in doRead
	    return self._dataReceived(data)
	  File "/home/cowrie/cowrie/cowrie-env/lib64/python3.6/site-packages/twisted/internet/tcp.py", line 251, in _dataReceived
	    rval = self.protocol.dataReceived(data)
	  File "/home/cowrie/cowrie/src/cowrie/ssh/transport.py", line 141, in dataReceived
	    self.dispatchMessage(messageNum, packet[1:])
	  File "/home/cowrie/cowrie/src/cowrie/ssh/transport.py", line 145, in dispatchMessage
	    transport.SSHServerTransport.dispatchMessage(self, message_num, payload)
	  File "/home/cowrie/cowrie/cowrie-env/lib64/python3.6/site-packages/twisted/conch/ssh/transport.py", line 747, in dispatchMessage
	    self.service.packetReceived(messageNum, payload)
	  File "/home/cowrie/cowrie/cowrie-env/lib64/python3.6/site-packages/twisted/conch/ssh/service.py", line 47, in packetReceived
	    return f(packet)
	  File "/home/cowrie/cowrie/cowrie-env/lib64/python3.6/site-packages/twisted/conch/ssh/connection.py", line 265, in ssh_CHANNEL_DATA
	    channel.dataReceived(data)
	  File "/home/cowrie/cowrie/cowrie-env/lib64/python3.6/site-packages/twisted/conch/ssh/session.py", line 174, in dataReceived
	    self.client.transport.write(data)
	  File "/home/cowrie/cowrie/cowrie-env/lib64/python3.6/site-packages/twisted/conch/ssh/session.py", line 230, in write
	    self.proto.dataReceived(data)
	  File "/home/cowrie/cowrie/src/cowrie/insults/insults.py", line 125, in dataReceived
	    insults.ServerProtocol.dataReceived(self, data)
	  File "/home/cowrie/cowrie/cowrie-env/lib64/python3.6/site-packages/twisted/conch/insults/insults.py", line 520, in dataReceived
	    self.terminalProtocol.keystrokeReceived(ch, None)
	  File "/home/cowrie/cowrie/cowrie-env/lib64/python3.6/site-packages/twisted/conch/recvline.py", line 436, in keystrokeReceived
	    m()
	  File "/home/cowrie/cowrie/src/cowrie/shell/protocol.py", line 328, in handle_RETURN
	    return recvline.RecvLine.handle_RETURN(self)
	  File "/home/cowrie/cowrie/cowrie-env/lib64/python3.6/site-packages/twisted/conch/recvline.py", line 494, in handle_RETURN
	    self.lineReceived(line)
	  File "/home/cowrie/cowrie/src/cowrie/shell/protocol.py", line 189, in lineReceived
	    self.cmdstack[-1].lineReceived(line)
	  File "/home/cowrie/cowrie/src/cowrie/shell/honeypot.py", line 116, in lineReceived
	    self.runCommand()
	  File "/home/cowrie/cowrie/src/cowrie/shell/honeypot.py", line 325, in runCommand
	    self.protocol.call_command(pp, cmdclass, *cmd_array[0]["rargs"])
	  File "/home/cowrie/cowrie/src/cowrie/shell/protocol.py", line 309, in call_command
	    HoneyPotBaseProtocol.call_command(self, pp, cmd, *args)
	  File "/home/cowrie/cowrie/src/cowrie/shell/protocol.py", line 198, in call_command
	    obj.start()
	  File "/home/cowrie/cowrie/src/cowrie/commands/wget.py", line 122, in start
	    self.deferred = self.download(self.url, self.outfile)
	  File "/home/cowrie/cowrie/src/cowrie/commands/wget.py", line 157, in download
	    if ipaddress.ip_address(host).is_private:
	  File "/usr/lib64/python3.6/ipaddress.py", line 54, in ip_address
	    address)
	builtins.ValueError: 'notino.cz' does not appear to be an IPv4 or IPv6 address



Discussion:

Resolving patch:
diff --git a/src/cowrie/output/mysql.py b/src/cowrie/output/mysql.py
--- a/src/cowrie/output/mysql.py
+++ b/src/cowrie/output/mysql.py
@@ -2,9 +2,6 @@
 MySQL output connector. Writes audit logs to MySQL database
 """
 
-
-import MySQLdb
-
 from twisted.enterprise import adbapi
 from twisted.internet import defer
 from twisted.python import log
@@ -12,6 +9,9 @@
 import cowrie.core.output
 from cowrie.core.config import CowrieConfig
 
+# For exceptions: https://dev.mysql.com/doc/connector-python/en/connector-python-api-errors-error.html
+import mysql.connector
+
 
 class ReconnectingConnectionPool(adbapi.ConnectionPool):
     """
@@ -22,6 +22,11 @@ class ReconnectingConnectionPool(adbapi.ConnectionPool):
     by checking exceptions by error code and only disconnecting the current
     connection instead of all of them.
 
+     CR_CONN_HOST_ERROR: 2003: Cant connect to MySQL server on server (10061)
+     CR_SERVER_GONE_ERROR: 2006: MySQL server has gone away
+     CR_SERVER_LOST 2013: Lost connection to MySQL server
+     ER_LOCK_DEADLOCK 1213: Deadlock found when trying to get lock)
+
     Also see:
     http://twistedmatrix.com/pipermail/twisted-python/2009-July/020007.html
     """
@@ -29,10 +34,17 @@ class ReconnectingConnectionPool(adbapi.ConnectionPool):
     def _runInteraction(self, interaction, *args, **kw):
         try:
             return adbapi.ConnectionPool._runInteraction(self, interaction, *args, **kw)
-        except (MySQLdb.OperationalError, MySQLdb._exceptions.OperationalError) as e:
-            if e.args[0] not in (2003, 2006, 2013):
+        except mysql.connector.Error as e:
+            # except (MySQLdb.OperationalError, MySQLdb._exceptions.OperationalError) as e:
+            if e.errno not in (
+                mysql.connector.errorcode.CR_CONN_HOST_ERROR,
+                mysql.connector.errorcode.CR_SERVER_GONE_ERROR,
+                mysql.connector.errorcode.CR_SERVER_LOST,
+                mysql.connector.errorcode.ER_LOCK_DEADLOCK,
+            ):
                 raise e
-            log.msg(f"RCP: got error {e}, retrying operation")
+
+            log.msg(f"output_mysql: got error {e!r}, retrying operation")
             conn = self.connections.get(self.threadID())
             self.disconnect(conn)
             # Try the interaction again
@@ -41,7 +53,7 @@ def _runInteraction(self, interaction, *args, **kw):
 
 class Output(cowrie.core.output.Output):
     """
-    mysql output
+    MySQL output
     """
 
     db = None
@@ -52,7 +64,7 @@ def start(self):
         port = CowrieConfig.getint("output_mysql", "port", fallback=3306)
         try:
             self.db = ReconnectingConnectionPool(
-                "MySQLdb",
+                "mysql.connector",
                 host=CowrieConfig.get("output_mysql", "host"),
                 db=CowrieConfig.get("output_mysql", "database"),
                 user=CowrieConfig.get("output_mysql", "username"),
@@ -64,11 +76,11 @@ def start(self):
                 cp_reconnect=True,
                 use_unicode=True,
             )
-        except (MySQLdb.Error, MySQLdb._exceptions.Error) as e:
+        # except (MySQLdb.Error, MySQLdb._exceptions.Error) as e:
+        except Exception as e:
             log.msg(f"output_mysql: Error {e.args[0]}: {e.args[1]}")
 
     def stop(self):
-        self.db.commit()
         self.db.close()
 
     def sqlerror(self, error):
@@ -78,7 +90,7 @@ def sqlerror(self, error):
         """
         if error.value.args[0] in (1146, 1406):
             log.msg(f"output_mysql: MySQL Error: {error.value.args!r}")
-            log.msg("MySQL schema maybe misconfigured, doublecheck database!")
+            log.msg("output_mysql: MySQL schema maybe misconfigured, doublecheck database!")
         else:
             log.msg(f"output_mysql: MySQL Error: {error.value.args!r}")
 
@@ -94,15 +106,19 @@ def simpleQuery(self, sql, args):
     @defer.inlineCallbacks
     def write(self, entry):
         if entry["eventid"] == "cowrie.session.connect":
+            if self.debug:
+                log.msg(f"output_mysql: SELECT `id` FROM `sensors` WHERE `ip` = '{self.sensor}'")
             r = yield self.db.runQuery(
-                "SELECT `id`" "FROM `sensors`" f"WHERE `ip` = {self.sensor}"
+                f"SELECT `id` FROM `sensors` WHERE `ip` = '{self.sensor}'"
             )
 
             if r:
                 sensorid = r[0][0]
             else:
+                if self.debug:
+                    log.msg(f"output_mysql: INSERT INTO `sensors` (`ip`) VALUES ('{self.sensor}')")
                 yield self.db.runQuery(
-                    "INSERT INTO `sensors` (`ip`) " f"VALUES ({self.sensor})"
+                    f"INSERT INTO `sensors` (`ip`) VALUES ('{self.sensor}')"
                 )
 
                 r = yield self.db.runQuery("SELECT LAST_INSERT_ID()")


Test patch: