pgsqlpot 2.0.0__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. core/__init__.py +0 -0
  2. core/config.py +50 -0
  3. core/logfile.py +74 -0
  4. core/output.py +39 -0
  5. core/paths.py +53 -0
  6. core/protocol.py +161 -0
  7. core/tools.py +170 -0
  8. output_plugins/__init__.py +0 -0
  9. output_plugins/couch.py +68 -0
  10. output_plugins/datadog.py +74 -0
  11. output_plugins/discord.py +133 -0
  12. output_plugins/elastic.py +137 -0
  13. output_plugins/hpfeed.py +43 -0
  14. output_plugins/influx2.py +66 -0
  15. output_plugins/jsonlog.py +36 -0
  16. output_plugins/kafka.py +57 -0
  17. output_plugins/localsyslog.py +66 -0
  18. output_plugins/mongodb.py +83 -0
  19. output_plugins/mysql.py +210 -0
  20. output_plugins/nlcvapi.py +119 -0
  21. output_plugins/postgres.py +154 -0
  22. output_plugins/redisdb.py +47 -0
  23. output_plugins/rethinkdblog.py +46 -0
  24. output_plugins/slack.py +94 -0
  25. output_plugins/socketlog.py +40 -0
  26. output_plugins/sqlite.py +141 -0
  27. output_plugins/telegram.py +141 -0
  28. output_plugins/textlog.py +46 -0
  29. output_plugins/xmpp.py +193 -0
  30. pgsqlpot/__init__.py +25 -0
  31. pgsqlpot/cli.py +512 -0
  32. pgsqlpot/data/Dockerfile +56 -0
  33. pgsqlpot/data/docs/INSTALL.md +400 -0
  34. pgsqlpot/data/docs/INSTALLWIN.md +411 -0
  35. pgsqlpot/data/docs/PLUGINS.md +21 -0
  36. pgsqlpot/data/docs/TODO.md +8 -0
  37. pgsqlpot/data/docs/datadog/README.md +32 -0
  38. pgsqlpot/data/docs/discord/README.md +58 -0
  39. pgsqlpot/data/docs/geoipupdtask.ps1 +270 -0
  40. pgsqlpot/data/docs/mysql/README.md +176 -0
  41. pgsqlpot/data/docs/mysql/READMEWIN.md +157 -0
  42. pgsqlpot/data/docs/mysql/mysql.sql +85 -0
  43. pgsqlpot/data/docs/postgres/README.md +184 -0
  44. pgsqlpot/data/docs/postgres/READMEWIN.md +196 -0
  45. pgsqlpot/data/docs/postgres/postgres.sql +73 -0
  46. pgsqlpot/data/docs/slack/README.md +68 -0
  47. pgsqlpot/data/docs/sqlite3/README.md +131 -0
  48. pgsqlpot/data/docs/sqlite3/READMEWIN.md +123 -0
  49. pgsqlpot/data/docs/sqlite3/sqlite3.sql +69 -0
  50. pgsqlpot/data/docs/telegram/README.md +103 -0
  51. pgsqlpot/data/etc/honeypot.cfg +415 -0
  52. pgsqlpot/data/etc/honeypot.cfg.base +418 -0
  53. pgsqlpot/data/test/.gitignore +3 -0
  54. pgsqlpot/data/test/test.py +51 -0
  55. pgsqlpot/honeypot.py +117 -0
  56. pgsqlpot-2.0.0.dist-info/METADATA +152 -0
  57. pgsqlpot-2.0.0.dist-info/RECORD +61 -0
  58. pgsqlpot-2.0.0.dist-info/WHEEL +6 -0
  59. pgsqlpot-2.0.0.dist-info/entry_points.txt +2 -0
  60. pgsqlpot-2.0.0.dist-info/licenses/LICENSE +674 -0
  61. pgsqlpot-2.0.0.dist-info/top_level.txt +3 -0
@@ -0,0 +1,40 @@
1
+
2
+ from __future__ import absolute_import
3
+
4
+ from json import dumps
5
+ from socket import socket, AF_INET, SOCK_STREAM
6
+
7
+ from core import output
8
+ from core.config import CONFIG
9
+ from core.tools import encode
10
+
11
+
12
+ class Output(output.Output):
13
+ """
14
+ socketlog output
15
+ """
16
+
17
+ def start(self):
18
+ timeout = CONFIG.getint('output_socketlog', 'timeout')
19
+ addr = CONFIG.get('output_socketlog', 'address')
20
+ host = addr.split(':')[0]
21
+ port = int(addr.split(':')[1])
22
+
23
+ self.sock = socket(AF_INET, SOCK_STREAM)
24
+ self.sock.settimeout(timeout)
25
+ self.sock.connect((host, port))
26
+
27
+ def stop(self):
28
+ self.sock.close()
29
+
30
+ def write(self, event):
31
+ message = dumps(event, sort_keys=True) + '\n'
32
+
33
+ try:
34
+ self.sock.sendall(encode(message))
35
+ except OSError as ex:
36
+ if ex.errno == 32: # Broken pipe
37
+ self.start()
38
+ self.sock.sendall(encode(message))
39
+ else:
40
+ raise
@@ -0,0 +1,141 @@
1
+
2
+ from __future__ import absolute_import
3
+
4
+ from core import output
5
+ from core.config import CONFIG
6
+ from core.tools import geolocate
7
+
8
+ from geoip2.database import Reader
9
+ from sqlite3 import OperationalError, IntegrityError
10
+
11
+ from twisted.enterprise.adbapi import ConnectionPool
12
+ from twisted.python.log import msg
13
+
14
+
15
+ class Output(output.Output):
16
+
17
+ def start(self):
18
+ db_name = CONFIG.get('output_sqlite', 'db_file', fallback='data/pgsqlpot.db')
19
+ self.debug = CONFIG.getboolean('output_sqlite', 'debug', fallback=False)
20
+ self.geoip = CONFIG.getboolean('output_sqlite', 'geoip', fallback=True)
21
+
22
+ try:
23
+ self.db = ConnectionPool(
24
+ 'sqlite3',
25
+ database=db_name,
26
+ check_same_thread=False
27
+ )
28
+ except OperationalError as e:
29
+ msg(e)
30
+
31
+ self.db.start()
32
+
33
+ if self.geoip:
34
+ geoipdb_city_path = CONFIG.get('output_sqlite', 'geoip_citydb', fallback='data/GeoLite2-City.mmdb')
35
+ geoipdb_asn_path = CONFIG.get('output_sqlite', 'geoip_asndb', fallback='data/GeoLite2-ASN.mmdb')
36
+
37
+ try:
38
+ self.reader_city = Reader(geoipdb_city_path)
39
+ except Exception:
40
+ self.reader_city = None
41
+ msg('Failed to open City GeoIP database {}'.format(geoipdb_city_path))
42
+ try:
43
+ self.reader_asn = Reader(geoipdb_asn_path)
44
+ except Exception:
45
+ self.reader_asn = None
46
+ msg('Failed to open ASN GeoIP database {}'.format(geoipdb_asn_path))
47
+
48
+ def stop(self):
49
+ if self.geoip:
50
+ if self.reader_city is not None:
51
+ self.reader_city.close()
52
+ if self.reader_asn is not None:
53
+ self.reader_asn.close()
54
+
55
+ def write(self, event):
56
+ self.db.runInteraction(self.connect_event, event)
57
+
58
+ def simple_query(self, txn, sql, args):
59
+ if self.debug:
60
+ if len(args):
61
+ msg('output_sqlite: SQLite3 query: {} {}'.format(sql, repr(args)))
62
+ else:
63
+ msg('output_sqlite: SQLite3 query: {}'.format(sql))
64
+ try:
65
+ if len(args):
66
+ txn.execute(sql, args)
67
+ else:
68
+ txn.execute(sql)
69
+ result = txn.fetchall()
70
+ except IntegrityError as e:
71
+ result = None
72
+ except Exception as e:
73
+ msg('output_sqlite: SQLite3 Error: {}'.format(e))
74
+ result = None
75
+ return result
76
+
77
+ def get_id(self, txn, table, column, entry):
78
+ r = self.simple_query(txn, "SELECT `id` FROM `{}` WHERE `{}` = ?".format(table, column), (entry, ))
79
+ if r:
80
+ id = r[0][0]
81
+ else:
82
+ self.simple_query(txn, "INSERT INTO `{}` (`{}`) VALUES (?)".format(table, column), (entry, ))
83
+ r = self.simple_query(txn, 'SELECT LAST_INSERT_ROWID()', ())
84
+ if r:
85
+ id = int(r[0][0])
86
+ else:
87
+ id = 0
88
+ return id
89
+
90
+ def connect_event(self, txn, event):
91
+ remote_ip = event['src_ip']
92
+
93
+ operation_id = self.get_id(txn, 'operations', 'op_name', event['operation'])
94
+ sensor_id = self.get_id(txn, 'sensors', 'name', event['sensor'])
95
+
96
+ self.simple_query(txn,
97
+ """
98
+ INSERT INTO `connections` (`session`, `timestamp`, `operation`, `ip`, `remote_port`, `local_host`, `local_port`, `sensor`)
99
+ VALUES (?, DATETIME(?, 'unixepoch', 'localtime'), ?, ?, ?, ?, ?, ?)
100
+ """,
101
+ (event['session'], event['unixtime'], operation_id, remote_ip, event['src_port'],
102
+ event['dst_ip'], event['dst_port'], sensor_id, ))
103
+
104
+ if event['operation'].lower() == 'login':
105
+ usr_id = self.get_id(txn, 'usernames', 'username', event['username'])
106
+ pwd_id = self.get_id(txn, 'passwords', 'password', event['password'])
107
+ self.simple_query(txn,
108
+ """
109
+ INSERT INTO `credentials` (`session`, `username`, `password`) VALUES(?, ?, ?)
110
+ """,
111
+ (event['session'], usr_id, pwd_id, ))
112
+ if 'variables' in event:
113
+ for key, value in event['variables'].items():
114
+ var_id = self.get_id(txn, 'vars', 'var_name', key)
115
+ val_id = self.get_id(txn, 'var_values', 'var_value', value)
116
+ self.simple_query(txn,
117
+ """
118
+ INSERT INTO `variables` (`session`, `var`, `val`) VALUES(?, ?, ?)
119
+ """,
120
+ (event['session'], var_id, val_id, ))
121
+
122
+ if self.geoip:
123
+ country, country_code, city, org, asn_num = geolocate(remote_ip, self.reader_city, self.reader_asn)
124
+ result = self.simple_query(txn,
125
+ """
126
+ INSERT INTO `geolocation` (`ip`, `country_name`, `country_iso_code`, `city_name`, `org`, `org_asn`)
127
+ VALUES (?, ?, ?, ?, ?, ?)
128
+ """,
129
+ (remote_ip, country, country_code, city, org, asn_num, ))
130
+ if result is None:
131
+ self.simple_query(txn,
132
+ """
133
+ UPDATE `geolocation` SET
134
+ `country_name` = ?,
135
+ `country_iso_code` = ?,
136
+ `city_name` = ?,
137
+ `org` = ?,
138
+ `org_asn` = ?
139
+ WHERE `ip` = ?
140
+ """,
141
+ (country, country_code, city, org, asn_num, remote_ip, ))
@@ -0,0 +1,141 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+
4
+ # Simple Telegram Bot logger
5
+
6
+ from __future__ import absolute_import
7
+
8
+ from json import loads
9
+ from time import gmtime, strftime, time
10
+
11
+ from core import output
12
+ from core.config import CONFIG
13
+ from core.tools import decode, encode
14
+
15
+ try:
16
+ from urllib import quote_plus
17
+ except ImportError:
18
+ from urllib.parse import quote_plus
19
+
20
+ from twisted.internet import reactor
21
+ from twisted.internet.ssl import ClientContextFactory
22
+ from twisted.internet.task import deferLater
23
+ from twisted.python.log import msg
24
+ from twisted.web.client import (
25
+ Agent,
26
+ HTTPConnectionPool,
27
+ _HTTP11ClientFactory,
28
+ readBody
29
+ )
30
+ from twisted.web.http_headers import Headers
31
+
32
+
33
+ class WebClientContextFactory(ClientContextFactory):
34
+
35
+ def getContext(self, hostname, port):
36
+ return ClientContextFactory.getContext(self)
37
+
38
+
39
+ class QuietHTTP11ClientFactory(_HTTP11ClientFactory):
40
+ noisy = False
41
+
42
+
43
+ class Output(output.Output):
44
+ """
45
+ Telegram bot output plugin.
46
+ """
47
+
48
+ def start(self):
49
+ self.bot_token = CONFIG.get('output_telegram', 'bot_token')
50
+ self.chat_id = CONFIG.get('output_telegram', 'chat_id')
51
+ self.delay = CONFIG.getfloat('output_telegram', 'delay', fallback=2.0)
52
+
53
+ contextFactory = WebClientContextFactory()
54
+ pool = HTTPConnectionPool(reactor)
55
+ pool._factory = QuietHTTP11ClientFactory
56
+ self.agent = Agent(reactor, contextFactory=contextFactory, pool=pool)
57
+ self.last_sent = 0
58
+ self.requests_list = []
59
+
60
+ def stop(self):
61
+ pass
62
+
63
+ def write(self, event):
64
+ operation = event['operation'].lower()
65
+ message = '[{} UTC] [PGSQLPot on {} ({})]: {}'.format(
66
+ strftime('%Y-%m-%d %H:%M:%S', gmtime(event['unixtime'])),
67
+ event['sensor'], event['session'], operation.capitalize()
68
+ )
69
+ if operation == 'unknown':
70
+ message += ' operation: "{}"'.format(event['username'])
71
+ elif operation == 'command':
72
+ message += ' "{}'.format(event['command'])
73
+ if event['args']:
74
+ message += ' {}'.format(event['args'])
75
+ message += '"'
76
+ message += ' from {}:{}'.format(event['src_ip'], event['dst_port'])
77
+ if operation == 'login':
78
+ message += ', username: "{}", password: "{}"'.format(
79
+ event['username'], event['password']
80
+ )
81
+ message += '.'
82
+ self.requests_list.append(message)
83
+ self._drain()
84
+
85
+ def _drain(self):
86
+ """Send the next queued message if the rate-limit window has elapsed.
87
+ If messages remain, schedule another drain after self.delay seconds."""
88
+ if not self.requests_list:
89
+ return
90
+ now = time()
91
+ elapsed = now - self.last_sent
92
+ if elapsed < self.delay:
93
+ deferLater(reactor, self.delay - elapsed, self._drain)
94
+ return
95
+ self.last_sent = now
96
+ message = self.requests_list.pop(0)
97
+ d = self._send(message)
98
+ if self.requests_list:
99
+ deferLater(reactor, self.delay, self._drain)
100
+ return d
101
+
102
+ def _send(self, message):
103
+
104
+ def cbBody(body):
105
+ return processResult(body)
106
+
107
+ def cbPartial(failure):
108
+ """
109
+ Google HTTP Server does not set Content-Length. Twisted marks it as partial
110
+ """
111
+ failure.printTraceback()
112
+ return processResult(failure.value.response)
113
+
114
+ def cbResponse(response):
115
+ if response.code in [200, 201]:
116
+ return
117
+ msg('Telegram error: {} {}'.format(response.code, decode(response.phrase)))
118
+ d = readBody(response)
119
+ d.addCallback(cbBody)
120
+ d.addErrback(cbPartial)
121
+ return d
122
+
123
+ def cbError(failure):
124
+ failure.printTraceback()
125
+
126
+ def processResult(result):
127
+ try:
128
+ j = loads(result)
129
+ msg('Telegram response: {}'.format(j.get('description', '')))
130
+ except Exception:
131
+ pass
132
+
133
+ headers = Headers({
134
+ b'User-Agent': [b'PGSQLPot']
135
+ })
136
+ params = 'chat_id={}&parse_mode=HTML&text={}'.format(self.chat_id, quote_plus(message))
137
+ url = 'https://api.telegram.org/bot{}/sendMessage?{}'.format(self.bot_token, params)
138
+ d = self.agent.request(b'GET', encode(url), headers, None)
139
+ d.addCallback(cbResponse)
140
+ d.addErrback(cbError)
141
+ return d
@@ -0,0 +1,46 @@
1
+
2
+ from __future__ import absolute_import
3
+
4
+ from os import linesep
5
+ from os.path import basename, dirname
6
+ from time import gmtime, strftime
7
+
8
+ from core import output
9
+ from core.config import CONFIG
10
+ from core.tools import mkdir
11
+ from core.logfile import HoneypotDailyLogFile
12
+
13
+ class Output(output.Output):
14
+
15
+ def start(self):
16
+ fn = CONFIG.get('output_textlog', 'logfile')
17
+ dirs = dirname(fn)
18
+ base = basename(fn)
19
+ mkdir(dirs)
20
+ self.outfile = HoneypotDailyLogFile(base, dirs, defaultMode=0o664)
21
+
22
+ def stop(self):
23
+ self.outfile.flush()
24
+
25
+ def write(self, event):
26
+ operation = event['operation'].lower()
27
+ message = '[{} UTC] [PGSQLPot on {} ({})]: {}'.format(
28
+ strftime('%Y-%m-%d %H:%M:%S', gmtime(event['unixtime'])),
29
+ event['sensor'], event['session'], operation.capitalize()
30
+ )
31
+ if operation == 'unknown':
32
+ message += ' operation: "{}"'.format(event['username'])
33
+ elif operation == 'command':
34
+ message += ' "{}'.format(event['command'])
35
+ if event['args']:
36
+ message += ' {}'.format(event['args'])
37
+ message += '"'
38
+ message += ' from {}:{}'.format(event['src_ip'], event['dst_port'])
39
+ if operation == 'login':
40
+ message += ', username: "{}", password: "{}"'.format(
41
+ event['username'], event['password']
42
+ )
43
+ message += '.' + linesep
44
+
45
+ self.outfile.write(message)
46
+ self.outfile.flush()
output_plugins/xmpp.py ADDED
@@ -0,0 +1,193 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+
4
+ """
5
+ XMPP output plugin
6
+ """
7
+
8
+ from __future__ import absolute_import
9
+
10
+ from sys import version_info
11
+ from threading import Event, Thread
12
+ from time import gmtime, strftime
13
+
14
+ from core import output
15
+ from core.config import CONFIG
16
+
17
+ import xmpp.dispatcher
18
+ import xmpp.simplexml
19
+ import xmpp.transports
20
+ from xmpp import Client
21
+ from xmpp.protocol import JID, Message
22
+
23
+ from twisted.python.log import msg
24
+
25
+
26
+ # ---------------------------------------------------------------------------
27
+ # Python 2.7 compatibility patches for xmpppy.
28
+ #
29
+ # xmpppy 0.7.3 has two functions with Python 3-only syntax that crash
30
+ # on Python 2.7:
31
+ #
32
+ # 1. simplexml.ustr(): calls str(r, ENCODING) which is Python 3 bytes-to-str
33
+ # syntax. On Python 2.7 the equivalent is unicode(r).
34
+ #
35
+ # 2. dispatcher.Dispatcher.Process(): calls .with_traceback() unconditionally
36
+ # on exception objects, but that method only exists on Python 3.
37
+ #
38
+ # Both are patched below before any xmpppy code runs.
39
+ # ---------------------------------------------------------------------------
40
+ if version_info[0] < 3:
41
+ # Patch 1: simplexml.ustr
42
+ def _ustr(what):
43
+ if isinstance(what, str):
44
+ return what
45
+ try:
46
+ r = what.__str__()
47
+ except AttributeError:
48
+ r = str(what)
49
+ if not isinstance(r, str):
50
+ return r
51
+ return r
52
+
53
+ xmpp.simplexml.ustr = _ustr
54
+ xmpp.transports.ustr = _ustr
55
+ # xmpp.protocol also does 'from .simplexml import ustr' — patch it too
56
+ import xmpp.protocol as _xmpp_protocol
57
+ if hasattr(_xmpp_protocol, 'ustr'):
58
+ _xmpp_protocol.ustr = _ustr
59
+
60
+ # Patch 2: dispatcher.Dispatcher - must be named 'Dispatcher' so that
61
+ # PlugIn() registers it under the right key in owner.__dict__, and must
62
+ # define plugin/plugout explicitly so PlugIn()'s __class__.__dict__ check
63
+ # finds them (inherited methods are not in __class__.__dict__ on Py2
64
+ # old-style classes).
65
+ _OriginalDispatcher = xmpp.dispatcher.Dispatcher
66
+
67
+ class Dispatcher(_OriginalDispatcher):
68
+ def plugin(self, owner):
69
+ _OriginalDispatcher.plugin(self, owner)
70
+
71
+ def plugout(self):
72
+ _OriginalDispatcher.plugout(self)
73
+
74
+ def Process(self, timeout=0):
75
+ for handler in self._cycleHandlers:
76
+ handler(self)
77
+ if len(self._pendingExceptions) > 0:
78
+ _pendingException = self._pendingExceptions.pop()
79
+ ex = _pendingException[0](_pendingException[1])
80
+ if hasattr(ex, 'with_traceback'):
81
+ ex = ex.with_traceback(_pendingException[2])
82
+ raise ex
83
+ if self._owner.Connection.pending_data(timeout):
84
+ try:
85
+ data = self._owner.Connection.receive()
86
+ except IOError:
87
+ return
88
+ self.Stream.Parse(data)
89
+ if len(self._pendingExceptions) > 0:
90
+ _pendingException = self._pendingExceptions.pop()
91
+ ex = _pendingException[0](_pendingException[1])
92
+ if hasattr(ex, 'with_traceback'):
93
+ ex = ex.with_traceback(_pendingException[2])
94
+ raise ex
95
+ if data:
96
+ return len(data)
97
+ return '0'
98
+
99
+ xmpp.dispatcher.Dispatcher = Dispatcher
100
+
101
+
102
+ class Output(output.Output):
103
+ """
104
+ XMPP output plugin.
105
+ Sends honeypot events as plain-text messages to a configured JID.
106
+
107
+ xmpppy's Process(1) blocks for up to one second per call, so it runs
108
+ in a daemon thread rather than in Twisted's reactor thread. write()
109
+ calls send() directly from the reactor thread; send() only writes to
110
+ the socket while Process() only reads, so there is no write-write race.
111
+ """
112
+
113
+ def start(self):
114
+ jabberid = CONFIG.get('output_xmpp', 'user')
115
+ password = CONFIG.get('output_xmpp', 'password', raw=True)
116
+ self.receiver = CONFIG.get('output_xmpp', 'muc')
117
+ self._stop_event = Event()
118
+ self._thread = None
119
+
120
+ jid = JID(jabberid)
121
+ self.connection = Client(server=jid.getDomain(), debug=[])
122
+
123
+ result = self.connection.connect()
124
+ if not result:
125
+ msg('output_xmpp: unable to connect to {}'.format(jid.getDomain()))
126
+ self.connection = None
127
+ return
128
+ msg('output_xmpp: connected ({})'.format(result))
129
+
130
+ if not self.connection.auth(user=jid.getNode(), password=password,
131
+ resource=jid.getResource()):
132
+ msg('output_xmpp: authentication failed for {}'.format(jabberid))
133
+ self.connection.disconnect()
134
+ self.connection = None
135
+ return
136
+ msg('output_xmpp: authenticated as {}'.format(jabberid))
137
+
138
+ self._thread = Thread(target=self._process_loop)
139
+ self._thread.daemon = True
140
+ self._thread.start()
141
+
142
+ def _process_loop(self):
143
+ while not self._stop_event.is_set():
144
+ try:
145
+ conn = self.connection
146
+ if conn is None:
147
+ break
148
+ if not conn.Process(1):
149
+ msg('output_xmpp: connection lost')
150
+ self.connection = None
151
+ break
152
+ except Exception as e:
153
+ msg('output_xmpp: error in Process loop: {}'.format(e))
154
+ self.connection = None
155
+ break
156
+
157
+ def stop(self):
158
+ self._stop_event.set()
159
+ if self._thread is not None:
160
+ self._thread.join(timeout=2)
161
+ if self.connection is not None:
162
+ self.connection.disconnect()
163
+ self.connection = None
164
+
165
+ def write(self, event):
166
+ if self.connection is None:
167
+ return
168
+
169
+ operation = event['operation'].lower()
170
+
171
+ message = '[{} UTC] [PGSQLPot on {} ({})]: {}'.format(
172
+ strftime('%Y-%m-%d %H:%M:%S', gmtime(event['unixtime'])),
173
+ event['sensor'], event['session'], operation.capitalize()
174
+ )
175
+ if operation == 'unknown':
176
+ message += ' operation: "{}"'.format(event['username'])
177
+ elif operation == 'command':
178
+ message += ' "{}'.format(event['command'])
179
+ if event['args']:
180
+ message += ' {}'.format(event['args'])
181
+ message += '"'
182
+ message += ' from {}:{}'.format(event['src_ip'], event['dst_port'])
183
+ if operation == 'login':
184
+ message += ', username: "{}", password: "{}"'.format(
185
+ event['username'], event['password']
186
+ )
187
+ message += '.'
188
+
189
+ try:
190
+ self.connection.send(Message(to=self.receiver, body=message))
191
+ except Exception as e:
192
+ msg('output_xmpp: send failed: {}'.format(e))
193
+ self.connection = None
pgsqlpot/__init__.py ADDED
@@ -0,0 +1,25 @@
1
+ # pgsqlpot: the installable Python package for the pgsqlpot honeypot.
2
+ #
3
+ # After `pip install pgsqlpot`, use the `pgsqlpot` command:
4
+ #
5
+ # pgsqlpot init -- scaffold a working directory
6
+ # pgsqlpot run -- start the honeypot in the foreground
7
+ # pgsqlpot start -- start the honeypot in the background
8
+ # pgsqlpot stop -- stop the background honeypot
9
+ # pgsqlpot restart -- restart the honeypot (stop and start the honeypot in
10
+ # the background)
11
+ # pgsqlpot status -- show running status
12
+ #
13
+ # NOTE: pgsqlpot/honeypot.py is generated at build time by the build_py
14
+ # hook in setup.py - it is a copy of the top-level honeypot.py bundled so
15
+ # that the `pgsqlpot run/start` entry point can locate and run it.
16
+ # It is listed in .gitignore and should not be committed.
17
+ #
18
+ # Contents:
19
+ # cli.py the `pgsqlpot` console entry point (init/run/start/stop/status)
20
+ # honeypot.py the main honeypot script (copied from repo root at build time)
21
+ # data/ bundled read-only assets copied to the working directory
22
+ # by `pgsqlpot init`:
23
+ # docs/ documentation and SQL schema files
24
+ # etc/ default configuration templates
25
+ # test/ test.py for verifying a running honeypot