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.
- {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/CHANGELOG.md +36 -2
- {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/LICENSE +2 -2
- pop3pot-2.0.2/MANIFEST.in +8 -0
- pop3pot-2.0.2/PKG-INFO +157 -0
- {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/README.md +3 -2
- pop3pot-2.0.2/core/httpclient.py +71 -0
- {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/core/protocol.py +3 -0
- {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/core/tools.py +5 -6
- {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/honeypot.py +8 -2
- {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/output_plugins/couch.py +7 -1
- {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/output_plugins/datadog.py +13 -14
- pop3pot-2.0.2/output_plugins/discord.py +133 -0
- pop3pot-2.0.2/output_plugins/elastic.py +139 -0
- {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/output_plugins/hpfeed.py +4 -1
- {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/output_plugins/influx2.py +2 -0
- {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/output_plugins/jsonlog.py +4 -3
- {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/output_plugins/kafka.py +8 -5
- {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/output_plugins/localsyslog.py +2 -0
- {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/output_plugins/mongodb.py +9 -8
- {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/output_plugins/mysql.py +108 -43
- {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/output_plugins/nlcvapi.py +48 -47
- {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/output_plugins/postgres.py +57 -45
- pop3pot-2.0.2/output_plugins/redisdb.py +47 -0
- pop3pot-2.0.2/output_plugins/rethinkdblog.py +46 -0
- {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/output_plugins/slack.py +43 -9
- {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/output_plugins/socketlog.py +6 -3
- {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/output_plugins/sqlite.py +11 -14
- {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/output_plugins/telegram.py +58 -38
- {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/output_plugins/textlog.py +2 -0
- pop3pot-2.0.2/output_plugins/xmpp.py +193 -0
- {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/pop3pot/cli.py +60 -17
- {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/pop3pot/data/Dockerfile +1 -0
- {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/pop3pot/data/docs/INSTALL.md +29 -29
- {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/pop3pot/data/docs/INSTALLWIN.md +27 -34
- pop3pot-2.0.2/pop3pot/data/docs/PLUGINS.md +21 -0
- {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/pop3pot/data/docs/mysql/READMEWIN.md +2 -2
- {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/pop3pot/data/docs/mysql/mysql.sql +6 -3
- {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/pop3pot/data/docs/postgres/READMEWIN.md +1 -1
- {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/pop3pot/data/docs/postgres/postgres.sql +15 -0
- {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/pop3pot/data/docs/sqlite3/README.md +1 -0
- {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/pop3pot/data/docs/sqlite3/READMEWIN.md +2 -1
- {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/pop3pot/data/docs/sqlite3/sqlite3.sql +5 -0
- {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/pop3pot/data/etc/honeypot.cfg.base +46 -31
- {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/pop3pot/honeypot.py +8 -2
- pop3pot-2.0.2/pop3pot.egg-info/PKG-INFO +157 -0
- {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/pop3pot.egg-info/SOURCES.txt +3 -17
- pop3pot-2.0.2/pop3pot.egg-info/requires.txt +160 -0
- {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/setup.cfg +0 -3
- {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/setup.py +102 -61
- pop3pot-2.0.0.dev0/MANIFEST.in +0 -8
- pop3pot-2.0.0.dev0/PKG-INFO +0 -125
- pop3pot-2.0.0.dev0/output_plugins/discord.py +0 -116
- pop3pot-2.0.0.dev0/output_plugins/elastic.py +0 -109
- pop3pot-2.0.0.dev0/output_plugins/redisdb.py +0 -41
- pop3pot-2.0.0.dev0/output_plugins/rethinkdblog.py +0 -38
- pop3pot-2.0.0.dev0/output_plugins/xmpp.py +0 -49
- pop3pot-2.0.0.dev0/pop3pot/data/test/develop/.gitignore +0 -2
- pop3pot-2.0.0.dev0/pop3pot/data/test/develop/POP3Pot.rtf +0 -198
- pop3pot-2.0.0.dev0/pop3pot/data/test/develop/announce1.txt +0 -16
- pop3pot-2.0.0.dev0/pop3pot/data/test/develop/announce2.txt +0 -13
- pop3pot-2.0.0.dev0/pop3pot/data/test/develop/couchdb/couchdb.bat +0 -2
- pop3pot-2.0.0.dev0/pop3pot/data/test/develop/hpfeeds/docker-compose.yml +0 -13
- pop3pot-2.0.0.dev0/pop3pot/data/test/develop/hpfeeds/docker.bat +0 -2
- pop3pot-2.0.0.dev0/pop3pot/data/test/develop/kafka/ctest.py +0 -37
- pop3pot-2.0.0.dev0/pop3pot/data/test/develop/kafka/ptest.py +0 -54
- pop3pot-2.0.0.dev0/pop3pot/data/test/develop/output_plugins/dshield.py +0 -158
- pop3pot-2.0.0.dev0/pop3pot/data/test/develop/output_plugins/graylog.py +0 -52
- pop3pot-2.0.0.dev0/pop3pot/data/test/develop/output_plugins/oraclecloud.py +0 -110
- pop3pot-2.0.0.dev0/pop3pot/data/test/develop/output_plugins/splunk.py +0 -107
- pop3pot-2.0.0.dev0/pop3pot/data/test/develop/redis/redis.bat +0 -2
- pop3pot-2.0.0.dev0/pop3pot/data/test/develop/rethinkdb/rethinkdb.bat +0 -4
- pop3pot-2.0.0.dev0/pop3pot.egg-info/PKG-INFO +0 -125
- pop3pot-2.0.0.dev0/pop3pot.egg-info/requires.txt +0 -86
- {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/core/__init__.py +0 -0
- {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/core/config.py +0 -0
- {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/core/logfile.py +0 -0
- {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/core/output.py +0 -0
- {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/core/paths.py +0 -0
- {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/output_plugins/README.md +0 -0
- {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/output_plugins/__init__.py +0 -0
- {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/pop3pot/__init__.py +0 -0
- {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/pop3pot/data/docs/TODO.md +0 -0
- {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/pop3pot/data/docs/datadog/README.md +0 -0
- {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/pop3pot/data/docs/discord/README.md +0 -0
- {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/pop3pot/data/docs/geoipupdtask.ps1 +0 -0
- {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/pop3pot/data/docs/mysql/README.md +0 -0
- {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/pop3pot/data/docs/postgres/README.md +0 -0
- {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/pop3pot/data/docs/slack/README.md +0 -0
- {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/pop3pot/data/docs/telegram/README.md +0 -0
- {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/pop3pot/data/etc/honeypot.cfg +0 -0
- {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/pop3pot/data/test/.gitignore +0 -0
- {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/pop3pot/data/test/README.md +0 -0
- {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/pop3pot/data/test/baseline +0 -0
- {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/pop3pot/data/test/test.py +0 -0
- {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/pop3pot.egg-info/dependency_links.txt +0 -0
- {pop3pot-2.0.0.dev0 → pop3pot-2.0.2}/pop3pot.egg-info/entry_points.txt +0 -0
- {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
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
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
|
|
18
|
-
|
|
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
|
+
)
|
|
@@ -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
|
|
18
|
+
from urllib2 import urlopen # type: ignore
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
if version_info[0] >= 3:
|
|
22
22
|
def decode(x):
|
|
23
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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')
|
|
31
|
-
self.api_key = CONFIG.get('output_datadog', 'api_key', fallback='')
|
|
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('
|
|
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 =
|
|
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)
|
|
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
|