├── .gitignore ├── README.rst ├── deb ├── DEBIAN │ ├── control │ └── postinst └── etc │ ├── nanopot.ini │ └── systemd │ └── system │ └── nanopot.service ├── docs ├── Makefile ├── conf.py ├── index.rst ├── make.bat └── pages │ └── quickstart.rst ├── nanopot.example.ini ├── nanopot ├── __init__.py └── __main__.py └── setup.py /.gitignore: -------------------------------------------------------------------------------- 1 | nanopot.test.ini 2 | nanopot.log 3 | venv 4 | *.egg-info 5 | dist/ 6 | __pycache__ 7 | *.pyc 8 | .idea 9 | *.deb 10 | _build 11 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | NanoPot 2 | ======= 3 | 4 | .. image:: https://readthedocs.org/projects/nanopot/badge/?version=latest 5 | :target: https://nanopot.readthedocs.io/en/latest/?badge=latest 6 | :alt: Documentation Status 7 | 8 | .. image:: https://badge.fury.io/py/nanopot.svg 9 | :target: https://badge.fury.io/py/nanopot 10 | 11 | .. image:: https://badge.fury.io/gh/DevDungeon%2FNanoPot.svg 12 | :target: https://badge.fury.io/gh/DevDungeon%2FNanoPot 13 | 14 | NanoPot is a simple TCP honeypot written in Python 3. 15 | 16 | Source Code 17 | ----------- 18 | 19 | https://github.com/DevDungeon/NanoPot 20 | 21 | PyPI package 22 | ------------ 23 | 24 | https://pypi.org/project/nanopot/ 25 | 26 | Documentation 27 | ------------- 28 | 29 | https://nanopot.rtfd.io 30 | 31 | Documentation can also be found in the `docs/` directory 32 | as reStructuredText files. Build the docs by running `make` 33 | in the `docs/` directory, then viewing `docs/_build/html/index.html`. 34 | 35 | Live coding of this project 36 | --------------------------- 37 | 38 | - https://www.youtube.com/watch?v=77qj9o9pmek 39 | - https://www.youtube.com/DevDungeon 40 | 41 | Author 42 | ------ 43 | 44 | NanoDano 45 | 46 | -------------------------------------------------------------------------------- /deb/DEBIAN/control: -------------------------------------------------------------------------------- 1 | Package: nanopot 2 | Version: 1.0.0 3 | Maintainer: NanoDano 4 | Description: Simple TCP honeypot in Python3 5 | Homepage: https://github.com/DevDungeon/NanoPot 6 | Architecture: all 7 | Depends: python3, python3-pip 8 | -------------------------------------------------------------------------------- /deb/DEBIAN/postinst: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | id -u nanopot &>/dev/null || useradd nanopot 4 | mkdir -p /home/nanopot 5 | 6 | /usr/bin/python3 -m pip uninstall -y nanopot 7 | /usr/bin/python3 -m pip install nanopot --no-cache-dir 8 | 9 | touch /var/log/nanopot.log 10 | chown -R nanopot:nanopot /var/log/nanopot.log 11 | 12 | systemctl enable nanopot 13 | -------------------------------------------------------------------------------- /deb/etc/nanopot.ini: -------------------------------------------------------------------------------- 1 | [default] 2 | ports=8080,8888,8808 3 | logfile=/var/log/nanopot.log 4 | 5 | -------------------------------------------------------------------------------- /deb/etc/systemd/system/nanopot.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=NanoPot honeypot 3 | After=network.target 4 | 5 | [Service] 6 | Type=simple 7 | User=nanopot 8 | WorkingDirectory=/home/nanopot 9 | ExecStart=/usr/bin/python3 -m nanopot /etc/nanopot.ini 10 | Restart=on-failure 11 | 12 | [Install] 13 | WantedBy=multi-user.target 14 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | SOURCEDIR = . 8 | BUILDDIR = _build 9 | 10 | # Put it first so that "make" without argument is like "make help". 11 | help: 12 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 13 | 14 | .PHONY: help Makefile 15 | 16 | # Catch-all target: route all unknown targets to Sphinx using the new 17 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 18 | %: Makefile 19 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Configuration file for the Sphinx documentation builder. 4 | # 5 | # This file does only contain a selection of the most common options. For a 6 | # full list see the documentation: 7 | # http://www.sphinx-doc.org/en/master/config 8 | 9 | # -- Path setup -------------------------------------------------------------- 10 | 11 | # If extensions (or modules to document with autodoc) are in another directory, 12 | # add these directories to sys.path here. If the directory is relative to the 13 | # documentation root, use os.path.abspath to make it absolute, like shown here. 14 | # 15 | # import os 16 | # import sys 17 | # sys.path.insert(0, os.path.abspath('.')) 18 | 19 | 20 | # -- Project information ----------------------------------------------------- 21 | 22 | project = u'NanoPot' 23 | copyright = u'2019, NanoDano' 24 | author = u'NanoDano' 25 | 26 | # The short X.Y version 27 | version = u'' 28 | # The full version, including alpha/beta/rc tags 29 | release = u'1.0.0' 30 | 31 | 32 | # -- General configuration --------------------------------------------------- 33 | 34 | # If your documentation needs a minimal Sphinx version, state it here. 35 | # 36 | # needs_sphinx = '1.0' 37 | 38 | # Add any Sphinx extension module names here, as strings. They can be 39 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 40 | # ones. 41 | extensions = [ 42 | 'sphinx.ext.autodoc', 43 | 'sphinx.ext.coverage', 44 | 'sphinx.ext.viewcode', 45 | ] 46 | 47 | # Add any paths that contain templates here, relative to this directory. 48 | templates_path = ['_templates'] 49 | 50 | # The suffix(es) of source filenames. 51 | # You can specify multiple suffix as a list of string: 52 | # 53 | # source_suffix = ['.rst', '.md'] 54 | source_suffix = '.rst' 55 | 56 | # The master toctree document. 57 | master_doc = 'index' 58 | 59 | # The language for content autogenerated by Sphinx. Refer to documentation 60 | # for a list of supported languages. 61 | # 62 | # This is also used if you do content translation via gettext catalogs. 63 | # Usually you set "language" from the command line for these cases. 64 | language = None 65 | 66 | # List of patterns, relative to source directory, that match files and 67 | # directories to ignore when looking for source files. 68 | # This pattern also affects html_static_path and html_extra_path. 69 | exclude_patterns = [u'_build', 'Thumbs.db', '.DS_Store'] 70 | 71 | # The name of the Pygments (syntax highlighting) style to use. 72 | pygments_style = None 73 | 74 | 75 | # -- Options for HTML output ------------------------------------------------- 76 | 77 | # The theme to use for HTML and HTML Help pages. See the documentation for 78 | # a list of builtin themes. 79 | # 80 | # html_theme = 'alabaster' 81 | 82 | # Theme options are theme-specific and customize the look and feel of a theme 83 | # further. For a list of options available for each theme, see the 84 | # documentation. 85 | # 86 | # html_theme_options = {} 87 | 88 | # Add any paths that contain custom static files (such as style sheets) here, 89 | # relative to this directory. They are copied after the builtin static files, 90 | # so a file named "default.css" will overwrite the builtin "default.css". 91 | html_static_path = ['_static'] 92 | 93 | # Custom sidebar templates, must be a dictionary that maps document names 94 | # to template names. 95 | # 96 | # The default sidebars (for documents that don't match any pattern) are 97 | # defined by theme itself. Builtin themes are using these templates by 98 | # default: ``['localtoc.html', 'relations.html', 'sourcelink.html', 99 | # 'searchbox.html']``. 100 | # 101 | # html_sidebars = {} 102 | 103 | 104 | # -- Options for HTMLHelp output --------------------------------------------- 105 | 106 | # Output file base name for HTML help builder. 107 | htmlhelp_basename = 'NanoPotdoc' 108 | 109 | 110 | # -- Options for LaTeX output ------------------------------------------------ 111 | 112 | latex_elements = { 113 | # The paper size ('letterpaper' or 'a4paper'). 114 | # 115 | # 'papersize': 'letterpaper', 116 | 117 | # The font size ('10pt', '11pt' or '12pt'). 118 | # 119 | # 'pointsize': '10pt', 120 | 121 | # Additional stuff for the LaTeX preamble. 122 | # 123 | # 'preamble': '', 124 | 125 | # Latex figure (float) alignment 126 | # 127 | # 'figure_align': 'htbp', 128 | } 129 | 130 | # Grouping the document tree into LaTeX files. List of tuples 131 | # (source start file, target name, title, 132 | # author, documentclass [howto, manual, or own class]). 133 | latex_documents = [ 134 | (master_doc, 'NanoPot.tex', u'NanoPot Documentation', 135 | u'NanoDano', 'manual'), 136 | ] 137 | 138 | 139 | # -- Options for manual page output ------------------------------------------ 140 | 141 | # One entry per manual page. List of tuples 142 | # (source start file, name, description, authors, manual section). 143 | man_pages = [ 144 | (master_doc, 'nanopot', u'NanoPot Documentation', 145 | [author], 1) 146 | ] 147 | 148 | 149 | # -- Options for Texinfo output ---------------------------------------------- 150 | 151 | # Grouping the document tree into Texinfo files. List of tuples 152 | # (source start file, target name, title, author, 153 | # dir menu entry, description, category) 154 | texinfo_documents = [ 155 | (master_doc, 'NanoPot', u'NanoPot Documentation', 156 | author, 'NanoPot', 'One line description of project.', 157 | 'Miscellaneous'), 158 | ] 159 | 160 | 161 | # -- Options for Epub output ------------------------------------------------- 162 | 163 | # Bibliographic Dublin Core info. 164 | epub_title = project 165 | 166 | # The unique identifier of the text. This can be a ISBN number 167 | # or the project homepage. 168 | # 169 | # epub_identifier = '' 170 | 171 | # A unique identification for the text. 172 | # 173 | # epub_uid = '' 174 | 175 | # A list of files that should not be packed into the epub file. 176 | epub_exclude_files = ['search.html'] 177 | 178 | 179 | # -- Extension configuration ------------------------------------------------- 180 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | .. NanoPot documentation master file, created by 2 | sphinx-quickstart on Wed Apr 3 23:31:08 2019. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to NanoPot's documentation! 7 | =================================== 8 | 9 | .. image:: https://readthedocs.org/projects/nanopot/badge/?version=latest 10 | :target: https://nanopot.readthedocs.io/en/latest/?badge=latest 11 | :alt: Documentation Status 12 | 13 | .. image:: https://badge.fury.io/py/nanopot.svg 14 | :target: https://badge.fury.io/py/nanopot 15 | 16 | .. image:: https://badge.fury.io/gh/DevDungeon%2FNanoPot.svg 17 | :target: https://badge.fury.io/gh/DevDungeon%2FNanoPot 18 | 19 | .. toctree:: 20 | :maxdepth: 2 21 | :caption: Contents: 22 | 23 | pages/quickstart.rst 24 | 25 | Indices and tables 26 | ================== 27 | 28 | * :ref:`genindex` 29 | * :ref:`modindex` 30 | * :ref:`search` 31 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=. 11 | set BUILDDIR=_build 12 | 13 | if "%1" == "" goto help 14 | 15 | %SPHINXBUILD% >NUL 2>NUL 16 | if errorlevel 9009 ( 17 | echo. 18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 19 | echo.installed, then set the SPHINXBUILD environment variable to point 20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 21 | echo.may add the Sphinx directory to PATH. 22 | echo. 23 | echo.If you don't have Sphinx installed, grab it from 24 | echo.http://sphinx-doc.org/ 25 | exit /b 1 26 | ) 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /docs/pages/quickstart.rst: -------------------------------------------------------------------------------- 1 | NanoPot Quickstart 2 | ================== 3 | 4 | NanoPot is a simple TCP honeypot written in Python 3. 5 | 6 | Installation 7 | ------------ 8 | 9 | python -m pip install nanopot 10 | 11 | Running 12 | ------- 13 | 14 | python -m nanopot 15 | 16 | 17 | Debian package 18 | -------------- 19 | 20 | NanoPot can also be installed as a systemd service on Debian 21 | based distributions. 22 | 23 | Dowload the package from GitHub release, or 24 | build the Debian package with: 25 | 26 | dpkg-deb --build ./deb nanopot-1.0.0.deb 27 | 28 | 29 | Install the Debian package with: 30 | 31 | sudo dpkg -i nanopot-1.0.0.deb 32 | 33 | Config defaults to `/etc/nanopot.ini`. 34 | Logs will be available in `/var/log/nanopot.log`. 35 | 36 | Source Code 37 | ----------- 38 | 39 | https://github.com/DevDungeon/NanoPot 40 | 41 | PyPI package 42 | ------------ 43 | 44 | https://pypi.org/project/nanopot/ 45 | 46 | Documentation 47 | ------------- 48 | 49 | https://nanopot.rtfd.io 50 | 51 | -------------------------------------------------------------------------------- /nanopot.example.ini: -------------------------------------------------------------------------------- 1 | [default] 2 | ports=7770,7771,7772 3 | logfile=/var/log/nanopot.log 4 | 5 | -------------------------------------------------------------------------------- /nanopot/__init__.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import threading 3 | from socket import socket, timeout 4 | 5 | 6 | class HoneyPot(object): 7 | 8 | def __init__(self, bind_ip, ports, log_filepath): 9 | if len(ports) < 1: 10 | raise Exception("No ports provided.") 11 | 12 | self.bind_ip = bind_ip 13 | self.ports = ports 14 | self.log_filepath = log_filepath 15 | self.listener_threads = {} 16 | self.logger = self.prepare_logger() 17 | 18 | self.logger.info("Honeypot initializing...") 19 | self.logger.info("Ports: %s" % self.ports) 20 | self.logger.info("Log filepath: %s" % self.log_filepath) 21 | 22 | def handle_connection(self, client_socket, port, ip, remote_port): 23 | self.logger.info("Connection received: %s: %s:%d" % (port, ip, remote_port)) 24 | 25 | client_socket.settimeout(4) 26 | try: 27 | data = client_socket.recv(64) 28 | self.logger.info("Data received: %s: %s:%d: %s" % (port, ip, remote_port, data)) 29 | client_socket.send("Access denied.\n".encode('utf8')) 30 | except timeout: 31 | pass 32 | client_socket.close() 33 | 34 | def start_new_listener_thread(self, port): 35 | # Create a new listener 36 | listener = socket() # Defaults (socket.AF_INET, socket.SOCK_STREAM) 37 | listener.bind((self.bind_ip, int(port))) 38 | listener.listen(5) 39 | while True: 40 | client, addr = listener.accept() 41 | client_handler = threading.Thread(target=self.handle_connection, args=(client, port, addr[0], addr[1])) 42 | client_handler.start() 43 | 44 | def start_listening(self): 45 | for port in self.ports: 46 | self.listener_threads[port] = threading.Thread(target=self.start_new_listener_thread, args=(port,)) 47 | self.listener_threads[port].start() 48 | 49 | def run(self): 50 | self.start_listening() 51 | 52 | def prepare_logger(self): 53 | logging.basicConfig(level=logging.DEBUG, 54 | format='%(asctime)s %(levelname)-8s %(message)s', 55 | datefmt='%Y-%m-%d %H:%M:%s', 56 | filename=self.log_filepath, 57 | filemode='w') 58 | logger = logging.getLogger(__name__) 59 | 60 | # Adding console handler 61 | console_handler = logging.StreamHandler() 62 | console_handler.setLevel(logging.DEBUG) 63 | logger.addHandler(console_handler) 64 | return logger 65 | 66 | 67 | -------------------------------------------------------------------------------- /nanopot/__main__.py: -------------------------------------------------------------------------------- 1 | """NanoPot. 2 | 3 | Simple TCP honeypot logger 4 | 5 | Usage: 6 | nanopot 7 | 8 | Options: 9 | Path to config options .ini file 10 | -h --help Show this screen. 11 | """ 12 | import configparser 13 | import sys 14 | from nanopot import HoneyPot 15 | 16 | # Check arguments 17 | if len(sys.argv) < 2 or sys.argv[1] in ['-h', '--help']: 18 | print(__doc__) 19 | sys.exit(1) 20 | 21 | # Load config 22 | config_filepath = sys.argv[1] 23 | config = configparser.ConfigParser() 24 | config.read(config_filepath) 25 | 26 | ports = config.get('default', 'ports', raw=True, fallback="8080,8888,9999") 27 | host = config.get('default', 'host', raw=True, fallback="0.0.0.0") 28 | log_filepath = config.get('default', 'logfile', raw=True, fallback="/var/log/nanopot.log") 29 | 30 | # Double check ports provided 31 | ports_list = [] 32 | try: 33 | ports_list = ports.split(',') 34 | except Exception as e: 35 | print('[-] Error parsing ports: %s.\nExiting.', ports) 36 | sys.exit(1) 37 | 38 | # Launch honeypot 39 | honeypot = HoneyPot(host, ports_list, log_filepath) 40 | honeypot.run() 41 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | 3 | 4 | def readme_file_contents(): 5 | with open('README.rst') as readme_file: 6 | data = readme_file.read() 7 | return data 8 | 9 | 10 | setup( 11 | name='nanopot', 12 | version='1.0.0', 13 | description='Simple TCP honeypot', 14 | long_description=readme_file_contents(), 15 | author='DevDungeon', 16 | author_email='nanodano@devdungeon.com', 17 | license='MIT', 18 | packages=['nanopot'], 19 | zip_safe=False, 20 | install_requires=[] 21 | ) 22 | --------------------------------------------------------------------------------