pop3pot 2.0.0.dev0__tar.gz → 2.0.2__tar.gz

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 (97) hide show
  1. {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/CHANGELOG.md +36 -2
  2. {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/LICENSE +2 -2
  3. pop3pot-2.0.2/MANIFEST.in +8 -0
  4. pop3pot-2.0.2/PKG-INFO +157 -0
  5. {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/README.md +3 -2
  6. pop3pot-2.0.2/core/httpclient.py +71 -0
  7. {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/core/protocol.py +3 -0
  8. {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/core/tools.py +5 -6
  9. {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/honeypot.py +8 -2
  10. {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/output_plugins/couch.py +7 -1
  11. {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/output_plugins/datadog.py +13 -14
  12. pop3pot-2.0.2/output_plugins/discord.py +133 -0
  13. pop3pot-2.0.2/output_plugins/elastic.py +139 -0
  14. {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/output_plugins/hpfeed.py +4 -1
  15. {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/output_plugins/influx2.py +2 -0
  16. {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/output_plugins/jsonlog.py +4 -3
  17. {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/output_plugins/kafka.py +8 -5
  18. {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/output_plugins/localsyslog.py +2 -0
  19. {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/output_plugins/mongodb.py +9 -8
  20. {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/output_plugins/mysql.py +108 -43
  21. {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/output_plugins/nlcvapi.py +48 -47
  22. {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/output_plugins/postgres.py +57 -45
  23. pop3pot-2.0.2/output_plugins/redisdb.py +47 -0
  24. pop3pot-2.0.2/output_plugins/rethinkdblog.py +46 -0
  25. {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/output_plugins/slack.py +43 -9
  26. {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/output_plugins/socketlog.py +6 -3
  27. {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/output_plugins/sqlite.py +11 -14
  28. {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/output_plugins/telegram.py +58 -38
  29. {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/output_plugins/textlog.py +2 -0
  30. pop3pot-2.0.2/output_plugins/xmpp.py +193 -0
  31. {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/pop3pot/cli.py +60 -17
  32. {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/pop3pot/data/Dockerfile +1 -0
  33. {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/pop3pot/data/docs/INSTALL.md +29 -29
  34. {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/pop3pot/data/docs/INSTALLWIN.md +27 -34
  35. pop3pot-2.0.2/pop3pot/data/docs/PLUGINS.md +21 -0
  36. {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/pop3pot/data/docs/mysql/READMEWIN.md +2 -2
  37. {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/pop3pot/data/docs/mysql/mysql.sql +6 -3
  38. {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/pop3pot/data/docs/postgres/READMEWIN.md +1 -1
  39. {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/pop3pot/data/docs/postgres/postgres.sql +15 -0
  40. {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/pop3pot/data/docs/sqlite3/README.md +1 -0
  41. {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/pop3pot/data/docs/sqlite3/READMEWIN.md +2 -1
  42. {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/pop3pot/data/docs/sqlite3/sqlite3.sql +5 -0
  43. {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/pop3pot/data/etc/honeypot.cfg.base +46 -31
  44. {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/pop3pot/honeypot.py +8 -2
  45. pop3pot-2.0.2/pop3pot.egg-info/PKG-INFO +157 -0
  46. {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/pop3pot.egg-info/SOURCES.txt +3 -17
  47. pop3pot-2.0.2/pop3pot.egg-info/requires.txt +160 -0
  48. {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/setup.cfg +0 -3
  49. {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/setup.py +102 -61
  50. pop3pot-2.0.0.dev0/MANIFEST.in +0 -8
  51. pop3pot-2.0.0.dev0/PKG-INFO +0 -125
  52. pop3pot-2.0.0.dev0/output_plugins/discord.py +0 -116
  53. pop3pot-2.0.0.dev0/output_plugins/elastic.py +0 -109
  54. pop3pot-2.0.0.dev0/output_plugins/redisdb.py +0 -41
  55. pop3pot-2.0.0.dev0/output_plugins/rethinkdblog.py +0 -38
  56. pop3pot-2.0.0.dev0/output_plugins/xmpp.py +0 -49
  57. pop3pot-2.0.0.dev0/pop3pot/data/test/develop/.gitignore +0 -2
  58. pop3pot-2.0.0.dev0/pop3pot/data/test/develop/POP3Pot.rtf +0 -198
  59. pop3pot-2.0.0.dev0/pop3pot/data/test/develop/announce1.txt +0 -16
  60. pop3pot-2.0.0.dev0/pop3pot/data/test/develop/announce2.txt +0 -13
  61. pop3pot-2.0.0.dev0/pop3pot/data/test/develop/couchdb/couchdb.bat +0 -2
  62. pop3pot-2.0.0.dev0/pop3pot/data/test/develop/hpfeeds/docker-compose.yml +0 -13
  63. pop3pot-2.0.0.dev0/pop3pot/data/test/develop/hpfeeds/docker.bat +0 -2
  64. pop3pot-2.0.0.dev0/pop3pot/data/test/develop/kafka/ctest.py +0 -37
  65. pop3pot-2.0.0.dev0/pop3pot/data/test/develop/kafka/ptest.py +0 -54
  66. pop3pot-2.0.0.dev0/pop3pot/data/test/develop/output_plugins/dshield.py +0 -158
  67. pop3pot-2.0.0.dev0/pop3pot/data/test/develop/output_plugins/graylog.py +0 -52
  68. pop3pot-2.0.0.dev0/pop3pot/data/test/develop/output_plugins/oraclecloud.py +0 -110
  69. pop3pot-2.0.0.dev0/pop3pot/data/test/develop/output_plugins/splunk.py +0 -107
  70. pop3pot-2.0.0.dev0/pop3pot/data/test/develop/redis/redis.bat +0 -2
  71. pop3pot-2.0.0.dev0/pop3pot/data/test/develop/rethinkdb/rethinkdb.bat +0 -4
  72. pop3pot-2.0.0.dev0/pop3pot.egg-info/PKG-INFO +0 -125
  73. pop3pot-2.0.0.dev0/pop3pot.egg-info/requires.txt +0 -86
  74. {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/core/__init__.py +0 -0
  75. {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/core/config.py +0 -0
  76. {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/core/logfile.py +0 -0
  77. {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/core/output.py +0 -0
  78. {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/core/paths.py +0 -0
  79. {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/output_plugins/README.md +0 -0
  80. {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/output_plugins/__init__.py +0 -0
  81. {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/pop3pot/__init__.py +0 -0
  82. {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/pop3pot/data/docs/TODO.md +0 -0
  83. {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/pop3pot/data/docs/datadog/README.md +0 -0
  84. {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/pop3pot/data/docs/discord/README.md +0 -0
  85. {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/pop3pot/data/docs/geoipupdtask.ps1 +0 -0
  86. {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/pop3pot/data/docs/mysql/README.md +0 -0
  87. {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/pop3pot/data/docs/postgres/README.md +0 -0
  88. {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/pop3pot/data/docs/slack/README.md +0 -0
  89. {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/pop3pot/data/docs/telegram/README.md +0 -0
  90. {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/pop3pot/data/etc/honeypot.cfg +0 -0
  91. {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/pop3pot/data/test/.gitignore +0 -0
  92. {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/pop3pot/data/test/README.md +0 -0
  93. {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/pop3pot/data/test/baseline +0 -0
  94. {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/pop3pot/data/test/test.py +0 -0
  95. {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/pop3pot.egg-info/dependency_links.txt +0 -0
  96. {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/pop3pot.egg-info/entry_points.txt +0 -0
  97. {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/pop3pot.egg-info/top_level.txt +0 -0
@@ -5,11 +5,41 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [2.0.2]
9
+
10
+ ### Added in version 2.0.2
11
+
12
+ * Nothing
13
+
14
+ ### Changed in version 2.0.2
15
+
16
+ * Increased the version number
17
+ * The `restart` command wasn't working correctly on Windows due to a race
18
+ condition. Fixed.
19
+ * Fixed a problem in the MySQL plugin that made it unresponsive under high
20
+ traffic
21
+
22
+ ## [2.0.1]
23
+
24
+ ### Added in version 2.0.1
25
+
26
+ * Nothing
27
+
28
+ ### Changed in version 2.0.1
29
+
30
+ * Increased the version number
31
+ * The `datadog`, `discord`, `nlcvapi`, and `telegram` plugins now use a secure
32
+ connection (HTTPS) by default
33
+ * The `elastic` plugin now warns if the `ssl` is set while certificate
34
+ verification (`verify_certs`) is off
35
+ * The `couch` plugin now uses authentication mechanism that does not pass the
36
+ username and password in the URL
37
+
8
38
  ## [2.0.0]
9
39
 
10
40
  ### Added in version 2.0.0
11
41
 
12
- * Made the project installable from PyPi
42
+ * Made the project installable from PyPI
13
43
  * `.gitlab-ci.yml` file to scan for secrets
14
44
 
15
45
  ### Changed in version 2.0.0
@@ -20,7 +50,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
20
50
  * Got rid of `getlist()`
21
51
  * Updated the documentation with information how to start the honeypot at boot
22
52
  time
53
+ * Fixed bugs in the Discord, PostgreSQL, Slack, and Telegram output plugins
23
54
  * Fixed a bug in the reporting (`ip` was referenced before being determined)
55
+ * Better error checking if another process is already listening to the same port
56
+ * Better Python 2.x/3.x compatibility
57
+ * Completely rewritten `Dockerfile`, uses hardened images
24
58
 
25
59
  ## [1.0.0]
26
60
 
@@ -42,7 +76,7 @@ time
42
76
  * Discord
43
77
  * Elasticsearch
44
78
  * HPFeeds
45
- * InfluxDB 2.0
79
+ * InfluxDB 2.0 (Python 3.6+ only)
46
80
  * JSON
47
81
  * Kafka
48
82
  * MongoDB
@@ -631,7 +631,7 @@ to attach them to the start of each source file to most effectively
631
631
  state the exclusion of warranty; and each file should have at least
632
632
  the "copyright" line and a pointer to where the full notice is found.
633
633
 
634
- ElasticPot
634
+ POP3Pot
635
635
  Copyright (C) 2020 Vesselin Bontchev
636
636
 
637
637
  This program is free software: you can redistribute it and/or modify
@@ -652,7 +652,7 @@ Also add information on how to contact you by electronic and paper mail.
652
652
  If the program does terminal interaction, make it output a short
653
653
  notice like this when it starts in an interactive mode:
654
654
 
655
- ElasticPot Copyright (C) 2020 Vesselin Bontchev
655
+ POP3Pot Copyright (C) 2020 Vesselin Bontchev
656
656
  This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
657
657
  This is free software, and you are welcome to redistribute it
658
658
  under certain conditions; type `show c' for details.
@@ -0,0 +1,8 @@
1
+ include CHANGELOG.md
2
+ include LICENSE
3
+ include README.md
4
+ include honeypot.py
5
+ graft core
6
+ graft output_plugins
7
+ graft pop3pot
8
+ prune pop3pot/data/test/develop
pop3pot-2.0.2/PKG-INFO ADDED
@@ -0,0 +1,157 @@
1
+ Metadata-Version: 2.4
2
+ Name: pop3pot
3
+ Version: 2.0.2
4
+ Summary: A POP3 Honeypot
5
+ Home-page: https://gitlab.com/bontchev/pop3pot
6
+ Author: Vesselin Bontchev
7
+ Author-email: vbontchev@yahoo.com
8
+ License: GPL-3.0-only
9
+ Classifier: Development Status :: 5 - Production/Stable
10
+ Classifier: Environment :: Console
11
+ Classifier: Intended Audience :: Information Technology
12
+ Classifier: Intended Audience :: Science/Research
13
+ Classifier: Intended Audience :: System Administrators
14
+ Classifier: Operating System :: Microsoft :: Windows
15
+ Classifier: Operating System :: POSIX :: Linux
16
+ Classifier: Programming Language :: Python :: 2
17
+ Classifier: Programming Language :: Python :: 2.7
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3.6
20
+ Classifier: Programming Language :: Python :: 3.7
21
+ Classifier: Programming Language :: Python :: 3.8
22
+ Classifier: Programming Language :: Python :: 3.9
23
+ Classifier: Programming Language :: Python :: 3.10
24
+ Classifier: Programming Language :: Python :: 3.11
25
+ Classifier: Programming Language :: Python :: 3.12
26
+ Classifier: Programming Language :: Python :: 3.13
27
+ Classifier: Programming Language :: Python :: 3.14
28
+ Classifier: Topic :: Security
29
+ Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*
30
+ Description-Content-Type: text/markdown
31
+ License-File: LICENSE
32
+ Requires-Dist: configparser>=3.5.0
33
+ Requires-Dist: geoip2>=2.7.0
34
+ Requires-Dist: ipaddress; python_version < "3"
35
+ Requires-Dist: maxminddb>=1.3.0
36
+ Requires-Dist: pytz
37
+ Requires-Dist: requests<=2.27.1; python_version < "3"
38
+ Requires-Dist: requests; python_version >= "3"
39
+ Requires-Dist: service_identity<=18.1.0; python_version < "3"
40
+ Requires-Dist: service_identity; python_version >= "3"
41
+ Requires-Dist: twisted<21,>=20.3.0; python_version < "3"
42
+ Requires-Dist: twisted>=21; python_version >= "3"
43
+ Provides-Extra: couchdb
44
+ Requires-Dist: couchdb; extra == "couchdb"
45
+ Provides-Extra: datadog
46
+ Requires-Dist: certifi; extra == "datadog"
47
+ Requires-Dist: cryptography<=2.8; python_version < "3" and extra == "datadog"
48
+ Requires-Dist: pyOpenSSL<=18.0.0; python_version < "3" and extra == "datadog"
49
+ Requires-Dist: cryptography; python_version >= "3" and extra == "datadog"
50
+ Requires-Dist: pyOpenSSL; python_version >= "3" and extra == "datadog"
51
+ Provides-Extra: discord
52
+ Requires-Dist: certifi; extra == "discord"
53
+ Provides-Extra: elastic
54
+ Requires-Dist: elasticsearch<=7.13; python_version < "3" and extra == "elastic"
55
+ Requires-Dist: numpy<=1.16.6; python_version < "3" and extra == "elastic"
56
+ Requires-Dist: elasticsearch8<9.0.0,>=8.12.0; python_version >= "3" and extra == "elastic"
57
+ Requires-Dist: numpy; python_version >= "3" and extra == "elastic"
58
+ Provides-Extra: hpfeed
59
+ Requires-Dist: Automat<20; python_version < "3" and extra == "hpfeed"
60
+ Requires-Dist: hpfeeds>=3.0.0; extra == "hpfeed"
61
+ Provides-Extra: influx2
62
+ Requires-Dist: influxdb-client; python_version >= "3" and extra == "influx2"
63
+ Provides-Extra: jsonlog
64
+ Provides-Extra: kafka
65
+ Requires-Dist: confluent-kafka<1.0; python_version < "3" and extra == "kafka"
66
+ Requires-Dist: confluent-kafka; python_version >= "3" and extra == "kafka"
67
+ Provides-Extra: localsyslog
68
+ Provides-Extra: mongodb
69
+ Requires-Dist: pymongo<=3.13.0; python_version < "3" and extra == "mongodb"
70
+ Requires-Dist: dnspython; python_version < "3" and extra == "mongodb"
71
+ Requires-Dist: pymongo; python_version >= "3" and extra == "mongodb"
72
+ Provides-Extra: mysql
73
+ Requires-Dist: PyMySQL; python_version < "3" and extra == "mysql"
74
+ Requires-Dist: mysqlclient>=1.3.12; python_version >= "3" and extra == "mysql"
75
+ Provides-Extra: nlcvapi
76
+ Requires-Dist: certifi; extra == "nlcvapi"
77
+ Requires-Dist: pyOpenSSL<=18.0.0; python_version < "3" and extra == "nlcvapi"
78
+ Requires-Dist: pyOpenSSL; python_version >= "3" and extra == "nlcvapi"
79
+ Provides-Extra: postgres
80
+ Requires-Dist: psycopg2-binary; extra == "postgres"
81
+ Provides-Extra: redisdb
82
+ Requires-Dist: redis<=3.5.3; python_version < "3" and extra == "redisdb"
83
+ Requires-Dist: redis; python_version >= "3" and extra == "redisdb"
84
+ Provides-Extra: rethinkdblog
85
+ Requires-Dist: rethinkdb>=2.4; extra == "rethinkdblog"
86
+ Requires-Dist: looseversion; extra == "rethinkdblog"
87
+ Provides-Extra: slack
88
+ Requires-Dist: slackclient<3; python_version < "3" and extra == "slack"
89
+ Requires-Dist: slack-sdk; python_version >= "3" and extra == "slack"
90
+ Provides-Extra: socketlog
91
+ Provides-Extra: sqlite
92
+ Provides-Extra: telegram
93
+ Requires-Dist: certifi; extra == "telegram"
94
+ Provides-Extra: textlog
95
+ Provides-Extra: xmpp
96
+ Requires-Dist: xmpppy>=0.7.3; extra == "xmpp"
97
+ Provides-Extra: all
98
+ Requires-Dist: Automat<20; python_version < "3" and extra == "all"
99
+ Requires-Dist: PyMySQL; python_version < "3" and extra == "all"
100
+ Requires-Dist: certifi; extra == "all"
101
+ Requires-Dist: confluent-kafka; python_version >= "3" and extra == "all"
102
+ Requires-Dist: confluent-kafka<1.0; python_version < "3" and extra == "all"
103
+ Requires-Dist: couchdb; extra == "all"
104
+ Requires-Dist: cryptography; python_version >= "3" and extra == "all"
105
+ Requires-Dist: cryptography<=2.8; python_version < "3" and extra == "all"
106
+ Requires-Dist: dnspython; python_version < "3" and extra == "all"
107
+ Requires-Dist: elasticsearch8<9.0.0,>=8.12.0; python_version >= "3" and extra == "all"
108
+ Requires-Dist: elasticsearch<=7.13; python_version < "3" and extra == "all"
109
+ Requires-Dist: hpfeeds>=3.0.0; extra == "all"
110
+ Requires-Dist: influxdb-client; python_version >= "3" and extra == "all"
111
+ Requires-Dist: looseversion; extra == "all"
112
+ Requires-Dist: mysqlclient>=1.3.12; python_version >= "3" and extra == "all"
113
+ Requires-Dist: numpy; python_version >= "3" and extra == "all"
114
+ Requires-Dist: numpy<=1.16.6; python_version < "3" and extra == "all"
115
+ Requires-Dist: psycopg2-binary; extra == "all"
116
+ Requires-Dist: pyOpenSSL; python_version >= "3" and extra == "all"
117
+ Requires-Dist: pyOpenSSL<=18.0.0; python_version < "3" and extra == "all"
118
+ Requires-Dist: pymongo; python_version >= "3" and extra == "all"
119
+ Requires-Dist: pymongo<=3.13.0; python_version < "3" and extra == "all"
120
+ Requires-Dist: redis; python_version >= "3" and extra == "all"
121
+ Requires-Dist: redis<=3.5.3; python_version < "3" and extra == "all"
122
+ Requires-Dist: rethinkdb>=2.4; extra == "all"
123
+ Requires-Dist: slack-sdk; python_version >= "3" and extra == "all"
124
+ Requires-Dist: slackclient<3; python_version < "3" and extra == "all"
125
+ Requires-Dist: xmpppy>=0.7.3; extra == "all"
126
+ Dynamic: author
127
+ Dynamic: author-email
128
+ Dynamic: classifier
129
+ Dynamic: description
130
+ Dynamic: description-content-type
131
+ Dynamic: home-page
132
+ Dynamic: license
133
+ Dynamic: license-file
134
+ Dynamic: provides-extra
135
+ Dynamic: requires-dist
136
+ Dynamic: requires-python
137
+ Dynamic: summary
138
+
139
+ # POP3Pot: a POP3 Honeypot
140
+
141
+ This is a honeypot simulating a POP3 e-mail server.
142
+
143
+ The honeypot does not emulate a full POP3 server after a successful login -
144
+ it only records the IP of the attacker, as well as the username and password
145
+ used, and the other commands used, if any, and returns a "bad login
146
+ credentials" error.
147
+
148
+ ## Prerequisites
149
+
150
+ - a working database server (only if you use an output plugin that outputs to
151
+ a database - e.g., MySQL)
152
+
153
+ ## Usage
154
+
155
+ Check the [Linux installation guide](https://gitlab.com/bontchev/pop3pot/-/blob/master/pop3pot/data/docs/INSTALL.md) or the
156
+ [Windows installation guide](https://gitlab.com/bontchev/pop3pot/-/blob/master/pop3pot/data/docs/INSTALLWIN.md) for complete
157
+ instructions on how to install, configure, and run the honeypot.
@@ -14,5 +14,6 @@ a database - e.g., MySQL)
14
14
 
15
15
  ## Usage
16
16
 
17
- Check the [installation document](pop3pot/data/docs/INSTALL.md) for more
18
- information how to properly install, configure, and run the honeypot.
17
+ Check the [Linux installation guide](pop3pot/data/docs/INSTALL.md) or the
18
+ [Windows installation guide](pop3pot/data/docs/INSTALLWIN.md) for complete
19
+ instructions on how to install, configure, and run the honeypot.
@@ -0,0 +1,71 @@
1
+ from __future__ import absolute_import
2
+
3
+ from io import open
4
+
5
+ from twisted.internet.ssl import Certificate, trustRootFromCertificates
6
+ from twisted.python.log import msg
7
+ from twisted.web.client import Agent, BrowserLikePolicyForHTTPS
8
+
9
+
10
+ class _LegacyWebClientContextFactory(object):
11
+ @staticmethod
12
+ def build():
13
+ from twisted.internet.ssl import ClientContextFactory
14
+
15
+ class WebClientContextFactory(ClientContextFactory):
16
+ def getContext(self, hostname, port):
17
+ return ClientContextFactory.getContext(self)
18
+
19
+ return WebClientContextFactory()
20
+
21
+
22
+ def _load_trust_root_from_pem_bundle(pem_path):
23
+ with open(pem_path, 'r', encoding='utf-8') as fh:
24
+ content = fh.read()
25
+ certs = []
26
+ end_marker = '-----END CERTIFICATE-----'
27
+ for chunk in content.split(end_marker):
28
+ chunk = chunk.strip()
29
+ if not chunk:
30
+ continue
31
+ pem = chunk + '\n' + end_marker + '\n'
32
+ certs.append(Certificate.loadPEM(pem))
33
+ if not certs:
34
+ return None
35
+ return trustRootFromCertificates(certs)
36
+
37
+
38
+ def _trust_root(ca_certs):
39
+ if ca_certs:
40
+ try:
41
+ return _load_trust_root_from_pem_bundle(ca_certs)
42
+ except Exception as e:
43
+ msg('Failed to load CA bundle {}: {}'.format(ca_certs, e))
44
+ return None
45
+
46
+ try:
47
+ import certifi
48
+ return _load_trust_root_from_pem_bundle(certifi.where())
49
+ except Exception:
50
+ return None
51
+
52
+
53
+ def create_http_agent(reactor, pool, plugin_name, verify_tls=True, ca_certs=None):
54
+ """
55
+ Build a Twisted Agent with sane HTTPS defaults.
56
+ verify_tls=True uses BrowserLikePolicyForHTTPS for cert + hostname checks.
57
+ verify_tls=False falls back to a legacy context factory for compatibility.
58
+ """
59
+ if verify_tls:
60
+ return Agent(
61
+ reactor,
62
+ contextFactory=BrowserLikePolicyForHTTPS(trustRoot=_trust_root(ca_certs)),
63
+ pool=pool
64
+ )
65
+
66
+ msg('{}: TLS certificate verification is disabled.'.format(plugin_name))
67
+ return Agent(
68
+ reactor,
69
+ contextFactory=_LegacyWebClientContextFactory.build(),
70
+ pool=pool
71
+ )
@@ -1,4 +1,7 @@
1
1
 
2
+ from __future__ import absolute_import
3
+
4
+
2
5
  from ipaddress import ip_address, ip_network
3
6
  from sys import version_info
4
7
  from time import time
@@ -15,12 +15,14 @@ from twisted.python.log import msg
15
15
  try:
16
16
  from urllib.request import urlopen
17
17
  except ImportError:
18
- from urllib import urlopen
18
+ from urllib2 import urlopen # type: ignore
19
19
 
20
20
 
21
21
  if version_info[0] >= 3:
22
22
  def decode(x):
23
- return x.decode('utf-8', errors='ignore')
23
+ if isinstance(x, bytes):
24
+ return x.decode('utf-8', errors='ignore')
25
+ return x
24
26
  def encode(x):
25
27
  return x.encode()
26
28
  def ord(x):
@@ -85,10 +87,7 @@ def stop_plugins(cfg):
85
87
 
86
88
  def get_public_ip(ip_reporter):
87
89
  try:
88
- if version_info[0] < 3:
89
- return urlopen(ip_reporter).read().decode('latin1', errors='replace').encode('utf-8')
90
- else:
91
- return decode(urlopen(ip_reporter).read())
90
+ return decode(urlopen(ip_reporter, timeout=10).read())
92
91
  except:
93
92
  return None
94
93
 
@@ -18,11 +18,12 @@ from core.tools import (
18
18
  stop_plugins,
19
19
  )
20
20
 
21
+ from twisted.internet import error
21
22
  from twisted.internet.reactor import listenTCP, run
22
23
  from twisted.python.log import msg
23
24
 
24
25
 
25
- __VERSION__ = '2.0.0-dev0'
26
+ __VERSION__ = '2.0.2'
26
27
  __description__ = 'A POP3 Honeypot'
27
28
  __license__ = 'GPLv3'
28
29
  __uri__ = 'https://gitlab.com/bontchev/pop3pot'
@@ -101,7 +102,12 @@ def main():
101
102
 
102
103
  cfg_options['output_plugins'] = import_plugins(cfg_options)
103
104
 
104
- listenTCP(cfg_options['port'], MyPOP3Factory(cfg_options))
105
+ try:
106
+ listenTCP(cfg_options['port'], MyPOP3Factory(cfg_options))
107
+ except error.CannotListenError as e:
108
+ msg('Cannot listen on port {}: {}'.format(e.port, e.socketError.strerror))
109
+ stop_plugins(cfg_options)
110
+ return
105
111
  run()
106
112
  msg('Shutdown requested, exiting...')
107
113
  stop_plugins(cfg_options)
@@ -1,4 +1,6 @@
1
1
 
2
+ from __future__ import absolute_import
3
+
2
4
  from core import output
3
5
  from core.config import CONFIG
4
6
  from core.tools import geolocate
@@ -11,6 +13,7 @@ from twisted.python.log import msg
11
13
  class Output(output.Output):
12
14
 
13
15
  def start(self):
16
+ scheme = CONFIG.get('output_couch', 'scheme', fallback='http')
14
17
  host = CONFIG.get('output_couch', 'host', fallback='localhost')
15
18
  port = CONFIG.getint('output_couch', 'port', fallback=5984)
16
19
  username = CONFIG.get('output_couch', 'username', fallback='pop3pot', raw=True)
@@ -18,7 +21,10 @@ class Output(output.Output):
18
21
  db_name = CONFIG.get('output_couch', 'database', fallback='pop3pot')
19
22
 
20
23
  try:
21
- couchserver = Server('http://{}:{}@{}:{}'.format(username, password, host, port))
24
+ base_url = '{}://{}:{}'.format(scheme, host, port)
25
+ couchserver = Server(base_url)
26
+ if username:
27
+ couchserver.resource.credentials = (username, password)
22
28
 
23
29
  if db_name in couchserver:
24
30
  self.couch_db = couchserver[db_name]
@@ -2,23 +2,21 @@
2
2
  Simple Datadog HTTP logger.
3
3
  """
4
4
 
5
+ from __future__ import absolute_import
6
+
5
7
  from io import BytesIO
6
8
  from json import dumps
7
9
  from platform import node
8
10
 
9
11
  from core import output
10
12
  from core.config import CONFIG
13
+ from core.httpclient import create_http_agent
14
+ from core.tools import to_bytes
11
15
 
12
16
  from twisted.internet import reactor
13
17
  from twisted.python.log import msg
14
18
  from twisted.web import client, http_headers
15
19
  from twisted.web.client import FileBodyProducer
16
- from twisted.internet.ssl import ClientContextFactory
17
-
18
-
19
- class WebClientContextFactory(ClientContextFactory):
20
- def getContext(self, hostname, port):
21
- return ClientContextFactory.getContext(self)
22
20
 
23
21
 
24
22
  class QuietHTTP11ClientFactory(client._HTTP11ClientFactory):
@@ -27,19 +25,20 @@ class QuietHTTP11ClientFactory(client._HTTP11ClientFactory):
27
25
 
28
26
  class Output(output.Output):
29
27
  def start(self):
30
- self.url = CONFIG.get('output_datadog', 'url').encode('utf-8')
31
- self.api_key = CONFIG.get('output_datadog', 'api_key', fallback='').encode('utf-8')
28
+ self.url = CONFIG.get('output_datadog', 'url')
29
+ self.api_key = CONFIG.get('output_datadog', 'api_key', fallback='')
32
30
  if len(self.api_key) == 0:
33
- msg('Datadog output module: API key is not defined.')
31
+ msg('output_datadog: API key is not defined.')
34
32
  self.ddsource = CONFIG.get('output_datadog', 'ddsource', fallback='pop3pot')
35
33
  self.ddtags = CONFIG.get('output_datadog', 'ddtags', fallback='env:dev')
36
34
  self.service = CONFIG.get('output_datadog', 'service', fallback='honeypot')
37
35
  self.hostname = CONFIG.get('output_datadog', 'hostname', fallback=node())
36
+ verify_tls = CONFIG.getboolean('output_datadog', 'verify_tls', fallback=True)
37
+ ca_certs = CONFIG.get('output_datadog', 'ca_certs', fallback=None)
38
38
 
39
- contextFactory = WebClientContextFactory()
40
39
  myQuietPool = client.HTTPConnectionPool(reactor)
41
40
  myQuietPool._factory = QuietHTTP11ClientFactory
42
- self.agent = client.Agent(reactor, contextFactory=contextFactory, pool=myQuietPool)
41
+ self.agent = create_http_agent(reactor, myQuietPool, 'output_datadog', verify_tls, ca_certs)
43
42
 
44
43
  def stop(self):
45
44
  pass
@@ -63,9 +62,9 @@ class Output(output.Output):
63
62
  base_headers = {
64
63
  b'Accept': [b'application/json'],
65
64
  b'Content-Type': [b'application/json'],
66
- b'DD-API-KEY': [self.api_key],
65
+ b'DD-API-KEY': [to_bytes(self.api_key)],
67
66
  }
68
67
  headers = http_headers.Headers(base_headers)
69
- body = FileBodyProducer(BytesIO(dumps(entry).encode('utf-8')))
70
- self.agent.request(b'POST', self.url, headers, body)
68
+ body = FileBodyProducer(BytesIO(to_bytes(dumps(entry, sort_keys=True))))
69
+ self.agent.request(b'POST', to_bytes(self.url), headers, body)
71
70
 
@@ -0,0 +1,133 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+
4
+ """
5
+ Simple Discord webhook logger
6
+ """
7
+
8
+ from __future__ import absolute_import
9
+
10
+ from io import BytesIO
11
+ from json import dumps, loads
12
+ from time import gmtime, strftime, time
13
+
14
+ from core import output
15
+ from core.config import CONFIG
16
+ from core.httpclient import create_http_agent
17
+ from core.tools import decode, to_bytes
18
+
19
+ from twisted.internet import reactor
20
+ from twisted.internet.task import deferLater
21
+ from twisted.python.log import msg
22
+ from twisted.web.client import (
23
+ FileBodyProducer,
24
+ HTTPConnectionPool,
25
+ _HTTP11ClientFactory,
26
+ readBody
27
+ )
28
+ from twisted.web.http_headers import Headers
29
+
30
+
31
+ class QuietHTTP11ClientFactory(_HTTP11ClientFactory):
32
+ noisy = False
33
+
34
+
35
+ class Output(output.Output):
36
+
37
+ def start(self):
38
+ self.url = to_bytes(CONFIG.get('output_discord', 'url'))
39
+ self.delay = CONFIG.getfloat('output_discord', 'delay', fallback=2.0)
40
+ verify_tls = CONFIG.getboolean('output_discord', 'verify_tls', fallback=True)
41
+ ca_certs = CONFIG.get('output_discord', 'ca_certs', fallback=None)
42
+ pool = HTTPConnectionPool(reactor)
43
+ pool._factory = QuietHTTP11ClientFactory
44
+ self.agent = create_http_agent(reactor, pool, 'output_discord', verify_tls, ca_certs)
45
+ self.last_sent = 0
46
+ self.requests_list = []
47
+
48
+ def stop(self):
49
+ pass
50
+
51
+ def write(self, event):
52
+ operation = event['operation'].lower()
53
+
54
+ message = '__New event__\n'
55
+ message += '[{} UTC] [POP3Pot on {} ({})]: {}'.format(
56
+ strftime('%Y-%m-%d %H:%M:%S', gmtime(event['unixtime'])), event['sensor'],
57
+ event['session'], operation.capitalize()
58
+ )
59
+
60
+ if operation == 'unknown':
61
+ message += ' operation: "{}"'.format(event['username'])
62
+ elif operation == 'command':
63
+ message += ' "{}'.format(event['command'])
64
+ if event['args']:
65
+ message += ' {}'.format(event['args'])
66
+ message += '"'
67
+
68
+ message += ' from {}:{}'.format(event['src_ip'], event['dst_port'])
69
+
70
+ if operation == 'login':
71
+ message += ', username: "{}", password: "{}"'.format(event['username'], event['password'])
72
+ message += '.\n'
73
+
74
+ self.requests_list.append({'content': message})
75
+ self._drain()
76
+
77
+ def _drain(self):
78
+ """
79
+ Send the next queued entry if the rate-limit window has elapsed.
80
+ If entries remain, schedule another drain after self.delay seconds.
81
+ """
82
+ if not self.requests_list:
83
+ return
84
+ now = time()
85
+ elapsed = now - self.last_sent
86
+ if elapsed < self.delay:
87
+ deferLater(reactor, self.delay - elapsed, self._drain)
88
+ return
89
+ self.last_sent = now
90
+ entry = self.requests_list.pop(0)
91
+ d = self._post(entry)
92
+ if self.requests_list:
93
+ deferLater(reactor, self.delay, self._drain)
94
+ return d
95
+
96
+ def _post(self, entry):
97
+
98
+ def cbBody(body):
99
+ return processResult(body)
100
+
101
+ def cbPartial(failure):
102
+ """
103
+ Google HTTP Server does not set Content-Length. Twisted marks it as partial
104
+ """
105
+ failure.printTraceback()
106
+ return processResult(failure.value)
107
+
108
+ def cbResponse(response):
109
+ if response is None or response.code in [200, 201, 204]:
110
+ return
111
+ msg('Discord error: {} {}'.format(response.code, decode(response.phrase)))
112
+ d = readBody(response)
113
+ d.addCallback(cbBody)
114
+ d.addErrback(cbPartial)
115
+ return d
116
+
117
+ def cbError(failure):
118
+ failure.printTraceback()
119
+
120
+ def processResult(result):
121
+ if result:
122
+ try:
123
+ j = loads(result)
124
+ msg('Discord response: {}'.format(j.get('message', '')))
125
+ except Exception:
126
+ pass
127
+
128
+ headers = Headers({b'Content-Type': [b'application/json']})
129
+ body = FileBodyProducer(BytesIO(to_bytes(dumps(entry, sort_keys=True))))
130
+ d = self.agent.request(b'POST', self.url, headers, body)
131
+ d.addCallback(cbResponse)
132
+ d.addErrback(cbError)
133
+ return d