├── .gitignore ├── .pylintrc ├── .travis.yml ├── Honey.py ├── LICENSE ├── Makefile ├── Pipfile ├── README.md ├── VERSION ├── docs ├── conf.py ├── configuring.md ├── developers.md ├── index.md ├── installing.md ├── plugins.md ├── quickstart.md └── references.md ├── etc ├── honeypy.cfg ├── honeypyd ├── profiles │ ├── services.common.profile │ ├── services.databases.profile │ ├── services.default.profile │ ├── services.iot.profile │ ├── services.kali.profile │ ├── services.kubernetes.profile │ ├── services.linux.profile │ ├── services.peer_to_peer.profile │ ├── services.streaming.profile │ ├── services.tcp_malware.profile │ ├── services.udp_malware.profile │ ├── services.windows_active_directory.profile │ └── services.windows_iis.profile └── services.cfg ├── lib ├── __init__.py ├── clilib │ ├── LICENSE │ ├── README.md │ ├── __init__.py │ ├── clilib.py │ ├── test.py │ ├── unix │ │ ├── __init__.py │ │ ├── busybox.py │ │ ├── cd.py │ │ ├── echo.py │ │ ├── enable.py │ │ ├── rm.py │ │ ├── sh.py │ │ ├── tftp.py │ │ ├── uname.py │ │ ├── unix.py │ │ ├── wget.py │ │ ├── which.py │ │ └── whoami.py │ └── windows │ │ ├── __init__.py │ │ └── windows.py ├── followtail.py ├── honeypy_console.py └── honeypy_logtail.py ├── loggers ├── __init__.py ├── elasticsearch │ ├── __init__.py │ └── honeypy_elasticsearch.py ├── file │ ├── __init__.py │ └── honeypy_file.py ├── honeydb │ ├── __init__.py │ └── honeypy_honeydb.py ├── hpfeeds │ ├── __init__.py │ └── honeypy_hpfeeds.py ├── logstash │ ├── __init__.py │ └── honeypy_logstash.py ├── rabbitmq │ ├── __init__.py │ └── honeypy_rabbitmq.py ├── slack │ ├── __init__.py │ └── honeypy_slack.py ├── splunk │ ├── __init__.py │ └── honeypy_splunk.py ├── sumologic │ ├── __init__.py │ └── honeypy_sumologic.py ├── telegram │ ├── __init__.py │ └── honeypy_telegram.py ├── template │ └── honeypy_template.py └── twitter │ ├── __init__.py │ └── honeypy_twitter.py ├── mkdocs.yml ├── plugins ├── DnsUdp │ ├── DnsUdp.py │ ├── __init__.py │ └── readme.txt ├── Echo │ ├── Echo.py │ └── __init__.py ├── Echo_udp │ ├── Echo.py │ └── __init__.py ├── Elasticsearch │ ├── Readme.md │ ├── __init__.py │ └── elasticsearch.py ├── HashCountRandom │ ├── HashCountRandom.py │ └── __init__.py ├── MOTD │ ├── MOTD.py │ └── __init__.py ├── MOTD_udp │ ├── MOTD.py │ └── __init__.py ├── NtpUdp │ ├── NtpUdp.py │ ├── __init__.py │ └── ntpserver.py ├── Random │ ├── Random.py │ └── __init__.py ├── SIP │ ├── SIP.py │ └── __init__.py ├── SmtpExim │ ├── SmtpExim.py │ └── __init__.py ├── TFTP │ ├── TFTP.py │ ├── __init__.py │ ├── credit.txt │ ├── file.bin │ ├── file.txt │ └── readme.txt ├── TelnetUnix │ ├── TelnetUnix.py │ ├── __init__.py │ └── readme.txt ├── TelnetWindows │ ├── TelnetWindows.py │ └── __init__.py ├── Web │ ├── Web.py │ └── __init__.py └── __init__.py └── requirements.txt /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | 5 | # C extensions 6 | *.so 7 | 8 | # Distribution / packaging 9 | .Python 10 | .env/ 11 | env/ 12 | venv/ 13 | build/ 14 | develop-eggs/ 15 | dist/ 16 | downloads/ 17 | eggs/ 18 | .eggs/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | 27 | # PyInstaller 28 | # Usually these files are written by a python script from a template 29 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 30 | *.manifest 31 | *.spec 32 | 33 | # Installer logs 34 | pip-log.txt 35 | pip-delete-this-directory.txt 36 | 37 | # Unit test / coverage reports 38 | htmlcov/ 39 | .tox/ 40 | .coverage 41 | .coverage.* 42 | .cache 43 | nosetests.xml 44 | coverage.xml 45 | *,cover 46 | 47 | # Translations 48 | *.mo 49 | *.pot 50 | 51 | # Django stuff: 52 | *.log 53 | log/ 54 | 55 | # Sphinx documentation 56 | docs/_build/ 57 | 58 | # PyBuilder 59 | target/ 60 | 61 | # PyCharm 62 | .idea/ 63 | 64 | # pipenv 65 | Pipfile.lock 66 | 67 | # custom stuff 68 | .vscode/ 69 | .DS_Store 70 | -------------------------------------------------------------------------------- /.pylintrc: -------------------------------------------------------------------------------- 1 | [MASTER] 2 | 3 | disable=invalid-name,line-too-long,too-many-lines,broad-except,missing-docstring,attribute-defined-outside-init,too-many-branches,too-many-public-methods,redefined-outer-name,too-many-instance-attributes,too-many-statements,redefined-builtin,too-few-public-methods,too-many-locals,too-many-nested-blocks,too-many-boolean-expressions,len-as-condition,signature-differs 4 | ignored-classes=twisted.internet.reactor -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3 | - "2.7" 4 | 5 | install: make install 6 | 7 | script: make lint -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | install: 2 | pip install -r requirements.txt 3 | 4 | lint: 5 | pylint Honey.py 6 | pylint lib/honeypy_console.py 7 | pylint lib/honeypy_logtail.py 8 | 9 | format: 10 | autopep8 --in-place --aggressive --aggressive --ignore=E501,W690 Honey.py 11 | autopep8 --in-place --aggressive --aggressive --ignore=E501,W690 lib/honeypy_console.py 12 | autopep8 --in-place --aggressive --aggressive --ignore=E501,W690 lib/honeypy_logtail.py 13 | 14 | clean: 15 | rm -f *.pyc -------------------------------------------------------------------------------- /Pipfile: -------------------------------------------------------------------------------- 1 | [[source]] 2 | 3 | name = "pypi" 4 | url = "https://pypi.python.org/simple" 5 | verify_ssl = true 6 | 7 | 8 | [dev-packages] 9 | 10 | 11 | 12 | [packages] 13 | 14 | dnslib = "==0.9.7" 15 | requests = "==2.20.0" 16 | Twisted = "==14.0.2" 17 | python-twitter = "==3.1" 18 | certifi = "*" 19 | "urllib3" = "*" 20 | pika = "==0.10.0" 21 | pylint = "*" 22 | "autopep8" = "*" 23 | 24 | 25 | [requires] 26 | 27 | python_version = "2.7" 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # HoneyPy 🍯 2 | 3 | [![Build Status](https://travis-ci.org/foospidy/HoneyPy.svg?branch=master)](https://travis-ci.org/foospidy/HoneyPy) 4 | [![Documentation Status](https://readthedocs.org/projects/honeypy/badge/?version=latest)](http://honeypy.readthedocs.io/en/latest/?badge=latest) 5 | 6 | A low interaction honeypot with the capability to be more of a medium interaction honeypot. 7 | 8 | **Project status:** 9 | 10 | * No longer in active development. 11 | * Repository will remain for anyone wanting to use or contribute to HoneyPy. 12 | * I recommend using the honeydb-agent instead: https://honeydb-agent-docs.readthedocs.io/ 13 | 14 | **Description** 15 | 16 | HoneyPy is written in Python2 and is intended to be easy to: 17 | * install and deploy 18 | * extend with plugins and loggers 19 | * run with custom configurations 20 | 21 | Feel free to follow the [QuickStart Guide](https://honeypy.readthedocs.io/en/latest/quickstart) to dive in directly. 22 | The main documentation can be found at the [HoneyPy Docs](https://honeypy.readthedocs.io/en/latest/) site. 23 | 24 | Live HoneyPy data gets posted to: 25 | * Twitter: https://twitter.com/HoneyPyLog 26 | * Web service endpoint and displayed via the HoneyDB web site: https://riskdiscovery.com/honeydb 27 | 28 | **Leave an issue or feature request!** Use the GitHub issue tracker to tell us whats on your mind. 29 | 30 | **Pull requests are welcome!** If you would like to create new plugins or improve existing ones, please do. 31 | 32 | __NOTE:__ HoneyPy has primarily been tested and run on Debian and Ubuntu using Python 2.7.9. 33 | 34 | 35 | ## Overview 36 | 37 | HoneyPy comes with a lot of plugins included. The level of interaction is determined by the functionality of the used 38 | plugin. Plugins can be created to emulate UDP or TCP based services to provide more interaction. All activity is logged 39 | to a file by default, but posting honeypot activity to Twitter or a web service endpoint can be configured as well. 40 | 41 | **Examples**: 42 | * Plugins: 43 | * ElasticSearch 44 | * SIP 45 | * etc. 46 | 47 | * Loggers: 48 | * HoneyDB 49 | * Twitter 50 | * etc. 51 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | 0.7.0 2 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | from recommonmark.parser import CommonMarkParser 4 | 5 | source_parsers = { 6 | '.md': CommonMarkParser, 7 | } 8 | 9 | source_suffix = ['.md'] 10 | 11 | # -- General configuration ----------------------------------------------------- 12 | 13 | # The master toctree document. 14 | master_doc = 'index' 15 | 16 | # General information about the project. 17 | project = u'HoneyPy' 18 | copyright = u'foospidy' 19 | 20 | # The language for content autogenerated by Sphinx. Refer to documentation 21 | # for a list of supported languages. 22 | language = 'en' 23 | -------------------------------------------------------------------------------- /docs/configuring.md: -------------------------------------------------------------------------------- 1 | # Configuring HoneyPy 2 | 3 | There are two configuration files for HoneyPy, both are located in the HoneyPy `etc` directory (e.g. `/opt/HoneyPy/etc`). The main configuration file is `honeypy.cfg`, and the services configuration file is `services.cfg`. 4 | 5 | ## HoneyPy 6 | 7 | In the `honeypy.cfg` file, the main configuration section is the `[honeypy]` section and only has two options to configure. 8 | 9 | Name | Description 10 | ---------- | ------- 11 | nodename | Name for this HoneyPy node to be displayed in tweets, Slack messages, and other integrations. 12 | limit_internal_logs | Enabling this will ensure that the internal log files are limited to one day, which can be useful for limited deployments e.g. automated containers (e.g. Yes or No). 13 | internal_log_dir | Directory for internal HoneyPy logs (not external loggers). Use leading slash for absolute path, or omit for relative path. Default: `log/` 14 | 15 | ### Loggers 16 | 17 | The remaining sections in the `honeypy.cfg` configuration file are for configuring loggers. Loggers are modules that make consuming or processing event data more convenient by sending the event data to another service. These other services and their configuration options are listed below. 18 | 19 | __NOTE:__ More than one logger can be configured at a time. For example, if the Elasticsearch, HoneyDB, and RabbitMQ loggers are configured then all events will be sent to all three services. 20 | 21 | __NOTE:__ By default, HoneyPy logs all events to the log file `/opt/HoneyPy/log/honeypy.log`. All events are logged to this file regardless of a logger being configured or not. 22 | 23 | #### Elasticsearch 24 | 25 | Name | Description 26 | ---------- | ------- 27 | enabled | Enable this logger (e.g. Yes or No). 28 | es_url | URL to Elasticsearch endpoint (e.g. http://localhost:9200/honeypot/honeypy). 29 | 30 | #### HoneyDB 31 | 32 | Name | Description 33 | ---------- | ------- 34 | enabled | Enable this logger (e.g. Yes or No). 35 | api_id | Your HoneyDB API id. 36 | api_key | Your HoneyDB API key. 37 | 38 | #### Logstash 39 | 40 | Name | Description 41 | ---------- | ------- 42 | enabled | Enable this logger (e.g. Yes or No). 43 | host | Logstash host. 44 | port | Logstash port. 45 | 46 | #### RabbitMQ 47 | 48 | Name | Description 49 | ---------- | ------- 50 | enabled | Enable this logger (e.g. Yes or No). 51 | url_param | RabbitMQ config url (e.g. amqp://username:password@rabbitmq_host/%2f). 52 | exchange | Name of the Rabbitmq Exchange 53 | routing_key | Rabbitmq routing Key (if not configured in RabbitmQ, leave blank) 54 | 55 | #### Slack 56 | 57 | Name | Description 58 | ---------- | ------- 59 | enabled | Enable this logger (e.g. Yes or No). 60 | webhook_url | Slack channel webhook URL. 61 | 62 | #### Splunk 63 | 64 | Name | Description 65 | ---------- | ------- 66 | enabled | Enable this logger (e.g. Yes or No). 67 | url | Splunk API endpoint (e.g. https://localhost:8089/services/receivers/simple). 68 | username | Username for authentication. 69 | password | Password for authentication. 70 | 71 | #### Telegram 72 | 73 | Name | Description 74 | ---------- | ------- 75 | enabled | Enable this logger (e.g. Yes or No). 76 | bot_id | Telegram bot HTTP API token. 77 | 78 | #### Twitter 79 | 80 | Name | Description 81 | ---------- | ------- 82 | enabled | Enable this logger (e.g. Yes or No). 83 | consumerkey | Your Twitter consumer key. 84 | consumersecret | Your Twitter consumer secret. 85 | oauthtoken | Your Twitter OAuth token. 86 | oauthsecret | Your Twitter OAuth secret. 87 | 88 | #### hpfeeds 89 | 90 | Name | Description 91 | ---------- | ------- 92 | enabled | Enable this logger (e.g. Yes or No). 93 | persistent | Is a persistent connection required (e.g. Yes). 94 | server | hpfeeds server 95 | port | hpfeeds port 96 | ident | hpfeeds ident 97 | secret | hpfeeds secret 98 | channel | hpfeeds channel 99 | serverid | hpfeeds server ID 100 | 101 | ## Services 102 | 103 | The `service.cfg` file tells HoneyPy which services to launch. There are several additional service configuration files located in the `etc/profiles` directory. The service config file is used to define service names, ports, and plugins to run on your honeypot. Each service defined in the file has an `enabled` option. This option can be set to Yes or No to determine which services run on start. You can also use one of the provided config files, or create your own. To use one of the other files simply copy the file over service.cfg. For example: 104 | 105 | ```bash 106 | cp profiles/services.windows_iis.profile service.cfg 107 | ``` 108 | 109 | If you want to revert back to the default service config file simply run 110 | 111 | ```bash 112 | cp profiles/service.default.profile service.cfg 113 | ``` 114 | 115 | ## Low Ports 116 | 117 | While you should not run HoneyPy with the root user, this means HoneyPy will not be able to listen on ports 1 through 1024. As a workaround you can use implement port redirection with IPTables. If you're not familiar with using IPTables you can try using [ipt-kit](https://github.com/foospidy/ipt-kit). You will need to run ipt-kit as root to modify IPTables. Once the redirection rules are in place you won't need to run HoneyPy as root for low ports. 118 | 119 | As an example, if you want HoneyPy to listen for telnet connections on port 23, choose a port above 1024. Edit the HoneyPy service config file to have telnet run on the high port (e.g. 2300). Then use ipt-kit to redirect 23 to 2300, example commands: 120 | 121 | if root user: 122 | 123 | ```bash 124 | ./ipt_set_tcp 23 2300 125 | ``` 126 | 127 | or if using sudo: 128 | 129 | ```bash 130 | $sudo ./ipt_set_tcp 23 2300 131 | ``` 132 | 133 | If you have low ports configured, when you run HoneyPy it will display a list of ipt-kit commands to run. For example: 134 | 135 | ``` 136 | ./ipt_set_tcp 7 10007 137 | ./ipt_set_udp 7 10007 138 | ./ipt_set_tcp 8 10008 139 | ./ipt_set_udp 8 10008 140 | ./ipt_set_tcp 21 10021 141 | ./ipt_set_tcp 23 10009 142 | ./ipt_set_tcp 24 10010 143 | ``` 144 | 145 | __NOTE:__ The commands above can be generated as a script using HoneyPy. First edit your `service.cfg`, then run `./Honey.py -ipt`. The script will be saved to `/tmp/honeypy-ipt.sh`. Copy the script to the ipt-kit directory, and make sure the script file has execute permissions, e.g. `chmod +x honeypy-ipt.sh`. Run the script as root or with sudo. 146 | 147 | Alternatively, you can use authbind to enabled the usage of low ports by HoneyPy's run user. More on authbind here: [https://debian-administration.org/article/386/Running_network_services_as_a_non-root_user](https://debian-administration.org/article/386/Running_network_services_as_a_non-root_user) 148 | -------------------------------------------------------------------------------- /docs/developers.md: -------------------------------------------------------------------------------- 1 | # Developers 2 | 3 | The core of HoneyPy is a framework that handles configuring and launching services as well as logging. Developers can easily create new service plugin or logging plugin to extend HoneyPy's capability. 4 | 5 | Terms: 6 | 7 | - Plugin - a service plugin that implements a network protocol (e.g. Telnet, SSH, HTTP, etc). All plugins reside in the `plugins` directory. 8 | - Logger - a logging plugin that sends event data to an external service or SIEM (e.g. Twitter, HoneyDB, Splunk, etc.). All loggers reside in the `loggers` directory. 9 | 10 | ## Plugins 11 | 12 | Hopefully creating new plugins is easy. HoneyPy takes care of sending/receiving data and logging, all you have to do is write the custom protocol/logic. The service emulators in the plugins directory can be used as templates to create new emulators. 13 | 14 | Example: [https://github.com/foospidy/HoneyPy/blob/master/plugins/HashCountRandom/HashCountRandom.py](https://github.com/foospidy/HoneyPy/blob/master/plugins/HashCountRandom/HashCountRandom.py) 15 | 16 | There are three sections to edit: custom import, custom protocol, and custom functions. To keep the template well organized, you should only make modifciaitons in the designated sections, note the comments that denote each section. 17 | 18 | Example of custom import. Import the Python modules you need: 19 | 20 | ```python 21 | ### START CUSTOM IMPORT 22 | import time 23 | import os 24 | import md5 25 | ### END CUSTOM IMPORT 26 | ``` 27 | 28 | Next, use the custom protocol section to write your logic. use the `self.tx()` function to transfer (send) data to the socket, and use the `self.rx()` function to receive data from the socket. 29 | 30 | ```python 31 | ### START CUSTOM PROTOCOL ########################################################### 32 | self.tx('ACCEPT_CONN: ' + str(self.remote_host) + ':' + str(self.remote_port) + '\n') 33 | count = 0 34 | 35 | while True: 36 | count = count + 1 37 | self.tx(self.md5sum(count) + ':' + str(os.urandom(99)) + '\n') 38 | self.rx() 39 | time.sleep(1) 40 | 41 | ### END CUSTOM PROTOCOL ############################################################# 42 | ``` 43 | 44 | Add custom functions as needed at the bottom. All functions must have the first parameter be `self`. When you call custom functions from the custom protocol section you must prefix them with `self.`, for example: `self.md5sum('test')` 45 | 46 | ```python 47 | ### START CUSTOM FUNCTIONS ########################################################## 48 | def md5sum(self, data): 49 | m = md5.new() 50 | m.update(str(data)) 51 | return m.hexdigest() 52 | 53 | ### END CUSTOM FUNCTIONS ############################################################ 54 | ``` 55 | 56 | ## Loggers 57 | 58 | todo 59 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | # Welcome to HoneyPy Docs! 2 | 3 | [![Build Status](https://travis-ci.org/foospidy/HoneyPy.svg?branch=master)](https://travis-ci.org/foospidy/HoneyPy) 4 | [![Documentation Status](https://readthedocs.org/projects/honeypy/badge/?version=latest)](http://honeypy.readthedocs.io/en/latest/?badge=latest) 5 | 6 | 7 | **A low interaction honeypot with the capability to be more of a medium interaction honeypot.** 8 | 9 | HoneyPy is written in Python2 and is intended to be easy to: 10 | * install and deploy 11 | * extend with plugins and loggers 12 | * run with custom configurations 13 | 14 | HoneyPy comes with a lot of plugins included. The level of interaction is determined by the functionality of the used 15 | plugin. Plugins can be created to emulate UDP or TCP based services to provide more interaction. All activity is logged 16 | to a file by default, but posting honeypot activity to Twitter or a web service endpoint can be configured as well. 17 | 18 | 19 | Feel free to follow the [QuickStart Guide](https://honeypy.readthedocs.io/en/latest/quickstart) to dive in directly. 20 | 21 | __NOTE:__ HoneyPy has primarily been tested and run on Debian and Ubuntu using Python 2.7.9. 22 | -------------------------------------------------------------------------------- /docs/installing.md: -------------------------------------------------------------------------------- 1 | # Installing HoneyPy 2 | 3 | ## System Requirements 4 | 5 | - Linux 6 | - Python 2.7 7 | 8 | ## Downloading 9 | 10 | __NOTE:__ You can run HoneyPy from any directory on your file system. For the purposes of this documentaiton `/opt/HoneyPy` will be referenced. 11 | 12 | Download the latest release from [https://github.com/foospidy/HoneyPy/releases/latest](https://github.com/foospidy/HoneyPy/releases/latest). 13 | 14 | Example script: 15 | 16 | ```bash 17 | #!/usr/bin/env bash 18 | 19 | cd /opt 20 | latest=`curl https://raw.githubusercontent.com/foospidy/HoneyPy/master/VERSION` 21 | curl -L -o HoneyPy.tar.gz https://github.com/foospidy/HoneyPy/archive/${latest}.tar.gz 22 | tar -xzf HoneyPy.tar.gz 23 | mv HoneyPy-${latest} HoneyPy 24 | ``` 25 | 26 | Or you can clone the repository from Github with from [https://github.com/foospidy/HoneyPy.git](https://github.com/foospidy/HoneyPy.git). 27 | 28 | Example script: 29 | 30 | ```bash 31 | #!/usr/bin/env bash 32 | 33 | cd /opt 34 | git clone https://github.com/foospidy/HoneyPy.git 35 | ``` 36 | 37 | __WARNING:__ Cloning the repository will pull any development changes that may be a work in progress. As a result you may experience bugs or breaks. Current build status [![Build Status](https://travis-ci.org/foospidy/HoneyPy.svg?branch=master)](https://travis-ci.org/foospidy/HoneyPy) 38 | 39 | ## Dependencies 40 | 41 | Before you can run HoneyPy you must ensure you have all required Python module dependencies installed. For a list of the dependencies see the [requirements.txt](https://raw.githubusercontent.com/foospidy/HoneyPy/master/requirements.txt) file. It is recommended to install dependencies using [pip](https://pypi.python.org/pypi/pip). 42 | 43 | __NOTE:__ Installing dependencies on your base system will require root access. Recommended alternatives to install dependencies and run HoneyPy are [Virtualenv](https://virtualenv.pypa.io/) or [pipenv](https://github.com/pypa/pipenv) as described below. Both create isolated Python environments, which may be beneficial if you are running other Python scripts and their dependencies on the same system. However, if you are using a dedicated system, or even a container, to run HoneyPy, then Virtualenv/pipenv may not be necessary. 44 | 45 | 46 | To install dependencies globally with pip and the requirements.txt file run: 47 | 48 | ```bash 49 | cd /opt/HoneyPy 50 | sudo pip install -r requirements.txt 51 | ``` 52 | 53 | To install dependencies using Virtualenv run: 54 | ```bash 55 | cd /opt/HoneyPy 56 | python -m venv venv 57 | source venv/bin/activate 58 | pip install -r requirements.txt 59 | ``` 60 | 61 | To install dependencies using pipenv run: 62 | ```bash 63 | cd /opt/HoneyPy 64 | pipenv install 65 | pipenv shell 66 | ``` 67 | 68 | __NOTE:__ Please keep in mind that you have to activate the Virtualenv/pipenv before using HoneyPy. 69 | 70 | ## Running 71 | 72 | There are several options for how you can launch and run HoneyPy, [console](#console) mode, [daemon](#daemon) mode, and [on boot](#on-boot) (also daemon mode). 73 | 74 | __WARNING:__ It is highly recommended to __NOT__ run HoneyPy as root. It is recommended to create a dedicated user account for running HoneyPy. 75 | 76 | ### Console 77 | 78 | You can run HoneyPy in console mode. From any terminal run: 79 | 80 | ```bash 81 | cd /opt/HoneyPy 82 | ./Honey.py 83 | ``` 84 | 85 | __NOTE:__ You can leverage the [screen](https://www.gnu.org/software/screen/manual/screen.html#Overview) utility to run HoneyPy in console mode. Using screen will keep HoneyPy running even if you lose your terminal connection. 86 | 87 | Example creating a screen session for HoneyPy: 88 | 89 | ```bash 90 | screen -S MyHoneyPyConsole 91 | ``` 92 | 93 | Example recovering the HoneyPy screen session: 94 | 95 | ```bash 96 | screen -r MyHoneyPyConsole 97 | ``` 98 | 99 | ### Daemon 100 | 101 | You can run HoneyPy as a daemon process. From any terminal run: 102 | 103 | ```bash 104 | /opt/Honey.py -d & 105 | ``` 106 | 107 | ### On Boot 108 | 109 | Configuring your system to launch HoneyPy on system boot will depend on what version of Linux you are using. Most likely you will need a startup script. HoneyPy comes with an example startup script, `honeypyd`, which has been tested on Debian (Jessie). You can find this script in the `/opt/HoneyPy/etc/` directory. View the top section of the stript for instructions. To view this script on Github, [click here](https://raw.githubusercontent.com/foospidy/HoneyPy/master/etc/honeypyd). 110 | -------------------------------------------------------------------------------- /docs/plugins.md: -------------------------------------------------------------------------------- 1 | # HoneyPy Plugins 2 | 3 | ## DNS 4 | 5 | Responds to DNS queries with a random ip address. 6 | 7 | - Medium interaction 8 | - udp: `plugins/DnsUdp` 9 | 10 | ## Echo 11 | 12 | Echos back data sent by connected clients. 13 | 14 | - Low interaction 15 | - tcp: `plugins/Echo` 16 | - udp: `plugins/Echo_udp` 17 | 18 | ## Elasticsearch 19 | 20 | Simple Elasticsearch emulation. Responds to requests for `/`, request for node information `/_nodes`, and search requests `/_search`. 21 | 22 | - Low interaction 23 | - tcp: `plugins/Elasticsearch` 24 | 25 | ## HashCountRandom 26 | 27 | A bogus service. For each instance of data sent by a connected client it increments a counter and returns a md5 hash of the count and some random data. 28 | 29 | - Low interaction 30 | - tcp: `plugins/HashCountRandom` 31 | 32 | ## MOTD 33 | 34 | For each connection it returns a message and closes the connection. 35 | 36 | - Low interaction 37 | - tcp: `plugins/MOTD` 38 | - udp: `plugins/MOTD_udp` 39 | 40 | ## NTP 41 | 42 | Accepts NTP requests, returns a packet with the current system time. 43 | 44 | - Low interaction 45 | - udp: `plugins/NtpUdp` 46 | 47 | ## Random 48 | 49 | For each instance of data sent by a connected client it returns some random data. 50 | 51 | - Low interaction 52 | - tcp: `plugins/Random` 53 | 54 | ## SIP 55 | 56 | Simple SIP (Session Initiation Protocol) emulation. 57 | 58 | - Low interaction 59 | - udp: `plugins/SIP` 60 | 61 | ## SMTP 62 | 63 | Simple SMTP server emulation. Provides interaction with a subset of commands. 64 | 65 | - Low interaction 66 | - tcp: `plugins/SmtpExim` 67 | 68 | ## TFTP 69 | 70 | TFTP (Trivial File Transfer Protocol) emulation. 71 | 72 | - Medium interaction 73 | - udp: `plugins/TFTP` 74 | 75 | ## Telnet 76 | 77 | Emulates a Telnet service. 78 | 79 | - Medium interaction 80 | - tcp: `plugins/TelnetUnix` 81 | 82 | ## Web 83 | 84 | Simple web server emulation. Responds to `/robots.txt`, `/wp-login.php`, and various PhpMysqlAdmin pages. All other requests receive a simple 200 OK response. 85 | 86 | - Low interaction 87 | - tcp: `plugins/Web` 88 | -------------------------------------------------------------------------------- /docs/quickstart.md: -------------------------------------------------------------------------------- 1 | # Quickstart 2 | 3 | __WARNING:__ Only do this if you know what you are doing! All the dangerous traps - like running 4 | a honeypot as root or installing packages globally - are explained in the upcoming sections. 5 | 6 | First you need a local copy of the repository: 7 | 8 | ```shell 9 | git clone https://github.com/foospidy/HoneyPy.git 10 | git checkout tags/ -b latest 11 | ``` 12 | 13 | Install and run: 14 | 15 | ```shell 16 | pipenv install && pipenv run ./HoneyPy 17 | ``` 18 | 19 | Check out the config files and stick to `.cfg`-syntax when changing them: 20 | 21 | ```shell 22 | cd etc/ 23 | vim *.cfg 24 | ``` 25 | -------------------------------------------------------------------------------- /docs/references.md: -------------------------------------------------------------------------------- 1 | # References 2 | 3 | - Blog series: [Getting Started With HoneyPy](https://medium.com/@foospidy/honeypy-getting-started-series-a49291e41a8e) 4 | - HoneyPy [tweets](https://twitter.com/HoneyPyLog)! 5 | - [Honeypot, añadiendo una capa de seguridad en una empresa de telecomunicaciones](http://hdl.handle.net/10609/59528) 6 | 7 | # Mentions 8 | 9 | - Thanks to the ISC StormCast for mentioning HoneyPy, [https://isc.sans.edu/podcastdetail.html?id=4755](https://isc.sans.edu/podcastdetail.html?id=4755). 10 | - Thanks to Tools Watch for including HoneyPy in Black Hat Arsenal 2016, [https://www.blackhat.com/us-16/arsenal.html#honeypy-and-honeydb](https://www.blackhat.com/us-16/arsenal.html#honeypy-and-honeydb). 11 | - Thanks to Def Con for including HoneyPy in Def Con 24 Demo Labs, [https://defcon.org/html/defcon-24/dc-24-demolabs.html#Maddux](https://defcon.org/html/defcon-24/dc-24-demolabs.html#Maddux). 12 | -------------------------------------------------------------------------------- /etc/honeypy.cfg: -------------------------------------------------------------------------------- 1 | # HoneyPy/etc/honeypy.cfg 2 | # https://github.com/foospidy/HoneyPy 3 | 4 | [honeypy] 5 | # select any name for this HoneyPy node, it can be anything you want (default is: honeypy). 6 | # It will be displayed in tweets, Slack messages, and other integrations. 7 | nodename = honeypy 8 | 9 | #add a comma seperated list of ip addresses to supress logging of your local scanners 10 | #whitelist = 192.168.0.5, 192.168.0.21 11 | 12 | #include the following service profiles (comma seperated), all services will be combined. 13 | #enabling this will disable the use of service.cfg, which will not be processed 14 | #service_profiles = services.databases.profile, services.linux.profile 15 | 16 | # Limit internal log files to a single day. Useful for deployments with limited disk space. 17 | limit_internal_logs = No 18 | 19 | # Directory for internal HoneyPy logs (not external loggers). 20 | # Use leading slash for absolute path, or omit for relative path 21 | internal_log_dir = log/ 22 | 23 | # Tweet events on Twitter. Having a dedicated Twitter account for this purpose is recommended. 24 | # You will need to Twitter API credentials for this to work. See https://dev.twitter.com/oauth/application-only 25 | [twitter] 26 | enabled = No 27 | consumerkey = 28 | consumersecret = 29 | oauthtoken = 30 | oauthsecret = 31 | 32 | ######################################################################################################## 33 | # Animus is dead! (http://morris.guru/the-life-and-death-of-animus/) This feature should be use no more. 34 | # enable tweats to include querying Animus Threat Bot (https://github.com/threatbot) 35 | # ask_animus = No 36 | ######################################################################################################## 37 | # 38 | # Animus rises from the ashes! https://animus.io/ 39 | # 40 | ######################################################################################################## 41 | # 42 | # Animus falls again. https://github.com/hslatman/awesome-threat-intelligence/pull/101 43 | # 44 | ######################################################################################################## 45 | 46 | # Post your events to HoneyDB. Your HoneyPy honepots can contribute threat information to HoneyDB. 47 | # You will need to create API credentails for this to work. See https://riskdiscovery.com/honeydb/#threats 48 | [honeydb] 49 | enabled = No 50 | api_id = 51 | api_key = 52 | 53 | # Post your events to a Slack channel. Having a dedicated Slack channel for this is recommended. 54 | # For setting up your Slack webhook see https://api.slack.com/incoming-webhooks 55 | [slack] 56 | enabled = No 57 | webhook_url = 58 | 59 | [logstash] 60 | enabled = No 61 | host = 62 | port = 63 | 64 | [elasticsearch] 65 | enabled = No 66 | # Elasticsearch url should include ":port/index/type 67 | # example: http://localhost:9200/honeypot/honeypy 68 | es_url = 69 | 70 | [telegram] 71 | # You need to add your bot to channel or group, and get the bot token see https://core.telegram.org/bots 72 | enabled = No 73 | # Telegram bot HTTP API Token 74 | bot_id = 75 | 76 | [sumologic] 77 | enabled = No 78 | # create a http collector source and use the url provided 79 | # https://help.sumologic.com/Send-Data/Sources/02Sources-for-Hosted-Collectors/HTTP-Source/Upload-Data-to-an-HTTP-Source 80 | url = 81 | custom_source_host = 82 | custom_source_name = 83 | custom_source_category = 84 | 85 | [splunk] 86 | enabled = No 87 | # In Splunk; Under "Settings" > "Data inputs" create a new HTTP Event Collector 88 | # When finished, add the token, correct source type and index here. 89 | # Your URL changes depending on if you use a self-serviced or managed Splunk. 90 | # See here for details; https://docs.splunk.com/Documentation/Splunk/7.3.1/Data/UsetheHTTPEventCollector#Send_data_to_HTTP_Event_Collector 91 | url = https:///services/collector 92 | token = 93 | index = main 94 | source = HoneyPy 95 | sourcetype = _json 96 | 97 | [rabbitmq] 98 | enabled = No 99 | # Here you need create rabbitmq config url to be used with pika python lib 100 | # For ex. 1) amqp://username:password@rabbitmq_host/%2f 101 | # 2) amqp://username:password@127.0.0.1/%2f 102 | url_param = 103 | # Name of the Rabbitmq Exchange 104 | # Ex. mycoolexchange 105 | exchange = 106 | # Rabbitmq routing Key if not configured in rabbitmq leave it 107 | # Ex. honeypy 108 | routing_key = 109 | 110 | [file] 111 | enabled = No 112 | filename = log/json.log 113 | 114 | [hpfeeds] 115 | enabled = No 116 | persistent = Yes 117 | server = 127.0.0.1 118 | port = 20000 119 | ident = ident 120 | secret = secret 121 | channel = channel 122 | serverid = id 123 | -------------------------------------------------------------------------------- /etc/honeypyd: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # honeypyd 3 | # 4 | # This script can be used to start HoneyPy in daemon mode when your system boots. 5 | # Note: this has been tested on Debian (Jessie). 6 | # 7 | # Instructions (need to be executed with root): 8 | # - Copy this file to /etc/init.d/honeypyd 9 | # - Set the HONEYPY_USER variable below to a user account to run HoneyPy as (do not use root!). 10 | # - Set the HONEYPY_HOME variable below to the absolute path to your HoneyPy directory. 11 | # - Run update-rc.d honeypyd defaults 12 | # HoneyPy will now start in daemon mode on boot. 13 | # 14 | # Manually start/stop 15 | # - /etc/init.d/honeypyd start 16 | # - /etc/init.d/honeypyd stop 17 | # 18 | # To remove honeypyd from starting on boot: 19 | # - update-rc.d -f honeypyd remove 20 | # 21 | 22 | HONEYPY_USER='' 23 | HONEYPY_HOME='' 24 | 25 | # Carry out specific functions when asked to by the system 26 | case "$1" in 27 | start) 28 | echo "Starting HoneyPy..." 29 | su -c ${HONEYPY_HOME}'/Honey.py -d &' ${HONEYPY_USER} 30 | ;; 31 | stop) 32 | echo "Stopping HoneyPy" 33 | pid=`ps -ef | grep "Honey.py -d" | grep -v grep | awk '{ print $2 }'` 34 | kill -9 $pid 35 | ;; 36 | status) 37 | pid=`ps -ef | grep "Honey.py -d" | grep -v grep | awk '{ print $2 }'` 38 | if [ -z $pid ]; 39 | then 40 | exit 5; 41 | else 42 | exit 0; 43 | fi 44 | ;; 45 | *) 46 | echo "Usage: /etc/init.d/honeypyd {start|stop|status}" 47 | exit 1 48 | ;; 49 | esac 50 | 51 | exit 0 52 | -------------------------------------------------------------------------------- /etc/profiles/services.databases.profile: -------------------------------------------------------------------------------- 1 | # HoneyPy Copyright (C) 2013-2017 foospidy 2 | # services.peer_to_peer.profile 3 | # Important: service names must not contain spaces. 4 | # Important: use port redirecting for services that listen on ports below 1024 (see https://github.com/foospidy/ipt-kit). 5 | 6 | [MSSQL] 7 | plugin = Echo 8 | low_port = tcp:1433 9 | port = tcp:1433 10 | description = MSSQL port 1433 11 | enabled = Yes 12 | 13 | [MSSQL] 14 | plugin = Echo 15 | low_port = tcp:1434 16 | port = tcp:1434 17 | description = MSSQL port 1434 18 | enabled = Yes 19 | 20 | [OracleXDB] 21 | plugin = Echo 22 | low_port = tcp:2100 23 | port = tcp:2100 24 | description = Oracle XDB port 2100 25 | enabled = Yes 26 | 27 | [OracleDB] 28 | plugin = Echo 29 | low_port = tcp:2483 30 | port = tcp:2483 31 | description = Oracle XDB port 2483 32 | enabled = Yes 33 | 34 | [OracleDB] 35 | plugin = Echo 36 | low_port = tcp:2484 37 | port = tcp:2484 38 | description = Oracle DB port 2484 39 | enabled = Yes 40 | 41 | [InterbaseDB] 42 | plugin = Echo 43 | low_port = tcp:3050 44 | port = tcp:3050 45 | description = Interbase DB port 3050 46 | enabled = Yes 47 | 48 | [MySQL] 49 | plugin = Echo 50 | low_port = tcp:3306 51 | port = tcp:3306 52 | description = MySQL DB port 3306 53 | enabled = Yes 54 | 55 | [mSQL] 56 | plugin = Echo 57 | low_port = tcp:4333 58 | port = tcp:4333 59 | description = mSQL port 4333 60 | enabled = Yes 61 | 62 | [PostgreSQL] 63 | plugin = Echo 64 | low_port = tcp:5432 65 | port = tcp:5432 66 | description = PostgreSQL port 5432 67 | enabled = Yes 68 | 69 | [Elasticsearch] 70 | plugin = Elasticsearch 71 | low_port = tcp:9200 72 | port = tcp:9200 73 | description = Send basic elasticsearch like replies 74 | enabled = No 75 | 76 | [DB2] 77 | plugin = Echo 78 | low_port = tcp:50000 79 | port = tcp:50000 80 | description = DB2 port 50000 81 | enabled = Yes 82 | -------------------------------------------------------------------------------- /etc/profiles/services.default.profile: -------------------------------------------------------------------------------- 1 | # HoneyPy Copyright (C) 2013-2017 foospidy 2 | # services.default.profile 3 | # Important: service names must not contain spaces. 4 | # Important: use port redirecting for services that listen on ports below 1024 (see https://github.com/foospidy/ipt-kit). 5 | 6 | [Echo] 7 | plugin = Echo 8 | low_port = tcp:7 9 | port = tcp:10007 10 | description = Echo back data received via tcp. 11 | enabled = Yes 12 | 13 | [Echo.udp] 14 | plugin = Echo_udp 15 | low_port = udp:7 16 | port = udp:10007 17 | description = Echo back data received via udp. 18 | enabled = Yes 19 | 20 | [MOTD] 21 | plugin = MOTD 22 | low_port = tcp:8 23 | port = tcp:10008 24 | description = Send a message via tcp and close connection. 25 | enabled = Yes 26 | 27 | [MOTD.udp] 28 | plugin = MOTD_udp 29 | low_port = udp:8 30 | port = udp:10008 31 | description = Send a message via udp. 32 | enabled = Yes 33 | 34 | [Telnet.Unix] 35 | plugin = TelnetUnix 36 | low_port = tcp:23 37 | port = tcp:10009 38 | description = Emulate Debian telnet login via tcp. 39 | enabled = Yes 40 | 41 | [Telnet.Windows] 42 | plugin = TelnetWindows 43 | low_port = tcp:24 44 | port = tcp:10010 45 | description = Emulate Windows telnet login via tcp. 46 | enabled = Yes 47 | 48 | [Random] 49 | plugin = Random 50 | low_port = tcp:2048 51 | port = tcp:2048 52 | description = Send random data via tcp. 53 | enabled = Yes 54 | 55 | [HashCountRandom] 56 | plugin = HashCountRandom 57 | low_port = tcp:4096 58 | port = tcp:4096 59 | description = Send random data prefixed with a hash of a counter via tcp. 60 | enabled = Yes 61 | -------------------------------------------------------------------------------- /etc/profiles/services.iot.profile: -------------------------------------------------------------------------------- 1 | # HoneyPy Copyright (C) 2013-2017 foospidy 2 | # services.iot.profile 3 | # Important: service names must not contain spaces. 4 | # Important: use port redirecting for services that listen on ports below 1024 (see https://github.com/foospidy/ipt-kit). 5 | # Internet of Things (IoT) related services 6 | # Including home modems/routers as IoT 7 | 8 | [Telnet] 9 | plugin = TelnetUnix 10 | low_port = tcp:23 11 | port = tcp:10023 12 | description = Telnet port 13 | enabled = Yes 14 | 15 | [TFTP] 16 | plugin = TFTP 17 | low_port = udp:69 18 | port = udp:10069 19 | description = Emulate TFTP service 20 | enabled = Yes 21 | 22 | [SNMP] 23 | plugin = Echo_udp 24 | low_port = udp:161 25 | port = udp:10161 26 | description = dumb snmp 27 | enabled = Yes 28 | 29 | [Telnet.IoT] 30 | plugin = TelnetUnix 31 | low_port = tcp:2323 32 | port = tcp:2323 33 | description = IoT telnet port, reference https://isc.sans.edu/diary/21563 34 | enabled = Yes 35 | 36 | [TR-069.1] 37 | plugin = Web 38 | low_port = tcp:5555 39 | port = tcp:5555 40 | description = Technical Report for modems/routers https://isc.sans.edu/forums/diary/TR069+NewNTPServer+Exploits+What+we+know+so+far/21763/ 41 | enabled = Yes 42 | 43 | [TR-069.2] 44 | plugin = Web 45 | low_port = tcp:7547 46 | port = tcp:7547 47 | description = Technical Report for modems/routers https://isc.sans.edu/forums/diary/TR069+NewNTPServer+Exploits+What+we+know+so+far/21763/ 48 | enabled = Yes 49 | 50 | [HTTP.alt] 51 | plugin = Web 52 | low_port = tcp:8080 53 | port = tcp:8080 54 | description = Alternative port for web services 55 | enabled = Yes 56 | 57 | [SIP] 58 | plugin = SIP 59 | low_port = udp:5060 60 | port = udp:5060 61 | description = The Session Initiation Protocol (SIP) is a communications protocol for signaling and controlling multimedia communication session such as voice and video calls. 62 | enabled = Yes 63 | 64 | [Cactus] 65 | plugin = Web 66 | low_port = tcp:49115 67 | port = tcp:49115 68 | description = IoT port, reference http://cactus.io/tutorials/web/connect-iot-device-to-the-internet 69 | enabled = Yes 70 | -------------------------------------------------------------------------------- /etc/profiles/services.kali.profile: -------------------------------------------------------------------------------- 1 | # HoneyPy Copyright (C) 2013-2017 foospidy 2 | # services.kali.profile 3 | # Important: service names must not contain spaces. 4 | # Important: use port redirecting for services that listen on ports below 1024 (see https://github.com/foospidy/ipt-kit). 5 | # Attempt at a Kali Linux profile 6 | 7 | [Bootp] 8 | plugin = Echo_udp 9 | low_port = udp:68 10 | port = udp:10068 11 | description = bootp client 12 | enabled = Yes 13 | 14 | [Beef.XSS] 15 | plugin = Echo 16 | low_port = tcp:2000 17 | port = tcp:2000 18 | description = Beef related port 19 | enabled = Yes 20 | 21 | [Beef.XSS] 22 | plugin = Echo 23 | low_port = tcp:3000 24 | port = tcp:3000 25 | description = beef related port 26 | enabled = Yes 27 | 28 | [Armitage] 29 | plugin = Echo 30 | low_port = tcp:55553 31 | port = tcp:55553 32 | description = Armitage team server 33 | enabled = Yes 34 | -------------------------------------------------------------------------------- /etc/profiles/services.kubernetes.profile: -------------------------------------------------------------------------------- 1 | # HoneyPy Copyright (C) foospidy 2 | # services.kubernetes.profile 3 | # Important: service names must not contain spaces. 4 | # Important: use port redirecting for services that listen on ports below 1024 (see https://github.com/foospidy/ipt-kit). 5 | # kubernetes profile 6 | 7 | [KubeAPI] 8 | plugin = Web 9 | low_port = tcp:6443 10 | port = tcp:6443 11 | description = Kubernetes API Server 12 | enabled = Yes 13 | 14 | [Kube.etcd] 15 | plugin = Echo 16 | low_port = tcp:2379 17 | port = tcp:2379 18 | description = etcd server client API 19 | enabled = Yes 20 | 21 | [Kube.etcd] 22 | plugin = Echo 23 | low_port = tcp:2380 24 | port = tcp:2380 25 | description = etcd server client API 26 | enabled = Yes 27 | 28 | [Kube.cAdvisor] 29 | plugin = Web 30 | low_port = tcp:4194 31 | port = tcp:4194 32 | description = cAdvisor 33 | enabled = Yes 34 | 35 | [Kube.healthzPort] 36 | plugin = Echo 37 | low_port = tcp:10248 38 | port = tcp:10248 39 | description = healthzPort 40 | enabled = Yes 41 | 42 | [KubeletAPI] 43 | plugin = Web 44 | low_port = tcp:10250 45 | port = tcp:10250 46 | description = Kubelet API 47 | enabled = Yes 48 | 49 | [KubeScheduler] 50 | plugin = Web 51 | low_port = tcp:10251 52 | port = tcp:10251 53 | description = kube-scheduler 54 | enabled = Yes 55 | 56 | [KubeScheduler] 57 | plugin = Web 58 | low_port = tcp:10252 59 | port = tcp:10252 60 | description = kube-controller-manager 61 | enabled = Yes 62 | 63 | [KubeScheduler] 64 | plugin = Web 65 | low_port = tcp:10255 66 | port = tcp:10255 67 | description = Read-Only Kubelet API 68 | enabled = Yes 69 | -------------------------------------------------------------------------------- /etc/profiles/services.linux.profile: -------------------------------------------------------------------------------- 1 | # HoneyPy Copyright (C) 2013-2017 foospidy 2 | # services.linux.profile 3 | # Important: service names must not contain spaces. 4 | # Important: use port redirecting for services that listen on ports below 1024 (see https://github.com/foospidy/ipt-kit). 5 | # Reference: https://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers 6 | 7 | [Echo] 8 | plugin = Echo 9 | low_port = tcp:7 10 | port = tcp:10007 11 | description = Echo back data received via tcp. 12 | enabled = Yes 13 | 14 | [Echo.udp] 15 | plugin = Echo_udp 16 | low_port = udp:7 17 | port = udp:10007 18 | description = Echo back data received via udp. 19 | enabled = Yes 20 | 21 | [MOTD] 22 | plugin = MOTD 23 | low_port = tcp:8 24 | port = tcp:10008 25 | description = Send a message via tcp and close connection. 26 | enabled = Yes 27 | 28 | [MOTD.udp] 29 | plugin = MOTD_udp 30 | low_port = udp:8 31 | port = udp:10008 32 | description = Send a message via udp. 33 | enabled = Yes 34 | 35 | [FTP] 36 | plugin = Echo 37 | low_port = tcp:21 38 | port = tcp:10021 39 | description = Echo back data received via tcp. 40 | enabled = Yes 41 | 42 | [SSH] 43 | plugin = Random 44 | low_port = tcp:22 45 | port = tcp:10022 46 | description = Send random data via tcp. 47 | enabled = Yes 48 | 49 | [Telnet] 50 | plugin = TelnetUnix 51 | low_port = tcp:23 52 | port = tcp:10023 53 | description = Emulate Debian telnet login via tcp. 54 | enabled = Yes 55 | 56 | [SMTP] 57 | plugin = SmtpExim 58 | low_port = tcp:25 59 | port = tcp:10025 60 | description = Echo back data received via tcp. 61 | enabled = Yes 62 | 63 | [DNS] 64 | plugin = Echo 65 | low_port = tcp:53 66 | port = tcp:10053 67 | description = Echo back data received via tcp. 68 | enabled = Yes 69 | 70 | [DNS.udp] 71 | plugin = DnsUdp 72 | low_port = udp:53 73 | port = udp:10053 74 | description = Echo back data received via udp. 75 | enabled = Yes 76 | 77 | [Bootp] 78 | plugin = Echo_udp 79 | low_port = udp:67 80 | port = udp:10067 81 | description = Echo back data received via tcp. 82 | enabled = Yes 83 | 84 | [TFTP] 85 | plugin = TFTP 86 | low_port = udp:69 87 | port = udp:10069 88 | description = Echo back data received via udp. 89 | enabled = Yes 90 | 91 | [HTTP] 92 | plugin = Web 93 | low_port = tcp:80 94 | port = tcp:10080 95 | description = Echo back data received via tcp. 96 | enabled = Yes 97 | 98 | [Kerberos] 99 | plugin = Echo 100 | low_port = tcp:88 101 | port = tcp:10088 102 | description = Echo back data received via tcp. 103 | enabled = Yes 104 | 105 | [Kerberos.udp] 106 | plugin = Echo_udp 107 | low_port = udp:88 108 | port = udp:10088 109 | description = Echo back data received via udp. 110 | enabled = Yes 111 | 112 | [POP3] 113 | plugin = Echo 114 | low_port = tcp:110 115 | port = tcp:10110 116 | description = Echo back data received via tcp. 117 | enabled = Yes 118 | 119 | [SunRPC] 120 | plugin = Echo 121 | low_port = tcp:111 122 | port = tcp:10111 123 | description = Echo back data received via tcp. 124 | enabled = Yes 125 | 126 | [SunRPC.udp] 127 | plugin = Echo_udp 128 | low_port = udp:111 129 | port = udp:10111 130 | description = Echo back data received via udp. 131 | enabled = Yes 132 | 133 | [NTP] 134 | plugin = NtpUdp 135 | low_port = udp:123 136 | port = udp:10123 137 | description = Echo back data received via udp. 138 | enabled = Yes 139 | 140 | [NetBIOS] 141 | plugin = Echo_udp 142 | low_port = udp:137 143 | port = udp:10137 144 | description = Echo back data received via udp. 145 | enabled = Yes 146 | 147 | [Samba] 148 | plugin = Echo 149 | low_port = tcp:139 150 | port = tcp:10139 151 | description = Echo back data received via tcp. 152 | enabled = Yes 153 | 154 | [IMAP] 155 | plugin = Echo 156 | low_port = tcp:143 157 | port = tcp:10143 158 | description = Echo back data received via tcp. 159 | enabled = Yes 160 | 161 | [SNMP] 162 | plugin = Echo_udp 163 | low_port = udp:161 164 | port = udp:10161 165 | description = Echo back data received via udp. 166 | enabled = Yes 167 | 168 | [LDAP] 169 | plugin = Echo 170 | low_port = tcp:389 171 | port = tcp:10389 172 | description = Echo back data received via tcp. 173 | enabled = Yes 174 | 175 | [LDAP.udp] 176 | plugin = Echo_udp 177 | low_port = udp:389 178 | port = udp:10389 179 | description = Echo back data received via udp. 180 | enabled = Yes 181 | 182 | [HTTPS] 183 | plugin = Random 184 | low_port = tcp:443 185 | port = tcp:10443 186 | description = Send random data via tcp. 187 | enabled = Yes 188 | 189 | [Syslog] 190 | plugin = Echo_udp 191 | low_port = udp:514 192 | port = udp:10514 193 | description = Echo back data received via udp. 194 | enabled = Yes 195 | 196 | [SLDAP] 197 | plugin = Echo 198 | low_port = tcp:636 199 | port = tcp:10636 200 | description = Echo back data received via tcp. 201 | enabled = Yes 202 | 203 | [SLDAP.udp] 204 | plugin = Echo_udp 205 | low_port = udp:636 206 | port = udp:10636 207 | description = Echo back data received via udp. 208 | enabled = Yes 209 | 210 | [Rsync] 211 | plugin = Echo 212 | low_port = tcp:873 213 | port = tcp:10873 214 | description = Echo back data received via tcp. 215 | enabled = Yes 216 | 217 | [MySQL] 218 | plugin = Random 219 | low_port = tcp:3306 220 | port = tcp:3306 221 | description = Send random data via tcp. 222 | enabled = Yes 223 | 224 | [NFS] 225 | plugin = Echo 226 | low_port = tcp:2049 227 | port = tcp:2049 228 | description = Echo back data received via tcp. 229 | enabled = Yes 230 | 231 | [NFS.udp] 232 | plugin = Echo_udp 233 | low_port = udp:2049 234 | port = udp:2049 235 | description = Echo back data received via udp. 236 | enabled = Yes 237 | 238 | [PostgreSQL] 239 | plugin = Echo 240 | low_port = tcp:5432 241 | port = tcp:5432 242 | description = Echo back data received via tcp. 243 | enabled = Yes 244 | 245 | [X11] 246 | plugin = Echo 247 | low_port = tcp:6000 248 | port = tcp:6000 249 | description = Echo back data received via tcp. 250 | enabled = Yes 251 | -------------------------------------------------------------------------------- /etc/profiles/services.streaming.profile: -------------------------------------------------------------------------------- 1 | # HoneyPy Copyright (C) 2013-2017 foospidy 2 | # services.peer_to_peer.profile 3 | # Important: service names must not contain spaces. 4 | # Important: use port redirecting for services that listen on ports below 1024 (see https://github.com/foospidy/ipt-kit). 5 | # Streaming related ports as noted by http://packetlife.net/media/library/23/common_ports.pdf 6 | 7 | [MS_Media_Server] 8 | plugin = Echo 9 | low_port = tcp:1755 10 | port = tcp:1755 11 | description = MS Media Server port 1755 12 | enabled = Yes 13 | 14 | [Ventrilo] 15 | plugin = Echo 16 | low_port = tcp:3784 17 | port = tcp:3784 18 | description = Ventrilo port 3784 19 | enabled = Yes 20 | 21 | [Ventrilo] 22 | plugin = Echo 23 | low_port = tcp:3785 24 | port = tcp:3785 25 | description = Ventrilo port 3785 26 | enabled = Yes 27 | 28 | [Slingbox] 29 | plugin = Echo 30 | low_port = tcp:5001 31 | port = tcp:5001 32 | description = Slingbox port 5001 33 | enabled = Yes 34 | 35 | [RTP] 36 | plugin = Echo 37 | low_port = tcp:5004 38 | port = tcp:5004 39 | description = RTP port 5004 40 | enabled = Yes 41 | 42 | [RTP] 43 | plugin = Echo 44 | low_port = tcp:5005 45 | port = tcp:5005 46 | description = RTP port 5005 47 | enabled = Yes 48 | 49 | [SIP] 50 | plugin = Echo 51 | low_port = tcp:5060 52 | port = tcp:5060 53 | description = SIP port 5060 54 | enabled = Yes 55 | 56 | [Quicktime] 57 | plugin = Echo 58 | low_port = tcp:6970 59 | port = tcp:6970 60 | description = Quicktime port 6970 61 | enabled = Yes 62 | 63 | [Internet_Radio] 64 | plugin = Echo 65 | low_port = tcp:8000 66 | port = tcp:8000 67 | description = Internet Radio port 8000 68 | enabled = Yes 69 | 70 | [Synergy] 71 | plugin = Echo 72 | low_port = tcp:24800 73 | port = tcp:24800 74 | description = Synergy port 24800 75 | enabled = Yes 76 | -------------------------------------------------------------------------------- /etc/profiles/services.windows_active_directory.profile: -------------------------------------------------------------------------------- 1 | # HoneyPy Copyright (C) 2013-2017 foospidy 2 | # services.windows_active_directory.example 3 | # Important: service names must not contain spaces. 4 | # Important: use port redirecting for services that listen on ports below 1024 (see https://github.com/foospidy/ipt-kit). 5 | # References: http://technet.microsoft.com/en-us/library/dd772723(v=ws.10).aspx 6 | 7 | [LDAP] 8 | plugin = Echo 9 | low_port = tcp:389 10 | port = tcp:30389 11 | description = Echo back data received via tcp. 12 | enabled = Yes 13 | 14 | [LDAP.udp] 15 | plugin = Echo_udp 16 | low_port = udp:389 17 | port = udp:30389 18 | description = Echo back data received via udp. 19 | enabled = Yes 20 | 21 | [SLDAP] 22 | plugin = Echo 23 | low_port = tcp:636 24 | port = tcp:30636 25 | description = Echo back data received via tcp. 26 | enabled = Yes 27 | 28 | [LDAP.GC] 29 | plugin = Echo 30 | low_port = tcp:3268 31 | port = tcp:3268 32 | description = Echo back data received via tcp. 33 | enabled = Yes 34 | 35 | [SLDAP.GC] 36 | plugin = Echo 37 | low_port = tcp:3269 38 | port = tcp:3269 39 | description = Echo back data received via tcp. 40 | enabled = Yes 41 | 42 | [Kerberos] 43 | plugin = Echo 44 | low_port = tcp:88 45 | port = tcp:30088 46 | description = Echo back data received via tcp. 47 | enabled = Yes 48 | 49 | [Kerberos.udp] 50 | plugin = Echo_udp 51 | low_port = udp:88 52 | port = udp:30088 53 | description = Echo back data received via udp. 54 | enabled = Yes 55 | 56 | [DNS] 57 | plugin = Echo 58 | low_port = tcp:53 59 | port = tcp:30053 60 | description = Echo back data received via tcp. 61 | enabled = Yes 62 | 63 | [DNS.udp] 64 | plugin = Echo_udp 65 | low_port = udp:53 66 | port = udp:30053 67 | description = Echo back data received via udp. 68 | enabled = Yes 69 | 70 | [CIFS] 71 | plugin = Echo 72 | low_port = tcp:445 73 | port = tcp:30445 74 | description = Echo back data received via tcp. 75 | enabled = Yes 76 | 77 | [CIFS.udp] 78 | plugin = Echo_udp 79 | low_port = udp:445 80 | port = udp:30445 81 | description = Echo back data received via udp. 82 | enabled = Yes 83 | 84 | [SMTP] 85 | plugin = Echo 86 | low_port = tcp:25 87 | port = tcp:30025 88 | description = Echo back data received via tcp. 89 | enabled = Yes 90 | 91 | [RPC] 92 | plugin = Echo 93 | low_port = tcp:135 94 | port = tcp:30135 95 | description = Echo back data received via tcp. 96 | enabled = Yes 97 | 98 | [NTP] 99 | plugin = Echo_udp 100 | low_port = udp:123 101 | port = udp:30123 102 | description = Echo back data received via udp. 103 | enabled = Yes 104 | 105 | [KerberosChangePassword] 106 | plugin = Echo 107 | low_port = tcp:464 108 | port = tcp:30464 109 | description = Echo back data received via tcp. 110 | enabled = Yes 111 | 112 | [KerberosChangePassword.udp] 113 | plugin = Echo_udp 114 | low_port = udp:464 115 | port = udp:30464 116 | description = Echo back data received via udp. 117 | enabled = Yes 118 | 119 | [DFS] 120 | plugin = Echo_udp 121 | low_port = udp:138 122 | port = udp:30138 123 | description = Echo back data received via udp. 124 | enabled = Yes 125 | 126 | [AD.DS_WS] 127 | plugin = Echo 128 | low_port = tcp:9389 129 | port = tcp:9389 130 | description = Echo back data received via tcp. 131 | enabled = Yes 132 | 133 | [DHCP] 134 | plugin = Echo_udp 135 | low_port = udp:67 136 | port = udp:30067 137 | description = Echo back data received via udp. 138 | enabled = Yes 139 | 140 | [NetLogon] 141 | plugin = Echo_udp 142 | low_port = udp:137 143 | port = udp:30137 144 | description = Echo back data received via udp. 145 | enabled = Yes 146 | 147 | [DFSN] 148 | plugin = Echo 149 | low_port = tcp:139 150 | port = tcp:30139 151 | description = Echo back data received via tcp. 152 | enabled = Yes 153 | -------------------------------------------------------------------------------- /etc/profiles/services.windows_iis.profile: -------------------------------------------------------------------------------- 1 | # HoneyPy Copyright (C) 2013-2017 foospidy 2 | # services.windows_iis.profile 3 | # Important: service names must not contain spaces. 4 | # Important: use port redirecting for services that listen on ports below 1024 (see https://github.com/foospidy/ipt-kit). 5 | 6 | [SMTP] 7 | plugin = Echo 8 | low_port = tcp:25 9 | port = tcp:30025 10 | description = Echo back data received via tcp. 11 | enabled = Yes 12 | 13 | [FTP] 14 | plugin = Echo 15 | low_port = tcp:21 16 | port = tcp:30021 17 | description = Echo back data received via tcp. 18 | enabled = Yes 19 | 20 | [Telnet] 21 | plugin = TelnetWindows 22 | low_port = tcp:23 23 | port = tcp:30023 24 | description = Emulate Windows telnet via tcp. 25 | enabled = Yes 26 | 27 | [HTTP] 28 | plugin = Echo 29 | low_port = tcp:80 30 | port = tcp:30080 31 | description = Echo back data received via tcp. 32 | enabled = Yes 33 | 34 | [HTTPS] 35 | plugin = Random 36 | low_port = tcp:443 37 | port = tcp:30443 38 | description = Send random data received via tcp. 39 | enabled = Yes 40 | 41 | [CIFS] 42 | plugin = Echo 43 | low_port = tcp:445 44 | port = tcp:30445 45 | description = Echo back data received via tcp. 46 | enabled = Yes 47 | 48 | [CIFS.udp] 49 | plugin = Echo_udp 50 | low_port = udp:445 51 | port = udp:30445 52 | description = Echo back data received via udp. 53 | enabled = Yes 54 | -------------------------------------------------------------------------------- /etc/services.cfg: -------------------------------------------------------------------------------- 1 | # HoneyPy Copyright (C) 2013-2017 foospidy 2 | # services.default.profile 3 | # Important: service names must not contain spaces. 4 | # Important: use port redirecting for services that listen on ports below 1024 (see https://github.com/foospidy/ipt-kit). 5 | 6 | [Echo] 7 | plugin = Echo 8 | low_port = tcp:7 9 | port = tcp:10007 10 | description = Echo back data received via tcp. 11 | enabled = Yes 12 | 13 | [Echo.udp] 14 | plugin = Echo_udp 15 | low_port = udp:7 16 | port = udp:10007 17 | description = Echo back data received via udp. 18 | enabled = Yes 19 | 20 | [MOTD] 21 | plugin = MOTD 22 | low_port = tcp:8 23 | port = tcp:10008 24 | description = Send a message via tcp and close connection. 25 | enabled = Yes 26 | 27 | [MOTD.udp] 28 | plugin = MOTD_udp 29 | low_port = udp:8 30 | port = udp:10008 31 | description = Send a message via udp. 32 | enabled = Yes 33 | 34 | [Telnet] 35 | plugin = TelnetUnix 36 | low_port = tcp:23 37 | port = tcp:10009 38 | description = Emulate Debian telnet login via tcp. 39 | enabled = Yes 40 | 41 | [Telnet.Windows] 42 | plugin = TelnetWindows 43 | low_port = tcp:24 44 | port = tcp:10010 45 | description = Emulate Windows telnet login via tcp. 46 | enabled = Yes 47 | 48 | [Random] 49 | plugin = Random 50 | low_port = tcp:2048 51 | port = tcp:2048 52 | description = Send random data via tcp. 53 | enabled = Yes 54 | 55 | [HashCountRandom] 56 | plugin = HashCountRandom 57 | low_port = tcp:4096 58 | port = tcp:4096 59 | description = Send random data prefixed with a hash of a counter via tcp. 60 | enabled = Yes 61 | 62 | [Elasticsearch] 63 | plugin = Elasticsearch 64 | low_port = tcp:9200 65 | port = tcp:9200 66 | description = Send basic elasticsearch like replies 67 | enabled = No 68 | -------------------------------------------------------------------------------- /lib/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 foospidy 2 | # https://github.com/foospidy/HoneyPy 3 | # See LICENSE for details 4 | 5 | import sys 6 | # prevent creation of compiled bytecode files 7 | sys.dont_write_bytecode = True 8 | -------------------------------------------------------------------------------- /lib/clilib/README.md: -------------------------------------------------------------------------------- 1 | # clilib 2 | A library of emulated command line commands. The goal of this library is to 3 | emulate the most common cammands for Unix and Windows. The primary 4 | use case for this library is in honeypots. 5 | 6 | ### Usage 7 | Import clilib into your script with `from clilib import *` 8 | 9 | You should now be able to call command cuntions form your script. Command functions always return printable output so you can store the output to a variable or print it directly. Examples: 10 | 11 | `myvar = print uname('-a')` 12 | `print myvar` 13 | 14 | or 15 | 16 | `print uname('-a')` 17 | 18 | more examples are in the test script here: https://github.com/foospidy/HoneyPy/blob/master/lib/clilib/test.py 19 | -------------------------------------------------------------------------------- /lib/clilib/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | clilib 3 | ====== 4 | A library of emulated command line commands. The goal of this library is to 5 | emulate at least the most common cammands for Unix and Windows. The primary 6 | use case for this library is in honeypots. 7 | 8 | Contribute to the library! 9 | https://github.com/foospidy/clilib 10 | 11 | Example use in a honeypot: 12 | https://github.com/foospidy/HoneyPy 13 | """ 14 | from clilib import * 15 | -------------------------------------------------------------------------------- /lib/clilib/clilib.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | sys.dont_write_bytecode = True 5 | 6 | UNIX = {'posix', 'mac'} 7 | WINDOWS = {'nt'} 8 | 9 | if os.name in UNIX: 10 | from unix import * 11 | elif os.name in WINDOWS: 12 | from windows import * 13 | else: 14 | print 'Error!' 15 | -------------------------------------------------------------------------------- /lib/clilib/test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | from clilib import * 4 | 5 | print man('') 6 | print man('uname') 7 | 8 | print uname() 9 | print uname('-a') 10 | 11 | print echo() 12 | print echo('test') 13 | print echo("-e '\x67\x61\x79\x66\x67\x74'") 14 | 15 | print "rm soemthing" 16 | print rm() 17 | print "rm -rf somepath" 18 | print rm('/some/file/path') 19 | 20 | print tftp() 21 | 22 | print busybox('ECCHI') 23 | print busybox('thing') 24 | print busybox() 25 | 26 | print enable() 27 | -------------------------------------------------------------------------------- /lib/clilib/unix/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | clilib.unix 3 | =========== 4 | """ 5 | 6 | from unix import * 7 | -------------------------------------------------------------------------------- /lib/clilib/unix/busybox.py: -------------------------------------------------------------------------------- 1 | def busybox(*params): 2 | """ 3 | No manual entry for busybox 4 | """ 5 | 6 | output = '' 7 | 8 | if None != params: 9 | for param in params: 10 | 11 | #https://isc.sans.edu/diary/21543 12 | if 'ECCHI' == param: 13 | output = 'ECCHI: applet not found' 14 | 15 | return output 16 | -------------------------------------------------------------------------------- /lib/clilib/unix/cd.py: -------------------------------------------------------------------------------- 1 | def cd(params=None): 2 | """ 3 | No manual entry for cd 4 | """ 5 | return '' 6 | -------------------------------------------------------------------------------- /lib/clilib/unix/echo.py: -------------------------------------------------------------------------------- 1 | def echo(*params): 2 | """ 3 | ECHO(1) User Commands ECHO(1) 4 | 5 | NAME 6 | echo - display a line of text 7 | 8 | SYNOPSIS 9 | echo [SHORT-OPTION]... [STRING]... 10 | echo LONG-OPTION 11 | 12 | DESCRIPTION 13 | Echo the STRING(s) to standard output. 14 | 15 | -n do not output the trailing newline 16 | 17 | -e enable interpretation of backslash escapes 18 | 19 | -E disable interpretation of backslash escapes (default) 20 | 21 | --help display this help and exit 22 | 23 | --version 24 | output version information and exit 25 | 26 | If -e is in effect, the following sequences are recognized: 27 | 28 | \\ backslash 29 | 30 | \a alert (BEL) 31 | 32 | \b backspace 33 | 34 | \c produce no further output 35 | 36 | \e escape 37 | 38 | \f form feed 39 | 40 | \n new line 41 | 42 | \r carriage return 43 | 44 | \t horizontal tab 45 | 46 | \v vertical tab 47 | 48 | \0NNN byte with octal value NNN (1 to 3 digits) 49 | 50 | \\xHH byte with hexadecimal value HH (1 to 2 digits) 51 | 52 | NOTE: your shell may have its own version of echo, which usually supersedes the version described here. Please refer to your shell's documentation for 53 | details about the options it supports. 54 | 55 | AUTHOR 56 | Written by Brian Fox and Chet Ramey. 57 | 58 | REPORTING BUGS 59 | GNU coreutils online help: 60 | Report echo translation bugs to 61 | 62 | COPYRIGHT 63 | Copyright @ 2014 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later . 64 | This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. 65 | 66 | SEE ALSO 67 | Full documentation at: 68 | or available locally via: info '(coreutils) echo invocation' 69 | 70 | GNU coreutils 8.23 March 2015 ECHO(1) 71 | """ 72 | 73 | output = '' 74 | escape = False 75 | 76 | if None != params: 77 | for param in params: 78 | if param in {'-e'}: 79 | escape = True 80 | else: 81 | # remove quotes if quoted 82 | if param.startswith('"') and param.endswith('"'): 83 | param = param[1:-1] 84 | 85 | if param.startswith("'") and param.endswith("'"): 86 | param = param[1:-1] 87 | 88 | if escape: 89 | output = output + str(param).decode('string_escape') 90 | else: 91 | output = output + str(param) 92 | 93 | return output 94 | -------------------------------------------------------------------------------- /lib/clilib/unix/enable.py: -------------------------------------------------------------------------------- 1 | def enable(params=None): 2 | """ 3 | No manual entry for busybox 4 | """ 5 | 6 | output = """enable . 7 | enable : 8 | enable [ 9 | enable alias 10 | enable bg 11 | enable bind 12 | enable break 13 | enable builtin 14 | enable caller 15 | enable cd 16 | enable command 17 | enable compgen 18 | enable complete 19 | enable compopt 20 | enable continue 21 | enable declare 22 | enable dirs 23 | enable disown 24 | enable echo 25 | enable enable 26 | enable eval 27 | enable exec 28 | enable exit 29 | enable export 30 | enable false 31 | enable fc 32 | enable fg 33 | enable getopts 34 | enable hash 35 | enable help 36 | enable history 37 | enable jobs 38 | enable kill 39 | enable let 40 | enable local 41 | enable logout 42 | enable mapfile 43 | enable popd 44 | enable printf 45 | enable pushd 46 | enable pwd 47 | enable read 48 | enable readarray 49 | enable readonly 50 | enable return 51 | enable set 52 | enable shift 53 | enable shopt 54 | enable source 55 | enable suspend 56 | enable test 57 | enable times 58 | enable trap 59 | enable true 60 | enable type 61 | enable typeset 62 | enable ulimit 63 | enable umask 64 | enable unalias 65 | enable unset 66 | enable wait""" 67 | 68 | return output 69 | -------------------------------------------------------------------------------- /lib/clilib/unix/rm.py: -------------------------------------------------------------------------------- 1 | def rm(params=None): 2 | """ 3 | RM(1) User Commands RM(1) 4 | 5 | NAME 6 | rm - remove files or directories 7 | 8 | SYNOPSIS 9 | rm [OPTION]... FILE... 10 | 11 | DESCRIPTION 12 | This manual page documents the GNU version of rm. rm removes each specified file. By default, it does not remove directories. 13 | 14 | If the -I or --interactive=once option is given, and there are more than three files or the -r, -R, or --recursive are given, then rm prompts the user for 15 | whether to proceed with the entire operation. If the response is not affirmative, the entire command is aborted. 16 | 17 | Otherwise, if a file is unwritable, standard input is a terminal, and the -f or --force option is not given, or the -i or --interactive=always option is 18 | given, rm prompts the user for whether to remove the file. If the response is not affirmative, the file is skipped. 19 | 20 | OPTIONS 21 | Remove (unlink) the FILE(s). 22 | 23 | -f, --force 24 | ignore nonexistent files and arguments, never prompt 25 | 26 | -i prompt before every removal 27 | 28 | -I prompt once before removing more than three files, or when removing recursively; less intrusive than -i, while still giving protection against most 29 | mistakes 30 | 31 | --interactive[=WHEN] 32 | prompt according to WHEN: never, once (-I), or always (-i); without WHEN, prompt always 33 | 34 | --one-file-system 35 | when removing a hierarchy recursively, skip any directory that is on a file system different from that of the corresponding command line argument 36 | 37 | --no-preserve-root 38 | do not treat '/' specially 39 | 40 | --preserve-root 41 | do not remove '/' (default) 42 | 43 | -r, -R, --recursive 44 | remove directories and their contents recursively 45 | 46 | 47 | -d, --dir 48 | remove empty directories 49 | 50 | -v, --verbose 51 | explain what is being done 52 | 53 | --help display this help and exit 54 | 55 | --version 56 | output version information and exit 57 | 58 | By default, rm does not remove directories. Use the --recursive (-r or -R) option to remove each listed directory, too, along with all of its contents. 59 | 60 | To remove a file whose name starts with a '-', for example '-foo', use one of these commands: 61 | 62 | rm -- -foo 63 | 64 | rm ./-foo 65 | 66 | Note that if you use rm to remove a file, it might be possible to recover some of its contents, given sufficient expertise and/or time. For greater assur ance that the contents are truly unrecoverable, consider using shred. 67 | 68 | AUTHOR 69 | Written by Paul Rubin, David MacKenzie, Richard M. Stallman, and Jim Meyering. 70 | 71 | REPORTING BUGS 72 | GNU coreutils online help: 73 | Report rm translation bugs to 74 | 75 | COPYRIGHT 76 | Copyright @ 2014 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later . 77 | This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. 78 | 79 | SEE ALSO 80 | unlink(1), unlink(2), chattr(1), shred(1) 81 | 82 | Full documentation at: 83 | or available locally via: info '(coreutils) rm invocation' 84 | 85 | GNU coreutils 8.23 March 2015 RM(1) 86 | """ 87 | 88 | return '' 89 | -------------------------------------------------------------------------------- /lib/clilib/unix/sh.py: -------------------------------------------------------------------------------- 1 | def sh(params=None): 2 | """ 3 | No manual entry for cd 4 | """ 5 | return '' 6 | -------------------------------------------------------------------------------- /lib/clilib/unix/tftp.py: -------------------------------------------------------------------------------- 1 | def tftp(params=None): 2 | """ 3 | TFTP(1) BSD General Commands Manual TFTP(1) 4 | 5 | NAME 6 | tftp - trivial file transfer program 7 | 8 | SYNOPSIS 9 | tftp [host] 10 | 11 | DESCRIPTION 12 | Tftp is the user interface to the Internet TFTP (Trivial File Transfer Protocol), which allows users to transfer files to and from a remote machine. The remote 13 | host may be specified on the command line, in which case tftp uses host as the default host for future transfers (see the connect command below). 14 | 15 | COMMANDS 16 | Once tftp is running, it issues the prompt and recognizes the following commands: 17 | 18 | ? command-name ... 19 | Print help information. 20 | 21 | ascii Shorthand for "mode ascii" 22 | 23 | binary Shorthand for "mode binary" 24 | 25 | connect host-name [port] 26 | Set the host (and optionally port) for transfers. Note that the TFTP protocol, unlike the FTP protocol, does not maintain connections betwen transfers; 27 | thus, the connect command does not actually create a connection, but merely remembers what host is to be used for transfers. You do not have to use the 28 | connect command; the remote host can be specified as part of the get or put commands. 29 | 30 | get filename 31 | get remotename localname 32 | get file1 file2 ... fileN 33 | Get a file or set of files from the specified sources. Source can be in one of two forms: a filename on the remote host, if the host has already been 34 | specified, or a string of the form hosts:filename to specify both a host and filename at the same time. If the latter form is used, the last hostname 35 | specified becomes the default for future transfers. 36 | 37 | mode transfer-mode 38 | Set the mode for transfers; transfer-mode may be one of ascii or binary. The default is ascii. 39 | 40 | put file 41 | put localfile remotefile 42 | put file1 file2 ... fileN remote-directory 43 | Put a file or set of files to the specified remote file or directory. The destination can be in one of two forms: a filename on the remote host, if the 44 | host has already been specified, or a string of the form hosts:filename to specify both a host and filename at the same time. If the latter form is used, 45 | the hostname specified becomes the default for future transfers. If the remote-directory form is used, the remote host is assumed to be a UNIX machine. 46 | 47 | connect host-name [port] 48 | Set the host (and optionally port) for transfers. Note that the TFTP protocol, unlike the FTP protocol, does not maintain connections betwen transfers; 49 | thus, the connect command does not actually create a connection, but merely remembers what host is to be used for transfers. You do not have to use the 50 | connect command; the remote host can be specified as part of the get or put commands. 51 | 52 | get filename 53 | get remotename localname 54 | get file1 file2 ... fileN 55 | Get a file or set of files from the specified sources. Source can be in one of two forms: a filename on the remote host, if the host has already been 56 | specified, or a string of the form hosts:filename to specify both a host and filename at the same time. If the latter form is used, the last hostname 57 | specified becomes the default for future transfers. 58 | 59 | mode transfer-mode 60 | Set the mode for transfers; transfer-mode may be one of ascii or binary. The default is ascii. 61 | 62 | put file 63 | put localfile remotefile 64 | put file1 file2 ... fileN remote-directory 65 | Put a file or set of files to the specified remote file or directory. The destination can be in one of two forms: a filename on the remote host, if the 66 | host has already been specified, or a string of the form hosts:filename to specify both a host and filename at the same time. If the latter form is used, 67 | the hostname specified becomes the default for future transfers. If the remote-directory form is used, the remote host is assumed to be a UNIX machine. 68 | 69 | quit Exit tftp. An end of file also exits. 70 | 71 | rexmt retransmission-timeout 72 | Set the per-packet retransmission timeout, in seconds. 73 | 74 | status Show current status. 75 | 76 | timeout total-transmission-timeout 77 | Set the total transmission timeout, in seconds. 78 | 79 | trace Toggle packet tracing. 80 | 81 | verbose Toggle verbose mode. 82 | 83 | BUGS 84 | Because there is no user-login or validation within the TFTP protocol, the remote site will probably have some sort of file-access restrictions in place. The exact 85 | methods are specific to each site and therefore difficult to document here. 86 | 87 | HISTORY 88 | The tftp command appeared in 4.3BSD. 89 | 90 | Linux NetKit (0.17) August 15, 1999 Linux NetKit (0.17) 91 | """ 92 | return '' 93 | -------------------------------------------------------------------------------- /lib/clilib/unix/uname.py: -------------------------------------------------------------------------------- 1 | def uname(*params): 2 | """ 3 | UNAME(1) User Commands UNAME(1) 4 | 5 | NAME 6 | uname - print system information 7 | 8 | SYNOPSIS 9 | uname [OPTION]... 10 | 11 | DESCRIPTION 12 | Print certain system information. With no OPTION, same as -s. 13 | 14 | -a, --all 15 | print all information, in the following order, except omit -p 16 | and -i if unknown: 17 | 18 | -s, --kernel-name 19 | print the kernel name 20 | 21 | -n, --nodename 22 | print the network node hostname 23 | 24 | -r, --kernel-release 25 | print the kernel release 26 | 27 | -v, --kernel-version 28 | print the kernel version 29 | 30 | -m, --machine 31 | print the machine hardware name 32 | 33 | -p, --processor 34 | print the processor type or "unknown" 35 | 36 | -i, --hardware-platform 37 | print the hardware platform or "unknown" 38 | 39 | -o, --operating-system 40 | print the operating system 41 | 42 | --help display this help and exit 43 | 44 | --version 45 | output version information and exit 46 | 47 | AUTHOR 48 | Written by David MacKenzie. 49 | 50 | REPORTING BUGS 51 | GNU coreutils online help: http://www.gnu.org/software/coreutils/ 52 | Report uname translation bugs to http://translationproject.org/team/ 53 | 54 | COPYRIGHT 55 | Copyright @ 2014 Free Software Foundation, Inc. License GPLv3+: GNU 56 | GPL version 3 or later http://gnu.org/licenses/gpl.html. 57 | This is free software: you are free to change and redistribute it. 58 | There is NO WARRANTY, to the extent permitted by law. 59 | """ 60 | output = 'Linux' 61 | 62 | if None != params: 63 | for param in params: 64 | if param in ('-a', '--all'): 65 | output = 'Linux bitminer 3.16.0-4-amd64 #1 SMP Debian 3.16.7-ckt9-3~deb8u1 (2015-04-24) x86_64 GNU/Linux' 66 | 67 | return output 68 | -------------------------------------------------------------------------------- /lib/clilib/unix/unix.py: -------------------------------------------------------------------------------- 1 | from busybox import * 2 | from cd import * 3 | from echo import * 4 | from enable import * 5 | from rm import * 6 | from sh import * 7 | from tftp import * 8 | from uname import * 9 | from wget import * 10 | from which import * 11 | from whoami import * 12 | 13 | 14 | def man(command=None): 15 | if None == command or '' == command: 16 | return 'What manual page do you want?' 17 | else: 18 | return eval(command).__doc__ 19 | -------------------------------------------------------------------------------- /lib/clilib/unix/wget.py: -------------------------------------------------------------------------------- 1 | def wget(params=None): 2 | """ 3 | No manual entry for wget 4 | """ 5 | return '' 6 | -------------------------------------------------------------------------------- /lib/clilib/unix/whoami.py: -------------------------------------------------------------------------------- 1 | def whoami(user, *params): 2 | """ 3 | WHOAMI(1) User Commands WHOAMI(1) 4 | 5 | NAME 6 | whoami - print effective userid 7 | 8 | SYNOPSIS 9 | whoami [OPTION]... 10 | 11 | DESCRIPTION 12 | Print the user name associated with the current effective user ID. Same as id -un. 13 | 14 | --help display this help and exit 15 | 16 | --version 17 | output version information and exit 18 | 19 | AUTHOR 20 | Written by Richard Mlynarik. 21 | 22 | REPORTING BUGS 23 | GNU coreutils online help: 24 | Report whoami translation bugs to 25 | 26 | COPYRIGHT 27 | Copyright @ 2014 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later 28 | . 29 | This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent 30 | permitted by law. 31 | 32 | SEE ALSO 33 | Full documentation at: 34 | or available locally via: info '(coreutils) whoami invocation' 35 | 36 | GNU coreutils 8.23 March 2015 WHOAMI(1) 37 | """ 38 | 39 | output = str(user) 40 | 41 | if None != params: 42 | for param in params: 43 | if param in ('--help'): 44 | output = "Usage: whoami [OPTION]...\nPrint the user name associated with the current effective user ID.\nSame as id -un.\n\n --help display this help and exit\n --version output version information and exit\n\nGNU coreutils online help: \nFull documentation at: \nor available locally via: info '(coreutils) whoami invocation'" 45 | elif param in ('--version'): 46 | output = 'whoami (GNU coreutils) 8.23\nCopyright (C) 2014 Free Software Foundation, Inc.\nLicense GPLv3+: GNU GPL version 3 or later .\nThis is free software: you are free to change and redistribute it.\nThere is NO WARRANTY, to the extent permitted by law.\n\nWritten by Richard Mlynarik.' 47 | 48 | return output 49 | -------------------------------------------------------------------------------- /lib/clilib/windows/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | clilib.windows 3 | =========== 4 | """ 5 | 6 | from windows import * 7 | -------------------------------------------------------------------------------- /lib/clilib/windows/windows.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/foospidy/HoneyPy/6ca3d6eb603b7aa11aac5c908db12c0a3e78000f/lib/clilib/windows/windows.py -------------------------------------------------------------------------------- /lib/followtail.py: -------------------------------------------------------------------------------- 1 | # Twisted FollowTail 2 | # Mohit Muthanna 3 | # 4 | # A Twisted version of POE::Wheel::FollowTail. Adapted from 5 | # a post by Kragen Sitaker on the Kragen-hacks mailing list. 6 | # 7 | # http://lists.canonical.org/pipermail/kragen-hacks/2005-June/000413.html 8 | # http://0xfe.blogspot.com/2006/03/following-log-file-with-twisted.html 9 | 10 | from twisted.internet import reactor 11 | from twisted.protocols import basic 12 | import os, stat 13 | 14 | class FollowTail: 15 | from os import linesep as newline 16 | __line_buffer = "" 17 | 18 | def __init__( self, filename = None, seekend = True, delay = 1 ): 19 | self.filename = filename 20 | self.delay = delay 21 | self.seekend = seekend 22 | self.keeprunning = False 23 | 24 | def fileIdentity( self, struct_stat ): 25 | return struct_stat[stat.ST_DEV], struct_stat[stat.ST_INO] 26 | 27 | def start( self ): 28 | self.keeprunning = True 29 | self.followTail() 30 | 31 | def stop( self ): 32 | self.keeprunning = False 33 | 34 | def followTail( self, fileobj = None, fstat = None, offset = 0 ): 35 | if fileobj is None: 36 | fileobj = open( self.filename ) 37 | if self.seekend: fileobj.seek( 0, 2 ) 38 | # Save offset of reference pointer 39 | offset = fileobj.tell() 40 | 41 | # Seek to the reference pointer 42 | fileobj.seek(offset) 43 | 44 | line = fileobj.read() 45 | if line: self.dataReceived( line ) 46 | 47 | # Save new reference pointer after read 48 | offset = fileobj.tell() 49 | 50 | if fstat is None: fstat = os.fstat( fileobj.fileno() ) 51 | 52 | try: stat = os.stat( self.filename ) 53 | except: stat = fstat 54 | 55 | if self.fileIdentity( stat ) != self.fileIdentity( fstat ): 56 | fileobj = open( self.filename ) 57 | offset = 0 58 | fstat = os.fstat( fileobj.fileno() ) 59 | self.fileReset() 60 | 61 | if self.keeprunning: 62 | reactor.callLater( self.delay, lambda: self.followTail( fileobj, fstat, offset ) ) 63 | 64 | def dataReceived( self, data ): 65 | # Fill buffer 66 | self.__line_buffer += data 67 | 68 | # Split lines 69 | lines = self.__line_buffer.splitlines() 70 | 71 | if not data.endswith( self.newline ): 72 | self.__line_buffer = lines.pop() 73 | else: 74 | self.__line_buffer = "" 75 | 76 | for line in lines: 77 | self.lineReceived( line ) 78 | 79 | def lineReceived( self, line ): 80 | """Override This""" 81 | 82 | def fileReset( self ): 83 | """Override This""" 84 | -------------------------------------------------------------------------------- /lib/honeypy_console.py: -------------------------------------------------------------------------------- 1 | # HoneyPy Copyright (C) 2013-2017 foospidy 2 | # https://github.com/foospidy/HoneyPy 3 | # See LICENSE for details 4 | # HoneyPy Console 5 | 6 | import os 7 | import shutil 8 | from twisted.internet import reactor 9 | from twisted.protocols import basic 10 | 11 | 12 | class HoneyPyConsole(basic.LineReceiver): 13 | from os import linesep as delimiter 14 | 15 | def connectionMade(self): 16 | self.do_banner() 17 | self.sendLine('HoneyPy Console. For help type \'help\'.') 18 | self.transport.write('HoneyPy> ') 19 | 20 | def lineReceived(self, line): 21 | if not line: 22 | self.transport.write('HoneyPy> ') 23 | return 24 | 25 | # Parse command 26 | commandParts = line.split() 27 | command = commandParts[0].lower() 28 | args = commandParts[1:] 29 | 30 | try: 31 | method = getattr(self, 'do_' + command) 32 | except AttributeError, e: 33 | self.sendLine('Error: no such command.') 34 | else: 35 | try: 36 | method(*args) 37 | except Exception, e: 38 | self.sendLine('Error: ' + str(e)) 39 | 40 | exit_commands = ['exit', 'quit'] 41 | 42 | if command not in exit_commands: 43 | self.transport.write('HoneyPy> ') 44 | 45 | def do_help(self, command=None): 46 | """help [command]: List commands, or show help on the given command""" 47 | if command: 48 | self.sendLine(getattr(self, 'do_' + command).__doc__) 49 | else: 50 | commands = [cmd[3:] for cmd in dir(self) if cmd.startswith('do_')] 51 | self.sendLine("Valid commands: " + " ".join(commands)) 52 | 53 | def do_start(self): 54 | """start: Start all configured services""" 55 | if len(self.services[1]) == 0: 56 | self.sendLine('No services are enabled.') 57 | else: 58 | i = 0 59 | for i in range(len(self.services[1])): 60 | self.services[1][i].startListening() 61 | 62 | self.sendLine(str(i + 1) + ' service(s) started!') 63 | 64 | def do_stop(self): 65 | """stop: Stop all configured services""" 66 | i = 0 67 | for i in range(len(self.services[1])): 68 | self.services[1][i].stopListening() 69 | 70 | self.sendLine(str(i + 1) + ' service(s) stopped!') 71 | 72 | def do_banner(self): 73 | """banner: Display HoneyPy banner""" 74 | banner = 'ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBfX18gICAgICAgCiAgL1wgIC9cX19fICBfIF9fICAgX19fIF8gICBfICAvIF8gXF8gICBfIAogLyAvXy8gLyBfIFx8ICdfIFwgLyBfIFwgfCB8IHwvIC9fKS8gfCB8IHwKLyBfXyAgLyAoXykgfCB8IHwgfCAgX18vIHxffCAvIF9fXy98IHxffCB8ClwvIC9fLyBcX19fL3xffCB8X3xcX19ffFxfXywgXC8gICAgIFxfXywgfAogICAgICAgICAgICAgICAgICAgICAgICB8X19fLyAgICAgICB8X19fLyAKCg==' 75 | 76 | self.sendLine(banner.decode("base64")) 77 | self.sendLine('[HoneyPy Copyright (c) 2013-2017. foospidy]\n') 78 | 79 | def do_list(self, list='services'): 80 | """list: List information. Usage: list [services|profiles|loggers]""" 81 | if list == 'profiles': 82 | self._list_profiles() 83 | elif list == 'loggers': 84 | self._list_loggers() 85 | else: 86 | self._list_services() 87 | 88 | def _list_services(self): 89 | """list services: List all configured services""" 90 | for i in range(len(self.services[0])): 91 | self.sendLine(self.services[0][i] + '\t' + str(self.services[1][i])) 92 | 93 | def _list_loggers(self): 94 | """list loggers: List all enabled loggers""" 95 | for section in self.config.sections(): 96 | if section != 'honeypy': 97 | if self.config.get(section, 'enabled').lower() == 'yes': 98 | self.sendLine('\t Enabled\t'+section) 99 | else: 100 | self.sendLine('\t Disabled\t'+section) 101 | 102 | @staticmethod 103 | def _list_profiles(): 104 | """list profiles: List all availible profiles""" 105 | path = 'etc/profiles/' 106 | files = next(os.walk(path))[2] 107 | 108 | for f in files: 109 | parts = f.split('.') 110 | if parts[0] == 'services' and parts[2] == 'profile': 111 | print parts[1] 112 | 113 | def do_set(self, setting='profile', value='default'): 114 | """set: Change settings. Usage: set profile """ 115 | if self._set_profile(value) and setting == 'profile': 116 | print 'Profile changed to ' + value 117 | print 'Quit and restart HoneyPy for profile change to take effect!' 118 | else: 119 | print 'Error! No change.' 120 | 121 | @staticmethod 122 | def _set_profile(profile='default'): 123 | changed = False 124 | src = 'etc/profiles/services.' + profile + '.profile' 125 | dst = 'etc/services.cfg' 126 | 127 | if os.path.isfile(dst): 128 | shutil.copy2(src, dst) 129 | changed = True 130 | 131 | return changed 132 | 133 | def do_test(self, test='loggers'): 134 | """test: Generate a test event""" 135 | if test == 'loggers': 136 | self._test_loggers() 137 | 138 | @staticmethod 139 | def _test_loggers(): 140 | """test loggers: generate atest event""" 141 | from twisted.python import log 142 | log.msg('%s %s TCP TEST %s %s %s %s %s %s' % ('session', "test", '127.0.0.1', '-1', 'test', '127.0.0.1', '-1', 'TestFromHoneyPyConsole'), system='test') 143 | 144 | def do_exit(self): 145 | """exit: Exit HoneyPy""" 146 | self.sendLine('Goodbye.') 147 | self.transport.loseConnection() 148 | 149 | def do_quit(self): 150 | """quit: Quit HoneyPy""" 151 | self.sendLine('Goodbye.') 152 | self.transport.loseConnection() 153 | 154 | def connectionLost(self, reason): 155 | # stop the reactor, only because this is meant to be run in Stdio. 156 | reactor.stop() 157 | 158 | def __init__(self, config, services): 159 | self.config = config 160 | self.services = services 161 | -------------------------------------------------------------------------------- /lib/honeypy_logtail.py: -------------------------------------------------------------------------------- 1 | import os 2 | from importlib import import_module 3 | from twisted.python import log 4 | from twisted.python.logfile import DailyLogFile 5 | from lib.followtail import FollowTail 6 | 7 | class HoneyPyLogTail(FollowTail): 8 | config = None 9 | persistent_conns = {} 10 | 11 | def lineReceived(self, line): 12 | parts = line.split() 13 | # TCP 14 | # parts[0]: date 15 | # parts[1]: time_parts 16 | # parts[2]: plugin 17 | # parts[3]: session 18 | # parts[4]: protocol 19 | # parts[5]: event 20 | # parts[6]: local_host 21 | # parts[7]: local_port 22 | # parts[8]: service 23 | # parts[9]: remote_host 24 | # parts[10]: remote_port 25 | # parts[11]: data 26 | # UDP 27 | # parts[0]: date 28 | # parts[1]: time_parts 29 | # parts[2]: plugin string part 30 | # parts[3]: plugin string part 31 | # parts[4]: session 32 | # parts[5]: protocol 33 | # parts[6]: event 34 | # parts[7]: local_host 35 | # parts[8]: local_port 36 | # parts[9]: service 37 | # parts[10]: remote_host 38 | # parts[11]: remote_port 39 | # parts[12]: data 40 | 41 | # only process actual events 42 | if len(parts) > 10: 43 | # this is a bit hacky - need to handle log message parsing better. 44 | if parts[2] != '[-]' and parts[0] != 'details': 45 | # time_parts[0]: time 46 | # time_parts[1]: millisecond 47 | # time_parts[2]: time zone 48 | time_parts = parts[1].split(',') 49 | 50 | #determin remote_host 51 | if parts[4] == 'TCP': 52 | remote_host = parts[9] 53 | else: 54 | remote_host = parts[10] 55 | 56 | #check if remote host is in whitelist 57 | if self.config.has_option('honeypy', 'whitelist') and remote_host in self.config.get('honeypy', 'whitelist').split(','): 58 | log.msg("Remote host %s is whitelisted, external logging surpressed." % remote_host) 59 | else: 60 | try: 61 | # iterate through the configured sections, but not the main app section 62 | for section in self.config.sections(): 63 | if section != 'honeypy' and self.config.get(section, 'enabled').lower() == 'yes': 64 | module_name = "loggers.%s.honeypy_%s" % (section, section) 65 | logger_module = import_module(module_name) 66 | if section in self.persistent_conns: 67 | logger_module.process(self.config, self.persistent_conns[section], section, parts, time_parts) 68 | else: 69 | logger_module.process(self.config, section, parts, time_parts) 70 | 71 | except Exception as e: 72 | log.msg('Exception: HoneyPyLogTail: {}: {}'.format(str(e), str(parts))) 73 | 74 | 75 | class SingleDailyLogFile(DailyLogFile): 76 | def rotate(self): 77 | DailyLogFile.rotate(self) 78 | dir = os.path.dirname(self.path) 79 | files = os.listdir(dir) 80 | for file in files: 81 | if file.startswith("honeypy.log."): 82 | os.remove(os.path.join(dir, file)) 83 | -------------------------------------------------------------------------------- /loggers/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 foospidy 2 | # https://github.com/foospidy/HoneyPy 3 | # See LICENSE for details 4 | 5 | import sys 6 | # prevent creation of compiled bytecode files 7 | sys.dont_write_bytecode = True 8 | -------------------------------------------------------------------------------- /loggers/elasticsearch/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 foospidy 2 | # https://github.com/foospidy/HoneyPy 3 | # See LICENSE for details 4 | 5 | import sys 6 | # prevent creation of compiled bytecode files 7 | sys.dont_write_bytecode = True 8 | -------------------------------------------------------------------------------- /loggers/elasticsearch/honeypy_elasticsearch.py: -------------------------------------------------------------------------------- 1 | # HoneyPy Copyright (C) 2013-2017 foospidy 2 | # https://github.com/foospidy/HoneyPy 3 | # See LICENSE for details 4 | # HoneyPy elasticsearch logger 5 | 6 | import sys 7 | import hashlib 8 | from datetime import datetime 9 | import requests 10 | from twisted.python import log 11 | 12 | # prevent creation of compiled bytecode files 13 | sys.dont_write_bytecode = True 14 | 15 | def process(config, section, parts, time_parts): 16 | # TCP 17 | # parts[0]: date 18 | # parts[1]: time_parts 19 | # parts[2]: plugin 20 | # parts[3]: session 21 | # parts[4]: protocol 22 | # parts[5]: event 23 | # parts[6]: local_host 24 | # parts[7]: local_port 25 | # parts[8]: service 26 | # parts[9]: remote_host 27 | # parts[10]: remote_port 28 | # parts[11]: data 29 | # UDP 30 | # parts[0]: date 31 | # parts[1]: time_parts 32 | # parts[2]: plugin string part 33 | # parts[3]: plugin string part 34 | # parts[4]: session 35 | # parts[5]: protocol 36 | # parts[6]: event 37 | # parts[7]: local_host 38 | # parts[8]: local_port 39 | # parts[9]: service 40 | # parts[10]: remote_host 41 | # parts[11]: remote_port 42 | # parts[12]: data 43 | if parts[4] == 'TCP': 44 | if len(parts) == 11: 45 | parts.append('') # no data for CONNECT events 46 | 47 | post(config, section, parts[0], time_parts[0], parts[0] + ' ' + time_parts[0], time_parts[1], parts[3], parts[4], parts[5], parts[6], parts[7], parts[8], parts[9], parts[10], parts[11]) 48 | else: 49 | # UDP splits differently (see comment section above) 50 | if len(parts) == 12: 51 | parts.append('') # no data sent 52 | 53 | post(config, section, parts[0], time_parts[0], parts[0] + ' ' + time_parts[0], time_parts[1], parts[4], parts[5], parts[6], parts[7], parts[8], parts[9], parts[10], parts[11], parts[12]) 54 | 55 | 56 | def post(config, section, date, time, date_time, millisecond, session, protocol, event, local_host, local_port, service, remote_host, remote_port, data): 57 | useragent = config.get('honeypy', 'useragent') 58 | url = config.get(section, 'es_url') 59 | # post events to honeydb logger 60 | h = hashlib.md5() 61 | h.update(data) 62 | 63 | #formatting date_time as iso format so that Kibana will recognize it as a date field 64 | date_time = datetime.strptime(date_time, "%Y-%m-%d %H:%M:%S").isoformat() 65 | 66 | headers = {'User-Agent': useragent, "Content-Type": "application/json"} 67 | # applying [:-3] to time to truncate millisecond 68 | data = { 69 | 'date': date, 70 | 'time': time, 71 | 'date_time': date_time, 72 | 'millisecond': str(millisecond)[:-3], 73 | 'session': session, 74 | 'protocol': protocol, 75 | 'event': event, 76 | 'local_host': local_host, 77 | 'local_port': local_port, 78 | 'service': service, 79 | 'remote_host': remote_host, 80 | 'remote_port': remote_port, 81 | 'data': data, 82 | 'bytes': str(len(data)), 83 | 'data_hash': h.hexdigest() 84 | } 85 | 86 | try: 87 | r = requests.post(url, headers=headers, json=data, timeout=3) 88 | page = r.text 89 | 90 | log.msg('Post event to %s, response: %s' % (section, str(page).strip())) 91 | except Exception as e: 92 | log.msg('Error posting to %s: %s' % (section, str(e.message).strip())) 93 | -------------------------------------------------------------------------------- /loggers/file/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 foospidy 2 | # https://github.com/foospidy/HoneyPy 3 | # See LICENSE for details 4 | 5 | import sys 6 | # prevent creation of compiled bytecode files 7 | sys.dont_write_bytecode = True 8 | -------------------------------------------------------------------------------- /loggers/file/honeypy_file.py: -------------------------------------------------------------------------------- 1 | # HoneyPy Copyright (C) 2013-2017 foospidy 2 | # https://github.com/foospidy/HoneyPy 3 | # See LICENSE for details 4 | import sys 5 | import hashlib 6 | from datetime import datetime 7 | from twisted.python import log 8 | import json 9 | import os 10 | 11 | # prevent creation of compiled bytecode files 12 | sys.dont_write_bytecode = True 13 | file = None 14 | 15 | def process(config, section, parts, time_parts): 16 | # TCP 17 | # parts[0]: date 18 | # parts[1]: time_parts 19 | # parts[2]: plugin 20 | # parts[3]: session 21 | # parts[4]: protocol 22 | # parts[5]: event 23 | # parts[6]: local_host 24 | # parts[7]: local_port 25 | # parts[8]: service 26 | # parts[9]: remote_host 27 | # parts[10]: remote_port 28 | # parts[11]: data 29 | # UDP 30 | # parts[0]: date 31 | # parts[1]: time_parts 32 | # parts[2]: plugin string part 33 | # parts[3]: plugin string part 34 | # parts[4]: session 35 | # parts[5]: protocol 36 | # parts[6]: event 37 | # parts[7]: local_host 38 | # parts[8]: local_port 39 | # parts[9]: service 40 | # parts[10]: remote_host 41 | # parts[11]: remote_port 42 | # parts[12]: data 43 | 44 | if parts[4] == 'TCP': 45 | if len(parts) == 11: 46 | parts.append('') # no data for CONNECT events 47 | 48 | post(config, section, parts[0], time_parts[0], parts[0] + ' ' + time_parts[0], time_parts[1], parts[3], parts[4], parts[5], parts[6], parts[7], parts[8], parts[9], parts[10], parts[11]) 49 | else: 50 | # UDP splits differently (see comment section above) 51 | if len(parts) == 12: 52 | parts.append('') # no data sent 53 | 54 | post(config, section, parts[0], time_parts[0], parts[0] + ' ' + time_parts[0], time_parts[1], parts[4], parts[5], parts[6], parts[7], parts[8], parts[9], parts[10], parts[11], parts[12]) 55 | 56 | 57 | def post(config, section, date, time, date_time, millisecond, session, protocol, event, local_host, local_port, service, remote_host, remote_port, data): 58 | global file 59 | 60 | h = hashlib.md5() 61 | h.update(data) 62 | 63 | date_time = datetime.strptime(date_time, "%Y-%m-%d %H:%M:%S").isoformat() 64 | 65 | # applying [:-3] to time to truncate millisecond 66 | data = { 67 | 'date': date, 68 | 'time': time, 69 | 'date_time': date_time, 70 | 'millisecond': str(millisecond)[:-3], 71 | 'session': session, 72 | 'protocol': protocol, 73 | 'event': event, 74 | 'local_host': local_host, 75 | 'local_port': local_port, 76 | 'service': service, 77 | 'remote_host': remote_host, 78 | 'remote_port': remote_port, 79 | 'data': data, 80 | 'bytes': str(len(data)), 81 | 'data_hash': h.hexdigest() 82 | } 83 | 84 | if not file: 85 | file = open(config.get(section, 'filename'), 'a+', 1) 86 | 87 | file.write(json.dumps(data) + os.linesep) 88 | -------------------------------------------------------------------------------- /loggers/honeydb/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 foospidy 2 | # https://github.com/foospidy/HoneyPy 3 | # See LICENSE for details 4 | 5 | import sys 6 | # prevent creation of compiled bytecode files 7 | sys.dont_write_bytecode = True 8 | -------------------------------------------------------------------------------- /loggers/honeydb/honeypy_honeydb.py: -------------------------------------------------------------------------------- 1 | # HoneyPy Copyright (C) 2013-2017 foospidy 2 | # https://github.com/foospidy/HoneyPy 3 | # See LICENSE for details 4 | # HoneyPy HoneyDB logger 5 | 6 | import sys 7 | import hashlib 8 | import itertools 9 | import operator 10 | import json 11 | import random 12 | from uuid import getnode 13 | import requests 14 | from twisted.python import log 15 | 16 | # prevent creation of compiled bytecode files 17 | sys.dont_write_bytecode = True 18 | 19 | 20 | def process(config, section, parts, time_parts): 21 | # TCP 22 | # parts[0]: date 23 | # parts[1]: time_parts 24 | # parts[2]: plugin 25 | # parts[3]: session 26 | # parts[4]: protocol 27 | # parts[5]: event 28 | # parts[6]: local_host 29 | # parts[7]: local_port 30 | # parts[8]: service 31 | # parts[9]: remote_host 32 | # parts[10]: remote_port 33 | # parts[11]: data 34 | # UDP 35 | # parts[0]: date 36 | # parts[1]: time_parts 37 | # parts[2]: plugin string part 38 | # parts[3]: plugin string part 39 | # parts[4]: session 40 | # parts[5]: protocol 41 | # parts[6]: event 42 | # parts[7]: local_host 43 | # parts[8]: local_port 44 | # parts[9]: service 45 | # parts[10]: remote_host 46 | # parts[11]: remote_port 47 | # parts[12]: data 48 | # class varaibles for HoneyDB 49 | got_hmac = False 50 | hmac_hash = None 51 | hmac_message = None 52 | 53 | if hmac_hash is None: 54 | log.msg('HoneyDB logger: retrieving initial hmac.') 55 | got_hmac, hmac_hash, hmac_message, collectors = get_hmac(config, section) 56 | 57 | for i in range(1, 4): 58 | log.msg('HoneyDB logger: post attempt {}.'.format(i)) 59 | 60 | if got_hmac: 61 | response = None 62 | 63 | if parts[4] == 'TCP': 64 | if len(parts) == 11: 65 | parts.append('') # no data for CONNECT events 66 | 67 | response = post(hmac_hash, hmac_message, collectors, config, section, parts[0], time_parts[0], parts[0] + ' ' + time_parts[0], time_parts[1], parts[3], parts[4], parts[5], parts[6], parts[7], parts[8], parts[9], parts[10], parts[11]) 68 | 69 | else: 70 | # UDP splits differently (see comment section above) 71 | if len(parts) == 12: 72 | parts.append('') # no data sent 73 | 74 | response = post(hmac_hash, hmac_message, collectors, config, section, parts[0], time_parts[0], parts[0] + ' ' + time_parts[0], time_parts[1], parts[4], parts[5], parts[6], parts[7], parts[8], parts[9], parts[10], parts[11], parts[12]) 75 | 76 | if response == 'Success': 77 | break 78 | 79 | else: 80 | if response == 'Invalid HMAC' and i < 3: 81 | log.msg('HoneyDB logger: hmac invalid, retrieving new hmac.') 82 | got_hmac, hmac_hash, hmac_message, collectors = get_hmac(config, section) 83 | 84 | elif response == 'Invalid HMAC' and i == 3: 85 | log.msg('HoneyDB logger: hmac invalid, 3 failed attempts, giving up.') 86 | 87 | elif i < 3: 88 | log.msg('HoneyDB logger: {}, make another attempt.'.format(response)) 89 | 90 | else: 91 | log.msg('HoneyDB logger: {}, 3 failed attempts, giving up.'.format(response)) 92 | 93 | def get_hmac(config, section): 94 | useragent = config.get('honeypy', 'useragent') 95 | api_id = config.get('honeydb', 'api_id') 96 | api_key = config.get('honeydb', 'api_key') 97 | 98 | hmac_url = 'https://riskdiscovery.com/honeydb/api/hmac' 99 | 100 | headers = {'User-Agent': useragent, 'X-HoneyDb-ApiId': api_id, 'X-HoneyDb-ApiKey': api_key} 101 | 102 | try: 103 | r = requests.get(hmac_url, headers=headers, timeout=3) 104 | j = json.loads(r.text) 105 | 106 | if j['status'] == 'Success': 107 | log.msg('HoneyDB logger: hmac received with message: {}'.format(j['hmac_message'])) 108 | return True, j['hmac_hash'], j['hmac_message'], j['collectors'] 109 | else: 110 | raise Exception(j['status']) 111 | 112 | except Exception as e: 113 | log.msg('HoneyDB logger: Error retrieving hmac: %s' % (str(e.message).strip())) 114 | return False, None, None 115 | 116 | def post(hmac_hash, hmac_message, collectors, config, section, date, time, date_time, millisecond, session, protocol, event, local_host, local_port, service, remote_host, remote_port, data): 117 | useragent = config.get('honeypy', 'useragent') 118 | url = random.choice(collectors) 119 | 120 | # post events to honeydb logger 121 | h = hashlib.md5() 122 | h.update(data) 123 | 124 | mac_addr = ':'.join((itertools.starmap(operator.add, zip(*([iter("%012X" % getnode())] * 2))))) 125 | 126 | headers = {'User-Agent': useragent, "Content-Type": "application/json"} 127 | # applying [:-3] to time to truncate millisecond 128 | data = { 129 | 'date': date, 130 | 'time': time, 131 | 'date_time': date_time, 132 | 'millisecond': str(millisecond)[:-3], 133 | 'hmac_hash': hmac_hash, 134 | 'hmac_message': hmac_message, 135 | 'session': session, 136 | 'protocol': protocol, 137 | 'event': event, 138 | 'local_host': local_host, 139 | 'local_port': local_port, 140 | 'service': service, 141 | 'remote_host': remote_host, 142 | 'remote_port': remote_port, 143 | 'data': data, 144 | 'bytes': str(len(data)), 145 | 'data_hash': h.hexdigest(), 146 | 'node': mac_addr 147 | } 148 | 149 | try: 150 | r = requests.post(url, headers=headers, json=data, timeout=10) 151 | response = json.loads(r.text) 152 | 153 | log.msg('Post event to %s, response: %s' % (section, str(response).strip().replace('\n', ' '))) 154 | 155 | return response['status'] 156 | 157 | except Exception as e: 158 | log.msg('%s logger, post error: %s' % (section, str(e.message).strip().replace('\n', ' '))) 159 | 160 | return 'Error' 161 | -------------------------------------------------------------------------------- /loggers/hpfeeds/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 foospidy 2 | # https://github.com/foospidy/HoneyPy 3 | # See LICENSE for details 4 | 5 | import sys 6 | # prevent creation of compiled bytecode files 7 | sys.dont_write_bytecode = True 8 | -------------------------------------------------------------------------------- /loggers/hpfeeds/honeypy_hpfeeds.py: -------------------------------------------------------------------------------- 1 | # HoneyPy hpfeeds module 2 | 3 | import sys 4 | import hashlib 5 | from datetime import datetime 6 | from twisted.python import log 7 | import json 8 | import os 9 | import socket 10 | 11 | 12 | class hpflogger: 13 | def __init__(self, hpfserver, hpfport, hpfident, hpfsecret, hpfchannel, serverid): 14 | self.hpfserver = hpfserver 15 | self.hpfport = hpfport 16 | self.hpfident = hpfident 17 | self.hpfsecret = hpfsecret 18 | self.hpfchannel = hpfchannel 19 | self.serverid = serverid 20 | self.hpc = None 21 | if (self.hpfserver and self.hpfport and self.hpfident and self.hpfport and self.hpfchannel and self.serverid): 22 | import logging 23 | logging.basicConfig() 24 | import hpfeeds 25 | try: 26 | self.hpc = hpfeeds.new(self.hpfserver, self.hpfport, self.hpfident, self.hpfsecret) 27 | self.status = "Logging to hpfeeds using server: {0}, channel {1}.".format(self.hpfserver, self.hpfchannel) 28 | except (hpfeeds.FeedException, socket.error, hpfeeds.Disconnect): 29 | self.status = "hpfeeds connection not successful" 30 | def log(self, message): 31 | if self.hpc: 32 | message['serverid'] = self.serverid 33 | self.hpc.publish(self.hpfchannel, json.dumps(message)) 34 | 35 | def conn(config, section): 36 | environreq = [ 37 | 'HPFEEDS_SERVER', 38 | 'HPFEEDS_PORT', 39 | 'HPFEEDS_IDENT', 40 | 'HPFEEDS_SECRET', 41 | 'HPFEEDS_CHANNEL', 42 | 'SERVERID', 43 | ] 44 | if all(var in os.environ for var in environreq): 45 | hpfserver = os.environ.get('HPFEEDS_SERVER') 46 | hpfport = int(os.environ.get('HPFEEDS_PORT')) 47 | hpfident = os.environ.get('HPFEEDS_IDENT') 48 | hpfsecret = os.environ.get('HPFEEDS_SECRET') 49 | hpfchannel = os.environ.get('HPFEEDS_CHANNEL') 50 | serverid = os.environ.get('SERVERID') 51 | else: 52 | hpfserver = config.get(section, 'server') 53 | hpfport = int(config.get(section, 'port')) 54 | hpfident = config.get(section, 'ident') 55 | hpfsecret = config.get(section, 'secret') 56 | hpfchannel = config.get(section, 'channel') 57 | serverid = config.get(section, 'server') 58 | 59 | return hpflogger(hpfserver, hpfport, hpfident, hpfsecret, hpfchannel, serverid) 60 | 61 | def process(config, connection, section, parts, time_parts): 62 | # TCP 63 | # parts[0]: date 64 | # parts[1]: time_parts 65 | # parts[2]: plugin 66 | # parts[3]: session 67 | # parts[4]: protocol 68 | # parts[5]: event 69 | # parts[6]: local_host 70 | # parts[7]: local_port 71 | # parts[8]: service 72 | # parts[9]: remote_host 73 | # parts[10]: remote_port 74 | # parts[11]: data 75 | # UDP 76 | # parts[0]: date 77 | # parts[1]: time_parts 78 | # parts[2]: plugin string part 79 | # parts[3]: plugin string part 80 | # parts[4]: session 81 | # parts[5]: protocol 82 | # parts[6]: event 83 | # parts[7]: local_host 84 | # parts[8]: local_port 85 | # parts[9]: service 86 | # parts[10]: remote_host 87 | # parts[11]: remote_port 88 | # parts[12]: data 89 | 90 | if parts[4] == 'TCP': 91 | if len(parts) == 11: 92 | parts.append('') # no data for CONNECT events 93 | post(config, section, parts[0], time_parts[0], time_parts[1], parts[3], parts[4], parts[5], parts[6], parts[7], parts[8], parts[9], parts[10], parts[11], connection) 94 | else: 95 | # UDP splits differently (see comment section above) 96 | if len(parts) == 12: 97 | parts.append('') # no data sent 98 | post(config, section, parts[0], time_parts[0], time_parts[1], parts[4], parts[5], parts[6], parts[7], parts[8], parts[9], parts[10], parts[11], parts[12], connection) 99 | 100 | 101 | def post(config, section, date, time, millisecond, session, protocol, event, local_host, local_port, service, remote_host, remote_port, data, connection): 102 | 103 | date_time = date + ' ' + time + '.' + str(millisecond) 104 | date_time = datetime.strptime(date_time, "%Y-%m-%d %H:%M:%S.%f").isoformat() + 'Z' 105 | 106 | msg = { 107 | 'date_time': date_time, 108 | 'protocol': protocol, 109 | 'service': service, 110 | 'dst_host': local_host, 111 | 'dst_port': local_port, 112 | 'src_host': remote_host, 113 | 'src_port': remote_port, 114 | 'session': session, 115 | 'event': event, 116 | 'data': data, 117 | } 118 | 119 | # submit log 120 | connection.log(msg) -------------------------------------------------------------------------------- /loggers/logstash/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 foospidy 2 | # https://github.com/foospidy/HoneyPy 3 | # See LICENSE for details 4 | 5 | import sys 6 | # prevent creation of compiled bytecode files 7 | sys.dont_write_bytecode = True 8 | -------------------------------------------------------------------------------- /loggers/logstash/honeypy_logstash.py: -------------------------------------------------------------------------------- 1 | # HoneyPy Copyright (C) 2013-2017 foospidy 2 | # https://github.com/foospidy/HoneyPy 3 | # See LICENSE for details 4 | # HoneyPy logstash logger 5 | 6 | import sys 7 | import hashlib 8 | import socket 9 | import json 10 | from twisted.python import log 11 | 12 | # prevent creation of compiled bytecode files 13 | sys.dont_write_bytecode = True 14 | 15 | def process(config, section, parts, time_parts): 16 | # TCP 17 | # parts[0]: date 18 | # parts[1]: time_parts 19 | # parts[2]: plugin 20 | # parts[3]: session 21 | # parts[4]: protocol 22 | # parts[5]: event 23 | # parts[6]: local_host 24 | # parts[7]: local_port 25 | # parts[8]: service 26 | # parts[9]: remote_host 27 | # parts[10]: remote_port 28 | # parts[11]: data 29 | # UDP 30 | # parts[0]: date 31 | # parts[1]: time_parts 32 | # parts[2]: plugin string part 33 | # parts[3]: plugin string part 34 | # parts[4]: session 35 | # parts[5]: protocol 36 | # parts[6]: event 37 | # parts[7]: local_host 38 | # parts[8]: local_port 39 | # parts[9]: service 40 | # parts[10]: remote_host 41 | # parts[11]: remote_port 42 | # parts[12]: data 43 | 44 | if parts[4] == 'TCP': 45 | if len(parts) == 11: 46 | parts.append('') # no data for CONNECT events 47 | 48 | post(config.get(section, 'host'), config.get(section, 'port'), parts[0], time_parts[0], parts[0] + ' ' + time_parts[0], time_parts[1], parts[3], parts[4], parts[5], parts[6], parts[7], parts[8], parts[9], parts[10], parts[11]) 49 | else: 50 | # UDP splits differently (see comment section above) 51 | if len(parts) == 12: 52 | parts.append('') # no data sent 53 | 54 | post(config.get(section, 'host'), config.get(section, 'port'), parts[0], time_parts[0], parts[0] + ' ' + time_parts[0], time_parts[1], parts[4], parts[5], parts[6], parts[7], parts[8], parts[9], parts[10], parts[11], parts[12]) 55 | 56 | 57 | def post(host, port, date, time, date_time, millisecond, session, protocol, event, local_host, local_port, service, remote_host, remote_port, data): 58 | # post events to honeydb logger 59 | h = hashlib.md5() 60 | h.update(data) 61 | 62 | # applying [:-3] to time to truncate millisecond 63 | data = { 64 | 'date': date, 65 | 'time': time, 66 | 'date_time': date_time, 67 | 'millisecond': str(millisecond)[:-3], 68 | 'session': session, 69 | 'protocol': protocol, 70 | 'event': event, 71 | 'local_host': local_host, 72 | 'local_port': local_port, 73 | 'service': service, 74 | 'remote_host': remote_host, 75 | 'remote_port': remote_port, 76 | 'data': data, 77 | 'bytes': str(len(data)), 78 | 'data_hash': h.hexdigest() 79 | } 80 | 81 | try: 82 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 83 | sock.connect((host, int(port))) 84 | bytes_sent = sock.send(json.dumps(data)) 85 | sock.close() 86 | 87 | log.msg('Post event to logstash! (%s bytes)' % str(bytes_sent)) 88 | 89 | except socket.error, msg: 90 | log.msg('[ERROR] post_logstash, socket.error: %s' % msg[1]) 91 | 92 | except Exception as e: 93 | log.msg('Error posting to logstash: %s' % (str(e.message).strip())) 94 | -------------------------------------------------------------------------------- /loggers/rabbitmq/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 foospidy 2 | # https://github.com/foospidy/HoneyPy 3 | # See LICENSE for details 4 | 5 | import sys 6 | # prevent creation of compiled bytecode files 7 | sys.dont_write_bytecode = True 8 | -------------------------------------------------------------------------------- /loggers/rabbitmq/honeypy_rabbitmq.py: -------------------------------------------------------------------------------- 1 | # HoneyPy Copyright (C) 2013-2017 foospidy 2 | # https://github.com/foospidy/HoneyPy 3 | # See LICENSE for details 4 | # HoneyPy rabbitmq logger 5 | 6 | import sys 7 | import hashlib 8 | import socket 9 | import json 10 | from twisted.python import log 11 | 12 | #pika==0.10.0 13 | import pika 14 | 15 | # prevent creation of compiled bytecode files 16 | sys.dont_write_bytecode = True 17 | 18 | def process(config, section, parts, time_parts): 19 | # TCP 20 | # parts[0]: date 21 | # parts[1]: time_parts 22 | # parts[2]: plugin 23 | # parts[3]: session 24 | # parts[4]: protocol 25 | # parts[5]: event 26 | # parts[6]: local_host 27 | # parts[7]: local_port 28 | # parts[8]: service 29 | # parts[9]: remote_host 30 | # parts[10]: remote_port 31 | # parts[11]: data 32 | # UDP 33 | # parts[0]: date 34 | # parts[1]: time_parts 35 | # parts[2]: plugin string part 36 | # parts[3]: plugin string part 37 | # parts[4]: session 38 | # parts[5]: protocol 39 | # parts[6]: event 40 | # parts[7]: local_host 41 | # parts[8]: local_port 42 | # parts[9]: service 43 | # parts[10]: remote_host 44 | # parts[11]: remote_port 45 | # parts[12]: data 46 | 47 | if parts[4] == 'TCP': 48 | if len(parts) == 11: 49 | parts.append('') # no data for CONNECT events 50 | 51 | post(config.get(section, 'url_param'), config.get(section, 'exchange'), config.get(section, 'routing_key'), parts[0], time_parts[0], parts[0] + ' ' + time_parts[0], time_parts[1], parts[3], parts[4], parts[5], parts[6], parts[7], parts[8], parts[9], parts[10], parts[11]) 52 | 53 | else: 54 | # UDP splits differently (see comment section above) 55 | if len(parts) == 12: 56 | parts.append('') # no data sent 57 | 58 | post(config.get(section, 'url_param'), config.get(section, 'exchange'), config.get(section, 'routing_key'), parts[0], time_parts[0], parts[0] + ' ' + time_parts[0], time_parts[1], parts[4], parts[5], parts[6], parts[7], parts[8], parts[9], parts[10], parts[11], parts[12]) 59 | 60 | 61 | def post(url_param, exchange, routing_key, date, time, date_time, millisecond, session, protocol, event, local_host, local_port, service, remote_host, remote_port, data): 62 | 63 | h = hashlib.md5() 64 | h.update(data) 65 | 66 | # applying [:-3] to time to truncate millisecond 67 | data1 = { 68 | 'date': date, 69 | 'time': time, 70 | 'date_time': date_time, 71 | 'millisecond': str(millisecond)[:-3], 72 | 'session': session, 73 | 'protocol': protocol, 74 | 'event': event, 75 | 'local_host': local_host, 76 | 'local_port': local_port, 77 | 'service': service, 78 | 'remote_host': remote_host, 79 | 'remote_port': remote_port, 80 | 'data': data, 81 | 'bytes': str(len(data)), 82 | 'data_hash': h.hexdigest() 83 | } 84 | 85 | logtosend = json.dumps(data1) 86 | 87 | try: 88 | connection = pika.BlockingConnection(pika.URLParameters(url_param)) 89 | channel = connection.channel() 90 | channel.basic_publish(exchange=exchange, routing_key=routing_key, body=str(logtosend)) 91 | 92 | connection.close() 93 | 94 | log.msg('Post event to rabbitmq! {%s} (%s bytes)' % (logtosend, len(logtosend))) 95 | 96 | except socket.error, msg: 97 | log.msg('[ERROR] post_rabbitmq, socket.error: %s' % msg[1]) 98 | 99 | except Exception as e: 100 | log.msg('Error posting to rabbitmq: %s' % (str(e.message).strip())) 101 | -------------------------------------------------------------------------------- /loggers/slack/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 foospidy 2 | # https://github.com/foospidy/HoneyPy 3 | # See LICENSE for details 4 | 5 | import sys 6 | # prevent creation of compiled bytecode files 7 | sys.dont_write_bytecode = True 8 | -------------------------------------------------------------------------------- /loggers/slack/honeypy_slack.py: -------------------------------------------------------------------------------- 1 | # HoneyPy Copyright (C) 2013-2017 foospidy 2 | # https://github.com/foospidy/HoneyPy 3 | # See LICENSE for details 4 | # HoneyPy Slack Integration 5 | 6 | import sys 7 | import requests 8 | from twisted.python import log 9 | 10 | # prevent creation of compiled bytecode files 11 | sys.dont_write_bytecode = True 12 | 13 | def process(config, section, parts, time_parts): 14 | # TCP 15 | # parts[0]: date 16 | # parts[1]: time_parts 17 | # parts[2]: plugin 18 | # parts[3]: session 19 | # parts[4]: protocol 20 | # parts[5]: event 21 | # parts[6]: local_host 22 | # parts[7]: local_port 23 | # parts[8]: service 24 | # parts[9]: remote_host 25 | # parts[10]: remote_port 26 | # parts[11]: data 27 | # UDP 28 | # parts[0]: date 29 | # parts[1]: time_parts 30 | # parts[2]: plugin string part 31 | # parts[3]: plugin string part 32 | # parts[4]: session 33 | # parts[5]: protocol 34 | # parts[6]: event 35 | # parts[7]: local_host 36 | # parts[8]: local_port 37 | # parts[9]: service 38 | # parts[10]: remote_host 39 | # parts[11]: remote_port 40 | # parts[12]: data 41 | 42 | if parts[4] == 'TCP' and parts[5] == 'CONNECT': 43 | post(config, section, parts[8], parts[9]) 44 | elif parts[6] == 'RX': 45 | # UDP splits differently (see comment section above) 46 | post(config, section, parts[9], parts[10]) 47 | 48 | def post(config, section, service, clientip): 49 | useragent = config.get('honeypy', 'useragent') 50 | url = config.get(section, 'webhook_url') 51 | 52 | headers = {'Content-type': 'application/json', 'User-Agent': useragent} 53 | data = '{"text": "' + config.get('honeypy', 'nodename') + ': Possible *' + service + '* attack from ' + clientip + ' "}' 54 | 55 | r = requests.post(url, headers=headers, data=data, timeout=3) 56 | 57 | if r.ok: 58 | log.msg(("%s response : %s" % (section, r.reason))) 59 | else: 60 | log.msg('Error posting to %s : %s' % (section, str(r.status_code))) 61 | -------------------------------------------------------------------------------- /loggers/splunk/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 foospidy 2 | # https://github.com/foospidy/HoneyPy 3 | # See LICENSE for details 4 | 5 | import sys 6 | # prevent creation of compiled bytecode files 7 | sys.dont_write_bytecode = True 8 | -------------------------------------------------------------------------------- /loggers/splunk/honeypy_splunk.py: -------------------------------------------------------------------------------- 1 | # HoneyPy Copyright (C) 2013-2019 foospidy 2 | # https://github.com/foospidy/HoneyPy 3 | # See LICENSE for details 4 | 5 | import sys 6 | import hashlib 7 | from datetime import datetime 8 | import time 9 | from twisted.python import log 10 | import requests 11 | 12 | # prevent creation of compiled bytecode files 13 | sys.dont_write_bytecode = True 14 | 15 | def process(config, section, parts, time_parts): 16 | # TCP 17 | # parts[0]: date 18 | # parts[1]: time_parts 19 | # parts[2]: plugin 20 | # parts[3]: session 21 | # parts[4]: protocol 22 | # parts[5]: event 23 | # parts[6]: local_host 24 | # parts[7]: local_port 25 | # parts[8]: service 26 | # parts[9]: remote_host 27 | # parts[10]: remote_port 28 | # parts[11]: data 29 | # UDP 30 | # parts[0]: date 31 | # parts[1]: time_parts 32 | # parts[2]: plugin string part 33 | # parts[3]: plugin string part 34 | # parts[4]: session 35 | # parts[5]: protocol 36 | # parts[6]: event 37 | # parts[7]: local_host 38 | # parts[8]: local_port 39 | # parts[9]: service 40 | # parts[10]: remote_host 41 | # parts[11]: remote_port 42 | # parts[12]: data 43 | 44 | if parts[4] == 'TCP': 45 | if len(parts) == 11: 46 | parts.append('') # no data for CONNECT events 47 | 48 | post(config, parts[0] + ' ' + time_parts[0], time_parts[1], parts[3], parts[4], parts[5], parts[6], parts[7], parts[8], parts[9], parts[10], parts[11]) 49 | else: 50 | # UDP splits differently (see comment section above) 51 | if len(parts) == 12: 52 | parts.append('') # no data sent 53 | 54 | post(config, parts[0] + ' ' + time_parts[0], time_parts[1], parts[4], parts[5], parts[6], parts[7], parts[8], parts[9], parts[10], parts[11], parts[12]) 55 | 56 | def post(config, date_time, millisecond, session, protocol, event, local_host, local_port, service, remote_host, remote_port, data): 57 | useragent = config.get('honeypy', 'useragent') 58 | host = config.get('honeypy', 'nodename') or 'honeypy' 59 | url = config.get('splunk', 'url') 60 | token = config.get('splunk', 'token') 61 | 62 | index = config.get('splunk', 'index') 63 | source = config.get('splunk', 'source') 64 | sourcetype = config.get('splunk', 'sourcetype') 65 | 66 | h = hashlib.md5() 67 | h.update(data) 68 | 69 | date_time_w_millisecond = date_time + '.' + str(millisecond) 70 | complete_date_time = datetime.strptime(date_time_w_millisecond, "%Y-%m-%d %H:%M:%S.%f").isoformat() + 'Z' 71 | 72 | epoch = str(int(time.mktime(time.strptime(date_time_w_millisecond, "%Y-%m-%d %H:%M:%S.%f")))) + '.' + str(millisecond) 73 | 74 | headers = { 75 | 'User-Agent': useragent, 76 | "Content-Type": "application/json", 77 | "Authorization": "Splunk " + token 78 | } 79 | 80 | eventdata = { 81 | 'date_time': complete_date_time, 82 | 'session_id': session, 83 | 'protocol': protocol, 84 | 'event': event, 85 | 'dest_ip': local_host, 86 | 'dest_port': local_port, 87 | 'service': service, 88 | 'src_ip': remote_host, 89 | 'src_port': remote_port, 90 | 'data': data, 91 | 'bytes': str(len(data)), 92 | 'data_hash': h.hexdigest() 93 | } 94 | 95 | parentdata = { 96 | 'time': epoch, 97 | 'index': index, 98 | 'source': source, 99 | 'sourcetype': sourcetype, 100 | 'host': host, 101 | 'event': eventdata 102 | } 103 | 104 | try: 105 | r = requests.post(url, headers=headers, json=parentdata, verify=False, timeout=3) 106 | resp = r.text 107 | 108 | log.msg('Post event to Splunk, response: %s' % (str(resp).strip())) 109 | except Exception as e: 110 | log.msg('Error posting to Splunk: %s' % (str(e.message).strip())) 111 | -------------------------------------------------------------------------------- /loggers/sumologic/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 foospidy 2 | # https://github.com/foospidy/HoneyPy 3 | # See LICENSE for details 4 | 5 | import sys 6 | # prevent creation of compiled bytecode files 7 | sys.dont_write_bytecode = True 8 | -------------------------------------------------------------------------------- /loggers/sumologic/honeypy_sumologic.py: -------------------------------------------------------------------------------- 1 | # HoneyPy Copyright (C) 2013-2017 foospidy 2 | # https://github.com/foospidy/HoneyPy 3 | # See LICENSE for details 4 | import sys 5 | import hashlib 6 | from datetime import datetime 7 | import requests 8 | from twisted.python import log 9 | 10 | # prevent creation of compiled bytecode files 11 | sys.dont_write_bytecode = True 12 | 13 | def process(config, section, parts, time_parts): 14 | # TCP 15 | # parts[0]: date 16 | # parts[1]: time_parts 17 | # parts[2]: plugin 18 | # parts[3]: session 19 | # parts[4]: protocol 20 | # parts[5]: event 21 | # parts[6]: local_host 22 | # parts[7]: local_port 23 | # parts[8]: service 24 | # parts[9]: remote_host 25 | # parts[10]: remote_port 26 | # parts[11]: data 27 | # UDP 28 | # parts[0]: date 29 | # parts[1]: time_parts 30 | # parts[2]: plugin string part 31 | # parts[3]: plugin string part 32 | # parts[4]: session 33 | # parts[5]: protocol 34 | # parts[6]: event 35 | # parts[7]: local_host 36 | # parts[8]: local_port 37 | # parts[9]: service 38 | # parts[10]: remote_host 39 | # parts[11]: remote_port 40 | # parts[12]: data 41 | 42 | if parts[4] == 'TCP': 43 | if len(parts) == 11: 44 | parts.append('') # no data for CONNECT events 45 | 46 | post(config, section, parts[0], time_parts[0], parts[0] + ' ' + time_parts[0], time_parts[1], parts[3], parts[4], parts[5], parts[6], parts[7], parts[8], parts[9], parts[10], parts[11]) 47 | else: 48 | # UDP splits differently (see comment section above) 49 | if len(parts) == 12: 50 | parts.append('') # no data sent 51 | 52 | post(config, section, parts[0], time_parts[0], parts[0] + ' ' + time_parts[0], time_parts[1], parts[4], parts[5], parts[6], parts[7], parts[8], parts[9], parts[10], parts[11], parts[12]) 53 | 54 | 55 | def post(config, section, date, time, date_time, millisecond, session, protocol, event, local_host, local_port, service, remote_host, remote_port, data): 56 | useragent = config.get('honeypy', 'useragent') 57 | url = config.get(section, 'url') 58 | custom_source_host = config.get(section, 'custom_source_host') 59 | custom_source_name = config.get(section, 'custom_source_name') 60 | custom_source_category = config.get(section, 'custom_source_category') 61 | 62 | h = hashlib.md5() 63 | h.update(data) 64 | 65 | date_time = datetime.strptime(date_time, "%Y-%m-%d %H:%M:%S").isoformat() 66 | 67 | headers = {'User-Agent': useragent, "Content-Type": "application/json"} 68 | 69 | if custom_source_host: 70 | headers.update({'X-Sumo-Host' : custom_source_host}) 71 | 72 | if custom_source_name: 73 | headers.update({'X-Sumo-Name' : custom_source_name}) 74 | 75 | if custom_source_category: 76 | headers.update({'X-Sumo-Category' : custom_source_category}) 77 | 78 | # applying [:-3] to time to truncate millisecond 79 | data = { 80 | 'date': date, 81 | 'time': time, 82 | 'date_time': date_time, 83 | 'millisecond': str(millisecond)[:-3], 84 | 'session': session, 85 | 'protocol': protocol, 86 | 'event': event, 87 | 'local_host': local_host, 88 | 'local_port': local_port, 89 | 'service': service, 90 | 'remote_host': remote_host, 91 | 'remote_port': remote_port, 92 | 'data': data, 93 | 'bytes': str(len(data)), 94 | 'data_hash': h.hexdigest() 95 | } 96 | 97 | try: 98 | r = requests.post(url, headers=headers, json=data, verify=True, timeout=3) 99 | page = r.text 100 | log.msg('Post event to %s, response: %s' % (section, str(page).strip())) 101 | except Exception as e: 102 | log.msg('Error posting to %s : %s' % (section, str(e.message).strip())) 103 | -------------------------------------------------------------------------------- /loggers/telegram/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 foospidy 2 | # https://github.com/foospidy/HoneyPy 3 | # See LICENSE for details 4 | 5 | import sys 6 | # prevent creation of compiled bytecode files 7 | sys.dont_write_bytecode = True 8 | -------------------------------------------------------------------------------- /loggers/telegram/honeypy_telegram.py: -------------------------------------------------------------------------------- 1 | # HoneyPy Copyright (C) 2013-2017 foospidy 2 | # https://github.com/foospidy/HoneyPy 3 | # See LICENSE for details 4 | # HoneyPy telegram module by aancw 5 | 6 | import json 7 | import urllib3 8 | import certifi 9 | 10 | 11 | def process(config, section, parts, time_parts): 12 | # TCP 13 | # parts[0]: date 14 | # parts[1]: time_parts 15 | # parts[2]: plugin 16 | # parts[3]: session 17 | # parts[4]: protocol 18 | # parts[5]: event 19 | # parts[6]: local_host 20 | # parts[7]: local_port 21 | # parts[8]: service 22 | # parts[9]: remote_host 23 | # parts[10]: remote_port 24 | # parts[11]: data 25 | # UDP 26 | # parts[0]: date 27 | # parts[1]: time_parts 28 | # parts[2]: plugin string part 29 | # parts[3]: plugin string part 30 | # parts[4]: session 31 | # parts[5]: protocol 32 | # parts[6]: event 33 | # parts[7]: local_host 34 | # parts[8]: local_port 35 | # parts[9]: service 36 | # parts[10]: remote_host 37 | # parts[11]: remote_port 38 | # parts[12]: data 39 | 40 | if parts[4] == 'TCP': 41 | post(config, parts[8], parts[9]) 42 | else: 43 | # UDP splits differently (see comment section above) 44 | post(config, parts[9], parts[10]) 45 | 46 | def get_chat_id(bot_id): 47 | try: 48 | https = urllib3.PoolManager(cert_reqs='CERT_REQUIRED', ca_certs=certifi.where()) 49 | r = https.request('GET', 'https://api.telegram.org/bot' + bot_id + '/getUpdates') 50 | result_dump = json.loads(r.data) 51 | chat_id = result_dump['result'][0]['message']['chat']['id'] 52 | return chat_id 53 | except urllib3.exceptions.SSLError as err: 54 | print('[ERROR] Telegram SSL error', err) 55 | 56 | def post(honeypycfg, service, clientip): 57 | bot_id = honeypycfg.get('telegram', 'bot_id') 58 | message = service + ' Possible ' + service + ' attack from ' + clientip + ' https://riskdiscovery.com/honeydb/#host/' + clientip 59 | chat_id = get_chat_id(bot_id) 60 | 61 | try: 62 | https = urllib3.PoolManager(cert_reqs='CERT_REQUIRED', ca_certs=certifi.where()) 63 | r = https.request('GET', 'https://api.telegram.org/bot' + bot_id + '/sendMessage?chat_id=' + str(chat_id) + '&text=' + message) 64 | except urllib3.exceptions.SSLError as err: 65 | print('[ERROR] Telegram SSL error', err) 66 | -------------------------------------------------------------------------------- /loggers/template/honeypy_template.py: -------------------------------------------------------------------------------- 1 | # HoneyPy Copyright (C) 2013-2017 foospidy 2 | # https://github.com/foospidy/HoneyPy 3 | # See LICENSE for details 4 | import sys 5 | import hashlib 6 | from datetime import datetime 7 | import requests 8 | from twisted.python import log 9 | 10 | # prevent creation of compiled bytecode files 11 | sys.dont_write_bytecode = True 12 | 13 | def process(config, section, parts, time_parts): 14 | # TCP 15 | # parts[0]: date 16 | # parts[1]: time_parts 17 | # parts[2]: plugin 18 | # parts[3]: session 19 | # parts[4]: protocol 20 | # parts[5]: event 21 | # parts[6]: local_host 22 | # parts[7]: local_port 23 | # parts[8]: service 24 | # parts[9]: remote_host 25 | # parts[10]: remote_port 26 | # parts[11]: data 27 | # UDP 28 | # parts[0]: date 29 | # parts[1]: time_parts 30 | # parts[2]: plugin string part 31 | # parts[3]: plugin string part 32 | # parts[4]: session 33 | # parts[5]: protocol 34 | # parts[6]: event 35 | # parts[7]: local_host 36 | # parts[8]: local_port 37 | # parts[9]: service 38 | # parts[10]: remote_host 39 | # parts[11]: remote_port 40 | # parts[12]: data 41 | 42 | if parts[4] == 'TCP': 43 | if len(parts) == 11: 44 | parts.append('') # no data for CONNECT events 45 | 46 | post(config, section, parts[0], time_parts[0], parts[0] + ' ' + time_parts[0], time_parts[1], parts[3], parts[4], parts[5], parts[6], parts[7], parts[8], parts[9], parts[10], parts[11]) 47 | else: 48 | # UDP splits differently (see comment section above) 49 | if len(parts) == 12: 50 | parts.append('') # no data sent 51 | 52 | post(config, section, parts[0], time_parts[0], parts[0] + ' ' + time_parts[0], time_parts[1], parts[4], parts[5], parts[6], parts[7], parts[8], parts[9], parts[10], parts[11], parts[12]) 53 | 54 | 55 | def post(config, section, date, time, date_time, millisecond, session, protocol, event, local_host, local_port, service, remote_host, remote_port, data): 56 | useragent = config.get('honeypy', 'useragent') 57 | url = config.get(section, 'url') 58 | 59 | h = hashlib.md5() 60 | h.update(data) 61 | 62 | date_time = datetime.strptime(date_time, "%Y-%m-%d %H:%M:%S").isoformat() 63 | 64 | headers = {'User-Agent': useragent, "Content-Type": "application/json"} 65 | 66 | # applying [:-3] to time to truncate millisecond 67 | data = { 68 | 'date': date, 69 | 'time': time, 70 | 'date_time': date_time, 71 | 'millisecond': str(millisecond)[:-3], 72 | 'session': session, 73 | 'protocol': protocol, 74 | 'event': event, 75 | 'local_host': local_host, 76 | 'local_port': local_port, 77 | 'service': service, 78 | 'remote_host': remote_host, 79 | 'remote_port': remote_port, 80 | 'data': data, 81 | 'bytes': str(len(data)), 82 | 'data_hash': h.hexdigest() 83 | } 84 | 85 | try: 86 | r = requests.post(url, headers=headers, json=data, verify=True, timeout=3) 87 | page = r.text 88 | log.msg('Post event to %s, response: %s' % (section, str(page).strip())) 89 | except Exception as e: 90 | log.msg('Error posting to %s : %s' % (section, str(e.message).strip())) 91 | -------------------------------------------------------------------------------- /loggers/twitter/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 foospidy 2 | # https://github.com/foospidy/HoneyPy 3 | # See LICENSE for details 4 | 5 | import sys 6 | # prevent creation of compiled bytecode files 7 | sys.dont_write_bytecode = True 8 | -------------------------------------------------------------------------------- /loggers/twitter/honeypy_twitter.py: -------------------------------------------------------------------------------- 1 | # HoneyPy Copyright (C) 2013-2017 foospidy 2 | # https://github.com/foospidy/HoneyPy 3 | # See LICENSE for details 4 | # HoneyPy twitter module 5 | 6 | from twitter import Twitter 7 | from twitter.oauth import OAuth 8 | from twisted.python import log 9 | 10 | def process(config, section, parts, time_parts): 11 | # TCP 12 | # parts[0]: date 13 | # parts[1]: time_parts 14 | # parts[2]: plugin 15 | # parts[3]: session 16 | # parts[4]: protocol 17 | # parts[5]: event 18 | # parts[6]: local_host 19 | # parts[7]: local_port 20 | # parts[8]: service 21 | # parts[9]: remote_host 22 | # parts[10]: remote_port 23 | # parts[11]: data 24 | # UDP 25 | # parts[0]: date 26 | # parts[1]: time_parts 27 | # parts[2]: plugin string part 28 | # parts[3]: plugin string part 29 | # parts[4]: session 30 | # parts[5]: protocol 31 | # parts[6]: event 32 | # parts[7]: local_host 33 | # parts[8]: local_port 34 | # parts[9]: service 35 | # parts[10]: remote_host 36 | # parts[11]: remote_port 37 | # parts[12]: data 38 | 39 | if parts[4] == 'TCP': 40 | post(config, parts[8], parts[9]) 41 | else: 42 | # UDP splits differently (see comment section above) 43 | post(config, parts[9], parts[10]) 44 | 45 | 46 | def post(honeypycfg, service, clientip): 47 | 48 | ck = honeypycfg.get('twitter', 'consumerkey') 49 | cs = honeypycfg.get('twitter', 'consumersecret') 50 | ot = honeypycfg.get('twitter', 'oauthtoken') 51 | os = honeypycfg.get('twitter', 'oauthsecret') 52 | 53 | t = Twitter(auth=OAuth(ot, os, ck, cs)) 54 | nodename = honeypycfg.get('honeypy', 'nodename') 55 | 56 | try: 57 | t.statuses.update(status=nodename + ': #' + service + ' Possible ' + service + ' attack from ' + clientip + ' https://riskdiscovery.com/honeydb/host/' + clientip) 58 | except Exception, err: 59 | log.msg('Error posting to Twitter: %s' % err) 60 | -------------------------------------------------------------------------------- /mkdocs.yml: -------------------------------------------------------------------------------- 1 | site_name: HoneyPy Docs 2 | theme: readthedocs 3 | pages: 4 | - Home: index.md 5 | - Quickstart: quickstart.md 6 | - Installing: installing.md 7 | - Configuring: configuring.md 8 | - Plugins: plugins.md 9 | - Developers: developers.md 10 | - References: references.md 11 | -------------------------------------------------------------------------------- /plugins/DnsUdp/DnsUdp.py: -------------------------------------------------------------------------------- 1 | # HoneyPy Copyright (C) 2013-2017 foospidy 2 | # https://github.com/foospidy/HoneyPy 3 | # See LICENSE for details 4 | 5 | from twisted.internet.protocol import DatagramProtocol 6 | from twisted.python import log 7 | import uuid 8 | 9 | ### START CUSTOM IMPORTS ### 10 | from dnslib import * 11 | import random 12 | import socket 13 | import struct 14 | ############################ 15 | 16 | class pluginMain(DatagramProtocol): 17 | 18 | def datagramReceived(self, data, (host, port)): 19 | self.rx(host, port, data) 20 | 21 | ### START CUSTOM CODE #################################################################### 22 | 23 | request = DNSRecord.parse(data) 24 | id = request.header.id 25 | qname = request.q.qname 26 | qtype = request.q.qtype 27 | 28 | IP = self.get_random_ip() 29 | BIND_VERSION = '8.2.2-P5' 30 | C_NAME = 'taco.burrito' 31 | 32 | reply = DNSRecord(DNSHeader(id=id, qr=1, aa=1, ra=1), q=request.q) 33 | 34 | if self.is_version_request(qname): 35 | reply.add_answer(RR(qname, QTYPE.TXT, rdata=TXT(BIND_VERSION))) 36 | elif QTYPE.A == qtype: 37 | reply.add_answer(RR(qname, qtype, rdata=A(IP))) 38 | elif QTYPE.MX == qtype: 39 | reply.add_answer(RR(qname, qtype, rdata=MX(IP))) 40 | elif QTYPE.CNAME == qtype: 41 | reply.add_answer(RR(qname, QTYPE.CNAME, rdata=CNAME(C_NAME))) 42 | else: 43 | reply.add_answer(RR(qname, QTYPE.A, rdata=A(IP))) 44 | reply.add_answer(RR(qname, QTYPE.MX, rdata=MX(IP))) 45 | reply.add_answer(RR(qname, QTYPE.TXT, rdata=TXT(IP))) 46 | 47 | self.tx(host, port, reply.pack()) 48 | 49 | ########################################################################################## 50 | 51 | ### START CUSTOM FUNCTIONS ################################################################### 52 | def is_version_request(self, qname): 53 | if 'versionbind' == str(qname).replace('.', '').lower(): 54 | return True 55 | else: 56 | return False 57 | 58 | def get_random_ip(self): 59 | ip = '0.0.0.0' 60 | 61 | while('0.0.0.0' == ip or '255.255.255.255' == ip): 62 | # http://stackoverflow.com/questions/21014618/python-randomly-generated-ip-address-of-the-string 63 | ip = socket.inet_ntoa(struct.pack('>I', random.randint(1, 0xffffffff))) 64 | 65 | return ip 66 | 67 | ############################################################################################## 68 | 69 | def tx(self, host, port, data): 70 | log.msg('%s UDP TX %s %s %s %s %s %s' % (self.session, self.host, self.port, self.name, host, port, str(data).encode("hex"))) 71 | self.transport.write(data, (host, port)) 72 | 73 | def rx(self, host, port, data): 74 | self.session = uuid.uuid1() 75 | log.msg('%s UDP RX %s %s %s %s %s %s' % (self.session, self.host, self.port, self.name, host, port, data.encode("hex"))) 76 | 77 | def __init__(self, name=None, host=None, port=None): 78 | self.name = name or 'HoneyPy' 79 | self.host = host or '???' 80 | self.port = port or '???' 81 | self.session = None 82 | -------------------------------------------------------------------------------- /plugins/DnsUdp/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 foospidy 2 | # https://github.com/foospidy/HoneyPy 3 | # See LICENSE for details 4 | 5 | from DnsUdp import pluginMain 6 | -------------------------------------------------------------------------------- /plugins/DnsUdp/readme.txt: -------------------------------------------------------------------------------- 1 | #### Description 2 | Answers dns queries with a random ip address. For cname queries it is a static response. Responds to versionbind queries with an old and unpatched version. 3 | 4 | #### Dependencies 5 | This plugin requires dnslib (https://pypi.python.org/pypi/dnslib). 6 | run: pip install dnslib 7 | -------------------------------------------------------------------------------- /plugins/Echo/Echo.py: -------------------------------------------------------------------------------- 1 | # HoneyPy Copyright (C) 2013-2017 foospidy 2 | # https://github.com/foospidy/HoneyPy 3 | # See LICENSE for details 4 | 5 | from twisted.internet import protocol, reactor, endpoints 6 | from twisted.python import log 7 | import uuid 8 | 9 | ### START CUSTOM IMPORTS ### 10 | 11 | ############################ 12 | 13 | class Echo(protocol.Protocol): ### Set custom protocol class name 14 | localhost = None 15 | remote_host = None 16 | session = None 17 | 18 | ### START CUSTOM VARIABLES ############################################################### 19 | 20 | ########################################################################################## 21 | 22 | # handle events 23 | def connectionMade(self): 24 | self.connect() 25 | 26 | ### START CUSTOM CODE #################################################################### 27 | 28 | ########################################################################################## 29 | 30 | def dataReceived(self, data): 31 | self.rx(data) 32 | 33 | ### START CUSTOM CODE #################################################################### 34 | self.tx(data) 35 | 36 | ########################################################################################## 37 | 38 | ### START CUSTOM FUNCTIONS ################################################################### 39 | 40 | ############################################################################################## 41 | 42 | def connect(self): 43 | self.local_host = self.transport.getHost() 44 | self.remote_host = self.transport.getPeer() 45 | self.session = uuid.uuid1() 46 | log.msg('%s %s CONNECT %s %s %s %s %s' % (self.session, self.remote_host.type, self.local_host.host, self.local_host.port, self.factory.name, self.remote_host.host, self.remote_host.port)) 47 | 48 | def clientConnectionLost(self): 49 | self.transport.loseConnection() 50 | 51 | def tx(self, data): 52 | log.msg('%s %s TX %s %s %s %s %s %s' % (self.session, self.remote_host.type, self.local_host.host, self.local_host.port, self.factory.name, self.remote_host.host, self.remote_host.port, data.encode("hex"))) 53 | self.transport.write(data) 54 | 55 | def rx(self, data): 56 | log.msg('%s %s RX %s %s %s %s %s %s' % (self.session, self.remote_host.type, self.local_host.host, self.local_host.port, self.factory.name, self.remote_host.host, self.remote_host.port, data.encode("hex"))) 57 | 58 | class pluginFactory(protocol.Factory): 59 | protocol = Echo ### Set protocol to custom protocol class name 60 | 61 | def __init__(self, name=None): 62 | self.name = name or 'HoneyPy' 63 | -------------------------------------------------------------------------------- /plugins/Echo/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 foospidy 2 | # https://github.com/foospidy/HoneyPy 3 | # See LICENSE for details 4 | 5 | from Echo import pluginFactory 6 | -------------------------------------------------------------------------------- /plugins/Echo_udp/Echo.py: -------------------------------------------------------------------------------- 1 | # HoneyPy Copyright (C) 2013-2017 foospidy 2 | # https://github.com/foospidy/HoneyPy 3 | # See LICENSE for details 4 | 5 | from twisted.internet.protocol import DatagramProtocol 6 | from twisted.python import log 7 | import uuid 8 | 9 | ### START CUSTOM IMPORTS ### 10 | 11 | ############################ 12 | 13 | class pluginMain(DatagramProtocol): 14 | 15 | def datagramReceived(self, data, (host, port)): 16 | self.rx(host, port, data) 17 | 18 | ### START CUSTOM CODE #################################################################### 19 | self.tx(host, port, data) 20 | 21 | ########################################################################################## 22 | 23 | ### START CUSTOM FUNCTIONS ################################################################### 24 | 25 | ############################################################################################## 26 | 27 | def tx(self, host, port, data): 28 | log.msg('%s UDP TX %s %s %s %s %s %s' % (self.session, self.host, self.port, self.name, host, port, data.encode("hex"))) 29 | self.transport.write(data, (host, port)) 30 | 31 | def rx(self, host, port, data): 32 | self.session = uuid.uuid1() 33 | log.msg('%s UDP RX %s %s %s %s %s %s' % (self.session, self.host, self.port, self.name, host, port, data.encode("hex"))) 34 | 35 | def __init__(self, name=None, host=None, port=None): 36 | self.name = name or 'HoneyPy' 37 | self.host = host or '???' 38 | self.port = port or '???' 39 | self.session = None 40 | -------------------------------------------------------------------------------- /plugins/Echo_udp/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 foospidy 2 | # https://github.com/foospidy/HoneyPy 3 | # See LICENSE for details 4 | 5 | from Echo import pluginMain 6 | -------------------------------------------------------------------------------- /plugins/Elasticsearch/Readme.md: -------------------------------------------------------------------------------- 1 | ### Low interactive Elasticsearch Plugin for Honeypy 2 | 3 | This plugin is based on elastichoney project (https://github.com/jordan-wright/elastichoney) 4 | 5 | Very simple only three requests are replied 6 | 7 | 1. Simple Get request / 8 | 2. Request for node information starting with /_nodes 9 | 3. Search requests starting with /_search 10 | 11 | By default runs on default elasticsearch port 9200. 12 | 13 | ToDo: 14 | 15 | 1. Add randomness to versions in replies 16 | 2. Add rnadom numbers for node replies 17 | -------------------------------------------------------------------------------- /plugins/Elasticsearch/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 foospidy 2 | # https://github.com/foospidy/HoneyPy 3 | # See LICENSE for details 4 | 5 | from elasticsearch import pluginFactory 6 | -------------------------------------------------------------------------------- /plugins/Elasticsearch/elasticsearch.py: -------------------------------------------------------------------------------- 1 | # HoneyPy Copyright (C) 2013-2017 foospidy 2 | # https://github.com/foospidy/HoneyPy 3 | # See LICENSE for details 4 | 5 | from twisted.internet import protocol, reactor, endpoints 6 | from twisted.python import log 7 | import uuid 8 | 9 | 10 | ### START CUSTOM IMPORTS ### 11 | 12 | ############################ 13 | 14 | class Elasticsearch(protocol.Protocol): ### Set custom protocol class name 15 | localhost = None 16 | remote_host = None 17 | session = None 18 | 19 | ### START CUSTOM VARIABLES ############################################################### 20 | 21 | ########################################################################################## 22 | 23 | # handle events 24 | def connectionMade(self): 25 | self.connect() 26 | 27 | ### START CUSTOM CODE #################################################################### 28 | 29 | ########################################################################################## 30 | 31 | def dataReceived(self, data): 32 | self.rx(data) 33 | 34 | ### START CUSTOM CODE #################################################################### 35 | 36 | # response = 'HTTP/1.1 200 OK\nServer: Apache/2.4.10 (Debian)\nConnection: close\nContent-Type: text/html\n\nOK!' 37 | if data.startswith("GET / HTTP"): 38 | response = """{ "status" : 200, "name" : "Flake", "cluster_name" : "elasticsearch", "version" : {"number" : "1.4.1","\ 39 | "build_hash" : "61ccbdf1fab017166ec4b96a88e82e8ab88f43fc",\ 40 | "build_timestamp" : "2016-04-11T03:14:12Z",\ 41 | "build_snapshot" : false, "lucene_version" : "4.10.4"},\ 42 | "tagline" : "You Know, for Search"}""" 43 | self.tx(response) 44 | 45 | elif "/_nodes" in data: 46 | response = self.fakeNodes() 47 | self.tx(response) 48 | 49 | elif "/_search" in data: 50 | response = self.fakeSearch() 51 | self.tx(response) # close connection anyways 52 | self.transport.loseConnection() 53 | 54 | ########################################################################################## 55 | 56 | ### START CUSTOM FUNCTIONS ################################################################### 57 | def fakeSearch(self): 58 | res = """{ 59 | "took" : 6, 60 | "timed_out" : false, 61 | "_shards" : { 62 | "total" : 6, 63 | "successful" : 6, 64 | "failed" : 0 65 | }, 66 | "hits" : { 67 | "total" : 1, 68 | "max_score" : 1.0, 69 | "hits" : [ { 70 | "_index" : ".kibana", 71 | "_type" : "index-pattern", 72 | "_id" : "logstash-*", 73 | "_score" : 1.0, 74 | "_source":{"title":"logstash-*","timeFieldName":"@timestamp","customFormats":"{}","fields":"[{\"type\":\"string\",\"indexed\":true,\"analyzed\":true,\"doc_values\":false,\"name\":\"host\",\"count\":0},{\"type\":\"string\",\"indexed\":false,\"analyzed\":false,\"name\":\"_source\",\"count\":0},{\"type\":\"string\",\"indexed\":true,\"analyzed\":false,\"doc_values\":false,\"name\":\"message.raw\",\"count\":0},{\"type\":\"string\",\"indexed\":false,\"analyzed\":false,\"name\":\"_index\",\"count\":0},{\"type\":\"string\",\"indexed\":true,\"analyzed\":false,\"doc_values\":false,\"name\":\"@version\",\"count\":0},{\"type\":\"string\",\"indexed\":true,\"analyzed\":true,\"doc_values\":false,\"name\":\"message\",\"count\":0},{\"type\":\"date\",\"indexed\":true,\"analyzed\":false,\"doc_values\":false,\"name\":\"@timestamp\",\"count\":0},{\"type\":\"string\",\"indexed\":true,\"analyzed\":false,\"name\":\"_type\",\"count\":0},{\"type\":\"string\",\"indexed\":true,\"analyzed\":false,\"name\":\"_id\",\"count\":0},{\"type\":\"string\",\"indexed\":true,\"analyzed\":false,\"doc_values\":false,\"name\":\"host.raw\",\"count\":0},{\"type\":\"geo_point\",\"indexed\":true,\"analyzed\":false,\"doc_values\":false,\"name\":\"geoip.location\",\"count\":0}]"} 75 | }] 76 | } 77 | }""" 78 | return res 79 | 80 | 81 | def fakeNodes(self): 82 | res = """{ 83 | "cluster_name" : "elasticsearch", 84 | "nodes" : { 85 | "x1JG6g9PRHy6ClCOO2-C4g" : { 86 | "name" : "%s", 87 | "transport_address" : "inet[/ 88 | %s:9300]", 89 | "host" : "elk", 90 | "ip" : "127.0.1.1", 91 | "version" : "%s", 92 | "build" : "89d3241", 93 | "http_address" : "inet[/%s:9200]", 94 | "os" : { 95 | "refresh_interval_in_millis" : 1000, 96 | "available_processors" : 12, 97 | "cpu" : { 98 | "total_cores" : 24, 99 | "total_sockets" : 48, 100 | "cores_per_socket" : 2 101 | } 102 | }, 103 | "process" : { 104 | "refresh_interval_in_millis" : 1000, 105 | "id" : 2039, 106 | "max_file_descriptors" : 65535, 107 | "mlockall" : false 108 | }, 109 | "jvm" : { 110 | "version" : "1.7.0_65" 111 | }, 112 | "network" : { 113 | "refresh_interval_in_millis" : 5000, 114 | "primary_interface" : { 115 | "address" : "%s", 116 | "name" : "eth0", 117 | "mac_address" : "08:01:c7:3F:15:DD" 118 | } 119 | }, 120 | "transport" : { 121 | "bound_address" : "inet[/0:0:0:0:0:0:0:0:9300]", 122 | "publish_address" : "inet[/%s:9300]" 123 | }, 124 | "http" : { 125 | "bound_address" : "inet[/0:0:0:0:0:0:0:0:9200]", 126 | "publish_address" : "inet[/%s:9200]", 127 | "max_content_length_in_bytes" : 104857600 128 | }} 129 | } 130 | }""" 131 | return res 132 | 133 | ############################################################################################## 134 | 135 | def connect(self): 136 | self.local_host = self.transport.getHost() 137 | self.remote_host = self.transport.getPeer() 138 | self.session = uuid.uuid1() 139 | log.msg('%s %s CONNECT %s %s %s %s %s' % ( 140 | self.session, self.remote_host.type, self.local_host.host, self.local_host.port, self.factory.name, 141 | self.remote_host.host, self.remote_host.port)) 142 | 143 | def clientConnectionLost(self): 144 | self.transport.loseConnection() 145 | 146 | def tx(self, data): 147 | # log.msg('%s %s TX %s %s %s %s %s %s' % (self.session, self.remote_host.type, self.local_host.host, self.local_host.port, self.factory.name, self.remote_host.host, self.remote_host.port, data.encode("hex"))) 148 | log.msg('%s %s TX %s %s %s %s %s %s' % ( 149 | self.session, self.remote_host.type, self.local_host.host, self.local_host.port, self.factory.name, 150 | self.remote_host.host, self.remote_host.port, data.encode('hex'))) 151 | self.transport.write(data) 152 | 153 | def rx(self, data): 154 | log.msg('%s %s RX %s %s %s %s %s %s' % ( 155 | self.session, self.remote_host.type, self.local_host.host, self.local_host.port, self.factory.name, 156 | self.remote_host.host, self.remote_host.port, data.encode('hex'))) 157 | 158 | 159 | class pluginFactory(protocol.Factory): 160 | protocol = Elasticsearch ### Set protocol to custom protocol class name 161 | 162 | def __init__(self, name=None): 163 | self.name = name or 'HoneyPy' 164 | -------------------------------------------------------------------------------- /plugins/HashCountRandom/HashCountRandom.py: -------------------------------------------------------------------------------- 1 | # HoneyPy Copyright (C) 2013-2017 foospidy 2 | # https://github.com/foospidy/HoneyPy 3 | # See LICENSE for details 4 | 5 | from twisted.internet import protocol, reactor, endpoints 6 | from twisted.python import log 7 | import uuid 8 | 9 | ### START CUSTOM IMPORTS ### 10 | import os 11 | import md5 12 | ############################ 13 | 14 | class HashCountRandom(protocol.Protocol): ### Set custom protocol class name 15 | localhost = None 16 | remote_host = None 17 | session = None 18 | 19 | ### START CUSTOM VARIABLES ############################################################### 20 | 21 | ########################################################################################## 22 | 23 | # handle events 24 | def connectionMade(self): 25 | self.connect() 26 | 27 | ### START CUSTOM CODE #################################################################### 28 | self.count = 0 29 | self.tx('ACCEPT_CONN: ' + str(self.remote_host.host) + '\n') 30 | 31 | ########################################################################################## 32 | 33 | def dataReceived(self, data): 34 | self.rx(data) 35 | 36 | ### START CUSTOM CODE #################################################################### 37 | # custom code 38 | self.count = self.count + 1 39 | self.tx(self.md5sum(self.count) + ':' + str(os.urandom(99)) + '\n') 40 | 41 | ########################################################################################## 42 | 43 | ### START CUSTOM FUNCTIONS ################################################################### 44 | def md5sum(self, data): 45 | m = md5.new() 46 | m.update(str(data)) 47 | return m.hexdigest() 48 | 49 | ############################################################################################## 50 | 51 | def connect(self): 52 | self.local_host = self.transport.getHost() 53 | self.remote_host = self.transport.getPeer() 54 | self.session = uuid.uuid1() 55 | log.msg('%s %s CONNECT %s %s %s %s %s' % (self.session, self.remote_host.type, self.local_host.host, self.local_host.port, self.factory.name, self.remote_host.host, self.remote_host.port)) 56 | 57 | def clientConnectionLost(self): 58 | self.transport.loseConnection() 59 | 60 | def tx(self, data): 61 | log.msg('%s %s TX %s %s %s %s %s %s' % (self.session, self.remote_host.type, self.local_host.host, self.local_host.port, self.factory.name, self.remote_host.host, self.remote_host.port, data.encode("hex"))) 62 | self.transport.write(data) 63 | 64 | def rx(self, data): 65 | log.msg('%s %s RX %s %s %s %s %s %s' % (self.session, self.remote_host.type, self.local_host.host, self.local_host.port, self.factory.name, self.remote_host.host, self.remote_host.port, data.encode("hex"))) 66 | 67 | class pluginFactory(protocol.Factory): 68 | protocol = HashCountRandom ### Set protocol to custom protocol class name 69 | 70 | def __init__(self, name=None): 71 | self.name = name or 'HoneyPy' 72 | -------------------------------------------------------------------------------- /plugins/HashCountRandom/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 foospidy 2 | # https://github.com/foospidy/HoneyPy 3 | # See LICENSE for details 4 | 5 | from HashCountRandom import pluginFactory 6 | -------------------------------------------------------------------------------- /plugins/MOTD/MOTD.py: -------------------------------------------------------------------------------- 1 | # HoneyPy Copyright (C) 2013-2017 foospidy 2 | # https://github.com/foospidy/HoneyPy 3 | # See LICENSE for details 4 | 5 | from twisted.internet import protocol, reactor, endpoints 6 | from twisted.python import log 7 | import uuid 8 | 9 | ### START CUSTOM IMPORTS ### 10 | 11 | ############################ 12 | 13 | class MOTD(protocol.Protocol): ### Set custom protocol class name 14 | localhost = None 15 | remote_host = None 16 | session = None 17 | 18 | ### START CUSTOM VARIABLES ############################################################### 19 | 20 | ########################################################################################## 21 | 22 | # handle events 23 | def connectionMade(self): 24 | self.connect() 25 | 26 | ### START CUSTOM CODE #################################################################### 27 | data = "Prototype unit 0001 is ready to accept programming\r\n" 28 | self.tx(data) 29 | self.transport.loseConnection() 30 | 31 | ########################################################################################## 32 | 33 | def dataReceived(self, data): 34 | self.rx(data) 35 | 36 | ### START CUSTOM CODE #################################################################### 37 | 38 | ########################################################################################## 39 | 40 | ### START CUSTOM FUNCTIONS ################################################################### 41 | 42 | ############################################################################################## 43 | 44 | def connect(self): 45 | self.local_host = self.transport.getHost() 46 | self.remote_host = self.transport.getPeer() 47 | self.session = uuid.uuid1() 48 | log.msg('%s %s CONNECT %s %s %s %s %s' % (self.session, self.remote_host.type, self.local_host.host, self.local_host.port, self.factory.name, self.remote_host.host, self.remote_host.port)) 49 | 50 | def clientConnectionLost(self): 51 | self.transport.loseConnection() 52 | 53 | def tx(self, data): 54 | log.msg('%s %s TX %s %s %s %s %s %s' % (self.session, self.remote_host.type, self.local_host.host, self.local_host.port, self.factory.name, self.remote_host.host, self.remote_host.port, data.encode("hex"))) 55 | self.transport.write(data) 56 | 57 | def rx(self, data): 58 | log.msg('%s %s RX %s %s %s %s %s %s' % (self.session, self.remote_host.type, self.local_host.host, self.local_host.port, self.factory.name, self.remote_host.host, self.remote_host.port, data.encode("hex"))) 59 | 60 | class pluginFactory(protocol.Factory): 61 | protocol = MOTD ### Set protocol to custom protocol class name 62 | 63 | def __init__(self, name=None): 64 | self.name = name or 'HoneyPy' 65 | -------------------------------------------------------------------------------- /plugins/MOTD/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 foospidy 2 | # https://github.com/foospidy/HoneyPy 3 | # See LICENSE for details 4 | 5 | from MOTD import pluginFactory 6 | -------------------------------------------------------------------------------- /plugins/MOTD_udp/MOTD.py: -------------------------------------------------------------------------------- 1 | # HoneyPy Copyright (C) 2013-2017 foospidy 2 | # https://github.com/foospidy/HoneyPy 3 | # See LICENSE for details 4 | 5 | from twisted.internet.protocol import DatagramProtocol 6 | from twisted.python import log 7 | import uuid 8 | 9 | ### START CUSTOM IMPORTS ### 10 | import os 11 | ############################ 12 | 13 | class pluginMain(DatagramProtocol): 14 | 15 | def datagramReceived(self, data, (host, port)): 16 | self.rx(host, port, data) 17 | 18 | ### START CUSTOM CODE #################################################################### 19 | data = "Prototype unit 0001 is ready to accept programming\r\n" 20 | self.tx(host, port, data) 21 | 22 | ########################################################################################## 23 | 24 | ### START CUSTOM FUNCTIONS ################################################################### 25 | 26 | ############################################################################################## 27 | 28 | def tx(self, host, port, data): 29 | log.msg('%s UDP TX %s %s %s %s %s %s' % (self.session, self.host, self.port, self.name, host, port, data.encode("hex"))) 30 | self.transport.write(data, (host, port)) 31 | 32 | def rx(self, host, port, data): 33 | self.session = uuid.uuid1() 34 | log.msg('%s UDP RX %s %s %s %s %s %s' % (self.session, self.host, self.port, self.name, host, port, data.encode("hex"))) 35 | 36 | def __init__(self, name=None, host=None, port=None): 37 | self.name = name or 'HoneyPy' 38 | self.host = host or '???' 39 | self.port = port or '???' 40 | self.session = None 41 | -------------------------------------------------------------------------------- /plugins/MOTD_udp/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 foospidy 2 | # https://github.com/foospidy/HoneyPy 3 | # See LICENSE for details 4 | 5 | from MOTD import pluginMain 6 | -------------------------------------------------------------------------------- /plugins/NtpUdp/NtpUdp.py: -------------------------------------------------------------------------------- 1 | # HoneyPy Copyright (C) 2013-2017 foospidy 2 | # https://github.com/foospidy/HoneyPy 3 | # See LICENSE for details 4 | 5 | from twisted.internet.protocol import DatagramProtocol 6 | from twisted.python import log 7 | import uuid 8 | 9 | ### START CUSTOM IMPORTS ### 10 | from ntpserver import * 11 | 12 | ############################ 13 | 14 | class pluginMain(DatagramProtocol): 15 | 16 | def datagramReceived(self, data, (host, port)): 17 | self.rx(host, port, data) 18 | 19 | ### START CUSTOM CODE #################################################################### 20 | 21 | recvTimestamp = system_to_ntp_time(time.time()) 22 | recvPacket = NTPPacket() 23 | 24 | # catch invalid ntp packets 25 | try: 26 | recvPacket.from_data(data) 27 | except NTPException as ntp_error: 28 | error_data = str(ntp_error) + ' : ' + str(data) 29 | self.log(host, port, error_data) 30 | 31 | 32 | timeStamp_high,timeStamp_low = recvPacket.GetTxTimeStamp() 33 | sendPacket = NTPPacket(version=3,mode=4) 34 | sendPacket.stratum = 2 35 | sendPacket.poll = 10 36 | sendPacket.ref_timestamp = recvTimestamp-5 37 | sendPacket.SetOriginTimeStamp(timeStamp_high,timeStamp_low) 38 | sendPacket.recv_timestamp = recvTimestamp 39 | sendPacket.tx_timestamp = system_to_ntp_time(time.time()) 40 | 41 | self.tx(host, port, sendPacket.to_data()) 42 | 43 | ########################################################################################## 44 | 45 | ### START CUSTOM FUNCTIONS ################################################################### 46 | def log(self, host, port, data): 47 | """Log info message""" 48 | log.msg('%s UDP INFO %s %s %s %s %s %s' % (self.session, self.host, self.port, self.name, host, port, data.encode("hex"))) 49 | ############################################################################################## 50 | 51 | def tx(self, host, port, data): 52 | log.msg('%s UDP TX %s %s %s %s %s %s' % (self.session, self.host, self.port, self.name, host, port, data.encode("hex"))) 53 | self.transport.write(data, (host, port)) 54 | 55 | def rx(self, host, port, data): 56 | self.session = uuid.uuid1() 57 | log.msg('%s UDP RX %s %s %s %s %s %s' % (self.session, self.host, self.port, self.name, host, port, data.encode("hex"))) 58 | 59 | def __init__(self, name=None, host=None, port=None): 60 | self.name = name or 'HoneyPy' 61 | self.host = host or '???' 62 | self.port = port or '???' 63 | self.session = None 64 | -------------------------------------------------------------------------------- /plugins/NtpUdp/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 foospidy 2 | # https://github.com/foospidy/HoneyPy 3 | # See LICENSE for details 4 | 5 | from NtpUdp import pluginMain 6 | 7 | -------------------------------------------------------------------------------- /plugins/NtpUdp/ntpserver.py: -------------------------------------------------------------------------------- 1 | # https://github.com/foospidy/ntpserver 2 | # thanks to: https://github.com/limifly/ntpserver 3 | import datetime 4 | import struct 5 | import time 6 | import mutex 7 | import select 8 | 9 | def system_to_ntp_time(timestamp): 10 | """Convert a system time to a NTP time. 11 | 12 | Parameters: 13 | timestamp -- timestamp in system time 14 | 15 | Returns: 16 | corresponding NTP time 17 | """ 18 | return timestamp + NTP.NTP_DELTA 19 | 20 | def _to_int(timestamp): 21 | """Return the integral part of a timestamp. 22 | 23 | Parameters: 24 | timestamp -- NTP timestamp 25 | 26 | Retuns: 27 | integral part 28 | """ 29 | return int(timestamp) 30 | 31 | def _to_frac(timestamp, n=32): 32 | """Return the fractional part of a timestamp. 33 | 34 | Parameters: 35 | timestamp -- NTP timestamp 36 | n -- number of bits of the fractional part 37 | 38 | Retuns: 39 | fractional part 40 | """ 41 | return int(abs(timestamp - _to_int(timestamp)) * 2**n) 42 | 43 | def _to_time(integ, frac, n=32): 44 | """Return a timestamp from an integral and fractional part. 45 | 46 | Parameters: 47 | integ -- integral part 48 | frac -- fractional part 49 | n -- number of bits of the fractional part 50 | 51 | Retuns: 52 | timestamp 53 | """ 54 | return integ + float(frac)/2**n 55 | 56 | 57 | 58 | class NTPException(Exception): 59 | """Exception raised by this module.""" 60 | pass 61 | 62 | 63 | class NTP: 64 | """Helper class defining constants.""" 65 | 66 | _SYSTEM_EPOCH = datetime.date(*time.gmtime(0)[0:3]) 67 | """system epoch""" 68 | _NTP_EPOCH = datetime.date(1900, 1, 1) 69 | """NTP epoch""" 70 | NTP_DELTA = (_SYSTEM_EPOCH - _NTP_EPOCH).days * 24 * 3600 71 | """delta between system and NTP time""" 72 | 73 | REF_ID_TABLE = { 74 | 'DNC': "DNC routing protocol", 75 | 'NIST': "NIST public modem", 76 | 'TSP': "TSP time protocol", 77 | 'DTS': "Digital Time Service", 78 | 'ATOM': "Atomic clock (calibrated)", 79 | 'VLF': "VLF radio (OMEGA, etc)", 80 | 'callsign': "Generic radio", 81 | 'LORC': "LORAN-C radionavidation", 82 | 'GOES': "GOES UHF environment satellite", 83 | 'GPS': "GPS UHF satellite positioning", 84 | } 85 | """reference identifier table""" 86 | 87 | STRATUM_TABLE = { 88 | 0: "unspecified", 89 | 1: "primary reference", 90 | } 91 | """stratum table""" 92 | 93 | MODE_TABLE = { 94 | 0: "unspecified", 95 | 1: "symmetric active", 96 | 2: "symmetric passive", 97 | 3: "client", 98 | 4: "server", 99 | 5: "broadcast", 100 | 6: "reserved for NTP control messages", 101 | 7: "reserved for private use", 102 | } 103 | """mode table""" 104 | 105 | LEAP_TABLE = { 106 | 0: "no warning", 107 | 1: "last minute has 61 seconds", 108 | 2: "last minute has 59 seconds", 109 | 3: "alarm condition (clock not synchronized)", 110 | } 111 | """leap indicator table""" 112 | 113 | class NTPPacket: 114 | """NTP packet class. 115 | 116 | This represents an NTP packet. 117 | """ 118 | 119 | _PACKET_FORMAT = "!B B B b 11I" 120 | """packet format to pack/unpack""" 121 | 122 | def __init__(self, version=2, mode=3, tx_timestamp=0): 123 | """Constructor. 124 | 125 | Parameters: 126 | version -- NTP version 127 | mode -- packet mode (client, server) 128 | tx_timestamp -- packet transmit timestamp 129 | """ 130 | self.leap = 0 131 | """leap second indicator""" 132 | self.version = version 133 | """version""" 134 | self.mode = mode 135 | """mode""" 136 | self.stratum = 0 137 | """stratum""" 138 | self.poll = 0 139 | """poll interval""" 140 | self.precision = 0 141 | """precision""" 142 | self.root_delay = 0 143 | """root delay""" 144 | self.root_dispersion = 0 145 | """root dispersion""" 146 | self.ref_id = 0 147 | """reference clock identifier""" 148 | self.ref_timestamp = 0 149 | """reference timestamp""" 150 | self.orig_timestamp = 0 151 | self.orig_timestamp_high = 0 152 | self.orig_timestamp_low = 0 153 | """originate timestamp""" 154 | self.recv_timestamp = 0 155 | """receive timestamp""" 156 | self.tx_timestamp = tx_timestamp 157 | self.tx_timestamp_high = 0 158 | self.tx_timestamp_low = 0 159 | """tansmit timestamp""" 160 | 161 | def to_data(self): 162 | """Convert this NTPPacket to a buffer that can be sent over a socket. 163 | 164 | Returns: 165 | buffer representing this packet 166 | 167 | Raises: 168 | NTPException -- in case of invalid field 169 | """ 170 | try: 171 | packed = struct.pack(NTPPacket._PACKET_FORMAT, 172 | (self.leap << 6 | self.version << 3 | self.mode), 173 | self.stratum, 174 | self.poll, 175 | self.precision, 176 | _to_int(self.root_delay) << 16 | _to_frac(self.root_delay, 16), 177 | _to_int(self.root_dispersion) << 16 | 178 | _to_frac(self.root_dispersion, 16), 179 | self.ref_id, 180 | _to_int(self.ref_timestamp), 181 | _to_frac(self.ref_timestamp), 182 | #Change by lichen, avoid loss of precision 183 | self.orig_timestamp_high, 184 | self.orig_timestamp_low, 185 | _to_int(self.recv_timestamp), 186 | _to_frac(self.recv_timestamp), 187 | _to_int(self.tx_timestamp), 188 | _to_frac(self.tx_timestamp)) 189 | except struct.error: 190 | raise NTPException("Invalid NTP packet fields.") 191 | return packed 192 | 193 | def from_data(self, data): 194 | """Populate this instance from a NTP packet payload received from 195 | the network. 196 | 197 | Parameters: 198 | data -- buffer payload 199 | 200 | Raises: 201 | NTPException -- in case of invalid packet format 202 | """ 203 | try: 204 | unpacked = struct.unpack(NTPPacket._PACKET_FORMAT, 205 | data[0:struct.calcsize(NTPPacket._PACKET_FORMAT)]) 206 | except struct.error: 207 | raise NTPException("Invalid NTP packet.") 208 | 209 | self.leap = unpacked[0] >> 6 & 0x3 210 | self.version = unpacked[0] >> 3 & 0x7 211 | self.mode = unpacked[0] & 0x7 212 | self.stratum = unpacked[1] 213 | self.poll = unpacked[2] 214 | self.precision = unpacked[3] 215 | self.root_delay = float(unpacked[4])/2**16 216 | self.root_dispersion = float(unpacked[5])/2**16 217 | self.ref_id = unpacked[6] 218 | self.ref_timestamp = _to_time(unpacked[7], unpacked[8]) 219 | self.orig_timestamp = _to_time(unpacked[9], unpacked[10]) 220 | self.orig_timestamp_high = unpacked[9] 221 | self.orig_timestamp_low = unpacked[10] 222 | self.recv_timestamp = _to_time(unpacked[11], unpacked[12]) 223 | self.tx_timestamp = _to_time(unpacked[13], unpacked[14]) 224 | self.tx_timestamp_high = unpacked[13] 225 | self.tx_timestamp_low = unpacked[14] 226 | 227 | def GetTxTimeStamp(self): 228 | return (self.tx_timestamp_high,self.tx_timestamp_low) 229 | 230 | def SetOriginTimeStamp(self,high,low): 231 | self.orig_timestamp_high = high 232 | self.orig_timestamp_low = low 233 | -------------------------------------------------------------------------------- /plugins/Random/Random.py: -------------------------------------------------------------------------------- 1 | # HoneyPy Copyright (C) 2013-2017 foospidy 2 | # https://github.com/foospidy/HoneyPy 3 | # See LICENSE for details 4 | 5 | from twisted.internet import protocol, reactor, endpoints 6 | from twisted.python import log 7 | import uuid 8 | 9 | ### START CUSTOM IMPORTS ### 10 | import os 11 | ############################ 12 | 13 | class Random(protocol.Protocol): 14 | localhost = None 15 | remote_host = None 16 | session = None 17 | 18 | ### START CUSTOM VARIABLES ############################################################### 19 | 20 | ########################################################################################## 21 | 22 | # handle events 23 | def connectionMade(self): 24 | self.connect() 25 | 26 | ### START CUSTOM CODE #################################################################### 27 | self.tx(str(os.urandom(99)) + '\n') 28 | self.transport.loseConnection() 29 | 30 | ########################################################################################## 31 | 32 | def dataReceived(self, data): 33 | self.rx(data) 34 | 35 | ### START CUSTOM CODE #################################################################### 36 | self.tx(str(os.urandom(99)) + '\n') 37 | 38 | ########################################################################################## 39 | 40 | ### START CUSTOM FUNCTIONS ################################################################### 41 | 42 | ############################################################################################## 43 | 44 | def connect(self): 45 | self.local_host = self.transport.getHost() 46 | self.remote_host = self.transport.getPeer() 47 | self.session = uuid.uuid1() 48 | log.msg('%s %s CONNECT %s %s %s %s %s' % (self.session, self.remote_host.type, self.local_host.host, self.local_host.port, self.factory.name, self.remote_host.host, self.remote_host.port)) 49 | 50 | def clientConnectionLost(self): 51 | self.transport.loseConnection() 52 | 53 | def tx(self, data): 54 | log.msg('%s %s TX %s %s %s %s %s %s' % (self.session, self.remote_host.type, self.local_host.host, self.local_host.port, self.factory.name, self.remote_host.host, self.remote_host.port, data.encode("hex"))) 55 | self.transport.write(data) 56 | 57 | def rx(self, data): 58 | log.msg('%s %s RX %s %s %s %s %s %s' % (self.session, self.remote_host.type, self.local_host.host, self.local_host.port, self.factory.name, self.remote_host.host, self.remote_host.port, data.encode("hex"))) 59 | 60 | class pluginFactory(protocol.Factory): 61 | protocol = Random ### Set protocol to custom protocol class name 62 | 63 | def __init__(self, name=None): 64 | self.name = name or 'HoneyPy' 65 | -------------------------------------------------------------------------------- /plugins/Random/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 foospidy 2 | # https://github.com/foospidy/HoneyPy 3 | # See LICENSE for details 4 | 5 | from Random import pluginFactory 6 | -------------------------------------------------------------------------------- /plugins/SIP/SIP.py: -------------------------------------------------------------------------------- 1 | # HoneyPy Copyright (C) 2013-2017 foospidy 2 | # https://github.com/foospidy/HoneyPy 3 | # See LICENSE for details 4 | 5 | from twisted.internet.protocol import DatagramProtocol 6 | from twisted.python import log 7 | import uuid 8 | 9 | ### START CUSTOM IMPORTS ### 10 | ############################ 11 | 12 | class pluginMain(DatagramProtocol): 13 | 14 | def datagramReceived(self, data, (host, port)): 15 | self.rx(host, port, data) 16 | 17 | ### START CUSTOM CODE #################################################################### 18 | sipheaders = {'Via':'', 'From':'', 'To':'', 'CallID':'', 'Cseq':'', 'UserAgent':'', 'Contact':'', 'Expires':'', 'Allow':'', 'Lenght':'', 'Authorization':''} 19 | sip=data.split("\r\n") 20 | for header in sip: 21 | if "Via:" in header: 22 | sipheaders['Via']=header 23 | elif "From:" in header: 24 | sipheaders['From']=header 25 | elif "To:" in header: 26 | sipheaders['To']=header 27 | elif "Call-ID:" in header: 28 | sipheaders['CallID']=header 29 | elif "CSeq:" in header: 30 | sipheaders['CSeq']=header 31 | elif "User-Agent:" in header: 32 | sipheaders['UserAgent']=header 33 | elif "Contact:" in header: 34 | sipheaders['Contact']=header 35 | elif "Expires:" in header: 36 | sipheaders['Expires']=header 37 | elif "Allow:" in header: 38 | sipheaders['Allow']=header 39 | elif "Content-Length:" in header: 40 | sipheaders['Length']=header 41 | elif "Authorization:" in header: 42 | sipheaders['Authorization']=header 43 | 44 | if "REGISTER" in sip[0]: 45 | if sipheaders['Authorization'] != "": 46 | OK=self.okmessage(sipheaders,sip) 47 | self.tx(host, port, OK) 48 | else: 49 | Unauthorized=self.unauthorizedmessage(sipheaders) 50 | self.tx(host, port, Unauthorized) 51 | if "INVITE" in sip[0]: 52 | if sipheaders['Authorization'] != "": 53 | Try=self.trymessage(sipheaders) 54 | self.tx(host, port, Try) 55 | Ringing=self.ringingmessage(sipheaders) 56 | self.tx(host, port, Ringing) 57 | else: 58 | Proxyauth=self.proxyauthenticationrequiredmessage(sipheaders) 59 | self.tx(host, port, Proxyauth) 60 | if "BYE" in sip[0]: 61 | OK=self.okmessage(sipheaders,sip) 62 | self.tx(host, port, OK) 63 | if "ACK" in sip[0]: 64 | pass 65 | if "CANCEL" in sip[0]: 66 | CANCEL=self.cancelingmessage(sipheaders) 67 | self.tx(host, port, CANCEL) 68 | else: 69 | Notsupported=self.notsupportedmessage(sipheaders) 70 | self.tx(host, port, Notsupported) 71 | 72 | ########################################################################################## 73 | 74 | ### START CUSTOM FUNCTIONS ################################################################### 75 | 76 | def unauthorizedmessage (self, sipheaders): 77 | Unauthorized="SIP/2.0 401 Unauthorized\r\n" 78 | Unauthorized+=sipheaders['Via']+"\r\n" 79 | Unauthorized+=sipheaders['From']+"\r\n" 80 | Unauthorized+=sipheaders['To']+"\r\n" 81 | Unauthorized+=sipheaders['CallID']+"\r\n" 82 | Unauthorized+="CSeq: 1 REGISTER\r\n" 83 | Unauthorized+='WWW-Authenticate: Digest realm="sipplugin.com", nonce="ea9c8e88gf84f1tec4342ae6cbe5a359"\r\n' 84 | Unauthorized+="Server: OpenSER\r\n" 85 | Unauthorized+="Content-Length: 0\r\n\r\n" 86 | 87 | return Unauthorized; 88 | 89 | def okmessage (self, sipheaders, sip): 90 | OK="SIP/2.0 200 OK\r\n" 91 | OK+=sipheaders['Via']+"\r\n" 92 | OK+=sipheaders['From']+"\r\n" 93 | OK+=sipheaders['To'] + "\r\n" 94 | OK+=sipheaders['CallID']+"\r\n" 95 | if "BYE" in sip[0]: 96 | OK+="CSeq: 2 BYE\r\n" 97 | else: 98 | OK+="CSeq: 2 REGISTER\r\n" 99 | OK+=sipheaders['Contact']+"\r\n" 100 | OK+="Server: OpenSER\r\n" 101 | OK+="Content-Length: 0\r\n\r\n" 102 | 103 | return OK; 104 | 105 | def ringingmessage (self, sipheaders): 106 | Ringing="SIP/2.0 180 Ringing\r\n" 107 | Ringing+=sipheaders['Via']+"\r\n" 108 | Ringing+=sipheaders['From']+"\r\n" 109 | Ringing+=sipheaders['To'] + "\r\n" 110 | Ringing+=sipheaders['CallID']+"\r\n" 111 | Ringing+="CSeq: 2 INVITE\r\n" 112 | Ringing+=sipheaders['Contact']+"\r\n" 113 | Ringing+="Allow: INVITE,ACK,BYE,CANCEL,REGISTER\r\n" 114 | Ringing+="Content-Length: 0\r\n\r\n" 115 | 116 | return Ringing; 117 | 118 | def notsupportedmessage (self, sipheaders): 119 | Notsupported="SIP/2.0 489 Event Package Not Supported\r\n" 120 | Notsupported+=sipheaders['Via']+"\r\n" 121 | Notsupported+=sipheaders['From']+"\r\n" 122 | Notsupported+=sipheaders['To'] + "\r\n" 123 | Notsupported+=sipheaders['CallID']+"\r\n" 124 | Notsupported+="Allow: INVITE,ACK,BYE,CANCEL,REGISTER\r\n" 125 | Notsupported+="Content-Length: 0\r\n\r\n" 126 | 127 | return Notsupported; 128 | 129 | def proxyauthenticationrequiredmessage (self, sipheaders): 130 | Proxyauth="SIP/2.0 407 Proxy Authentication Required\r\n" 131 | Proxyauth+=sipheaders['Via']+"\r\n" 132 | Proxyauth+=sipheaders['From']+"\r\n" 133 | Proxyauth+=sipheaders['To'] + "\r\n" 134 | Proxyauth+=sipheaders['CallID']+"\r\n" 135 | Proxyauth+="CSeq: 1 INVITE\r\n" 136 | Proxyauth+='Proxy-Authenticate: Digest realm="sipplugin.com", nonce="587993360c7c45282001e7b9552638d9509ed85f"\r\n' 137 | Proxyauth+="Server: OpenSER\r\n" 138 | Proxyauth+="Content-Length: 0\r\n\r\n" 139 | 140 | return Proxyauth; 141 | 142 | def trymessage (self, sipheaders): 143 | Try="SIP/2.0 100 Giving a try\r\n" 144 | Try+=sipheaders['Via']+"\r\n" 145 | Try+=sipheaders['From']+"\r\n" 146 | Try+=sipheaders['To'] + "\r\n" 147 | Try+=sipheaders['CallID']+"\r\n" 148 | Try+="CSeq: 2 INVITE\r\n" 149 | Try+="Server: OpenSER\r\n" 150 | Try+="Content-Length: 0\r\n\r\n" 151 | 152 | return Try; 153 | 154 | def cancelingmessage (self, sipheaders): 155 | Canceling="SIP/2.0 200 canceling\r\n" 156 | Canceling+=sipheaders['Via']+"\r\n" 157 | Canceling+=sipheaders['From']+"\r\n" 158 | Canceling+=sipheaders['To'] + "\r\n" 159 | Canceling+=sipheaders['CallID']+"\r\n" 160 | Canceling+="CSeq: 2 CANCEL\r\n" 161 | Canceling+="Server: OpenSER\r\n" 162 | Canceling+="Content-Length: 0\r\n\r\n" 163 | 164 | return Canceling; 165 | 166 | ############################################################################################## 167 | 168 | def tx(self, host, port, data): 169 | log.msg('%s UDP TX %s %s %s %s %s %s' % (self.session, self.host, self.port, self.name, host, port, str(data).encode("hex"))) 170 | self.transport.write(data, (host, port)) 171 | 172 | def rx(self, host, port, data): 173 | self.session = uuid.uuid1() 174 | log.msg('%s UDP RX %s %s %s %s %s %s' % (self.session, self.host, self.port, self.name, host, port, data.encode("hex"))) 175 | 176 | def __init__(self, name=None, host=None, port=None): 177 | self.name = name or 'HoneyPy' 178 | self.host = host or '???' 179 | self.port = port or '???' 180 | self.session = None 181 | -------------------------------------------------------------------------------- /plugins/SIP/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 foospidy 2 | # https://github.com/foospidy/HoneyPy 3 | # See LICENSE for details 4 | 5 | from SIP import pluginMain 6 | -------------------------------------------------------------------------------- /plugins/SmtpExim/SmtpExim.py: -------------------------------------------------------------------------------- 1 | # HoneyPy Copyright (C) 2013-2017 foospidy 2 | # https://github.com/foospidy/HoneyPy 3 | # See LICENSE for details 4 | 5 | from twisted.internet import protocol, reactor, endpoints 6 | from twisted.python import log 7 | import uuid 8 | 9 | ### START CUSTOM IMPORTS ### 10 | import time 11 | 12 | ############################ 13 | 14 | class SmtpExim(protocol.Protocol): ### Set custom protocol class name 15 | localhost = None 16 | remote_host = None 17 | session = None 18 | 19 | ### START CUSTOM VARIABLES ############################################################### 20 | state = 'COMMAND' 21 | ########################################################################################## 22 | 23 | # handle events 24 | def connectionMade(self): 25 | self.connect() 26 | 27 | ### START CUSTOM CODE #################################################################### 28 | self.tx('220 localhost ESMTP Exim 4.80 ' + time.strftime('%a, %d %b %H:%M:%S %z') + '\n'); 29 | 30 | 31 | ########################################################################################## 32 | 33 | def dataReceived(self, data): 34 | self.rx(data) 35 | 36 | ### START CUSTOM CODE #################################################################### 37 | 38 | if 'COMMAND' == self.state: 39 | # parse command 40 | commandParts = str(data).split() 41 | 42 | if 0 == len(commandParts): 43 | self.tx('') 44 | else: 45 | command = commandParts[0].lower() 46 | args = commandParts[1:] 47 | 48 | try: 49 | method = getattr(self, 'do_' + command) 50 | except AttributeError, e: 51 | self.tx('500 unrecognized command\n') 52 | else: 53 | try: 54 | method(*args) 55 | except Exception, e: 56 | self.tx('500 Too many unrecognized commands\n') 57 | self.transport.loseConnection() 58 | else: 59 | self.rx(data) 60 | if '.' == str(data).strip(): 61 | self.state = 'COMMAND' 62 | # todo: dynamically generate id 63 | self.tx('250 OK id=1ZaadR-0004Vi-1D\n') 64 | 65 | ########################################################################################## 66 | 67 | ### START CUSTOM FUNCTIONS ################################################################### 68 | def do_help(self): 69 | self.tx('214-Commands supported:\n214 AUTH HELO EHLO MAIL RCPT DATA NOOP QUIT RSET HELP\n') 70 | 71 | def do_ehlo(self, domain=None): 72 | if domain is None: 73 | self.tx('501 Syntactically invalid EHLO argument(s)\n') 74 | else: 75 | self.tx('250 localhost Hello ' + domain + ' [::1]\n250-SIZE 52428800\n250-8BITMIME\n250-PIPELINING\n250 HELP\n') 76 | 77 | def do_helo(self, domain=None): 78 | if domain is None: 79 | self.tx('501 Syntactically invalid HELO argument(s)\n') 80 | else: 81 | self.tx('250 localhost Hello ' + domain + ' [::1]\n') 82 | 83 | def do_mail(self, arg=None, sender=None): 84 | # todo: validate sender format (e.g. email address) 85 | if arg is None: 86 | self.tx('500 unrecognized command\n') 87 | elif 'from:' != arg: 88 | self.tx('500 unrecognized command\n') 89 | elif sender is None: 90 | self.tx('501 MAIL must have an address operand\n') 91 | else: 92 | self.tx('250 OK\n') 93 | 94 | def do_rcpt(self, arg=None, recipient=None): 95 | # todo: validate recipeint format (e.g. email address) 96 | if arg is None: 97 | self.tx('500 unrecognized command\n') 98 | elif 'to:' != arg: 99 | self.tx('500 unrecognized command\n') 100 | elif recipient is None: 101 | self.tx('501 RCPT must have an address operand\n') 102 | else: 103 | self.tx('250 Accepted\n') 104 | 105 | def do_data(self): 106 | self.state = 'DATA' 107 | self.tx('354 Enter message, ending with "." on a line by itself\n') 108 | 109 | def do_rset(self): 110 | self.tx('250 Reset OK\n') 111 | 112 | def do_auth(self): 113 | self.tx('503 AUTH command used when not advertised\n') 114 | 115 | def do_noop(self): 116 | self.tx('250 OK\n') 117 | 118 | def do_quit(self): 119 | self.tx('221 localhost closing connection\n') 120 | self.transport.loseConnection() 121 | 122 | 123 | ############################################################################################## 124 | 125 | def connect(self): 126 | self.local_host = self.transport.getHost() 127 | self.remote_host = self.transport.getPeer() 128 | self.session = uuid.uuid1() 129 | log.msg('%s %s CONNECT %s %s %s %s %s' % (self.session, self.remote_host.type, self.local_host.host, self.local_host.port, self.factory.name, self.remote_host.host, self.remote_host.port)) 130 | 131 | def clientConnectionLost(self): 132 | self.transport.loseConnection() 133 | 134 | def tx(self, data): 135 | log.msg('%s %s TX %s %s %s %s %s %s' % (self.session, self.remote_host.type, self.local_host.host, self.local_host.port, self.factory.name, self.remote_host.host, self.remote_host.port, data.encode("hex"))) 136 | self.transport.write(data) 137 | 138 | def rx(self, data): 139 | log.msg('%s %s RX %s %s %s %s %s %s' % (self.session, self.remote_host.type, self.local_host.host, self.local_host.port, self.factory.name, self.remote_host.host, self.remote_host.port, data.encode("hex"))) 140 | 141 | class pluginFactory(protocol.Factory): 142 | protocol = SmtpExim ### Set protocol to custom protocol class name 143 | 144 | def __init__(self, name=None): 145 | self.name = name or 'HoneyPy' 146 | -------------------------------------------------------------------------------- /plugins/SmtpExim/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 foospidy 2 | # https://github.com/foospidy/HoneyPy 3 | # See LICENSE for details 4 | 5 | from SmtpExim import pluginFactory 6 | -------------------------------------------------------------------------------- /plugins/TFTP/TFTP.py: -------------------------------------------------------------------------------- 1 | # HoneyPy Copyright (C) 2013-2017 foospidy 2 | # https://github.com/foospidy/HoneyPy 3 | # See LICENSE for details 4 | 5 | from twisted.internet.protocol import DatagramProtocol 6 | from twisted.python import log 7 | import uuid 8 | 9 | ### START CUSTOM IMPORTS ### 10 | import struct 11 | import os 12 | ############################ 13 | 14 | OPCODE_RRQ = 1 15 | OPCODE_WRQ = 2 16 | OPCODE_DATA = 3 17 | OPCODE_ACK = 4 18 | OPCODE_ERR = 5 19 | 20 | ASCII_FILE = 'file.txt' 21 | OCTET_FILE = 'file.bin' 22 | 23 | MAX_UPLOAD_SIZE = 3906 * 512 # 3906 * 512 = 2MB 24 | 25 | class pluginMain(DatagramProtocol): 26 | get_file = None 27 | block_number = 1 28 | put_file = None 29 | put_block_number = 0 30 | data = None 31 | 32 | def datagramReceived(self, data, (host, port)): 33 | #self.rx(host, port, data) 34 | 35 | ### START CUSTOM CODE #################################################################### 36 | command_string = '' 37 | opcode = self.getOpcode(data) 38 | 39 | if opcode == OPCODE_RRQ: 40 | mode = self.getRRQMode(data) 41 | command_string = 'RRQ %s %s' % (self.getFileName(data), mode) 42 | 43 | if opcode == OPCODE_WRQ: 44 | mode = self.getWRQMode(data) 45 | command_string = 'WRQ %s %s' % (self.getFileName(data), mode) 46 | 47 | if opcode == OPCODE_DATA: 48 | block_number = self.getDataBlockNumber(data) 49 | command_string = 'DATA %s %s' % (block_number, str(data)) 50 | 51 | if opcode == OPCODE_ACK: 52 | command_string = 'ACK %s' % (str(data)) 53 | 54 | self.rx(host, port, '%s' % command_string) 55 | 56 | if opcode == OPCODE_RRQ: 57 | path = os.path.dirname(os.path.realpath(__file__)) + '/' 58 | 59 | if 'netascii' == mode: 60 | path += ASCII_FILE 61 | else: 62 | path += OCTET_FILE 63 | 64 | self.get_file = open(path, "r") 65 | self.block_number = 1 66 | 67 | self.resetFile(self.get_file) 68 | self.transmit(self.get_file, host, port) 69 | 70 | if opcode == OPCODE_WRQ: 71 | packet = struct.pack("!hh", OPCODE_ACK, self.put_block_number) 72 | self.tx(host, port, packet) 73 | 74 | 75 | if opcode == OPCODE_DATA: 76 | self.put_block_number += 1 77 | 78 | if (self.put_block_number * 512) > MAX_UPLOAD_SIZE: 79 | error_message = "Disk full or allocation exceeded.\000" 80 | packet = struct.pack("!hh%ds" % len(error_message), OPCODE_ERR, 3, error_message) 81 | else: 82 | packet = struct.pack("!hh", OPCODE_ACK, self.put_block_number) 83 | 84 | self.tx(host, port, packet) 85 | 86 | if opcode == OPCODE_ACK: 87 | block_number = struct.unpack("!H", data[2:4])[0] 88 | self.ack(block_number) 89 | self.transmit(self.get_file, host, port) 90 | 91 | ########################################################################################## 92 | 93 | ### START CUSTOM FUNCTIONS ################################################################### 94 | def getOpcode(self, packet): 95 | opcode = struct.unpack("!H", packet[0:2])[0] 96 | return opcode 97 | 98 | def getRRQMode(self, packet): 99 | rrqmode = packet[packet[2:].index("\0") + 3:-1].lower() 100 | return rrqmode 101 | 102 | def getFileName(self, packet): 103 | return packet.split("\0")[1] 104 | 105 | def getDataBlockNumber(self, packet): 106 | block_number = struct.unpack("!H", packet[2:4])[0] 107 | return block_number 108 | 109 | def getWRQMode(self, packet): 110 | wrqmode = packet[packet[2:].index("\0") + 3:-1].lower() 111 | return wrqmode 112 | 113 | def resetFile(self, theFile): 114 | theFile.seek(0, 0) 115 | 116 | def transmit(self, theFile, host, port): 117 | self.data = theFile.read(512) 118 | packet = struct.pack("!HH%ds" % len(self.data), OPCODE_DATA, self.block_number, self.data) 119 | #transmit_string = '%s DATA %s %s' % (len(data), self.block_number, str(data)) 120 | #print transmit_string 121 | 122 | self.tx(host, port, packet) 123 | 124 | def ack(self, block_number): 125 | if block_number == self.block_number: 126 | if len(self.data) < 512: 127 | # EOF, transmission complete 128 | return True 129 | else: 130 | self.data = self.get_file.read(512) 131 | self.block_number += 1 132 | 133 | #else - if unknown block number then possible tampering 134 | 135 | ############################################################################################## 136 | 137 | def tx(self, host, port, data): 138 | log.msg('%s UDP TX %s %s %s %s %s %s' % (self.session, self.host, self.port, self.name, host, port, data.encode("hex"))) 139 | self.transport.write(data, (host, int(port))) 140 | 141 | def rx(self, host, port, data): 142 | self.session = uuid.uuid1() 143 | log.msg('%s UDP RX %s %s %s %s %s %s' % (self.session, self.host, self.port, self.name, host, port, data.encode("hex"))) 144 | 145 | def __init__(self, name=None, host=None, port=None): 146 | self.name = name or 'HoneyPy' 147 | self.host = host or '???' 148 | self.port = port or '???' 149 | self.session = None 150 | -------------------------------------------------------------------------------- /plugins/TFTP/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 foospidy 2 | # https://github.com/foospidy/HoneyPy 3 | # See LICENSE for details 4 | 5 | from TFTP import pluginMain 6 | -------------------------------------------------------------------------------- /plugins/TFTP/credit.txt: -------------------------------------------------------------------------------- 1 | Giving credit to references: 2 | 3 | http://www.pcvr.nl/tcpip/tftp_tri.htm 4 | 5 | https://mail.python.org/pipermail/python-list/2001-January/104857.html 6 | 7 | http://www.codefu.org/people/darkness/tptftpserver.py 8 | 9 | tptftpserver.py 10 | ======================================================================== 11 | #!/usr/bin/python 12 | # 13 | # tptftpserver: a minimal TFTP server made to get to DRAC cards behind 14 | # The Planet's firewalls. 15 | # $Id: tptftpserver.py,v 1.3 2005/01/03 17:13:39 darkness Exp $ 16 | # 17 | # Copyright (c) 2005, darkness@codefu.org 18 | # All rights reserved. 19 | # 20 | # Redistribution and use in source and binary forms, with or without 21 | # modification, are permitted provided that the following conditions 22 | # are met: 23 | # 24 | # * Redistributions of source code must retain the above copyright 25 | # notice, this list of conditions and the following disclaimer. 26 | # * Redistributions in binary form must reproduce the above 27 | # copyright notice, this list of conditions and the following 28 | # disclaimer in the documentation and/or other materials 29 | # provided with the distribution. 30 | # * The names of the contributors may not be used to endorse or 31 | # promote products derived from this software without specific 32 | # prior written permission. 33 | # 34 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 35 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 36 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 37 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 38 | # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 39 | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 40 | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 41 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 42 | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 43 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 44 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 45 | # 46 | # Some notes: 47 | # 48 | # * This script was written under Python 2.3. For the maximum chance 49 | # of working, I suggest you use 2.3 or later. 50 | # 51 | # * To use this script, start it like "tptftpserver.py " 52 | # where "filename" is the only file that will be served up. For any 53 | # file that is requested, this file will be the only one served up. 54 | # 55 | # * To start the server on a different port, use "tptftpserver.py 56 | # " where is the port you want 57 | # it to run on. You will get some extra debugging information when 58 | # you supply the port number, as well. If you want this debugging 59 | # information on the standard port, start with "tptftpserver.py 60 | # 69" (69 being the well-known TFTP port). 61 | # 62 | # * If a file transfer is aborted before it is finished, you will need 63 | # to restart this TFTP server. Once a file transmission has begun, 64 | # the server doesn't recognize anything until it finishes. In 65 | # general, it never hurts to restart the server before/after 66 | # transfers, successful or otherwise. 67 | # 68 | # * This server is far, far from a complete implementation of TFTP. I 69 | # doubt it even compiles with the RFC in the functionality it does 70 | # implement. All that said, I have used this to successfully send a 71 | # remote floppy image to a Dell RAC III card. I implemented TFTP as 72 | # described in RFC 1350. 73 | 74 | import logging 75 | import struct 76 | import sys 77 | from StringIO import StringIO 78 | import socket as socketlib 79 | from os import path 80 | 81 | # This is the TFTP port. 82 | DEFAULT_PORT = 69 83 | 84 | # I chose this to be the maximum size for a UDP packet, but I might 85 | # not have chosen big enough. I'm too lazy to look up the IP header 86 | # format. 87 | RECVFROM_BUFSIZE = 65536 88 | 89 | # TRANSMISSION_TIMEOUT is measured in seconds. 90 | TRANSMISSION_TIMEOUT = 2.0 91 | 92 | OPCODE_RRQ = 1 93 | OPCODE_DATA = 3 94 | OPCODE_ACK = 4 95 | 96 | log = logging.getLogger("tptftpserver") 97 | 98 | class Transmitter: 99 | # send aFile to client over socket 100 | def __init__(self, aFile, client, socket): 101 | self.__file = aFile 102 | self.__client = client 103 | self.__socket = socket 104 | self.__blockNumber = 1 105 | self.__data = self.__file.read(512) 106 | 107 | def transmit(self): 108 | log.debug("transmitting block number %d" % self.__blockNumber) 109 | self.__socket.sendto(struct.pack("!HH%ds" % len(self.__data), 110 | OPCODE_DATA, self.__blockNumber, 111 | self.__data), 112 | self.__client) 113 | 114 | def ack(self, blockNumber): 115 | if blockNumber == self.__blockNumber: 116 | if len(self.__data) < 512: 117 | # EOF, transmission complete 118 | return True 119 | else: 120 | self.__data = self.__file.read(512) 121 | self.__blockNumber += 1 122 | else: 123 | log.warning("unknown ack block number %d" % blockNumber) 124 | 125 | def isSameClient(self, client): 126 | return client == self.__client 127 | 128 | WAIT_FOR_RRQ = 1 129 | WAIT_FOR_ACK = 2 130 | 131 | def main(path, port=DEFAULT_PORT): 132 | theFile = open(path, "r") 133 | socket = __makeServerSocket(port) 134 | while True: 135 | client = __waitForRRQ(socket) 136 | log.debug("transmitting to %r" % (client,)) 137 | __rewindFile(theFile) 138 | __transmitFile(theFile, client, socket) 139 | log.debug("transmission complete") 140 | 141 | def __waitForRRQ(socket): 142 | socket.settimeout(None) 143 | while True: 144 | packet, client = socket.recvfrom(RECVFROM_BUFSIZE) 145 | log.debug("received packet=%r" % packet) 146 | opcode = __getOpcode(packet) 147 | if opcode == OPCODE_RRQ: 148 | mode = __getRRQMode(packet) 149 | if mode == "octet": 150 | break 151 | else: 152 | log.warning("request has unsupported mode %r, ignoring" 153 | % mode) 154 | return client 155 | 156 | def __transmitFile(theFile, client, socket): 157 | transmitter = Transmitter(theFile, client, socket) 158 | socket.settimeout(TRANSMISSION_TIMEOUT) 159 | while True: 160 | try: 161 | packet, client = socket.recvfrom(RECVFROM_BUFSIZE) 162 | except socketlib.timeout: 163 | log.debug("ACK timeout") 164 | transmitter.transmit() 165 | continue 166 | if not transmitter.isSameClient(client): 167 | log.warning("Packet from %r received while transmitting elsewhere" 168 | % client) 169 | continue 170 | log.debug("received possible ack %r" % (packet,)) 171 | opcode = __getOpcode(packet) 172 | if opcode == OPCODE_ACK: 173 | if transmitter.ack(struct.unpack("!H", packet[2:4])[0]): 174 | break 175 | transmitter.transmit() 176 | else: 177 | log.warning("unknown opcode %#x, expected ACK" % opcode) 178 | 179 | def __rewindFile(theFile): 180 | theFile.seek(0, 0) 181 | 182 | def __getRRQMode(packet): 183 | return packet[packet[2:].index("\0") + 3:-1].lower() 184 | 185 | def __getOpcode(packet): 186 | return struct.unpack("!H", packet[0:2])[0] 187 | 188 | def __makeServerSocket(port): 189 | socket = socketlib.socket(socketlib.AF_INET, socketlib.SOCK_DGRAM) 190 | socket.bind(('', port)) 191 | return socket 192 | 193 | def __checkNumberOfArgumentsToProgram(): 194 | if len(sys.argv) < 2: 195 | log.error("expected path to file to serve as first argument") 196 | sys.exit(1) 197 | elif len(sys.argv) > 3: 198 | log.error("too many arguments given") 199 | sys.exit(1) 200 | 201 | if __name__ == "__main__": 202 | logging.basicConfig() 203 | __checkNumberOfArgumentsToProgram() 204 | path = sys.argv[1] 205 | if len(sys.argv) == 3: 206 | logging.getLogger().setLevel(logging.DEBUG) 207 | main(path, int(sys.argv[2])) 208 | else: 209 | main(path) 210 | -------------------------------------------------------------------------------- /plugins/TFTP/file.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/foospidy/HoneyPy/6ca3d6eb603b7aa11aac5c908db12c0a3e78000f/plugins/TFTP/file.bin -------------------------------------------------------------------------------- /plugins/TFTP/file.txt: -------------------------------------------------------------------------------- 1 | access_key_id="AKIAIOSFODNN7" 2 | secret_access_key="wJalrXUtnFEMI/K7MDENG/bPxRfiCY" -------------------------------------------------------------------------------- /plugins/TFTP/readme.txt: -------------------------------------------------------------------------------- 1 | TFTP HoneyPy plugin! 2 | 3 | Basic functionality: 4 | - When the client sends the get command, no matter what path/file the specify it will always return 5 | file.txt or file.bin, depending on the mode, e.g. netascii or octet. 6 | - When the client sends the put command, the file will not be written to disk but will end up in logs, 7 | also there is a max file size allowed set by the MAX_UPLOAD_SIZE variable. 8 | 9 | References to tftp related stuff: 10 | 11 | - https://www.akamai.com/uk/en/multimedia/documents/state-of-the-internet/trivial-file-transfer-protocol-reflection-ddos-threat-advisory.pdf 12 | -------------------------------------------------------------------------------- /plugins/TelnetUnix/TelnetUnix.py: -------------------------------------------------------------------------------- 1 | # HoneyPy Copyright (C) 2013-2017 foospidy 2 | # https://github.com/foospidy/HoneyPy 3 | # See LICENSE for details 4 | 5 | from twisted.internet import protocol, reactor, endpoints, defer 6 | from twisted.python import log 7 | import uuid 8 | 9 | ### START CUSTOM IMPORTS ### 10 | from twisted.protocols.telnet import * 11 | from lib.clilib import * 12 | 13 | ############################ 14 | 15 | class TelnetUnix(Telnet): ### Set custom protocol class name 16 | localhost = None 17 | remote_host = None 18 | session = None 19 | 20 | ### START CUSTOM VARIABLES ############################################################### 21 | username = None 22 | prompt = '$' 23 | 24 | ########################################################################################## 25 | 26 | # handle events 27 | def connectionMade(self): 28 | self.connect() 29 | 30 | ### START CUSTOM CODE #################################################################### 31 | Telnet.connectionMade(self) 32 | 33 | ########################################################################################## 34 | 35 | def dataReceived(self, data): 36 | self.rx(data) 37 | 38 | ### START CUSTOM CODE #################################################################### 39 | Telnet.dataReceived(self, data) 40 | 41 | ########################################################################################## 42 | 43 | ### START CUSTOM FUNCTIONS ################################################################### 44 | def welcomeMessage(self): 45 | return "Debian GNU/Linux 7\r\n" 46 | 47 | def loginPrompt(self): 48 | return "Login: " 49 | 50 | def telnet_Password(self, password): 51 | self.write(IAC+WONT+ECHO+"\r\n") 52 | 53 | try: 54 | successful_login = self.checkUserAndPass(password) 55 | 56 | if not successful_login: 57 | self.tx("\r\ninvalid login\r\npassword:") 58 | return 'Password' # return the mode 59 | else: 60 | self.loggedIn() 61 | 62 | self.username = self.username.strip() 63 | 64 | if 'root' == self.username: 65 | self.prompt = '#' 66 | 67 | self.tx(self.username + self.prompt + ' ') 68 | 69 | return 'Command' # return the mode 70 | 71 | except Exception, e: 72 | print 'Error performing telnet authentication: ' + e + '\r\n' 73 | return 'Done' # return the mode 74 | 75 | def checkUserAndPass(self, password): 76 | authenticated = False 77 | 78 | password_list = ('admin', 'password', 'root', '12345', '123456') 79 | 80 | if password in password_list: 81 | authenticated = True 82 | 83 | return authenticated 84 | 85 | def telnet_Command(self, cmd): 86 | 87 | # parse command 88 | commands = str(cmd).split(';') 89 | 90 | for c in commands: 91 | commandParts = str(c.strip()).split() 92 | 93 | if 0 == len(commandParts): 94 | if 'root' == self.username: 95 | self.prompt = '#' 96 | 97 | self.tx(self.username + self.prompt + ' ') 98 | else: 99 | command = commandParts[0].lower() 100 | # if using path, get last element (the command) 101 | command = command.split('/')[-1:] 102 | args = commandParts[1:] 103 | 104 | try: 105 | method = getattr(self, 'do_' + command[0]) 106 | except AttributeError, e: 107 | self.tx('- bash: ' + command[0] + ': command not found\r\n') 108 | self.tx(self.username + self.prompt + ' ') 109 | else: 110 | try: 111 | method(*args) 112 | self.tx('\r\n' + self.username + self.prompt + ' ') 113 | except Exception, e: 114 | self.tx('WARNING: System error, closing connection.\n') 115 | print str(e) 116 | self.transport.loseConnection() 117 | 118 | return 'Command' 119 | 120 | def do_exit(self, args=None): 121 | self.mode = 'Done' 122 | self.transport.loseConnection() 123 | 124 | def do_man(self, *args): 125 | command = '' 126 | 127 | if len(args) > 0: 128 | command = args[0] 129 | 130 | self.tx(man(command)) 131 | 132 | def do_echo(self, *args): 133 | self.tx(echo(*args)) 134 | 135 | def do_enable(self, *args): 136 | self.tx(enable()) 137 | 138 | def do_uname(self, *args): 139 | self.tx(uname(*args)) 140 | 141 | def do_whoami(self, *args): 142 | self.tx(whoami(self.username, *args)) 143 | 144 | def do_which(self, *args): 145 | command = '' 146 | 147 | if len(args) > 0: 148 | command = args[0] 149 | 150 | self.tx(which(command)) 151 | 152 | def do_rm(self, *args): 153 | self.tx(rm()) 154 | 155 | def do_sh(self, *args): 156 | self.tx(sh()) 157 | 158 | def do_cd(self, *args): 159 | self.tx(cd()) 160 | 161 | def do_busybox(self, *args): 162 | self.tx(busybox(*args)) 163 | 164 | def do_wget(self, *args): 165 | self.tx(wget()) 166 | 167 | ############################################################################################## 168 | 169 | def connect(self): 170 | self.local_host = self.transport.getHost() 171 | self.remote_host = self.transport.getPeer() 172 | self.session = uuid.uuid1() 173 | log.msg('%s %s CONNECT %s %s %s %s %s' % (self.session, self.remote_host.type, self.local_host.host, self.local_host.port, self.factory.name, self.remote_host.host, self.remote_host.port)) 174 | 175 | def clientConnectionLost(self): 176 | self.transport.loseConnection() 177 | 178 | def tx(self, data): 179 | log.msg('%s %s TX %s %s %s %s %s %s' % (self.session, self.remote_host.type, self.local_host.host, self.local_host.port, self.factory.name, self.remote_host.host, self.remote_host.port, data.encode("hex"))) 180 | self.transport.write(data) 181 | 182 | def rx(self, data): 183 | log.msg('%s %s RX %s %s %s %s %s %s' % (self.session, self.remote_host.type, self.local_host.host, self.local_host.port, self.factory.name, self.remote_host.host, self.remote_host.port, data.encode("hex"))) 184 | 185 | class pluginFactory(protocol.Factory): 186 | protocol = TelnetUnix ### Set protocol to custom protocol class name 187 | 188 | def __init__(self, name=None): 189 | self.name = name or 'HoneyPy' 190 | -------------------------------------------------------------------------------- /plugins/TelnetUnix/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 foospidy 2 | # https://github.com/foospidy/HoneyPy 3 | # See LICENSE for details 4 | 5 | from TelnetUnix import pluginFactory 6 | -------------------------------------------------------------------------------- /plugins/TelnetUnix/readme.txt: -------------------------------------------------------------------------------- 1 | #### Description 2 | A telnet service implemented with the Twisted telnet protocol. 3 | 4 | #### Dependencies 5 | This plugin requires clilib, which is now included in HoneyPy 6 | -------------------------------------------------------------------------------- /plugins/TelnetWindows/TelnetWindows.py: -------------------------------------------------------------------------------- 1 | # HoneyPy Copyright (C) 2013-2017 foospidy 2 | # https://github.com/foospidy/HoneyPy 3 | # See LICENSE for details 4 | 5 | from twisted.internet import protocol, reactor, endpoints, defer 6 | from twisted.python import log 7 | import uuid 8 | 9 | ### START CUSTOM IMPORTS ### 10 | 11 | ############################ 12 | 13 | class TelnetWindows(protocol.Protocol): ### Set custom protocol class name 14 | localhost = None 15 | remote_host = None 16 | session = None 17 | 18 | ### START CUSTOM VARIABLES ############################################################### 19 | state = 'NO_UNAME' 20 | uname = None 21 | pword = None 22 | count = 0 23 | 24 | ########################################################################################## 25 | 26 | # handle events 27 | def connectionMade(self): 28 | self.connect() 29 | 30 | ### START CUSTOM CODE #################################################################### 31 | self.tx('Welcome to Microsoft Telnet Service\n\nlogin: ') 32 | 33 | ########################################################################################## 34 | 35 | def dataReceived(self, data): 36 | self.rx(data) 37 | 38 | ### START CUSTOM CODE #################################################################### 39 | if 'NO_UNAME' == self.state: 40 | self.uname = data.rstrip() 41 | self.state = 'NO_PWORD' 42 | self.tx('password: ') 43 | elif 'NO_PWORD' == self.state: 44 | self.pword = data.rstrip() 45 | self.count = self.count + 1 46 | 47 | if 'Pa$$word' == self.pword: 48 | self.tx('WARNING: System error, closing connection.\n') 49 | self.transport.loseConnection() 50 | else: 51 | if 3 == self.count: 52 | self.transport.loseConnection() 53 | else: 54 | self.state = 'NO_UNAME' 55 | self.tx('\n') 56 | self.tx('login: ') 57 | 58 | ########################################################################################## 59 | 60 | ### START CUSTOM FUNCTIONS ################################################################### 61 | 62 | 63 | ############################################################################################## 64 | 65 | def connect(self): 66 | self.local_host = self.transport.getHost() 67 | self.remote_host = self.transport.getPeer() 68 | self.session = uuid.uuid1() 69 | log.msg('%s %s CONNECT %s %s %s %s %s' % (self.session, self.remote_host.type, self.local_host.host, self.local_host.port, self.factory.name, self.remote_host.host, self.remote_host.port)) 70 | 71 | def tx(self, data): 72 | log.msg('%s %s TX %s %s %s %s %s %s' % (self.session, self.remote_host.type, self.local_host.host, self.local_host.port, self.factory.name, self.remote_host.host, self.remote_host.port, data.encode("hex"))) 73 | self.transport.write(data) 74 | 75 | def rx(self, data): 76 | log.msg('%s %s RX %s %s %s %s %s %s' % (self.session, self.remote_host.type, self.local_host.host, self.local_host.port, self.factory.name, self.remote_host.host, self.remote_host.port, data.encode("hex"))) 77 | 78 | class pluginFactory(protocol.Factory): 79 | protocol = TelnetWindows ### Set protocol to custom protocol class name 80 | 81 | def __init__(self, name=None): 82 | self.name = name or 'HoneyPy' 83 | -------------------------------------------------------------------------------- /plugins/TelnetWindows/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 foospidy 2 | # https://github.com/foospidy/HoneyPy 3 | # See LICENSE for details 4 | 5 | from TelnetWindows import pluginFactory 6 | -------------------------------------------------------------------------------- /plugins/Web/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 foospidy 2 | # https://github.com/foospidy/HoneyPy 3 | # See LICENSE for details 4 | 5 | from Web import pluginFactory 6 | -------------------------------------------------------------------------------- /plugins/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/foospidy/HoneyPy/6ca3d6eb603b7aa11aac5c908db12c0a3e78000f/plugins/__init__.py -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | dnslib == 0.9.7 2 | requests == 2.20.0 3 | Twisted == 14.0.2 4 | python_twitter == 3.1 5 | certifi 6 | urllib3 7 | pika == 0.10.0 8 | pylint 9 | autopep8 10 | hpfeeds3 == 0.9.8 11 | --------------------------------------------------------------------------------