├── requirements.txt ├── docs ├── logo.png ├── services │ ├── mssql.rst │ ├── mysql.rst │ ├── webserver.rst │ └── windows.rst ├── requirements.txt ├── alerts │ ├── hpfeeds.rst │ ├── webhook.md │ └── email.rst ├── starting │ ├── opencanary.rst │ └── correlator.rst └── index.rst ├── opencanary ├── test │ ├── requirements.txt │ ├── logger.py │ └── opencanary.conf ├── modules │ ├── data │ │ ├── rdp │ │ │ ├── login.rss │ │ │ ├── default.rss │ │ │ ├── login-failed.rss │ │ │ └── login-passreset.rss │ │ ├── http │ │ │ └── skin │ │ │ │ ├── nasLogin │ │ │ │ ├── static │ │ │ │ │ ├── img │ │ │ │ │ │ ├── 02.jpg │ │ │ │ │ │ ├── favicon.ico │ │ │ │ │ │ ├── icon_tile.png │ │ │ │ │ │ ├── icon_dsm_16.png │ │ │ │ │ │ ├── icon_dsm_32.png │ │ │ │ │ │ ├── icon_dsm_48.png │ │ │ │ │ │ ├── icon_dsm_64.png │ │ │ │ │ │ ├── icon_dsm_96.png │ │ │ │ │ │ └── synohdpack │ │ │ │ │ │ │ └── images │ │ │ │ │ │ │ ├── Components │ │ │ │ │ │ │ ├── trigger.png │ │ │ │ │ │ │ ├── bt_pagebar.png │ │ │ │ │ │ │ ├── checkbox.png │ │ │ │ │ │ │ ├── icon_error.png │ │ │ │ │ │ │ ├── tab_arrow.png │ │ │ │ │ │ │ ├── tab_shadow.png │ │ │ │ │ │ │ ├── tree_arrow.png │ │ │ │ │ │ │ ├── bt_dropdown.png │ │ │ │ │ │ │ ├── icon_filter.png │ │ │ │ │ │ │ ├── icon_loading.gif │ │ │ │ │ │ │ ├── icon_search.png │ │ │ │ │ │ │ ├── icon_success.png │ │ │ │ │ │ │ ├── radio_button.png │ │ │ │ │ │ │ ├── trigger_date.png │ │ │ │ │ │ │ ├── c_icon_general.png │ │ │ │ │ │ │ ├── category_expand.png │ │ │ │ │ │ │ ├── col-move-bottom.png │ │ │ │ │ │ │ ├── date_dropdown.png │ │ │ │ │ │ │ ├── date_prev_next.png │ │ │ │ │ │ │ ├── fieldset_expand.png │ │ │ │ │ │ │ ├── shadow_category.png │ │ │ │ │ │ │ ├── shadow_footbar.png │ │ │ │ │ │ │ ├── bt_grid_dropdown.png │ │ │ │ │ │ │ ├── icon_information.png │ │ │ │ │ │ │ ├── icon_search_clear.png │ │ │ │ │ │ │ ├── dropdown_menu_parent.png │ │ │ │ │ │ │ ├── dropdown_menu_tick.png │ │ │ │ │ │ │ ├── icon_advanced_search.png │ │ │ │ │ │ │ └── superbox_button_cancel.png │ │ │ │ │ │ │ ├── dsm │ │ │ │ │ │ │ ├── resources │ │ │ │ │ │ │ │ └── images │ │ │ │ │ │ │ │ │ ├── bt_bugs.png │ │ │ │ │ │ │ │ │ ├── folder.png │ │ │ │ │ │ │ │ │ ├── rt_button.png │ │ │ │ │ │ │ │ │ ├── login │ │ │ │ │ │ │ │ │ ├── dark │ │ │ │ │ │ │ │ │ │ ├── 0.png │ │ │ │ │ │ │ │ │ │ ├── 1.png │ │ │ │ │ │ │ │ │ │ ├── 2.png │ │ │ │ │ │ │ │ │ │ ├── 3.png │ │ │ │ │ │ │ │ │ │ ├── 4.png │ │ │ │ │ │ │ │ │ │ ├── 5dot.png │ │ │ │ │ │ │ │ │ │ ├── DSM.png │ │ │ │ │ │ │ │ │ │ ├── beta.png │ │ │ │ │ │ │ │ │ │ ├── synology.png │ │ │ │ │ │ │ │ │ │ ├── copyright_2014.png │ │ │ │ │ │ │ │ │ │ └── copyright_2015.png │ │ │ │ │ │ │ │ │ ├── icon_pw.png │ │ │ │ │ │ │ │ │ ├── icon_user.png │ │ │ │ │ │ │ │ │ ├── light │ │ │ │ │ │ │ │ │ │ ├── 0.png │ │ │ │ │ │ │ │ │ │ ├── 1.png │ │ │ │ │ │ │ │ │ │ ├── 2.png │ │ │ │ │ │ │ │ │ │ ├── 3.png │ │ │ │ │ │ │ │ │ │ ├── 4.png │ │ │ │ │ │ │ │ │ │ ├── DSM.png │ │ │ │ │ │ │ │ │ │ ├── 5dot.png │ │ │ │ │ │ │ │ │ │ ├── beta.png │ │ │ │ │ │ │ │ │ │ ├── synology.png │ │ │ │ │ │ │ │ │ │ ├── copyright_2014.png │ │ │ │ │ │ │ │ │ │ └── copyright_2015.png │ │ │ │ │ │ │ │ │ ├── icon_phone.png │ │ │ │ │ │ │ │ │ ├── login_bkg_highlight_top.png │ │ │ │ │ │ │ │ │ ├── login_bkg_highlight_bottom.png │ │ │ │ │ │ │ │ │ └── weather │ │ │ │ │ │ │ │ │ │ ├── login_icon_weather_cold.png │ │ │ │ │ │ │ │ │ │ ├── login_icon_weather_fog.png │ │ │ │ │ │ │ │ │ │ ├── login_icon_weather_hail.png │ │ │ │ │ │ │ │ │ │ ├── login_icon_weather_moon.png │ │ │ │ │ │ │ │ │ │ ├── login_icon_weather_rain.png │ │ │ │ │ │ │ │ │ │ ├── login_icon_weather_snow.png │ │ │ │ │ │ │ │ │ │ ├── login_icon_weather_sun.png │ │ │ │ │ │ │ │ │ │ ├── login_icon_weather_cloudy.png │ │ │ │ │ │ │ │ │ │ ├── login_icon_weather_thunder.png │ │ │ │ │ │ │ │ │ │ ├── login_icon_weather_tornado.png │ │ │ │ │ │ │ │ │ │ ├── login_icon_weather_windy.png │ │ │ │ │ │ │ │ │ │ ├── login_icon_weather_moon_clouds.png │ │ │ │ │ │ │ │ │ │ └── login_icon_weather_sun_clouds.png │ │ │ │ │ │ │ │ │ ├── wizard_bkg_h.png │ │ │ │ │ │ │ │ │ ├── bt_dsm_mobile.png │ │ │ │ │ │ │ │ │ ├── desktop │ │ │ │ │ │ │ │ │ ├── add_one.png │ │ │ │ │ │ │ │ │ ├── spotlight.png │ │ │ │ │ │ │ │ │ ├── icon_app_category.png │ │ │ │ │ │ │ │ │ └── taskbar_spinner.gif │ │ │ │ │ │ │ │ │ ├── dsm5_badge_num.png │ │ │ │ │ │ │ │ │ ├── icon_drag_add.png │ │ │ │ │ │ │ │ │ ├── icon_drag_ban.png │ │ │ │ │ │ │ │ │ ├── icon_question.png │ │ │ │ │ │ │ │ │ ├── preview_bar_bg.png │ │ │ │ │ │ │ │ │ ├── shadow_footbar.png │ │ │ │ │ │ │ │ │ ├── item_drag_status.png │ │ │ │ │ │ │ │ │ ├── taskbar │ │ │ │ │ │ │ │ │ ├── more_apps.png │ │ │ │ │ │ │ │ │ ├── showdesktop.png │ │ │ │ │ │ │ │ │ ├── taskbar_bg.png │ │ │ │ │ │ │ │ │ ├── taskbar_bt.png │ │ │ │ │ │ │ │ │ ├── taskbar_shadow.png │ │ │ │ │ │ │ │ │ ├── taskbar_split.png │ │ │ │ │ │ │ │ │ ├── taskbar_bt_apps.png │ │ │ │ │ │ │ │ │ ├── tray_icon_search.png │ │ │ │ │ │ │ │ │ ├── tray_icon_widget.png │ │ │ │ │ │ │ │ │ ├── user_menu_about.png │ │ │ │ │ │ │ │ │ ├── user_menu_logout.png │ │ │ │ │ │ │ │ │ ├── user_menu_options.png │ │ │ │ │ │ │ │ │ ├── user_menu_restart.png │ │ │ │ │ │ │ │ │ ├── tray_icon_user_menu.png │ │ │ │ │ │ │ │ │ ├── user_menu_shutdown.png │ │ │ │ │ │ │ │ │ ├── tray_icon_notification.png │ │ │ │ │ │ │ │ │ ├── tray_icon_pilot_view.png │ │ │ │ │ │ │ │ │ └── taskbar_bt_widgets_shadow.png │ │ │ │ │ │ │ │ │ ├── components │ │ │ │ │ │ │ │ │ ├── icon_error.png │ │ │ │ │ │ │ │ │ ├── status_fail.png │ │ │ │ │ │ │ │ │ ├── status_loading.gif │ │ │ │ │ │ │ │ │ ├── status_success.png │ │ │ │ │ │ │ │ │ └── icon_image_selector.png │ │ │ │ │ │ │ │ │ ├── dsm5_notification_num.png │ │ │ │ │ │ │ │ │ ├── dsmv5_wizard_bkg_v_01.png │ │ │ │ │ │ │ │ │ ├── dsmv5_wizard_bkg_v_02.png │ │ │ │ │ │ │ │ │ ├── module_list_icon │ │ │ │ │ │ │ │ │ ├── c_icon_CMS.png │ │ │ │ │ │ │ │ │ ├── c_icon_backup.png │ │ │ │ │ │ │ │ │ ├── c_icon_groups.png │ │ │ │ │ │ │ │ │ ├── c_icon_portal.png │ │ │ │ │ │ │ │ │ ├── c_icon_region.png │ │ │ │ │ │ │ │ │ ├── c_icon_speed.png │ │ │ │ │ │ │ │ │ ├── c_icon_syslog.png │ │ │ │ │ │ │ │ │ ├── c_icon_users.png │ │ │ │ │ │ │ │ │ ├── c_icon_volume.png │ │ │ │ │ │ │ │ │ ├── c_icon_business.png │ │ │ │ │ │ │ │ │ ├── c_icon_connect.png │ │ │ │ │ │ │ │ │ ├── c_icon_contact.png │ │ │ │ │ │ │ │ │ ├── c_icon_dsm_apps.png │ │ │ │ │ │ │ │ │ ├── c_icon_general.png │ │ │ │ │ │ │ │ │ ├── c_icon_network.png │ │ │ │ │ │ │ │ │ ├── c_icon_overview.png │ │ │ │ │ │ │ │ │ ├── c_icon_process.png │ │ │ │ │ │ │ │ │ ├── c_icon_security.png │ │ │ │ │ │ │ │ │ ├── c_icon_wireless.png │ │ │ │ │ │ │ │ │ ├── c_icon_community.png │ │ │ │ │ │ │ │ │ ├── c_icon_expansion.png │ │ │ │ │ │ │ │ │ ├── c_icon_hot_spare.png │ │ │ │ │ │ │ │ │ ├── c_icon_info_center.png │ │ │ │ │ │ │ │ │ ├── c_icon_installed.png │ │ │ │ │ │ │ │ │ ├── c_icon_iscsi_lun.png │ │ │ │ │ │ │ │ │ ├── c_icon_login_style.png │ │ │ │ │ │ │ │ │ ├── c_icon_networkmap.png │ │ │ │ │ │ │ │ │ ├── c_icon_performance.png │ │ │ │ │ │ │ │ │ ├── c_icon_privilege.png │ │ │ │ │ │ │ │ │ ├── c_icon_purchases.png │ │ │ │ │ │ │ │ │ ├── c_icon_raid_group.png │ │ │ │ │ │ │ │ │ ├── c_icon_recommend.png │ │ │ │ │ │ │ │ │ ├── c_icon_ssd_cache.png │ │ │ │ │ │ │ │ │ ├── c_icon_utilities.png │ │ │ │ │ │ │ │ │ ├── c_icon_web_server.png │ │ │ │ │ │ │ │ │ ├── c_icon_file_services.png │ │ │ │ │ │ │ │ │ ├── c_icon_iscsi_target.png │ │ │ │ │ │ │ │ │ ├── c_icon_media_library.png │ │ │ │ │ │ │ │ │ ├── c_icon_notifications.png │ │ │ │ │ │ │ │ │ ├── c_icon_public_access.png │ │ │ │ │ │ │ │ │ ├── c_icon_quickconnect.png │ │ │ │ │ │ │ │ │ ├── c_icon_external_devices.png │ │ │ │ │ │ │ │ │ ├── c_icon_hdd_management.png │ │ │ │ │ │ │ │ │ ├── c_icon_shared_folders.png │ │ │ │ │ │ │ │ │ ├── c_icon_task_scheduler.png │ │ │ │ │ │ │ │ │ ├── c_icon_update_and_reset.png │ │ │ │ │ │ │ │ │ ├── c_icon_directory_service.png │ │ │ │ │ │ │ │ │ ├── c_icon_hardware_and_power.png │ │ │ │ │ │ │ │ │ └── c_icon_terminal_and_SNMP.png │ │ │ │ │ │ │ │ │ └── widget_window │ │ │ │ │ │ │ │ │ └── widget_rt_button.png │ │ │ │ │ │ │ └── modules │ │ │ │ │ │ │ │ ├── ExternalDevices │ │ │ │ │ │ │ │ └── images │ │ │ │ │ │ │ │ │ └── tray_icon_device.png │ │ │ │ │ │ │ │ ├── FileTaskMonitor │ │ │ │ │ │ │ │ └── images │ │ │ │ │ │ │ │ │ ├── tray_icon_bgtask.gif │ │ │ │ │ │ │ │ │ ├── tray_icon_bgtask.png │ │ │ │ │ │ │ │ │ ├── tray_icon_upload.gif │ │ │ │ │ │ │ │ │ ├── tray_icon_upload.png │ │ │ │ │ │ │ │ │ ├── tray_icon_download.gif │ │ │ │ │ │ │ │ │ └── tray_icon_download.png │ │ │ │ │ │ │ │ ├── PollingTask │ │ │ │ │ │ │ │ └── images │ │ │ │ │ │ │ │ │ └── tray_icon_disk_port.png │ │ │ │ │ │ │ │ └── ThumbConvertProgress │ │ │ │ │ │ │ │ └── images │ │ │ │ │ │ │ │ ├── tray_icon_creating_thumbnail.gif │ │ │ │ │ │ │ │ └── tray_icon_creating_thumbnail.png │ │ │ │ │ │ │ └── scrollbar │ │ │ │ │ │ │ ├── scrollbar_black_h.png │ │ │ │ │ │ │ ├── scrollbar_black_v.png │ │ │ │ │ │ │ ├── scrollbar_white_h.png │ │ │ │ │ │ │ └── scrollbar_white_v.png │ │ │ │ │ ├── fonts │ │ │ │ │ │ └── roboto.woff │ │ │ │ │ ├── css │ │ │ │ │ │ └── style.css │ │ │ │ │ └── js │ │ │ │ │ │ └── misc.js │ │ │ │ ├── 400.html │ │ │ │ ├── 404.html │ │ │ │ ├── 403.html │ │ │ │ └── redirect.html │ │ │ │ └── basicLogin │ │ │ │ ├── 404.html │ │ │ │ ├── 403.html │ │ │ │ └── index.html │ │ └── httpproxy │ │ │ └── skin │ │ │ └── squid │ │ │ └── auth.html │ ├── sip.py │ ├── snmp.py │ ├── example0.py │ ├── ntp.py │ ├── tftp.py │ ├── rdp.py │ ├── example1.py │ ├── git.py │ ├── samba.py │ ├── llmnr.py │ ├── ftp.py │ ├── telnet.py │ ├── https.py │ ├── httpproxy.py │ ├── vnc.py │ ├── __init__.py │ └── mysql.py ├── __init__.py ├── data │ ├── settings-usermodule.json │ └── settings.json ├── iphelper.py └── honeycred.py ├── .flake8 ├── MANIFEST.in ├── opencanary.service ├── run.sh ├── .readthedocs.yaml ├── Dockerfile.stable ├── .pre-commit-config.yaml ├── .github └── workflows │ ├── stale_issues.yml │ ├── publish.yml │ ├── opencanary_tests.yml │ └── docker-build.yml ├── Dockerfile.latest ├── docker-compose.yml ├── LICENSE ├── .gitignore ├── setup.py ├── bin ├── opencanaryd └── opencanary.tac └── data └── .opencanary.conf /requirements.txt: -------------------------------------------------------------------------------- 1 | -e . 2 | -------------------------------------------------------------------------------- /docs/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/docs/logo.png -------------------------------------------------------------------------------- /opencanary/test/requirements.txt: -------------------------------------------------------------------------------- 1 | requests 2 | paramiko==2.12.0 3 | PyMySQL 4 | gitpython 5 | pytest 6 | -------------------------------------------------------------------------------- /opencanary/modules/data/rdp/login.rss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/rdp/login.rss -------------------------------------------------------------------------------- /opencanary/modules/data/rdp/default.rss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/rdp/default.rss -------------------------------------------------------------------------------- /opencanary/modules/data/rdp/login-failed.rss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/rdp/login-failed.rss -------------------------------------------------------------------------------- /opencanary/__init__.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | __version__ = "0.9.7" 4 | 5 | STDPATH = os.pathsep.join(["/usr/bin", "/bin", "/usr/sbin", "/sbin"]) 6 | -------------------------------------------------------------------------------- /opencanary/modules/data/rdp/login-passreset.rss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/rdp/login-passreset.rss -------------------------------------------------------------------------------- /opencanary/test/logger.py: -------------------------------------------------------------------------------- 1 | from opencanary.logger import logger 2 | 3 | for i in range(10): 4 | logger.log({"Test": i, "Random": "FJEd8dfdhsxf2f"}) 5 | -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/02.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/02.jpg -------------------------------------------------------------------------------- /.flake8: -------------------------------------------------------------------------------- 1 | [flake8] 2 | ignore = E501, W503, E203 3 | exclude = .git,__pycache__,docs/conf.py,build,dist,opencanary/modules/des.py 4 | max-complexity = 10 5 | min_python_version = 3.9 6 | -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/fonts/roboto.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/fonts/roboto.woff -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/favicon.ico -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/icon_tile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/icon_tile.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/icon_dsm_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/icon_dsm_16.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/icon_dsm_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/icon_dsm_32.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/icon_dsm_48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/icon_dsm_48.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/icon_dsm_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/icon_dsm_64.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/icon_dsm_96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/icon_dsm_96.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/Components/trigger.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/Components/trigger.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/Components/bt_pagebar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/Components/bt_pagebar.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/Components/checkbox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/Components/checkbox.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/Components/icon_error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/Components/icon_error.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/Components/tab_arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/Components/tab_arrow.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/Components/tab_shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/Components/tab_shadow.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/Components/tree_arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/Components/tree_arrow.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/Components/bt_dropdown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/Components/bt_dropdown.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/Components/icon_filter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/Components/icon_filter.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/Components/icon_loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/Components/icon_loading.gif -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/Components/icon_search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/Components/icon_search.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/Components/icon_success.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/Components/icon_success.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/Components/radio_button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/Components/radio_button.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/Components/trigger_date.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/Components/trigger_date.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/Components/c_icon_general.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/Components/c_icon_general.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/Components/category_expand.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/Components/category_expand.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/Components/col-move-bottom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/Components/col-move-bottom.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/Components/date_dropdown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/Components/date_dropdown.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/Components/date_prev_next.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/Components/date_prev_next.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/Components/fieldset_expand.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/Components/fieldset_expand.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/Components/shadow_category.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/Components/shadow_category.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/Components/shadow_footbar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/Components/shadow_footbar.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/Components/bt_grid_dropdown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/Components/bt_grid_dropdown.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/Components/icon_information.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/Components/icon_information.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/Components/icon_search_clear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/Components/icon_search_clear.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/bt_bugs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/bt_bugs.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/folder.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/scrollbar/scrollbar_black_h.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/scrollbar/scrollbar_black_h.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/scrollbar/scrollbar_black_v.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/scrollbar/scrollbar_black_v.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/scrollbar/scrollbar_white_h.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/scrollbar/scrollbar_white_h.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/scrollbar/scrollbar_white_v.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/scrollbar/scrollbar_white_v.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/Components/dropdown_menu_parent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/Components/dropdown_menu_parent.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/Components/dropdown_menu_tick.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/Components/dropdown_menu_tick.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/Components/icon_advanced_search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/Components/icon_advanced_search.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/rt_button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/rt_button.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/Components/superbox_button_cancel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/Components/superbox_button_cancel.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/dark/0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/dark/0.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/dark/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/dark/1.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/dark/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/dark/2.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/dark/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/dark/3.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/dark/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/dark/4.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/wizard_bkg_h.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/wizard_bkg_h.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/bt_dsm_mobile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/bt_dsm_mobile.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/desktop/add_one.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/desktop/add_one.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/dsm5_badge_num.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/dsm5_badge_num.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/icon_drag_add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/icon_drag_add.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/icon_drag_ban.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/icon_drag_ban.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/icon_question.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/icon_question.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/dark/5dot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/dark/5dot.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/dark/DSM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/dark/DSM.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/dark/beta.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/dark/beta.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/icon_pw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/icon_pw.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/icon_user.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/icon_user.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/light/0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/light/0.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/light/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/light/1.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/light/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/light/2.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/light/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/light/3.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/light/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/light/4.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/light/DSM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/light/DSM.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/preview_bar_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/preview_bar_bg.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/shadow_footbar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/shadow_footbar.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/desktop/spotlight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/desktop/spotlight.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/item_drag_status.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/item_drag_status.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/icon_phone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/icon_phone.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/light/5dot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/light/5dot.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/light/beta.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/light/beta.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/taskbar/more_apps.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/taskbar/more_apps.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/dark/synology.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/dark/synology.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/light/synology.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/light/synology.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/taskbar/showdesktop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/taskbar/showdesktop.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/taskbar/taskbar_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/taskbar/taskbar_bg.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/taskbar/taskbar_bt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/taskbar/taskbar_bt.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/components/icon_error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/components/icon_error.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/components/status_fail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/components/status_fail.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/dsm5_notification_num.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/dsm5_notification_num.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/dsmv5_wizard_bkg_v_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/dsmv5_wizard_bkg_v_01.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/dsmv5_wizard_bkg_v_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/dsmv5_wizard_bkg_v_02.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/taskbar/taskbar_shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/taskbar/taskbar_shadow.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/taskbar/taskbar_split.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/taskbar/taskbar_split.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/components/status_loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/components/status_loading.gif -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/components/status_success.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/components/status_success.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/desktop/icon_app_category.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/desktop/icon_app_category.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/desktop/taskbar_spinner.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/desktop/taskbar_spinner.gif -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/dark/copyright_2014.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/dark/copyright_2014.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/dark/copyright_2015.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/dark/copyright_2015.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/taskbar/taskbar_bt_apps.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/taskbar/taskbar_bt_apps.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/taskbar/tray_icon_search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/taskbar/tray_icon_search.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/taskbar/tray_icon_widget.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/taskbar/tray_icon_widget.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/taskbar/user_menu_about.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/taskbar/user_menu_about.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/taskbar/user_menu_logout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/taskbar/user_menu_logout.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/taskbar/user_menu_options.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/taskbar/user_menu_options.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/taskbar/user_menu_restart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/taskbar/user_menu_restart.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/light/copyright_2014.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/light/copyright_2014.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/light/copyright_2015.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/light/copyright_2015.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_CMS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_CMS.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/taskbar/tray_icon_user_menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/taskbar/tray_icon_user_menu.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/taskbar/user_menu_shutdown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/taskbar/user_menu_shutdown.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/modules/ExternalDevices/images/tray_icon_device.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/modules/ExternalDevices/images/tray_icon_device.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/modules/FileTaskMonitor/images/tray_icon_bgtask.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/modules/FileTaskMonitor/images/tray_icon_bgtask.gif -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/modules/FileTaskMonitor/images/tray_icon_bgtask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/modules/FileTaskMonitor/images/tray_icon_bgtask.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/modules/FileTaskMonitor/images/tray_icon_upload.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/modules/FileTaskMonitor/images/tray_icon_upload.gif -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/modules/FileTaskMonitor/images/tray_icon_upload.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/modules/FileTaskMonitor/images/tray_icon_upload.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/modules/PollingTask/images/tray_icon_disk_port.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/modules/PollingTask/images/tray_icon_disk_port.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/components/icon_image_selector.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/components/icon_image_selector.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/login_bkg_highlight_top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/login_bkg_highlight_top.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_backup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_backup.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_groups.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_groups.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_portal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_portal.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_region.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_region.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_speed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_speed.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_syslog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_syslog.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_users.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_users.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_volume.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_volume.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/taskbar/tray_icon_notification.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/taskbar/tray_icon_notification.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/taskbar/tray_icon_pilot_view.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/taskbar/tray_icon_pilot_view.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/widget_window/widget_rt_button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/widget_window/widget_rt_button.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/400.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 400 Bad Request 4 | 5 |

Bad Request

6 |

Your browser sent a request that this server could not understand.
7 |

8 | 9 | -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/modules/FileTaskMonitor/images/tray_icon_download.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/modules/FileTaskMonitor/images/tray_icon_download.gif -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/modules/FileTaskMonitor/images/tray_icon_download.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/modules/FileTaskMonitor/images/tray_icon_download.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/login_bkg_highlight_bottom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/login_bkg_highlight_bottom.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_business.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_business.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_connect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_connect.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_contact.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_contact.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_dsm_apps.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_dsm_apps.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_general.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_general.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_network.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_network.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_overview.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_process.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_process.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_security.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_security.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_wireless.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_wireless.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_community.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_community.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_expansion.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_expansion.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_hot_spare.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_hot_spare.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_info_center.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_info_center.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_installed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_installed.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_iscsi_lun.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_iscsi_lun.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_login_style.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_login_style.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_networkmap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_networkmap.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_performance.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_performance.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_privilege.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_privilege.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_purchases.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_purchases.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_raid_group.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_raid_group.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_recommend.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_recommend.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_ssd_cache.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_ssd_cache.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_utilities.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_utilities.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_web_server.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_web_server.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/taskbar/taskbar_bt_widgets_shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/taskbar/taskbar_bt_widgets_shadow.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/weather/login_icon_weather_cold.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/weather/login_icon_weather_cold.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/weather/login_icon_weather_fog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/weather/login_icon_weather_fog.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/weather/login_icon_weather_hail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/weather/login_icon_weather_hail.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/weather/login_icon_weather_moon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/weather/login_icon_weather_moon.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/weather/login_icon_weather_rain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/weather/login_icon_weather_rain.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/weather/login_icon_weather_snow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/weather/login_icon_weather_snow.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/weather/login_icon_weather_sun.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/weather/login_icon_weather_sun.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_file_services.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_file_services.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_iscsi_target.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_iscsi_target.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_media_library.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_media_library.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_notifications.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_notifications.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_public_access.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_public_access.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_quickconnect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_quickconnect.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/weather/login_icon_weather_cloudy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/weather/login_icon_weather_cloudy.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/weather/login_icon_weather_thunder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/weather/login_icon_weather_thunder.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/weather/login_icon_weather_tornado.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/weather/login_icon_weather_tornado.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/weather/login_icon_weather_windy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/weather/login_icon_weather_windy.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_external_devices.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_external_devices.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_hdd_management.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_hdd_management.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_shared_folders.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_shared_folders.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_task_scheduler.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_task_scheduler.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_update_and_reset.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_update_and_reset.png -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | recursive-include opencanary/data * 2 | recursive-include opencanary/modules/data * 3 | 4 | recursive-exclude opencanary/test * 5 | recursive-exclude .github * 6 | recursive-exclude docs * 7 | 8 | exclude Dockerfile.latest 9 | exclude Dockerfile.* 10 | exclude docker-compose.yml 11 | exclude .gitignore 12 | -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_directory_service.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_directory_service.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_hardware_and_power.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_hardware_and_power.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_terminal_and_SNMP.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/module_list_icon/c_icon_terminal_and_SNMP.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/weather/login_icon_weather_moon_clouds.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/weather/login_icon_weather_moon_clouds.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/weather/login_icon_weather_sun_clouds.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/resources/images/login/weather/login_icon_weather_sun_clouds.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 404 Not Found 4 | 5 |

Not Found

6 |

The requested URL [[URL]] was not found on this server.

7 |
8 |
[[BANNER]] Server
9 | 10 | -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/modules/ThumbConvertProgress/images/tray_icon_creating_thumbnail.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/modules/ThumbConvertProgress/images/tray_icon_creating_thumbnail.gif -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/modules/ThumbConvertProgress/images/tray_icon_creating_thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinkst/opencanary/HEAD/opencanary/modules/data/http/skin/nasLogin/static/img/synohdpack/images/dsm/modules/ThumbConvertProgress/images/tray_icon_creating_thumbnail.png -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/basicLogin/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 404 Not Found 4 | 5 |

Not Found

6 |

The requested URL [[URL]] was not found on this server.

7 |
8 |
[[BANNER]] Server
9 | 10 | -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/403.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 403 Forbidden 4 | 5 |

Forbidden

6 |

You don't have permission to access [[URL]] 7 | on this server.

8 |
9 |
[[BANNER]] Server
10 | 11 | -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/basicLogin/403.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 403 Forbidden 4 | 5 |

Forbidden

6 |

You don't have permission to access [[URL]] 7 | on this server.

8 |
9 |
[[BANNER]] Server
10 | 11 | -------------------------------------------------------------------------------- /docs/services/mssql.rst: -------------------------------------------------------------------------------- 1 | MSSQL Server 2 | ================ 3 | 4 | Inside ~/.opencanary.conf: 5 | 6 | .. code-block:: json 7 | 8 | { 9 | "mssql.enabled": true, 10 | "mssql.port": 1433, 11 | "mssql.version": "2012", 12 | "rdp.enabled": true, 13 | "rdp.port", 3389, 14 | // [..] # logging configuration 15 | } 16 | -------------------------------------------------------------------------------- /opencanary.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=OpenCanary 3 | After=syslog.target 4 | After=network-online.target 5 | 6 | [Service] 7 | User=root 8 | Type=oneshot 9 | RemainAfterExit=yes 10 | Restart=always 11 | ExecStart=/bin/opencanaryd --start 12 | ExecStop=/bin/opencanaryd --stop 13 | 14 | [Install] 15 | WantedBy=multi-user.target 16 | -------------------------------------------------------------------------------- /docs/services/mysql.rst: -------------------------------------------------------------------------------- 1 | MySQL Server 2 | ================ 3 | 4 | Inside ~/.opencanary.conf: 5 | 6 | .. code-block:: json 7 | 8 | { 9 | "mysql.banner": "5.5.43-0ubuntu0.14.04.1", 10 | "mysql.enabled": true, 11 | "mysql.port": 3306, 12 | "ssh.enabled": true, 13 | "ssh.port": 22, 14 | "ssh.version": "SSH-2.0-OpenSSH_5.1p1 Debian-4", 15 | // [..] # logging configuration 16 | } 17 | -------------------------------------------------------------------------------- /run.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | CONF="/etc/opencanaryd/opencanary.conf" 4 | TEMP_CONF="/etc/opencanaryd/.opencanary.conf" 5 | 6 | if [ -f $CONF ]; then 7 | echo "INFO: Main configuration file found" 8 | opencanaryd --start 9 | elif [ -f $TEMP_CONF ]; then 10 | echo "INFO: Temp configuration file found" 11 | opencanaryd --dev 12 | else 13 | opencanaryd --copyconfig && echo "A Config file was generated at /etc/opencanaryd/.opencanary.conf." 14 | fi 15 | -------------------------------------------------------------------------------- /opencanary/data/settings-usermodule.json: -------------------------------------------------------------------------------- 1 | { 2 | "device.node_id": "opencanary-1", 3 | "logger": { 4 | "class": "PyLogger", 5 | "kwargs": { 6 | "formatters": { 7 | "plain": { 8 | "format": "%(message)s" 9 | } 10 | }, 11 | "handlers": { 12 | "console": { 13 | "class": "logging.StreamHandler", 14 | "stream": "ext://sys.stdout" 15 | } 16 | } 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | # .readthedocs.yaml 2 | # Read the Docs configuration file 3 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 4 | 5 | # Required 6 | version: 2 7 | 8 | # Set the version of Python and other tools you might need 9 | build: 10 | os: ubuntu-22.04 11 | tools: 12 | python: "3.11" 13 | 14 | # Build documentation in the docs/ directory with Sphinx 15 | sphinx: 16 | configuration: docs/conf.py 17 | 18 | # If using Sphinx, optionally build your docs in additional formats such as PDF 19 | # formats: 20 | # - pdf 21 | 22 | # Optionally declare the Python requirements required to build your docs 23 | python: 24 | install: 25 | - requirements: docs/requirements.txt 26 | -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | alabaster==0.7.13 2 | Babel==2.12.1 3 | certifi==2023.7.22 4 | charset-normalizer==3.1.0 5 | docutils==0.19 6 | idna==3.4 7 | imagesize==1.4.1 8 | importlib-metadata==6.6.0 9 | Jinja2==3.1.2 10 | markdown-it-py==2.2.0 11 | MarkupSafe==2.1.2 12 | mdit-py-plugins==0.3.5 13 | mdurl==0.1.2 14 | myst-parser==1.0.0 15 | packaging==23.1 16 | Pygments==2.15.1 17 | pytz==2023.3 18 | PyYAML==6.0 19 | requests==2.31.0 20 | snowballstemmer==2.2.0 21 | Sphinx==6.2.1 22 | sphinxcontrib-applehelp==1.0.4 23 | sphinxcontrib-devhelp==1.0.2 24 | sphinxcontrib-htmlhelp==2.0.1 25 | sphinxcontrib-jsmath==1.0.1 26 | sphinxcontrib-qthelp==1.0.3 27 | sphinxcontrib-serializinghtml==1.1.5 28 | urllib3==2.0.7 29 | zipp==3.15.0 30 | -------------------------------------------------------------------------------- /Dockerfile.stable: -------------------------------------------------------------------------------- 1 | FROM python:3.10-buster 2 | 3 | # Download cache lists and install minimal versions 4 | RUN apt-get update && apt-get -yq install --no-install-recommends \ 5 | # Required linux dependencies 6 | sudo vim build-essential libssl-dev libffi-dev python-dev libpcap-dev && \ 7 | # Remove cache lists and clean up anything not needed to minimize image size 8 | apt-get autoremove -yq && apt-get clean && rm -rf /var/lib/apt/lists/* 9 | 10 | # Install required pip dependencies 11 | RUN pip install opencanary 12 | RUN pip install scapy pcapy-ng 13 | 14 | # Set the default application we are running 15 | ENTRYPOINT [ "opencanaryd" ] 16 | 17 | # Set the default arguments to be used for the entrypoint 18 | CMD [ "--dev", "--uid=nobody", "--gid=nogroup" ] 19 | -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/redirect.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Redirect 4 | 20 | 21 | 22 |
23 |
24 | Click here 25 |
26 |
27 | 28 | 29 | -------------------------------------------------------------------------------- /docs/alerts/hpfeeds.rst: -------------------------------------------------------------------------------- 1 | HPFeeds 2 | ======== 3 | 4 | OpenCanary can be used directly (without the Correlator) with daemons supporting the `hpfeeds `_ protocol. 5 | 6 | To enable hpfeeds add the following to the logging section of settings.json: 7 | 8 | .. code-block:: json 9 | 10 | "hpfeeds": { 11 | "class": "opencanary.logger.HpfeedsHandler", 12 | "host": "127.0.0.1", 13 | "port": 10000, 14 | "ident": "test", 15 | "secret":"12345", 16 | "channels":["test.events"] 17 | } 18 | 19 | Environment Variables 20 | --------------------- 21 | 22 | You can use environment variables in the configuration file to pass confidential information such as passwords or tokens from the host machine to the application. 23 | 24 | For more information, see the [Configuration page](../starting/configuration.rst#environment-variables). 25 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | exclude: > 2 | (?x)^( 3 | dist/| 4 | .devcontainer/devcontainer.json 5 | ) 6 | fail_fast: true 7 | repos: 8 | - repo: https://github.com/pre-commit/pre-commit-hooks 9 | rev: v4.1.0 10 | hooks: 11 | - id: trailing-whitespace 12 | - id: end-of-file-fixer 13 | - id: check-docstring-first 14 | - id: check-json 15 | - id: check-added-large-files 16 | - id: check-yaml 17 | - id: debug-statements 18 | # - id: no-commit-to-branch 19 | # # GitHub only allows branch protection for teams or enterprise. 20 | # args: ['--pattern', '^(?!T\d+.*)'] 21 | - repo: https://github.com/psf/black 22 | rev: 22.3.0 23 | hooks: 24 | - id: black 25 | - repo: https://github.com/PyCQA/flake8 26 | rev: 4.0.1 27 | hooks: 28 | - id: flake8 29 | additional_dependencies: [flake8-typing-imports==1.12.0] 30 | -------------------------------------------------------------------------------- /.github/workflows/stale_issues.yml: -------------------------------------------------------------------------------- 1 | name: Close inactive issues/PRs 2 | on: 3 | schedule: 4 | - cron: "0 12 * * *" 5 | 6 | jobs: 7 | stale: 8 | runs-on: ubuntu-latest 9 | permissions: 10 | issues: write 11 | steps: 12 | - uses: actions/stale@v9 13 | with: 14 | days-before-issue-stale: 14 15 | days-before-issue-close: 14 16 | stale-issue-label: "stale" 17 | stale-issue-message: "This issue is stale because it has been open for 14 days with no activity." 18 | close-issue-message: "This issue was closed because it has been inactive for 14 days since being marked as stale." 19 | days-before-pr-close: -1 20 | exempt-all-pr-assignees: true 21 | exempt-issue-labels: "exempt" 22 | exempt-pr-labels: "exempt" 23 | start-date: '2023-08-21T00:00:00Z' 24 | repo-token: ${{ secrets.GITHUB_TOKEN }} 25 | -------------------------------------------------------------------------------- /opencanary/iphelper.py: -------------------------------------------------------------------------------- 1 | import struct 2 | import socket 3 | 4 | 5 | def ip2int(addr): 6 | """ 7 | Convert an IP in string format to decimal format 8 | """ 9 | 10 | return struct.unpack("!I", socket.inet_aton(addr))[0] 11 | 12 | 13 | def check_ip(ip, network_range): 14 | """ 15 | Test if the IP is in range 16 | 17 | Range is expected to be in CIDR notation format. If no MASK is 18 | given /32 is used. It return True if the IP is in the range. 19 | """ 20 | 21 | netItem = str(network_range).split("/") 22 | rangeIP = netItem[0] 23 | if len(netItem) == 2: 24 | rangeMask = int(netItem[1]) 25 | else: 26 | rangeMask = 32 27 | 28 | try: 29 | ripInt = ip2int(rangeIP) 30 | ipInt = ip2int(ip) 31 | result = not ((ipInt ^ ripInt) & 0xFFFFFFFF << (32 - rangeMask)) 32 | except: # noqa: E722 33 | result = False 34 | 35 | return result 36 | -------------------------------------------------------------------------------- /docs/services/webserver.rst: -------------------------------------------------------------------------------- 1 | Linux Web Server 2 | ================ 3 | 4 | Inside ~/.opencanary.conf: 5 | 6 | .. code-block:: json 7 | 8 | { 9 | "ftp.banner": "FTP server ready", 10 | "ftp.enabled": true, 11 | "ftp.port":21, 12 | "http.banner": "Apache/2.2.22 (Ubuntu)", 13 | "http.enabled": true, 14 | "http.port": 80, 15 | "http.skin": "nasLogin", 16 | "http.skin.list": [ 17 | { 18 | "desc": "Plain HTML Login", 19 | "name": "basicLogin" 20 | }, 21 | { 22 | "desc": "Synology NAS Login", 23 | "name": "nasLogin" 24 | } 25 | ], 26 | "https.enabled": true, 27 | "https.port": 443, 28 | "https.skin": "nasLogin", 29 | "https.certificate": "/etc/ssl/opencanary/opencanary.pem", 30 | "https.key": "/etc/ssl/opencanary/opencanary.key", 31 | "ssh.enabled": true, 32 | "ssh.port": 8022, 33 | "ssh.version": "SSH-2.0-OpenSSH_5.1p1 Debian-4", 34 | // [..] # logging configuration 35 | } 36 | -------------------------------------------------------------------------------- /Dockerfile.latest: -------------------------------------------------------------------------------- 1 | FROM python:3.10-bookworm 2 | 3 | # Download cache lists and install minimal versions 4 | RUN apt-get update && apt-get -yq install --no-install-recommends \ 5 | # Required linux dependencies 6 | sudo vim build-essential libssl-dev libffi-dev libpcap-dev && \ 7 | # Remove cache lists and clean up anything not needed to minimize image size 8 | apt-get autoremove -yq && apt-get clean && rm -rf /var/lib/apt/lists/* 9 | 10 | # Create and set the working directory 11 | WORKDIR /opencanary 12 | 13 | # Copy only the files needed to install dependencies 14 | COPY opencanary/__init__.py ./opencanary/__init__.py 15 | COPY requirements.txt setup.py ./ 16 | COPY bin /opencanary/bin 17 | 18 | # Install the required dependencies 19 | RUN pip install -r requirements.txt 20 | RUN pip install scapy pcapy-ng 21 | 22 | # Copy in the latest version 23 | COPY opencanary ./opencanary 24 | 25 | # Set the default application we are running 26 | ENTRYPOINT [ "opencanaryd" ] 27 | 28 | # Set the default arguments to be used for the entrypoint 29 | CMD [ "--dev", "--uid=nobody", "--gid=nogroup" ] 30 | -------------------------------------------------------------------------------- /opencanary/honeycred.py: -------------------------------------------------------------------------------- 1 | import functools 2 | from passlib.context import CryptContext 3 | 4 | __all__ = ["buildHoneyCredHook", "cryptcontext"] 5 | 6 | cryptcontext = CryptContext( 7 | schemes=["pbkdf2_sha512", "bcrypt", "sha512_crypt", "plaintext"] 8 | ) 9 | 10 | 11 | def buildHoneyCredHook(creds): 12 | return functools.partial(testManyCreds, creds) 13 | 14 | 15 | def testCred(cred, username=None, password=None): 16 | """ 17 | Test if given credentials matches specified credentials 18 | 19 | If specified credentials doesn't have username or password, it 20 | will still match on the other. 21 | 22 | """ 23 | cred_username = cred.get("username", None) 24 | cred_password = cred.get("password", None) 25 | 26 | user_match = True 27 | if cred_username is not None: 28 | user_match = cred_username.encode() == username 29 | 30 | password_match = True 31 | if cred_password is not None: 32 | password_match = cryptcontext.verify(password, cred_password) 33 | 34 | return user_match and password_match 35 | 36 | 37 | def testManyCreds(creds, username=None, password=None): 38 | for c in creds: 39 | if testCred(c, username, password): 40 | return True 41 | return False 42 | -------------------------------------------------------------------------------- /opencanary/modules/sip.py: -------------------------------------------------------------------------------- 1 | """ 2 | A log-only SIP server. It won't respond, but it will log any 3 | SIP requests sent its way. 4 | """ 5 | 6 | from opencanary.modules import CanaryService 7 | 8 | from twisted.application import internet 9 | from twisted.protocols.sip import Base 10 | 11 | from twisted.internet.address import IPv4Address 12 | 13 | 14 | class SIPServer(Base): 15 | def handle_request(self, request, addr): 16 | try: 17 | logdata = {"HEADERS": request.headers} 18 | self.transport.getPeer = lambda: IPv4Address("UDP", addr[0], addr[1]) 19 | self.factory.log(logdata=logdata, transport=self.transport) 20 | except Exception as e: 21 | self.factory.log(logdata={"ERROR": e}, transport=self.transport) 22 | 23 | 24 | class CanarySIP(CanaryService): 25 | NAME = "SIP" 26 | 27 | def __init__(self, config=None, logger=None): 28 | CanaryService.__init__(self, config=config, logger=logger) 29 | self.port = int(config.getVal("sip.port", default=5060)) 30 | self.logtype = self.logger.LOG_SIP_REQUEST 31 | self.listen_addr = config.getVal("device.listen_addr", default="") 32 | 33 | def getService(self): 34 | f = SIPServer() 35 | f.factory = self 36 | return internet.UDPServer(self.port, f, interface=self.listen_addr) 37 | -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/basicLogin/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Login 4 | 20 | 21 | 22 |
23 |
24 |

Network Storage v5.13

25 | 26 |

Login failed

27 | 28 |
29 |
30 |
Username:
31 |
32 |
Password:
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 | 41 | 42 | -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/css/style.css: -------------------------------------------------------------------------------- 1 | .syno-backup-repo-cloud-azure_blob{background-image:url("/webman/3rdparty/addon-azure_blob/images/icon.png") !important}@media (-webkit-min-device-pixel-ratio: 1.5), (-o-min-device-pixel-ratio: 3 / 2), (min-resolution: 144dpi){.synohdpack .syno-backup-repo-cloud-azure_blob{background-image:url("/webman/3rdparty/addon-azure_blob/images/icon@2x.png") !important;background-size:32px 32px !important}}@media (-webkit-min-device-pixel-ratio: 1.5), (-o-min-device-pixel-ratio: 3 / 2), (min-resolution: 144dpi){.synohdpackdebug .syno-backup-repo-cloud-azure_blob{background-image:url("/webman/3rdparty/addon-azure_blob/images/icon@2x.png") !important;background-size:32px 32px !important;outline:1px red dashed}}.syno-backup-task-cloud-azure_blob{background-image:url("/webman/3rdparty/addon-azure_blob/images/icon.png") !important}@media (-webkit-min-device-pixel-ratio: 1.5), (-o-min-device-pixel-ratio: 3 / 2), (min-resolution: 144dpi){.synohdpack .syno-backup-task-cloud-azure_blob{background-image:url("/webman/3rdparty/addon-azure_blob/images/icon@2x.png") !important;background-size:32px 32px !important}}@media (-webkit-min-device-pixel-ratio: 1.5), (-o-min-device-pixel-ratio: 3 / 2), (min-resolution: 144dpi){.synohdpackdebug .syno-backup-task-cloud-azure_blob{background-image:url("/webman/3rdparty/addon-azure_blob/images/icon@2x.png") !important;background-size:32px 32px !important;outline:1px red dashed}} 2 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.4" 2 | 3 | x-common: &common 4 | restart: unless-stopped 5 | volumes: 6 | - ./data/.opencanary.conf:/root/.opencanary.conf 7 | # uncomment below if running Samba 8 | # - /var/log/samba-audit.log:/var/log/samba-audit.log 9 | image: "opencanary" 10 | network_mode: "host" 11 | ports: 12 | # Comment/un-comment the port lines below to disable/enable the services you are using 13 | # FTP 14 | - "21:21" 15 | # SSH 16 | # - "22:22" 17 | # Telnet 18 | # - "23:23" 19 | # TFTP 20 | # - "69:69" 21 | # HTTP 22 | - "80:80" 23 | # NTP 24 | # - "123:123" 25 | # SNMP 26 | # - "161:161" 27 | # MSSQL 28 | # - "1433:1433" 29 | # MYSQL 30 | # - "3306:3306" 31 | # RDP 32 | # - "3389:3389" 33 | # VNC 34 | # - "5000:5000" 35 | # SIP 36 | # - "5060:5060" 37 | # REDIS 38 | # - "6379:6379" 39 | # TCP Banner 40 | # - "8001:8001" 41 | # HTTP Proxy 42 | # - "8080:8080" 43 | # Git 44 | # - "9418:9418" 45 | 46 | services: 47 | latest: # docker-compose up --build -d latest 48 | <<: *common 49 | container_name: opencanary_latest 50 | image: thinkst/opencanary 51 | build: 52 | context: . 53 | dockerfile: Dockerfile.latest 54 | 55 | stable: # docker-compose up --build -d stable 56 | <<: *common 57 | container_name: opencanary_stable 58 | build: 59 | context: . 60 | dockerfile: Dockerfile.stable 61 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018, Thinkst Applied Research 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 7 | 8 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 9 | 10 | 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 11 | 12 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 13 | -------------------------------------------------------------------------------- /opencanary/modules/snmp.py: -------------------------------------------------------------------------------- 1 | """ 2 | A log-only SNMP server. It won't respond, but it will log SNMP queries. 3 | """ 4 | 5 | from opencanary.modules import CanaryService 6 | 7 | from twisted.application import internet 8 | from twisted.internet.protocol import DatagramProtocol 9 | 10 | from twisted.internet.address import IPv4Address 11 | 12 | from scapy.all import SNMP 13 | 14 | 15 | class MiniSNMP(DatagramProtocol): 16 | def datagramReceived(self, data, host_and_port): 17 | try: 18 | snmp = SNMP(data) 19 | community = snmp.community.val 20 | requests = [x.oid.val for x in snmp.PDU.varbindlist] 21 | 22 | logdata = {"REQUESTS": requests, "COMMUNITY_STRING": community} 23 | self.transport.getPeer = lambda: IPv4Address( 24 | "UDP", host_and_port[0], host_and_port[1] 25 | ) 26 | self.factory.log(logdata=logdata, transport=self.transport) 27 | except Exception as e: 28 | print(e) 29 | pass 30 | 31 | 32 | class CanarySNMP(CanaryService): 33 | NAME = "SNMP" 34 | 35 | def __init__(self, config=None, logger=None): 36 | CanaryService.__init__(self, config=config, logger=logger) 37 | self.port = int(config.getVal("snmp.port", default=161)) 38 | self.logtype = logger.LOG_SNMP_CMD 39 | self.listen_addr = config.getVal("device.listen_addr", default="") 40 | 41 | def getService(self): 42 | f = MiniSNMP() 43 | f.factory = self 44 | return internet.UDPServer(self.port, f, interface=self.listen_addr) 45 | -------------------------------------------------------------------------------- /opencanary/modules/example0.py: -------------------------------------------------------------------------------- 1 | from opencanary.modules import CanaryService 2 | 3 | from twisted.internet.protocol import Protocol 4 | from twisted.internet.protocol import Factory 5 | 6 | 7 | class Example0Protocol(Protocol): 8 | """ 9 | Example (Fictional) Protocol 10 | 11 | $ nc localhost 8007 12 | Welcome! 13 | password: wrong0 14 | password: wrong1 15 | password: wrong2 16 | Bad passwords 17 | $ 18 | """ 19 | 20 | def __init__(self): 21 | self.prompts = 0 22 | 23 | def connectionMade(self): 24 | self.transport.write("Welcome!\r\npassword: ") 25 | self.prompts += 1 26 | 27 | def dataReceived(self, data): 28 | """ 29 | Careful, data received here is unbuffered. See example1 30 | for how this can be better handled. 31 | """ 32 | password = data.strip("\r\n") 33 | logdata = {"PASSWORD": password} 34 | self.factory.log(logdata, transport=self.transport) 35 | 36 | if self.prompts < 3: 37 | self.transport.write("\r\npassword: ") 38 | self.prompts += 1 39 | else: 40 | self.transport.write("\r\nBad passwords\r\n") 41 | self.transport.loseConnection() 42 | 43 | 44 | class CanaryExample0(Factory, CanaryService): 45 | NAME = "example0" 46 | protocol = Example0Protocol 47 | 48 | def __init__(self, config=None, logger=None): 49 | CanaryService.__init__(self, config, logger) 50 | self.port = 8007 51 | self.logtype = logger.LOG_BASE_EXAMPLE 52 | 53 | 54 | CanaryServiceFactory = CanaryExample0 55 | -------------------------------------------------------------------------------- /opencanary/modules/data/http/skin/nasLogin/static/js/misc.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var montharray = new Array(); 4 | montharray[0] = "Jan"; 5 | montharray[1] = "Feb"; 6 | montharray[2] = "Mar"; 7 | montharray[3] = "Apr"; 8 | montharray[4] = "May"; 9 | montharray[5] = "Jun"; 10 | montharray[6] = "Jul"; 11 | montharray[7] = "Aug"; 12 | montharray[8] = "Sep"; 13 | montharray[9] = "Oct"; 14 | montharray[10] = "Nov"; 15 | montharray[11] = "Dec"; 16 | 17 | var dayarray = new Array(); 18 | dayarray[0] = "Sun"; 19 | dayarray[1] = "Mon"; 20 | dayarray[2] = "Tue"; 21 | dayarray[3] = "Wed"; 22 | dayarray[4] = "Thu"; 23 | dayarray[5] = "Fri"; 24 | dayarray[6] = "Sat"; 25 | 26 | 27 | function updateTime() { 28 | var d = new Date(); 29 | var h = d.getHours(); 30 | var m = d.getMinutes(); 31 | m = new String(m); 32 | if (m.length == 1) 33 | m = "0" + m; 34 | 35 | var pms = "AM"; 36 | if (h > 12) 37 | { 38 | pms = "PM" 39 | h = h % 12; 40 | } 41 | 42 | document.getElementById('ext-comp-1007').innerHTML = h + ":" + m + '' + pms + ''; 43 | 44 | var month = montharray[d.getMonth()]; 45 | var wkday = dayarray[d.getDay()]; 46 | var day = d.getDate(); 47 | 48 | document.getElementById('ext-comp-1008').innerHTML = wkday + ", " + month + " " + day; 49 | 50 | } 51 | 52 | var cb = document.getElementById('ext-gen32'); 53 | cb.addEventListener('click', function () { 54 | if(cb.classList.contains('syno-ux-cb-unchecked')){ 55 | cb.className = "syno-ux-checkbox-icon syno-ux-cb-checked"; 56 | }else{ 57 | cb.className = "syno-ux-checkbox-icon syno-ux-cb-unchecked"; 58 | } 59 | }) 60 | 61 | updateTime(); 62 | window.setInterval(updateTime, 2000); 63 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish to PyPI 2 | on: 3 | release: 4 | types: 5 | - published 6 | 7 | workflow_dispatch: 8 | 9 | jobs: 10 | pypi-publish: 11 | name: Upload release to PyPI 12 | runs-on: ubuntu-latest 13 | environment: 14 | name: release 15 | url: https://pypi.org/p/opencanary 16 | permissions: 17 | id-token: write # IMPORTANT: this permission is mandatory for trusted publishing 18 | steps: 19 | # retrieve your distributions here 20 | - name: Set up Python 21 | uses: actions/setup-python@v3 22 | - name: "Check out repository code" 23 | uses: "actions/checkout@v3" 24 | - name: Install setuptools 25 | run: pip3 install setuptools>=63.2.0 26 | - name: Install wheel 27 | run: pip3 install wheel 28 | - name: Create package 29 | run: python3 setup.py sdist 30 | - name: check version matches tag 31 | run: | 32 | python3 -m pip install dist/* 33 | version_to_release=$(opencanaryd --version) 34 | tag_name="${{ github.event.release.tag_name }}" 35 | tag_name_without_v="${tag_name#v}" 36 | if [[ "$version_to_release" == "$tag_name_without_v" ]]; then 37 | echo "Versions match - may it be a great release" 38 | exit 0 39 | else 40 | echo "Versions do not match - not publishing" 41 | echo "Opencanary version is: $version_to_release" 42 | echo "Git tag is: $tag_name -> $tag_name_without_v" 43 | exit 1 44 | fi 45 | 46 | - name: Publish package distributions to PyPI 47 | uses: pypa/gh-action-pypi-publish@release/v1 48 | -------------------------------------------------------------------------------- /opencanary/modules/ntp.py: -------------------------------------------------------------------------------- 1 | """ 2 | A log-only NTP server. It won't respond, but it will log attempts 3 | to trigger the MON_GETLIST_1 NTP commands, which is used for DDOS 4 | and network recon. 5 | """ 6 | 7 | from opencanary.modules import CanaryService 8 | from twisted.application import internet 9 | from twisted.internet.protocol import DatagramProtocol 10 | from twisted.internet.address import IPv4Address 11 | 12 | 13 | class MiniNtp(DatagramProtocol): 14 | def datagramReceived(self, data, host_and_port): 15 | for encoding in ["utf8", "latin1"]: 16 | try: 17 | d = data.decode(encoding) 18 | break 19 | except UnicodeDecodeError: 20 | print("Failed decoding: {}".format(encoding)) 21 | pass 22 | 23 | if d and (len(data) < 4 or d[3] != "*"): # monlist command 24 | # bogus packet, discard 25 | return 26 | logdata = {"NTP CMD": "monlist"} 27 | self.transport.getPeer = lambda: IPv4Address( 28 | "UDP", host_and_port[0], host_and_port[1] 29 | ) 30 | self.factory.log(logdata=logdata, transport=self.transport) 31 | 32 | 33 | class CanaryNtp(CanaryService): 34 | NAME = "ntp" 35 | 36 | def __init__(self, config=None, logger=None): 37 | CanaryService.__init__(self, config=config, logger=logger) 38 | self.port = int(config.getVal("ntp.port", default=123)) 39 | self.logtype = logger.LOG_NTP_MONLIST 40 | self.listen_addr = config.getVal("device.listen_addr", default="") 41 | 42 | def getService(self): 43 | f = MiniNtp() 44 | f.factory = self 45 | return internet.UDPServer(self.port, f, interface=self.listen_addr) 46 | -------------------------------------------------------------------------------- /.github/workflows/opencanary_tests.yml: -------------------------------------------------------------------------------- 1 | name: OpenCanary Tests 2 | 3 | on: 4 | - "push" 5 | 6 | jobs: 7 | precommit_tests: 8 | runs-on: "ubuntu-22.04" 9 | steps: 10 | - name: "Check out repository code" 11 | uses: "actions/checkout@v3" 12 | - name: Set up Python 3.10 13 | uses: actions/setup-python@v3 14 | with: 15 | python-version: "3.10" 16 | - name: Install pre-commit 17 | run: pip install pre-commit 18 | - name: Check pre-commit is happy 19 | run: pre-commit run --all-files 20 | opencanary_tests: 21 | strategy: 22 | matrix: 23 | python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"] 24 | os: ["ubuntu-22.04", "ubuntu-24.04", "macos-13", "macos-14", "macos-15"] 25 | fail-fast: false 26 | runs-on: ${{ matrix.os }} 27 | steps: 28 | - name: "Check out repository code" 29 | uses: "actions/checkout@v3" 30 | - name: Set up Python ${{ matrix.python-version }} 31 | uses: actions/setup-python@v3 32 | with: 33 | python-version: "${{ matrix.python-version }}" 34 | - name: Install setuptools 35 | run: pip3 install setuptools>=63.2.0 36 | - name: Install wheel 37 | run: pip3 install wheel 38 | - name: Create package 39 | run: python3 setup.py sdist 40 | - name: Install package 41 | run: pip3 install dist/opencanary-*.tar.gz 42 | - name: Install test dependencies 43 | run: pip3 install -r opencanary/test/requirements.txt 44 | - name: Copy config file 45 | run: cp opencanary/test/opencanary.conf . 46 | - name: Start OpenCanary 47 | run: opencanaryd --start 48 | - name: Run Pytest 49 | run: pytest -s 50 | -------------------------------------------------------------------------------- /opencanary/modules/tftp.py: -------------------------------------------------------------------------------- 1 | """ 2 | A log-only Tftp server. It won't respond, but it will log attempts 3 | to either read or write files. 4 | """ 5 | 6 | from opencanary.modules import CanaryService 7 | 8 | from twisted.application import internet 9 | from twisted.internet.protocol import DatagramProtocol 10 | 11 | from twisted.internet.address import IPv4Address 12 | 13 | 14 | class Tftp(DatagramProtocol): 15 | def datagramReceived(self, data, host_and_port): 16 | if len(data) < 5: 17 | # bogus packet, discard 18 | return 19 | 20 | if data[:2] == b"\x00\x01": 21 | opcode = "READ" 22 | elif data[:2] == b"\x00\x02": 23 | opcode = "WRITE" 24 | else: 25 | # don't log other opcodes 26 | return 27 | 28 | try: 29 | (filename, mode, *_) = data[2:].split(b"\x00") 30 | except ValueError: 31 | return 32 | 33 | logdata = {"FILENAME": filename, "OPCODE": opcode, "MODE": mode} 34 | self.transport.getPeer = lambda: IPv4Address( 35 | "UDP", host_and_port[0], host_and_port[1] 36 | ) 37 | self.factory.log(logdata=logdata, transport=self.transport) 38 | 39 | 40 | class CanaryTftp(CanaryService): 41 | NAME = "tftp" 42 | 43 | def __init__(self, config=None, logger=None): 44 | CanaryService.__init__(self, config=config, logger=logger) 45 | self.port = int(config.getVal("tftp.port", default=69)) 46 | self.logtype = self.logger.LOG_TFTP 47 | self.listen_addr = config.getVal("device.listen_addr", default="") 48 | 49 | def getService(self): 50 | f = Tftp() 51 | f.factory = self 52 | return internet.UDPServer(self.port, f, interface=self.listen_addr) 53 | -------------------------------------------------------------------------------- /.github/workflows/docker-build.yml: -------------------------------------------------------------------------------- 1 | name: Docker build 2 | on: 3 | push: 4 | branches: 5 | - master 6 | release: 7 | types: [published] 8 | 9 | workflow_dispatch: 10 | inputs: 11 | opencanary-branch: 12 | description: "Branch of the opencanary repo to use" 13 | default: 'master' 14 | required: false 15 | 16 | jobs: 17 | docker-build: 18 | runs-on: ubuntu-latest 19 | steps: 20 | - name: Checkout 21 | uses: actions/checkout@v4.2.0 22 | with: 23 | ref: ${{ inputs.opencanary-branch }} 24 | 25 | - name: Set up Docker Buildx 26 | uses: docker/setup-buildx-action@v3.6.1 27 | 28 | - name: Login to Dockerhub Registry 29 | uses: docker/login-action@v3.3.0 30 | with: 31 | username: ${{ secrets.DOCKERHUB_USERNAME }} 32 | password: ${{ secrets.DOCKERHUB_TOKEN }} 33 | 34 | - name: Extract metadata (tags, labels) for Docker 35 | id: meta 36 | uses: docker/metadata-action@v5.5.1 37 | with: 38 | images: | 39 | thinkst/opencanary 40 | tags: | 41 | type=raw,value=latest 42 | type=schedule 43 | type=ref,event=branch 44 | type=ref,event=pr 45 | type=semver,pattern={{version}} 46 | type=semver,pattern={{major}}.{{minor}} 47 | type=semver,pattern={{major}} 48 | type=sha 49 | 50 | - name: Build and push 51 | uses: docker/build-push-action@v6.8.0 52 | with: 53 | context: . 54 | file: Dockerfile.latest 55 | platforms: linux/amd64,linux/arm64 56 | push: true 57 | cache-from: type=gha 58 | cache-to: type=gha,mode=max 59 | tags: ${{ steps.meta.outputs.tags }} 60 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # Ignore environments 7 | py3env/ 8 | openv/ 9 | 10 | # C extensions 11 | *.so 12 | 13 | # Distribution / packaging 14 | .Python 15 | build/ 16 | develop-eggs/ 17 | dist/ 18 | downloads/ 19 | eggs/ 20 | .eggs/ 21 | launchctl/ 22 | lib/ 23 | lib64/ 24 | parts/ 25 | sdist/ 26 | var/ 27 | wheels/ 28 | pip-wheel-metadata/ 29 | share/python-wheels/ 30 | *.egg-info/ 31 | .installed.cfg 32 | *.egg 33 | MANIFEST 34 | 35 | # PyInstaller 36 | # Usually these files are written by a python script from a template 37 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 38 | *.manifest 39 | *.spec 40 | 41 | # Installer logs 42 | pip-log.txt 43 | pip-delete-this-directory.txt 44 | 45 | # Unit test / coverage reports 46 | htmlcov/ 47 | .tox/ 48 | .nox/ 49 | .coverage 50 | .coverage.* 51 | .cache 52 | nosetests.xml 53 | coverage.xml 54 | *.cover 55 | .hypothesis/ 56 | .pytest_cache/ 57 | 58 | # Translations 59 | *.mo 60 | *.pot 61 | 62 | # Django stuff: 63 | *.log 64 | local_settings.py 65 | db.sqlite3 66 | 67 | # Flask stuff: 68 | instance/ 69 | .webassets-cache 70 | 71 | # Scrapy stuff: 72 | .scrapy 73 | 74 | # Sphinx documentation 75 | docs/_build/ 76 | 77 | # PyBuilder 78 | target/ 79 | 80 | # Jupyter Notebook 81 | .ipynb_checkpoints 82 | 83 | # IPython 84 | profile_default/ 85 | ipython_config.py 86 | 87 | # pyenv 88 | .python-version 89 | 90 | # celery beat schedule file 91 | celerybeat-schedule 92 | 93 | # SageMath parsed files 94 | *.sage.py 95 | 96 | # Environments 97 | .env 98 | .venv 99 | env/ 100 | venv/ 101 | ENV/ 102 | env.bak/ 103 | venv.bak/ 104 | 105 | # Spyder project settings 106 | .spyderproject 107 | .spyproject 108 | 109 | # Rope project settings 110 | .ropeproject 111 | 112 | # mkdocs documentation 113 | /site 114 | 115 | # mypy 116 | .mypy_cache/ 117 | .dmypy.json 118 | dmypy.json 119 | 120 | # Pyre type checker 121 | .pyre/ 122 | 123 | # PyCharm user settings 124 | .idea/ 125 | 126 | # MacOS detritus 127 | .DS_Store 128 | -------------------------------------------------------------------------------- /docs/starting/opencanary.rst: -------------------------------------------------------------------------------- 1 | OpenCanary 2 | ========== 3 | 4 | Getting Started 5 | ---------------- 6 | 7 | To get started create a virtual environment to play in: 8 | 9 | .. code-block:: sh 10 | 11 | $ virtualenv env 12 | $ . env/bin/activate 13 | 14 | Inside the virtualenv, install OpenCanary following the instructions in the `README `_. 15 | 16 | OpenCanary ships with a default config, which we'll copy and edit to get started. The config is a single `JSON `_ dictionary. 17 | 18 | .. code-block:: sh 19 | 20 | $ opencanaryd --copyconfig 21 | $ $EDITOR ~/.opencanary.conf 22 | 23 | In the config file we'll change **device.node_id** which must be unique for 24 | each instance of opencanaryd, and we'll configure **logger** to log 25 | alerts to a file. 26 | 27 | .. code-block:: json 28 | 29 | { 30 | "device.node_id": "Your-very-own-unique-name", 31 | // ... 32 | "logger": { 33 | "class": "PyLogger", 34 | "kwargs": { 35 | "handlers": { 36 | "file": { 37 | "class": "logging.FileHandler", 38 | "filename": "/var/tmp/opencanary.log" 39 | } 40 | } 41 | } 42 | } 43 | // ... 44 | } 45 | 46 | 47 | With that in place, we can run the daemon and test that it logs a failed FTP login attempt to the log file. 48 | 49 | .. code-block:: sh 50 | 51 | $ opencanaryd --start 52 | [...] 53 | $ ftp localhost 54 | [...] 55 | $ cat /var/tmp/opencanary.log 56 | [...] 57 | {"dst_host": "127.0.0.1", "dst_port": 21, "local_time": "2015-07-20 13:38:21.281259", "logdata": {"PASSWORD": "default", "USERNAME": "admin"}, "logtype": 2000, "node_id": "opencanary-0", "src_host": "127.0.0.1", "src_port": 49635} 58 | 59 | 60 | Troubleshooting 61 | --------------- 62 | 63 | The tool JQ can be used to check that the config file is well-formed JSON. 64 | 65 | .. code-block:: sh 66 | 67 | $ jq . ~/.opencanary.conf 68 | 69 | Run opencanaryd in the foreground to see more error messages. 70 | 71 | .. code-block:: sh 72 | 73 | $ opencanaryd --dev 74 | 75 | You may also easily restart the service using, 76 | 77 | .. code-block:: sh 78 | 79 | $ opencanaryd --restart 80 | -------------------------------------------------------------------------------- /opencanary/modules/rdp.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | from opencanary.modules import CanaryService 4 | 5 | from twisted.internet.protocol import Protocol 6 | from twisted.internet.protocol import Factory 7 | from twisted.application import internet 8 | 9 | 10 | class RemoteDesktopProtocol(Protocol): 11 | """ 12 | A simple service that logs RDP connection attempts 13 | and mimics an NLA-enabled RDP server but responds with login failure 14 | """ 15 | 16 | def __init__(self): 17 | self.initial_connection = True 18 | 19 | def dataReceived(self, data): 20 | # Decode the data to unicode, so we can search it, and ignore any errors 21 | # caused by bytes that can't be decoded. 22 | decoded_data = data.decode(encoding="utf-8", errors="ignore") 23 | # Use regex to extract the username. 24 | match = re.search(r"mstshash=(?P[a-zA-Z0-9-_@]*)", decoded_data) 25 | username = match and match.groupdict().get("username") 26 | # Log the connection attempt 27 | self.factory.log(logdata={"USERNAME": username}, transport=self.transport) 28 | 29 | if self.initial_connection: 30 | # Respond as an NLA-enabled RDP server 31 | self.transport.write( 32 | bytes.fromhex("030000130ed000001234000209080002000000") 33 | ) 34 | self.initial_connection = False 35 | else: 36 | # Always respond with a negotiation failure, details from 37 | # https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/96327ab4-d43f-4803-9aff-392ce1fc2073 38 | self.transport.write(bytes.fromhex("0001000400010000052e")) 39 | self.transport.loseConnection() 40 | 41 | 42 | class CanaryRDP(Factory, CanaryService): 43 | NAME = "rdp" 44 | protocol = RemoteDesktopProtocol 45 | 46 | def __init__(self, config=None, logger=None): 47 | CanaryService.__init__(self, config, logger) 48 | self.port = config.getVal("rdp.port", 3389) 49 | self.listen_addr = config.getVal("device.listen_addr", default="") 50 | self.logtype = logger.LOG_RDP 51 | 52 | def getService(self): 53 | return internet.TCPServer(self.port, self, interface=self.listen_addr) 54 | 55 | 56 | CanaryServiceFactory = CanaryRDP 57 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | OpenCanary 2 | =========== 3 | 4 | Welcome to the OpenCanary guide. 5 | 6 | Please note we have a wiki on Github with FAQ and Samba Setup help over `here `_. 7 | 8 | OpenCanary is a daemon that runs canary services, which trigger alerts 9 | when (ab) is used. The alerts can be sent to a variety of sources, 10 | including Syslog, emails, and a companion daemon opencanary-correlator. 11 | 12 | This project is maintained by `Thinkst Canary `_. 13 | 14 | The Correlator coalesces multiple related events (eg. individual 15 | brute-force login attempts) into a single alert sent via email or 16 | SMS. 17 | 18 | 19 | .. _getting-started: 20 | 21 | Getting Started 22 | --------------- 23 | 24 | The first section will get you quickly up and running with canary 25 | services sending alerts. 26 | 27 | .. toctree:: 28 | :maxdepth: 1 29 | 30 | starting/opencanary 31 | starting/configuration 32 | starting/correlator 33 | 34 | Services 35 | --------- 36 | 37 | Try these out in the OpenCanary configs for more typical server personalities. 38 | 39 | .. toctree:: 40 | :maxdepth: 1 41 | 42 | services/webserver 43 | services/windows 44 | services/mysql 45 | services/mssql 46 | 47 | 48 | Alerting 49 | --------- 50 | 51 | :ref:`getting-started` walks through two different ways to configure alerting: logging directly to a file, and sending alerts to the Correlator for email and SMS alerts. Other possibilities are below: 52 | 53 | .. toctree:: 54 | :maxdepth: 2 55 | 56 | alerts/email 57 | alerts/hpfeeds 58 | alerts/webhook 59 | 60 | 61 | Upgrading 62 | --------- 63 | 64 | If you have a previous version of OpenCanary installed already, you can upgrade it easily. 65 | 66 | Start by activating your virtual environment (`env` in the below example) that has your installed version of OpenCanary, 67 | 68 | .. code-block:: sh 69 | 70 | $ . env/bin/activate 71 | 72 | 73 | Inside the virtualenv, you can upgrade your OpenCanary by, 74 | 75 | .. code-block:: sh 76 | 77 | $ pip install opencanary --upgrade 78 | 79 | Please note that this will not wipe your existing OpenCanary config file. If you would like a new one (with the new settings), please regenerate the config file using, 80 | 81 | .. code-block:: sh 82 | 83 | $ opencanaryd --copyconfig 84 | 85 | 86 | 87 | Indices and tables 88 | ------------------ 89 | * :ref:`genindex` 90 | * :ref:`modindex` 91 | * :ref:`search` 92 | -------------------------------------------------------------------------------- /opencanary/modules/example1.py: -------------------------------------------------------------------------------- 1 | from opencanary.modules import CanaryService 2 | 3 | from twisted.internet.protocol import Protocol 4 | from twisted.internet.protocol import Factory 5 | 6 | 7 | class Example1Protocol(Protocol): 8 | """ 9 | Example Telnet Protocol 10 | 11 | $ telnet localhost 8025 12 | Trying 127.0.0.1... 13 | Connected to localhost. 14 | Escape character is '^]'. 15 | password: 16 | password: 17 | password: 18 | % Bad passwords 19 | Connection closed by foreign host. 20 | 21 | Nmap's version detection is convinced: 22 | 23 | $ nmap -sV 127.0.0.1 -p 8025 24 | Starting Nmap 6.47 ( http://nmap.org ) at 2015-07-24 11:40 SAST 25 | Nmap scan report for localhost (127.0.0.1) 26 | Host is up (0.000079s latency). 27 | PORT STATE SERVICE VERSION 28 | 8025/tcp open telnet D-Link ADSL router telnetd 29 | Service Info: Device: router 30 | """ 31 | 32 | def __init__(self): 33 | self.prompts = 0 34 | self.buffer = "" 35 | 36 | def connectionMade(self): 37 | self.transport.write("\xff\xfb\x03\xff\xfb\x01password: ") 38 | self.prompts += 1 39 | 40 | def dataReceived(self, data): 41 | """ 42 | Received data is unbuffered so we buffer it for telnet. 43 | """ 44 | self.buffer += data 45 | print("Received data: ", repr(data)) 46 | 47 | # Discard initial telnet client control chars 48 | i = self.buffer.find("\x01") 49 | if i >= 0: 50 | self.buffer = self.buffer[i + 1 :] 51 | return 52 | 53 | if self.buffer.find("\x00") >= 0: 54 | password = self.buffer.strip("\r\n\x00") 55 | logdata = {"PASSWORD": password} 56 | self.factory.log(logdata, transport=self.transport) 57 | self.buffer = "" 58 | 59 | if self.prompts < 3: 60 | self.transport.write("\r\npassword: ") 61 | self.prompts += 1 62 | else: 63 | self.transport.write("\r\n% Bad passwords\r\n") 64 | self.transport.loseConnection() 65 | 66 | 67 | class CanaryExample1(Factory, CanaryService): 68 | NAME = "example1" 69 | protocol = Example1Protocol 70 | 71 | def __init__(self, config=None, logger=None): 72 | CanaryService.__init__(self, config, logger) 73 | self.port = config.getVal("example1.port", 8025) 74 | self.logtype = logger.LOG_BASE_EXAMPLE 75 | 76 | 77 | CanaryServiceFactory = CanaryExample1 78 | -------------------------------------------------------------------------------- /docs/services/windows.rst: -------------------------------------------------------------------------------- 1 | Windows Server 2 | ================ 3 | 4 | The Samba and RDP modules require an extra installation step. It's a 5 | good idea to consult the `README `_ before trying this out. 6 | 7 | Inside ~/.opencanary.conf: 8 | 9 | .. code-block:: json 10 | 11 | { 12 | "smb.auditfile": "/var/log/samba-audit.log", 13 | "smb.enabled": true 14 | } 15 | 16 | Below is an example of an `smb.conf` for a Samba installation, 17 | 18 | .. code-block:: dosini 19 | 20 | [global] 21 | workgroup = WORKGROUP 22 | server string = NBDocs 23 | netbios name = SRV01 24 | dns proxy = no 25 | log file = /var/log/samba/log.all 26 | log level = 0 27 | max log size = 100 28 | panic action = /usr/share/samba/panic-action %d 29 | server role = standalone 30 | passdb backend = tdbsam 31 | obey pam restrictions = yes 32 | unix password sync = no 33 | map to guest = bad user 34 | usershare allow guests = yes 35 | load printers = no 36 | vfs object = full_audit 37 | full_audit:prefix = %U|%I|%i|%m|%S|%L|%R|%a|%T|%D 38 | full_audit:success = flistxattr 39 | full_audit:failure = none 40 | full_audit:facility = local7 41 | full_audit:priority = notice 42 | [myshare] 43 | comment = All the stuff! 44 | path = /samba 45 | guest ok = yes 46 | read only = yes 47 | browseable = yes 48 | 49 | Please note that there are some details in the above config that you would want to change, 50 | 51 | * server string 52 | * NetBIOS name 53 | * [myshare] to the name of your share 54 | * path 55 | 56 | Of course, you may change other settings as long as the `smbd_audit` logs to the file that your 57 | OpenCanary daemon is watching (above we set it as `/var/log/samba-audit.log`). 58 | 59 | In the above config, we are relying on Samba using Syslog (rsyslog in newer systems). For our Samba 60 | to use rsyslog, we will edit the `/etc/rsyslog.conf` file. Below are two lines we add to the bottom, 61 | 62 | .. code-block:: unixconfig 63 | 64 | $FileCreateMode 0644 65 | local7.* /var/log/samba-audit.log 66 | 67 | This will redirect any message of facility local7 to your `/var/log/samba-audit.log` file, which will be 68 | watched by our OpenCanary daemon. 69 | 70 | Please note this is all written up in the GitHub Wiki. 71 | -------------------------------------------------------------------------------- /opencanary/modules/git.py: -------------------------------------------------------------------------------- 1 | from opencanary.modules import CanaryService 2 | 3 | from twisted.internet.protocol import Protocol 4 | from twisted.internet.protocol import Factory 5 | from twisted.application import internet 6 | 7 | 8 | class ProtocolError(Exception): 9 | pass 10 | 11 | 12 | class GitCommandLengthMismatch(Exception): 13 | pass 14 | 15 | 16 | class GitProtocol(Protocol): 17 | """ 18 | Implementation of Git-daemon up to request 19 | """ 20 | 21 | def _checkDataLength(self, data): 22 | try: 23 | actual_length = len(data) 24 | indata_length = int(data[0:4], base=16) 25 | if actual_length < indata_length: 26 | raise GitCommandLengthMismatch() 27 | elif actual_length > indata_length: 28 | raise ProtocolError() 29 | except ValueError: 30 | return False 31 | 32 | def _buildResponseAndSend(self, command): 33 | project = command[17 : 17 + command[17:].find("host")] 34 | request = command[command.find("=") + 1 :] 35 | self._logAlert(project, request) 36 | pre_response = "ERR no such repository: " + project 37 | response_size = "{:04x}".format(int(len(pre_response) + 4)) 38 | response = response_size + pre_response 39 | self.transport.write(response.encode() + "\n".encode()) 40 | 41 | def _logAlert(self, project, request): 42 | logdata = {"REPO": project[:-1], "HOST": request[:-1]} 43 | self.factory.log(logdata, transport=self.transport) 44 | 45 | def dataReceived(self, data): 46 | """ 47 | Received data is unbuffered so we buffer it for telnet. 48 | """ 49 | try: 50 | try: 51 | if not hasattr(self, "_data"): 52 | self._data = data 53 | else: 54 | self._data += data 55 | 56 | self._checkDataLength(self._data) 57 | 58 | git_command = self._data[4:] 59 | if git_command[:15] == b"git-upload-pack": 60 | self._buildResponseAndSend(git_command.decode("utf-8")) 61 | else: 62 | raise ProtocolError() 63 | 64 | except GitCommandLengthMismatch: 65 | pass 66 | 67 | except ProtocolError: 68 | self.transport.loseConnection() 69 | return 70 | 71 | 72 | class CanaryGit(Factory, CanaryService): 73 | NAME = "git" 74 | protocol = GitProtocol 75 | 76 | def __init__(self, config=None, logger=None): 77 | CanaryService.__init__(self, config=config, logger=logger) 78 | self.port = config.getVal("git.port", default=9418) 79 | self.listen_addr = config.getVal("device.listen_addr", default="") 80 | self.logtype = logger.LOG_GIT_CLONE_REQUEST 81 | 82 | def getService(self): 83 | return internet.TCPServer(self.port, self, interface=self.listen_addr) 84 | -------------------------------------------------------------------------------- /opencanary/modules/samba.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | if sys.platform.startswith("linux"): 4 | from opencanary.modules import CanaryService, FileSystemWatcher 5 | import re 6 | 7 | class SambaLogWatcher(FileSystemWatcher): 8 | def __init__(self, logFile=None, logger=None): 9 | self.logger = logger 10 | FileSystemWatcher.__init__(self, fileName=logFile) 11 | 12 | def handleLines(self, lines=None): 13 | audit_re = re.compile(r"^.*smbd_audit.*: (.*$)") 14 | 15 | for line in lines: 16 | matches = audit_re.match(line) 17 | 18 | # Skip lines that do not match the correct RegEx pattern 19 | if matches is None: 20 | continue 21 | 22 | data = matches.groups()[0].split("|") 23 | 24 | user = data[0] 25 | srcHost = data[1] 26 | dstHost = data[2] 27 | srcHostName = data[3] 28 | shareName = data[4] 29 | dstHostName = data[5] 30 | smbVersion = data[6] 31 | smbArch = data[7] 32 | domainName = data[9] 33 | auditAction = data[10] 34 | auditStatus = data[11] 35 | path = data[12] 36 | 37 | if user == "": 38 | user = "anonymous" 39 | 40 | data = {} 41 | data["src_host"] = srcHost 42 | data["src_port"] = "-1" 43 | data["dst_host"] = dstHost 44 | data["dst_port"] = 445 45 | data["logtype"] = self.logger.LOG_SMB_FILE_OPEN 46 | data["logdata"] = { 47 | "USER": user, 48 | "REMOTENAME": srcHostName, 49 | "SHARENAME": shareName, 50 | "LOCALNAME": dstHostName, 51 | "SMBVER": smbVersion, 52 | "SMBARCH": smbArch, 53 | "DOMAIN": domainName, 54 | "AUDITACTION": auditAction, 55 | "STATUS": auditStatus, 56 | "FILENAME": path, 57 | } 58 | self.logger.log(data) 59 | 60 | class CanarySamba(CanaryService): 61 | NAME = "smb" 62 | 63 | def __init__(self, config=None, logger=None): 64 | CanaryService.__init__(self, config=config, logger=logger) 65 | self.audit_file = config.getVal( 66 | "smb.auditfile", default="/var/log/samba-audit.log" 67 | ) 68 | self.config = config 69 | 70 | def startYourEngines(self, reactor=None): 71 | # create samba run dir, so testparm doesn't error 72 | # try: 73 | # os.stat('/var/run/samba') 74 | # except OSError: 75 | # os.mkdir('/var/run/samba') 76 | 77 | fs = SambaLogWatcher(logFile=self.audit_file, logger=self.logger) 78 | fs.start() 79 | -------------------------------------------------------------------------------- /docs/starting/correlator.rst: -------------------------------------------------------------------------------- 1 | Correlator 2 | ========== 3 | 4 | Getting Started 5 | --------------- 6 | 7 | To get started create a virtual environment to play in: 8 | 9 | .. code-block:: sh 10 | 11 | $ virtualenv env 12 | $ . env/bin/activate 13 | 14 | Inside the virtualenv, install OpenCanary Correlator following the instructions in the `README `_. 15 | 16 | The correlator runs with a default config, which we'll copy and edit to get started. 17 | 18 | .. code-block:: sh 19 | 20 | $ opencanary-correlator 21 | Warning: no config file specified. Using the template config: 22 | /[...]/opencanary_correlator.conf 23 | $ cp /[...]/opencanary_correlator.conf opencanary-correlator.conf 24 | 25 | In the config file, fill the Twilio or mandrill details (or both), and the notification addresses for both. 26 | 27 | .. code-block:: json 28 | 29 | { 30 | "console.sms_notification_enable": true, 31 | "console.sms_notification_numbers": ["+336522334455"], 32 | "console.email_notification_enable": true, 33 | "console.email_notification_address": ["notifications@opencanary.org"], 34 | "console.slack_notification_enable": true, 35 | "console.slack_notification_webhook": ["https://hooks.slack.com/services/example/webhookdata"], 36 | "twilio.auth_token": "fae9206628714fb2ce00f72e94f2258f", 37 | "twilio.from_number": "+1201253234", 38 | "twilio.sid": "BD742385c0810b431fe2ddb9fc327c85ad", 39 | "console.mandrill_key": "9HCjwugWjibxww7kPFej", 40 | "scans.network_portscan_horizon": 1000 41 | } 42 | 43 | With that in place, ensure that Redis is running and then run the correlator daemon. 44 | 45 | .. code-block:: sh 46 | 47 | $ pgrep redis-server || echo 'Redis is not running!' 48 | $ opencanary-correlator --config=./opencanary-correlator.conf 49 | 50 | To configure OpenCanary daemons to send their events to the correlator, edit the **logger** field in its config and restart the daemon to reload the config. 51 | 52 | .. code-block:: json 53 | 54 | "logger": { 55 | "class": "PyLogger", 56 | "kwargs": { 57 | "handlers": { 58 | "json-tcp": { 59 | "class": "opencanary.logger.SocketJSONHandler", 60 | "host": "127.0.0.1", // change to correlator IP 61 | "port": 1514 62 | } 63 | } 64 | } 65 | } 66 | 67 | 68 | Troubleshooting 69 | --------------- 70 | 71 | You can test that the Correlator alerts are working by sending an event directly to it (without using OpenCanary). 72 | 73 | .. code-block:: sh 74 | 75 | echo '{"dst_host": "9.9.9.9", "dst_port": 21, "local_time": "2015-07-20 13:38:21.281259", "logdata": {"PASSWORD": "default", "USERNAME": "admin"}, "logtype": 2000, "node_id": "AlertTest", "src_host": "8.8.8.8", "src_port": 49635}' | nc -v localhost 1514 76 | 77 | The tool `JQ `_ can be used to check that the config file is well-formed JSON. 78 | 79 | .. code-block:: sh 80 | 81 | $ jq . ./opencanary-correlator.conf 82 | -------------------------------------------------------------------------------- /opencanary/modules/llmnr.py: -------------------------------------------------------------------------------- 1 | from opencanary.modules import CanaryService 2 | from twisted.application import internet 3 | from twisted.internet.protocol import DatagramProtocol 4 | from twisted.internet.address import IPv4Address 5 | from twisted.internet import reactor 6 | from scapy.all import IP, UDP, send, DNS 7 | from scapy.layers.dns import DNSQR 8 | from scapy.layers.llmnr import LLMNRQuery 9 | import random 10 | 11 | 12 | class LLMNR(DatagramProtocol): 13 | def startQueryLoop(self): 14 | self.sendLLMNRQuery() 15 | next_interval = self.factory.query_interval + random.uniform( 16 | -self.factory.query_splay, self.factory.query_splay 17 | ) 18 | reactor.callLater(next_interval, self.startQueryLoop) 19 | 20 | def sendLLMNRQuery(self): 21 | # Craft an LLMNR query packet 22 | target_ip = "224.0.0.252" # LLMNR multicast IP address 23 | target_port = 5355 # LLMNR port 24 | llmnr_packet = ( 25 | IP(dst=target_ip, ttl=1) 26 | / UDP(dport=target_port) 27 | / LLMNRQuery(qd=DNSQR(qname=self.factory.query_hostname)) 28 | ) 29 | 30 | # Send the packet, set verbose to False to suppress "Sent 1 packet" std-out 31 | send(llmnr_packet, verbose=False) 32 | 33 | def datagramReceived(self, data, host_and_port): 34 | try: 35 | llmnr_response = DNS(data) 36 | # Decode bytes to string and remove trailing dot if present 37 | received_hostname = llmnr_response.qd.qname.decode("utf-8").rstrip(".") 38 | # If the received hostname matches the canary hostname, it's suspicous - log it 39 | if received_hostname == self.factory.query_hostname: 40 | source_ip = host_and_port[0] 41 | logdata = { 42 | "query_hostname": self.factory.query_hostname, 43 | "response": llmnr_response.summary(), 44 | } 45 | self.transport.getPeer = lambda: IPv4Address( 46 | "UDP", source_ip, host_and_port[1] 47 | ) 48 | self.factory.log( 49 | logdata=logdata, 50 | transport=self.transport, 51 | logtype=self.factory.logtype_query_response, 52 | ) 53 | 54 | except Exception as e: 55 | error_message = f"Error processing LLMNR response: {e}" 56 | self.factory.log(error_message, level="error") 57 | 58 | 59 | class CanaryLLMNR(CanaryService): 60 | NAME = "llmnr" 61 | 62 | def __init__(self, config=None, logger=None): 63 | super(CanaryLLMNR, self).__init__(config=config, logger=logger) 64 | self.logtype_query_response = logger.LOG_LLMNR_QUERY_RESPONSE 65 | self.query_hostname = config.getVal("llmnr.hostname", default="DC03") 66 | self.port = int(config.getVal("llmnr.port", default=5355)) 67 | self.query_interval = int( 68 | config.getVal("llmnr.query_interval", default=60) 69 | ) # Interval in seconds 70 | self.query_splay = int( 71 | config.getVal("llmnr.query_splay", default=5) 72 | ) # Default splay in seconds 73 | self.listen_addr = config.getVal("device.listen_addr", default="") 74 | 75 | def getService(self): 76 | f = LLMNR() 77 | f.factory = self 78 | reactor.callWhenRunning(f.startQueryLoop) 79 | return internet.UDPServer(self.port, f, interface=self.listen_addr) 80 | -------------------------------------------------------------------------------- /docs/alerts/webhook.md: -------------------------------------------------------------------------------- 1 | # HTTP Webhook Alerts 2 | OpenCanary includes a customizable Webhook logging handler to send data to an HTTP endpoint. The handler has a few defaults for a basic configuration but is flexible enough that it can be customized for advanced usage. 3 | 4 | The following configuration options are required for this handler: 5 | 6 | * **class** - Use "opencanary.logger.WebhookHandler". 7 | * **url** - The full URL (`http://domain.example.com/path`) of your HTTP endpoint. 8 | 9 | The following configuration options are optional: 10 | 11 | * **method** - The HTTP method to use (GET, POST, PUT). Defaults to POST. 12 | * **data** - The data or JSON payload to send. Defaults to {"message": "%(message)s"}. 13 | * See advanced data mapping below 14 | * Note: If sending a JSON payload, be sure to add the correct header (see advanced additional options below) 15 | * **status_code** - The HTTP status code that is expected for success. Defaults to 200. 16 | * **ignore** - A List of string patterns to ignore and not send. Defaults to None. 17 | * See advanced ignore below 18 | * **(option)** - Any additional options added will be forwarded directly to Python Requests 19 | * See advanced additional options below 20 | 21 | Here is a basic configuration: 22 | 23 | ```json 24 | "handlers": { 25 | "Webhook": { 26 | "class": "opencanary.logger.WebhookHandler", 27 | "url": "http://domain.example.com/path", 28 | "method": "POST", 29 | "data": {"message": "%(message)s"}, 30 | "status_code": 200 31 | } 32 | } 33 | ``` 34 | 35 | ## Advanced Usage 36 | 37 | ### Advanced Data Mapping 38 | 39 | The data payload that is sent to Python Requests can be as complex as your use case needs it to be. For the message to be included, the pattern `%(message)s` must be included somewhere, but it's not necessarily required if you just want to use the same message for all alerts. 40 | 41 | For example, you can move the message to a nested section of the data payload: 42 | 43 | ```json 44 | "data":{ 45 | "title": "OpenCanary Alert", 46 | "data": { 47 | "alert": "%(message)s" 48 | } 49 | } 50 | ``` 51 | 52 | ### Advanced Ignore 53 | 54 | The ignore option is just a list of strings that will not emit any log message that contains the pattern. 55 | 56 | For example, if you use the following ignore list: 57 | 58 | ```json 59 | "ignore": ["192.0.2."] 60 | ``` 61 | 62 | The following logs will drop: 63 | 64 | ```json 65 | {"dst_host": "192.0.2.5", "dst_port": "..."} 66 | {"src_host": "192.0.2.20", "src_port": "..."} 67 | ``` 68 | 69 | ### Advanced Additional Options 70 | 71 | In addition to the options listed above, you can include any extra options that you may need in your HTTP request. These options are directly passed to `requests.request()`. Below I have included a few examples, but for a full list of options please see the [official documentation](https://docs.python-requests.org/en/latest/api/#requests.request). 72 | 73 | Add headers: 74 | ```json 75 | "headers": { 76 | "Authorization": "Bearer 12345", 77 | "Content-Type": "application/json" 78 | } 79 | ``` 80 | 81 | > Note: If your data payload needs to be JSON serialized, you must include the `"Content-Type": "application/json"` (case sensitive) header. 82 | 83 | Add query parameters. For example to add `?test=yes&redirect=no` you would use: 84 | ```json 85 | "params": { 86 | "test": "yes", 87 | "redirect": "no" 88 | } 89 | ``` 90 | Disable SSL verification 91 | ```json 92 | "verify": false 93 | ``` 94 | -------------------------------------------------------------------------------- /docs/alerts/email.rst: -------------------------------------------------------------------------------- 1 | Email Alerts 2 | ============ 3 | 4 | To have an OpenCanary daemon directly send email alerts to edit the logger section of the *~/.opencanary.conf*. The file format is JSON. 5 | 6 | In the configurations below, set these configuration variables: 7 | 8 | * **mailhost** - The SMTP mail host and port. 9 | * **fromaddr** - The from address. Usually does not have to exist. 10 | * **toaddres** - An array of addresses that will receive the alert. Keep it short. 11 | * **subject** - The email's subject. 12 | * **credentials** - Optional parameter, if the SMTP server requires authentication. 13 | * **secure** - Optional parameter if TLS support is mandatory or wanted. 14 | 15 | More information can be found on the `PyLogger page `_. 16 | 17 | Send to a Gmail address 18 | ----------------------- 19 | 20 | .. code-block:: json 21 | 22 | // [..] # Services configuration 23 | "logger": { 24 | "class" : "PyLogger", 25 | "kwargs" : { 26 | "handlers": { 27 | "SMTP": { 28 | "class": "logging.handlers.SMTPHandler", 29 | "mailhost": ["smtp.gmail.com", 25], 30 | "fromaddr": "noreply@yourdomain.com", 31 | "toaddrs" : ["youraddress@gmail.com"], 32 | "subject" : "OpenCanary Alert" 33 | } 34 | } 35 | } 36 | } 37 | 38 | Depending on your ISP and their outbound spam protection mechanisms, you may need to send to TCP port 587, set up an `app password `_ and use credentials, as well as set an empty tuple for the **secure** parameter. Your configuration would then look like this: 39 | 40 | 41 | .. code-block:: json 42 | 43 | // [..] # Services configuration 44 | "logger": { 45 | "class" : "PyLogger", 46 | "kwargs" : { 47 | "handlers": { 48 | "SMTP": { 49 | "class": "logging.handlers.SMTPHandler", 50 | "mailhost": ["smtp.gmail.com", 587], 51 | "fromaddr": "noreply@yourdomain.com", 52 | "toaddrs" : ["youraddress@gmail.com"], 53 | "subject" : "OpenCanary Alert", 54 | "credentials" : ["youraddress", "abcdefghijklmnop"], 55 | "secure" : [] 56 | } 57 | } 58 | } 59 | } 60 | 61 | Send with SMTP authentication 62 | ----------------------------- 63 | 64 | .. code-block:: json 65 | 66 | // [..] # Services configuration 67 | "logger": { 68 | "class" : "PyLogger", 69 | "kwargs" : { 70 | "handlers": { 71 | "SMTP": { 72 | "class": "logging.handlers.SMTPHandler", 73 | "mailhost": ["authenticated.mail.server", 25], 74 | "fromaddr": "canary@yourdomain.com", 75 | "toaddrs" : ["youraddress@yourdomain.com"], 76 | "subject" : "OpenCanary Alert", 77 | "credentials" : ["myusername", "password1"], 78 | "secure" : [] 79 | } 80 | } 81 | } 82 | } 83 | 84 | Environment Variables 85 | --------------------- 86 | 87 | You can use environment variables in the configuration file to pass confidential information such as passwords or tokens from the host machine to the application. 88 | 89 | For more information, see the [Configuration page](../starting/configuration.rst#environment-variables). 90 | -------------------------------------------------------------------------------- /opencanary/modules/data/httpproxy/skin/squid/auth.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ERROR: Cache Access Denied 5 | 109 | 110 |
111 |

ERROR

112 |

Cache Access Denied.

113 |
114 |
115 | 116 |
117 |

The following error was encountered while trying to retrieve the URL: {{ url }}

118 | 119 |
120 |

Cache Access Denied.

121 |
122 | 123 |

Sorry, you are not currently allowed to request {{ url }} from this cache until you have authenticated yourself.

124 | 125 |

Please contact the cache administrator if you have difficulties authenticating yourself.

127 | 128 |
129 |
130 | 131 |
132 | 136 | 137 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import codecs 2 | import os.path 3 | from setuptools import setup, find_namespace_packages 4 | 5 | 6 | def read(rel_path): 7 | here = os.path.abspath(os.path.dirname(__file__)) 8 | with codecs.open(os.path.join(here, rel_path), "r") as fp: 9 | return fp.read() 10 | 11 | 12 | def get_version(rel_path): 13 | """ 14 | Reading the package version dynamically. 15 | https://packaging.python.org/en/latest/guides/single-sourcing-package-version/ 16 | """ 17 | for line in read(rel_path).splitlines(): 18 | if line.startswith("__version__"): 19 | delim = '"' if '"' in line else "'" 20 | return line.split(delim)[1] 21 | else: 22 | raise RuntimeError("Unable to find version string.") 23 | 24 | 25 | def get_long_description(): 26 | """ 27 | Safely read README.md for long_description. 28 | """ 29 | here = os.path.abspath(os.path.dirname(__file__)) 30 | readme_path = os.path.join(here, "README.md") 31 | if not os.path.isfile(readme_path): 32 | return "A low interaction honeypot intended to be run on internal networks." 33 | with open(readme_path, encoding="utf-8") as f: 34 | return f.read() 35 | 36 | 37 | requirements = [ 38 | "Twisted==24.11.0", 39 | "pyasn1==0.4.5", 40 | "cryptography==38.0.1", 41 | "simplejson==3.16.0", 42 | "requests==2.31.0", 43 | "zope.interface==7.2", 44 | "PyPDF2==1.26.0", 45 | "fpdf==1.7.2", 46 | "passlib==1.7.1", 47 | "Jinja2==3.0.1", 48 | "ntlmlib==0.72", 49 | "bcrypt==3.1.7", 50 | "setuptools==68.0.0", 51 | "urllib3==2.0.7", 52 | "hpfeeds==3.0.0", 53 | "pyOpenSSL==22.1.0", 54 | "service-identity==21.1.0", 55 | ] 56 | 57 | setup( 58 | name="opencanary", 59 | version=get_version("opencanary/__init__.py"), 60 | url="http://www.thinkst.com/", 61 | project_urls={ 62 | "Bug Tracker": "https://github.com/thinkst/opencanary/issues", 63 | "Documentation": "https://github.com/thinkst/opencanary#readme", 64 | "Source Code": "https://github.com/thinkst/opencanary", 65 | }, 66 | author="Thinkst Applied Research", 67 | author_email="info@thinkst.com", 68 | description="OpenCanary daemon", 69 | long_description=get_long_description(), 70 | long_description_content_type="text/markdown", 71 | install_requires=requirements, 72 | license="BSD", 73 | packages=find_namespace_packages( 74 | exclude=["docs", "docs*" "opencanary.test", "opencanary.test*"] 75 | ), 76 | include_package_data=True, 77 | scripts=["bin/opencanaryd", "bin/opencanary.tac"], 78 | platforms="any", 79 | classifiers=[ 80 | "Development Status :: 5 - Production/Stable", 81 | "Intended Audience :: Developers", 82 | "Framework :: Twisted", 83 | "Topic :: System :: Networking", 84 | "Topic :: Security", 85 | "Topic :: System :: Networking :: Monitoring", 86 | "Natural Language :: English", 87 | "Operating System :: Unix", 88 | "Operating System :: POSIX :: Linux", 89 | "Operating System :: POSIX :: BSD :: FreeBSD", 90 | "Programming Language :: Python :: 3", 91 | "Programming Language :: Python :: 3.8", 92 | "Programming Language :: Python :: 3.9", 93 | "Programming Language :: Python :: 3.10", 94 | "Programming Language :: Python :: 3.11", 95 | "Programming Language :: Python :: 3.12", 96 | "Programming Language :: Python :: 3.13", 97 | "License :: OSI Approved :: BSD License", 98 | ], 99 | ) 100 | -------------------------------------------------------------------------------- /opencanary/modules/ftp.py: -------------------------------------------------------------------------------- 1 | from opencanary.modules import CanaryService 2 | 3 | from twisted.application import internet 4 | from twisted.protocols.ftp import ( 5 | FTPFactory, 6 | FTPRealm, 7 | FTP, 8 | USR_LOGGED_IN_PROCEED, 9 | GUEST_LOGGED_IN_PROCEED, 10 | IFTPShell, 11 | AuthorizationError, 12 | ) 13 | from twisted.cred.portal import Portal 14 | from zope.interface import implementer 15 | from twisted.cred.checkers import ICredentialsChecker 16 | from twisted.python import failure 17 | from twisted.cred import error as cred_error, credentials 18 | 19 | FTP_PATH = "/briar/data/ftp" 20 | 21 | 22 | @implementer(ICredentialsChecker) 23 | class DenyAllAccess: 24 | credentialInterfaces = (credentials.IAnonymous, credentials.IUsernamePassword) 25 | 26 | def requestAvatarId(self, credentials): 27 | return failure.Failure(cred_error.UnauthorizedLogin()) 28 | 29 | 30 | class LoggingFTP(FTP): 31 | # ripped from main FTP class, overridden to extract connection info 32 | def ftp_PASS(self, password): 33 | """ 34 | Second part of login. Get the password the peer wants to 35 | authenticate with. 36 | """ 37 | if self.factory.canaryservice.config.getVal( 38 | "ftp.log_auth_attempt_initiated", default=False 39 | ): 40 | logtype = self.factory.canaryservice.logger.LOG_FTP_AUTH_ATTEMPT_INITIATED 41 | self.factory.canaryservice.log( 42 | {}, transport=self.transport, logtype=logtype 43 | ) 44 | 45 | if self.factory.allowAnonymous and self._user == self.factory.userAnonymous: 46 | # anonymous login 47 | creds = credentials.Anonymous() 48 | reply = GUEST_LOGGED_IN_PROCEED 49 | else: 50 | # user login 51 | creds = credentials.UsernamePassword(self._user, password) 52 | reply = USR_LOGGED_IN_PROCEED 53 | 54 | logdata = {"USERNAME": self._user, "PASSWORD": password} 55 | self.factory.canaryservice.log(logdata, transport=self.transport) 56 | 57 | del self._user 58 | 59 | def _cbLogin(login_details): 60 | # login_details is a list (interface, avatar, logout) 61 | assert login_details[0] is IFTPShell, "The realm is busted, jerk." 62 | self.shell = login_details[1] 63 | self.logout = login_details[2] 64 | self.workingDirectory = [] 65 | self.state = self.AUTHED 66 | return reply 67 | 68 | def _ebLogin(failure): 69 | failure.trap(cred_error.UnauthorizedLogin, cred_error.UnhandledCredentials) 70 | self.state = self.UNAUTH 71 | raise AuthorizationError 72 | 73 | d = self.portal.login(creds, None, IFTPShell) 74 | d.addCallbacks(_cbLogin, _ebLogin) 75 | return d 76 | 77 | 78 | class CanaryFTP(CanaryService): 79 | NAME = "ftp" 80 | 81 | def __init__(self, config=None, logger=None): 82 | CanaryService.__init__(self, config=config, logger=logger) 83 | 84 | self.banner = config.getVal("ftp.banner", default="FTP Ready.").encode("utf8") 85 | self.port = config.getVal("ftp.port", default=21) 86 | # find a place to check that logtype is initialised 87 | # find a place to check that factory has service attached 88 | self.logtype = logger.LOG_FTP_LOGIN_ATTEMPT 89 | self.listen_addr = config.getVal("device.listen_addr", default="") 90 | 91 | def getService(self): 92 | p = Portal(FTPRealm(FTP_PATH), [DenyAllAccess()]) 93 | f = FTPFactory(p) 94 | f.protocol = LoggingFTP 95 | f.welcomeMessage = self.banner.decode() 96 | f.canaryservice = self 97 | return internet.TCPServer(self.port, f, interface=self.listen_addr) 98 | -------------------------------------------------------------------------------- /opencanary/data/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "device.node_id": "opencanary-1", 3 | "ip.ignorelist": [ ], 4 | "logtype.ignorelist": [ ], 5 | "git.enabled": false, 6 | "git.port" : 9418, 7 | "ftp.enabled": true, 8 | "ftp.port": 21, 9 | "ftp.banner": "FTP server ready", 10 | "ftp.log_auth_attempt_initiated": false, 11 | "http.banner": "Apache/2.2.22 (Ubuntu)", 12 | "http.enabled": false, 13 | "http.port": 80, 14 | "http.skin": "nasLogin", 15 | "http.log_unimplemented_method_requests": false, 16 | "http.log_redirect_request": false, 17 | "https.enabled": false, 18 | "https.port": 443, 19 | "https.skin": "nasLogin", 20 | "https.certificate": "/etc/ssl/opencanary/opencanary.pem", 21 | "https.key": "/etc/ssl/opencanary/opencanary.key", 22 | "httpproxy.enabled" : false, 23 | "httpproxy.port": 8080, 24 | "httpproxy.skin": "squid", 25 | "llmnr.enabled": false, 26 | "llmnr.query_interval": 60, 27 | "llmnr.query_splay": 5, 28 | "llmnr.hostname": "DC03", 29 | "llmnr.port": 5355, 30 | "logger": { 31 | "class": "PyLogger", 32 | "kwargs": { 33 | "formatters": { 34 | "plain": { 35 | "format": "%(message)s" 36 | }, 37 | "syslog_rfc": { 38 | "format": "opencanaryd[%(process)-5s:%(thread)d]: %(name)s %(levelname)-5s %(message)s" 39 | } 40 | }, 41 | "handlers": { 42 | "console": { 43 | "class": "logging.StreamHandler", 44 | "stream": "ext://sys.stdout" 45 | }, 46 | "file": { 47 | "class": "logging.FileHandler", 48 | "filename": "/var/tmp/opencanary.log" 49 | } 50 | } 51 | } 52 | }, 53 | "portscan.enabled": false, 54 | "portscan.ignore_localhost": false, 55 | "portscan.logfile":"/var/log/kern.log", 56 | "portscan.synrate": 5, 57 | "portscan.nmaposrate": 5, 58 | "portscan.lorate": 3, 59 | "portscan.ignore_ports": [ ], 60 | "smb.auditfile": "/var/log/samba-audit.log", 61 | "smb.enabled": false, 62 | "mysql.enabled": false, 63 | "mysql.port": 3306, 64 | "mysql.banner": "5.5.43-0ubuntu0.14.04.1", 65 | "mysql.log_connection_made": false, 66 | "ssh.enabled": false, 67 | "ssh.port": 22, 68 | "ssh.version": "SSH-2.0-OpenSSH_5.1p1 Debian-4", 69 | "redis.enabled": false, 70 | "redis.port": 6379, 71 | "rdp.enabled": false, 72 | "rdp.port": 3389, 73 | "sip.enabled": false, 74 | "sip.port": 5060, 75 | "snmp.enabled": false, 76 | "snmp.port": 161, 77 | "ntp.enabled": false, 78 | "ntp.port": 123, 79 | "tftp.enabled": false, 80 | "tftp.port": 69, 81 | "tcpbanner.maxnum":10, 82 | "tcpbanner.enabled": false, 83 | "tcpbanner_1.enabled": false, 84 | "tcpbanner_1.port": 8001, 85 | "tcpbanner_1.datareceivedbanner": "", 86 | "tcpbanner_1.initbanner": "", 87 | "tcpbanner_1.alertstring.enabled": false, 88 | "tcpbanner_1.alertstring": "", 89 | "tcpbanner_1.keep_alive.enabled": false, 90 | "tcpbanner_1.keep_alive_secret": "", 91 | "tcpbanner_1.keep_alive_probes": 11, 92 | "tcpbanner_1.keep_alive_interval":300, 93 | "tcpbanner_1.keep_alive_idle": 300, 94 | "telnet.enabled": false, 95 | "telnet.port": 23, 96 | "telnet.banner": "", 97 | "telnet.honeycreds": [ 98 | { 99 | "username": "admin", 100 | "password": "$pbkdf2-sha512$19000$bG1NaY3xvjdGyBlj7N37Xw$dGrmBqqWa1okTCpN3QEmeo9j5DuV2u1EuVFD8Di0GxNiM64To5O/Y66f7UASvnQr8.LCzqTm6awC8Kj/aGKvwA" 101 | }, 102 | { 103 | "username": "admin", 104 | "password": "admin1" 105 | } 106 | ], 107 | "telnet.log_tcp_connection": false, 108 | "mssql.enabled": false, 109 | "mssql.version": "2012", 110 | "mssql.port":1433, 111 | "vnc.enabled": false, 112 | "vnc.port":5000 113 | } 114 | -------------------------------------------------------------------------------- /bin/opencanaryd: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) 3 | PIDFILE="${DIR}/opencanaryd.pid" 4 | 5 | cmd=$1 6 | 7 | function usage() { 8 | echo -e "\n OpenCanary\n" 9 | echo -e "\topencanaryd [ --start | --dev | --stop | --restart | --copyconfig | --usermodule | --version | --help ] [--uid=nobody] [--gid=nogroup]\n\n" 10 | echo -e "\t\t--start\tStarts the opencanaryd process" 11 | echo -e "\t\t--dev\tRun the opencanaryd process in the foreground" 12 | echo -e "\t\t--stop\tStops the opencanaryd process" 13 | echo -e "\t\t--usermodule\tRun opencanaryd in foreground with only usermodules enabled" 14 | echo -e "\t\t--copyconfig\tCreates a default config file at /etc/opencanaryd/opencanary.conf" 15 | echo -e "\t\t--version\tDisplays the current opencanary version." 16 | echo -e "\t\t--" 17 | echo -e "\t\t--help\tThis help\n" 18 | echo -e "\toptions" 19 | echo -e "\t\t--allow-run-as-root\tDo not drop privileges of the opencanary once process starts" 20 | echo -e "\t\t--uid\tSpecify a user or uid to drop privileges to" 21 | echo -e "\t\t--gid\tSpecify a group of gid to drop privileges to" 22 | } 23 | 24 | # Parse options 25 | for arg in "$@"; do 26 | case $arg in 27 | --uid=*) 28 | readonly TWISTD_UID_FLAG=" --uid=${arg#*=}" 29 | ;; 30 | --gid=*) 31 | readonly TWISTD_GID_FLAG=" --gid=${arg#*=}" 32 | ;; 33 | esac 34 | done 35 | 36 | function warn_drop_privileges { 37 | if [[ -z $TWISTD_UID_FLAG || -z $TWISTD_GID_FLAG ]]; then 38 | echo "WARNING: OpenCanary will not drop root user or group privileges after launching. Set both --uid=nobody and --gid=nogroup (or another low privilege user/group) to silence this warning." >&2 39 | fi 40 | } 41 | 42 | # Use sudo when not running as root 43 | function sudo() { 44 | if [ "$EUID" -ne 0 ]; then 45 | $(which sudo) $* 46 | else 47 | # Strip `sudo -E` before running the remaining command 48 | ${*:2} 49 | fi 50 | } 51 | 52 | if [ "${cmd}" == "--start" ]; then 53 | warn_drop_privileges 54 | sudo -E "${DIR}/twistd" -y "${DIR}/opencanary.tac" --pidfile "${PIDFILE}" --syslog --prefix=opencanaryd ${TWISTD_UID_FLAG:-} ${TWISTD_GID_FLAG:-} 55 | elif [ "${cmd}" == "--dev" ]; then 56 | warn_drop_privileges 57 | sudo -E "${DIR}/twistd" -noy "${DIR}/opencanary.tac" --pidfile "${PIDFILE}" ${TWISTD_UID_FLAG:-} ${TWISTD_GID_FLAG:-} 58 | elif [ "${cmd}" == "--usermodule" ]; then 59 | usermodconf=$(python3 -c "from pkg_resources import resource_filename; print(resource_filename('opencanary', 'data/settings-usermodule.json'))") 60 | 61 | if [ -f opencanary.conf ]; then 62 | if ! diff -q opencanary.conf "${usermodconf}" 2>&1 >/dev/null; then 63 | echo "Backing up old config to ./opencanary.conf.old" 64 | cp opencanary.conf{,.old} 65 | fi 66 | fi 67 | 68 | cp "${usermodconf}" opencanary.conf 69 | sudo -E "${DIR}/twistd" -noy "${DIR}/opencanary.tac" 70 | 71 | elif [ "${cmd}" == "--restart" ]; then 72 | pid=`sudo -E cat "${PIDFILE}"` 73 | sudo -E kill "$pid" 74 | warn_drop_privileges 75 | sudo -E "${DIR}/twistd" -y "${DIR}/opencanary.tac" --pidfile "${PIDFILE}" --syslog --prefix=opencanaryd ${TWISTD_UID_FLAG:-} ${TWISTD_GID_FLAG:-} 76 | elif [ "${cmd}" == "--stop" ]; then 77 | pid=`sudo -E cat "${PIDFILE}"` 78 | sudo -E kill "$pid" 79 | elif [ "${cmd}" == "--copyconfig" ]; then 80 | if [ -f /etc/opencanaryd/opencanary.conf ]; then 81 | echo "A config file already exists at /etc/opencanaryd/opencanary.conf, please move it first" 82 | exit 1 83 | fi 84 | defaultconf=$(python3 -c "from pkg_resources import resource_filename; print(resource_filename('opencanary', 'data/settings.json'))") 85 | sudo -E mkdir -p /etc/opencanaryd 86 | sudo -E cp "${defaultconf}" /etc/opencanaryd/opencanary.conf 87 | echo -e "[*] A sample config file is ready /etc/opencanaryd/opencanary.conf\n" 88 | echo "[*] Edit your configuration, then launch with \"opencanaryd --start\"" 89 | elif [ "${cmd}" == "--version" ]; then 90 | python3 -c "from opencanary import __version__; print(__version__);" 91 | else 92 | usage 93 | exit 1 94 | fi 95 | -------------------------------------------------------------------------------- /opencanary/test/opencanary.conf: -------------------------------------------------------------------------------- 1 | { 2 | "device.node_id": "opencanary-1", 3 | "ip.ignorelist": [ ], 4 | "git.enabled": true, 5 | "git.port" : 9418, 6 | "ftp.enabled": true, 7 | "ftp.port": 21, 8 | "ftp.banner": "FTP server ready", 9 | "ftp.log_auth_attempt_initiated": true, 10 | "http.banner": "Apache/2.2.22 (Ubuntu)", 11 | "http.enabled": true, 12 | "http.port": 80, 13 | "http.skin": "nasLogin", 14 | "http.skin.list": [ 15 | { 16 | "desc": "Plain HTML Login", 17 | "name": "basicLogin" 18 | }, 19 | { 20 | "desc": "Synology NAS Login", 21 | "name": "nasLogin" 22 | } 23 | ], 24 | "http.log_unimplemented_method_requests": true, 25 | "http.log_redirect_request": true, 26 | "https.enabled": true, 27 | "https.port": 443, 28 | "https.skin": "nasLogin", 29 | "httpproxy.enabled" : false, 30 | "httpproxy.port": 8080, 31 | "httpproxy.skin": "squid", 32 | "httproxy.skin.list": [ 33 | { 34 | "desc": "Squid", 35 | "name": "squid" 36 | }, 37 | { 38 | "desc": "Microsoft ISA Server Web Proxy", 39 | "name": "ms-isa" 40 | } 41 | ], 42 | "logger": { 43 | "class": "PyLogger", 44 | "kwargs": { 45 | "formatters": { 46 | "plain": { 47 | "format": "%(message)s" 48 | }, 49 | "syslog_rfc": { 50 | "format": "opencanaryd[%(process)-5s:%(thread)d]: %(name)s %(levelname)-5s %(message)s" 51 | } 52 | }, 53 | "handlers": { 54 | "console": { 55 | "class": "logging.StreamHandler", 56 | "stream": "ext://sys.stdout" 57 | }, 58 | "file": { 59 | "class": "logging.FileHandler", 60 | "filename": "/var/tmp/opencanary.log" 61 | } 62 | } 63 | } 64 | }, 65 | "portscan.enabled": false, 66 | "portscan.ignore_localhost": false, 67 | "portscan.logfile":"/var/log/kern.log", 68 | "portscan.synrate": 5, 69 | "portscan.nmaposrate": 5, 70 | "portscan.lorate": 3, 71 | "smb.auditfile": "/var/log/samba-audit.log", 72 | "smb.enabled": false, 73 | "mysql.enabled": true, 74 | "mysql.port": 3306, 75 | "mysql.banner": "5.5.43-0ubuntu0.14.04.1", 76 | "mysql.log_connection_made": true, 77 | "ssh.enabled": true, 78 | "ssh.port": 2222, 79 | "ssh.version": "SSH-2.0-OpenSSH_5.1p1 Debian-4", 80 | "redis.enabled": false, 81 | "redis.port": 6379, 82 | "rdp.enabled": true, 83 | "rdp.port": 3389, 84 | "sip.enabled": false, 85 | "sip.port": 5060, 86 | "snmp.enabled": false, 87 | "snmp.port": 161, 88 | "ntp.enabled": true, 89 | "ntp.port": 123, 90 | "tftp.enabled": false, 91 | "tftp.port": 69, 92 | "tcpbanner.maxnum":10, 93 | "tcpbanner.enabled": false, 94 | "tcpbanner_1.enabled": false, 95 | "tcpbanner_1.port": 8001, 96 | "tcpbanner_1.datareceivedbanner": "", 97 | "tcpbanner_1.initbanner": "", 98 | "tcpbanner_1.alertstring.enabled": false, 99 | "tcpbanner_1.alertstring": "", 100 | "tcpbanner_1.keep_alive.enabled": false, 101 | "tcpbanner_1.keep_alive_secret": "", 102 | "tcpbanner_1.keep_alive_probes": 11, 103 | "tcpbanner_1.keep_alive_interval":300, 104 | "tcpbanner_1.keep_alive_idle": 300, 105 | "telnet.enabled": false, 106 | "telnet.port": 23, 107 | "telnet.banner": "", 108 | "telnet.honeycreds": [ 109 | { 110 | "username": "admin", 111 | "password": "$pbkdf2-sha512$19000$bG1NaY3xvjdGyBlj7N37Xw$dGrmBqqWa1okTCpN3QEmeo9j5DuV2u1EuVFD8Di0GxNiM64To5O/Y66f7UASvnQr8.LCzqTm6awC8Kj/aGKvwA" 112 | }, 113 | { 114 | "username": "admin", 115 | "password": "admin1" 116 | } 117 | ], 118 | "telnet.log_tcp_connection": true, 119 | "mssql.enabled": false, 120 | "mssql.version": "2012", 121 | "mssql.port":1433, 122 | "vnc.enabled": false, 123 | "vnc.port":5000 124 | } 125 | -------------------------------------------------------------------------------- /opencanary/modules/telnet.py: -------------------------------------------------------------------------------- 1 | from opencanary.modules import CanaryService 2 | 3 | from zope.interface import implementer 4 | from twisted.application import internet 5 | from twisted.internet.error import ConnectionDone, ConnectionLost 6 | from twisted.internet import protocol 7 | from twisted.cred import portal 8 | from twisted.cred import credentials 9 | from twisted.conch.telnet import AuthenticatingTelnetProtocol 10 | from twisted.conch.telnet import ITelnetProtocol 11 | from twisted.conch.telnet import TelnetTransport 12 | from twisted.conch.telnet import ECHO 13 | from twisted.spread.pb import Avatar 14 | 15 | 16 | class MyTelnet(Avatar): 17 | def __init__(self, name): 18 | self.name = name 19 | 20 | 21 | @implementer(portal.IRealm) 22 | class Realm: 23 | def requestAvatar(self, avatarId, mind, *interfaces): 24 | if ITelnetProtocol in interfaces: 25 | av = MyTelnet() 26 | av.state = "Command" 27 | return ITelnetProtocol, av, lambda: None 28 | raise NotImplementedError("Not supported by this realm") 29 | 30 | 31 | class CanaryTelnetTransport(TelnetTransport): 32 | def dataReceived(self, data): 33 | try: 34 | TelnetTransport.dataReceived(self, data) 35 | except ValueError: 36 | print("Telnet client spoke weirdly, abandoning connection") 37 | self.loseConnection() 38 | 39 | def connectionLost(self, reason): 40 | # Avoids pointless logs on disconnect 41 | if reason.check(ConnectionDone) or reason.check(ConnectionLost): 42 | return 43 | TelnetTransport.connectionLost(self, reason) 44 | 45 | 46 | class AlertAuthTelnetProtocol(AuthenticatingTelnetProtocol): 47 | def connectionMade(self): 48 | # p/Cisco telnetd/ d/router/ o/IOS/ cpe:/a:cisco:telnet/ cpe:/o:cisco:ios/a 49 | # NB _write() is for raw data and write() handles telnet special bytes 50 | if self.factory.canaryservice.config.getVal( 51 | "telnet.log_tcp_connection", default=False 52 | ): 53 | logtype = self.factory.canaryservice.logger.LOG_TELNET_CONNECTION_MADE 54 | self.factory.canaryservice.log( 55 | {}, transport=self.transport, logtype=logtype 56 | ) 57 | 58 | self.transport._write( 59 | b"\xff\xfb\x01\xff\xfb\x03\xff\xfb\0\xff\xfd\0\xff\xfd\x1f\r\n" 60 | ) 61 | self.transport.write(self.factory.banner) 62 | self.transport._write(b"User Access Verification\r\n\r\nUsername: ") 63 | 64 | def telnet_Password(self, line): 65 | # Body of this method copied from 66 | # twisted.conch.telnet 67 | username, password = self.username, line 68 | del self.username 69 | 70 | def login(ignored): 71 | creds = credentials.UsernamePassword(username, password) 72 | d = self.portal.login(creds, None, ITelnetProtocol) 73 | d.addCallback(self._cbLogin) 74 | d.addErrback(self._ebLogin) 75 | 76 | self.transport.wont(ECHO).addCallback(login) 77 | 78 | logdata = {"USERNAME": username, "PASSWORD": password} 79 | self.factory.canaryservice.log(logdata, transport=self.transport) 80 | return "Discard" 81 | 82 | 83 | class Telnet(CanaryService): 84 | NAME = "telnet" 85 | 86 | def __init__(self, config=None, logger=None): 87 | CanaryService.__init__(self, config=config, logger=logger) 88 | self.port = int(config.getVal("telnet.port", default=8023)) 89 | self.banner = config.getVal("telnet.banner", "").encode("utf8") 90 | self.logtype = logger.LOG_TELNET_LOGIN_ATTEMPT 91 | self.listen_addr = config.getVal("device.listen_addr", default="") 92 | 93 | if self.banner: 94 | self.banner += b"\n" 95 | 96 | def getService(self): 97 | r = Realm() 98 | p = portal.Portal(r) 99 | f = protocol.ServerFactory() 100 | f.canaryservice = self 101 | f.logger = self.logger 102 | f.banner = self.banner 103 | f.protocol = lambda: CanaryTelnetTransport(AlertAuthTelnetProtocol, p) 104 | return internet.TCPServer(self.port, f, interface=self.listen_addr) 105 | -------------------------------------------------------------------------------- /data/.opencanary.conf: -------------------------------------------------------------------------------- 1 | { 2 | "device.node_id": "opencanary-1", 3 | "ip.ignorelist": [ ], 4 | "logtype.ignorelist": [ ], 5 | "git.enabled": false, 6 | "git.port" : 9418, 7 | "ftp.enabled": true, 8 | "ftp.port": 21, 9 | "ftp.banner": "FTP server ready", 10 | "ftp.log_auth_attempt_initiated": false, 11 | "http.banner": "Apache/2.2.22 (Ubuntu)", 12 | "http.enabled": true, 13 | "http.port": 80, 14 | "http.skin": "nasLogin", 15 | "http.skin.list": [ 16 | { 17 | "desc": "Plain HTML Login", 18 | "name": "basicLogin" 19 | }, 20 | { 21 | "desc": "Synology NAS Login", 22 | "name": "nasLogin" 23 | } 24 | ], 25 | "http.log_unimplemented_method_requests": false, 26 | "http.log_redirect_request": false, 27 | "https.enabled": true, 28 | "https.port": 443, 29 | "https.skin": "nasLogin", 30 | "https.certificate": "/etc/ssl/opencanary/opencanary.pem", 31 | "https.key": "/etc/ssl/opencanary/opencanary.key", 32 | "httpproxy.enabled" : false, 33 | "httpproxy.port": 8080, 34 | "httpproxy.skin": "squid", 35 | "httproxy.skin.list": [ 36 | { 37 | "desc": "Squid", 38 | "name": "squid" 39 | }, 40 | { 41 | "desc": "Microsoft ISA Server Web Proxy", 42 | "name": "ms-isa" 43 | } 44 | ], 45 | "llmnr.enabled": false, 46 | "llmnr.query_interval": 60, 47 | "llmnr.query_splay": 5, 48 | "llmnr.hostname": "DC03", 49 | "llmnr.port": 5355, 50 | "logger": { 51 | "class": "PyLogger", 52 | "kwargs": { 53 | "formatters": { 54 | "plain": { 55 | "format": "%(message)s" 56 | }, 57 | "syslog_rfc": { 58 | "format": "opencanaryd[%(process)-5s:%(thread)d]: %(name)s %(levelname)-5s %(message)s" 59 | } 60 | }, 61 | "handlers": { 62 | "console": { 63 | "class": "logging.StreamHandler", 64 | "stream": "ext://sys.stdout" 65 | }, 66 | "file": { 67 | "class": "logging.FileHandler", 68 | "filename": "/var/tmp/opencanary.log" 69 | } 70 | } 71 | } 72 | }, 73 | "portscan.enabled": true, 74 | "portscan.ignore_localhost": false, 75 | "portscan.logfile":"/var/log/kern.log", 76 | "portscan.synrate": 5, 77 | "portscan.nmaposrate": 5, 78 | "portscan.lorate": 3, 79 | "portscan.ignore_ports": [ ], 80 | "smb.auditfile": "/var/log/samba-audit.log", 81 | "smb.enabled": false, 82 | "mysql.enabled": false, 83 | "mysql.port": 3306, 84 | "mysql.banner": "5.5.43-0ubuntu0.14.04.1", 85 | "mysql.log_connection_made": false, 86 | "ssh.enabled": false, 87 | "ssh.port": 22, 88 | "ssh.version": "SSH-2.0-OpenSSH_5.1p1 Debian-4", 89 | "redis.enabled": false, 90 | "redis.port": 6379, 91 | "rdp.enabled": false, 92 | "rdp.port": 3389, 93 | "sip.enabled": false, 94 | "sip.port": 5060, 95 | "snmp.enabled": false, 96 | "snmp.port": 161, 97 | "ntp.enabled": false, 98 | "ntp.port": 123, 99 | "tftp.enabled": false, 100 | "tftp.port": 69, 101 | "tcpbanner.maxnum":10, 102 | "tcpbanner.enabled": false, 103 | "tcpbanner_1.enabled": false, 104 | "tcpbanner_1.port": 8001, 105 | "tcpbanner_1.datareceivedbanner": "", 106 | "tcpbanner_1.initbanner": "", 107 | "tcpbanner_1.alertstring.enabled": false, 108 | "tcpbanner_1.alertstring": "", 109 | "tcpbanner_1.keep_alive.enabled": false, 110 | "tcpbanner_1.keep_alive_secret": "", 111 | "tcpbanner_1.keep_alive_probes": 11, 112 | "tcpbanner_1.keep_alive_interval":300, 113 | "tcpbanner_1.keep_alive_idle": 300, 114 | "telnet.enabled": false, 115 | "telnet.port": 23, 116 | "telnet.banner": "", 117 | "telnet.honeycreds": [ 118 | { 119 | "username": "admin", 120 | "password": "$pbkdf2-sha512$19000$bG1NaY3xvjdGyBlj7N37Xw$dGrmBqqWa1okTCpN3QEmeo9j5DuV2u1EuVFD8Di0GxNiM64To5O/Y66f7UASvnQr8.LCzqTm6awC8Kj/aGKvwA" 121 | }, 122 | { 123 | "username": "admin", 124 | "password": "admin1" 125 | } 126 | ], 127 | "telnet.log_tcp_connection": false, 128 | "mssql.enabled": false, 129 | "mssql.version": "2012", 130 | "mssql.port":1433, 131 | "vnc.enabled": false, 132 | "vnc.port":5000 133 | } 134 | -------------------------------------------------------------------------------- /opencanary/modules/https.py: -------------------------------------------------------------------------------- 1 | import os 2 | from datetime import datetime, timedelta 3 | from pathlib import Path 4 | 5 | from cryptography import x509 6 | from cryptography.hazmat.primitives import hashes, serialization 7 | from cryptography.hazmat.primitives.asymmetric import rsa 8 | from cryptography.x509.oid import NameOID 9 | from twisted.application import internet 10 | from twisted.web.resource import EncodingResourceWrapper 11 | from twisted.web.server import Site, GzipEncoderFactory 12 | from twisted.internet.ssl import DefaultOpenSSLContextFactory 13 | 14 | from opencanary.modules import CanaryService 15 | from opencanary.modules.http import ( 16 | BasicLogin, 17 | CanaryHTTP, 18 | RedirectCustomHeaders, 19 | StaticNoDirListing, 20 | ) 21 | 22 | 23 | class CanaryHTTPS(CanaryService): 24 | NAME = "https" 25 | 26 | def __init__(self, config=None, logger=None): 27 | CanaryService.__init__(self, config=config, logger=logger) 28 | self.skin = config.getVal("https.skin", default="basicLogin") 29 | # We share the skin dir with HTTP rather than duplicate everything 30 | self.skindir = config.getVal("http.skindir", default="") 31 | if not os.path.isdir(self.skindir): 32 | self.skindir = os.path.join(CanaryHTTP.resource_dir(), "skin", self.skin) 33 | self.staticdir = os.path.join(self.skindir, "static") 34 | self.port = int(config.getVal("https.port", default=443)) 35 | ubanner = config.getVal("http.banner", default="Apache/2.2.22 (Ubuntu)") 36 | self.banner = ubanner.encode("utf8") 37 | StaticNoDirListing.BANNER = self.banner 38 | self.listen_addr = config.getVal("device.listen_addr", default="") 39 | self.domain_name = config.getVal( 40 | "https.domain_name", default="synologynas.local" 41 | ) 42 | self.certificate_path = Path( 43 | config.getVal( 44 | "https.certificate", default="/etc/ssl/opencanary/opencanary.pem" 45 | ) 46 | ) 47 | self.key_path = Path( 48 | config.getVal("https.key", default="/etc/ssl/opencanary/opencanary.key") 49 | ) 50 | self.load_certificates() 51 | 52 | def load_certificates(self): 53 | """ 54 | If certificates already exist, use them, otherwise we generate self signed certificates. 55 | """ 56 | if self.certificate_path.exists() and self.key_path.exists(): 57 | pass 58 | else: 59 | # Make the directory to save the keys into (if it doesn't already exist) 60 | self.key_path.parent.mkdir(parents=True, exist_ok=True) 61 | self.certificate_path.parent.mkdir(parents=True, exist_ok=True) 62 | 63 | # Generate our Key 64 | key = rsa.generate_private_key( 65 | public_exponent=65537, 66 | key_size=2048, 67 | ) 68 | # Write our key to disk for safe keeping 69 | with open(self.key_path, "wb") as key_file: 70 | key_file.write( 71 | key.private_bytes( 72 | encoding=serialization.Encoding.PEM, 73 | format=serialization.PrivateFormat.TraditionalOpenSSL, 74 | encryption_algorithm=serialization.NoEncryption(), 75 | ) 76 | ) 77 | # Various details about who we are. For a self-signed certificate the 78 | # subject and issuer are always the same. 79 | subject = issuer = x509.Name( 80 | [ 81 | x509.NameAttribute(NameOID.COUNTRY_NAME, "US"), 82 | x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, "California"), 83 | x509.NameAttribute(NameOID.LOCALITY_NAME, "San Francisco"), 84 | x509.NameAttribute(NameOID.ORGANIZATION_NAME, "Synology Inc. CA"), 85 | x509.NameAttribute(NameOID.COMMON_NAME, self.domain_name), 86 | ] 87 | ) 88 | cert = ( 89 | x509.CertificateBuilder() 90 | .subject_name(subject) 91 | .issuer_name(issuer) 92 | .public_key(key.public_key()) 93 | .serial_number(x509.random_serial_number()) 94 | .not_valid_before(datetime.utcnow()) 95 | .not_valid_after(datetime.utcnow() + timedelta(days=365)) 96 | .sign(key, hashes.SHA256()) 97 | ) 98 | # Write our certificate out to disk. 99 | with open(self.certificate_path, "wb") as f: 100 | f.write(cert.public_bytes(serialization.Encoding.PEM)) 101 | 102 | def getService(self): 103 | page = BasicLogin(factory=self) 104 | root = StaticNoDirListing(self.staticdir) 105 | root.createErrorPages(self) 106 | root.putChild(b"", RedirectCustomHeaders(b"/index.html", factory=self)) 107 | root.putChild(b"index.html", page) 108 | wrapped = EncodingResourceWrapper(root, [GzipEncoderFactory()]) 109 | site = Site(wrapped) 110 | return internet.SSLServer( 111 | self.port, 112 | site, 113 | DefaultOpenSSLContextFactory( 114 | privateKeyFileName=self.key_path, 115 | certificateFileName=self.certificate_path, 116 | ), 117 | interface=self.listen_addr, 118 | ) 119 | -------------------------------------------------------------------------------- /opencanary/modules/httpproxy.py: -------------------------------------------------------------------------------- 1 | import os 2 | import datetime 3 | 4 | from opencanary.modules import CanaryService 5 | 6 | from base64 import b64decode 7 | 8 | from twisted.application import internet 9 | from twisted.web.http import Request, HTTPChannel 10 | from twisted.web import http 11 | 12 | from jinja2 import Template 13 | 14 | PROFILES = { 15 | "ms-isa": { 16 | # p/Microsoft ISA Server Web Proxy/ 17 | # Force HTTP/1.1 reply even when sent HTTP/1.0 (to match the nmap version sig) 18 | "HTTP1.1_always": True, 19 | "headers": [ 20 | ("Via", "1.1 localhost"), 21 | ("Proxy-Authenticate", "Basic"), 22 | # TODO: more realistict authentication for ISA 23 | # ("Proxy-Authenticate", "NTLM"), 24 | # ("Proxy-Authenticate", "Kerberos"), 25 | # ("Proxy-Authenticate", "Negotiate"), 26 | ("Pragma", "no-cache"), 27 | ("Cache-Control", "no-cache"), 28 | ], 29 | "status_reason": b"Proxy Authentication Required ( The ISA Server requires authorization to fulfill the request. Access to the Web Proxy service is denied. )", 30 | }, 31 | "squid": { 32 | # p/Squid http proxy/ v/$1/ cpe:/a:squid-cache:squid:$1/ 33 | "banner": "Squid proxy-caching web server", 34 | "headers": [ 35 | ("Server", "squid/3.3.8"), 36 | ("Mime-Version", "1.0"), 37 | ("Vary", "Accept-Language"), 38 | ("Via", "1.1 localhost (squid/3.3.8)"), 39 | ("X-Cache", "MISS from localhost"), 40 | ("X-Cache-Lookup", "NONE from localhost"), # actually hostname:port 41 | ("X-Squid-Error", "ERR_CACHE_ACCESS_DENIED 0"), 42 | ], 43 | "status_reason": b"Proxy Authentication Required", 44 | }, 45 | } 46 | 47 | 48 | class AlertProxyRequest(Request): 49 | """ 50 | Used by Proxy to implement a simple web proxy. 51 | """ 52 | 53 | FACTORY = None 54 | 55 | def __init__(self, channel, queued): 56 | Request.__init__(self, channel, queued) 57 | 58 | def logAuth(self): 59 | auth = self.getHeader("Proxy-Authorization") 60 | if auth is None: 61 | return 62 | 63 | factory = AlertProxyRequest.FACTORY 64 | 65 | username, password = "Invalid auth-token submitted", "" 66 | auth_arr = auth.split(" ") 67 | if len(auth_arr) != 2: 68 | return 69 | 70 | atype, token = auth_arr 71 | if atype == "Basic": 72 | try: 73 | username, password = b64decode(token).split(":") 74 | except: # noqa: E722 75 | pass 76 | elif atype == "NTLM": 77 | # b64decode returns bytes not str in python2 78 | print(b64decode(token).decode("utf-8").split(":")) 79 | exit(1) 80 | print("something NTLM") 81 | # Shouldn't this return something? 82 | return 83 | 84 | logdata = {"USERNAME": username, "PASSWORD": password} 85 | factory.log(logdata, transport=self.transport) 86 | 87 | def process(self): 88 | self.logAuth() 89 | 90 | factory = AlertProxyRequest.FACTORY 91 | profile = PROFILES[factory.skin] 92 | content = factory.auth_template.render( 93 | url=self.uri.decode(), 94 | date=datetime.datetime.utcnow().strftime("%a, %d %b %Y %H:%M:%S %ZGMT"), 95 | clientip=self.transport.getPeer().host, 96 | ) 97 | if factory.banner: 98 | prompt = factory.banner 99 | else: 100 | prompt = profile.get("banner", "") 101 | 102 | # for fooling nmap service detection 103 | if profile.get("HTTP1.1_always", False): 104 | self.clientproto = "HTTP/1.1" 105 | 106 | # match http-proxy m|^HTTP/1\.[01] \d\d\d .*\r\nServer: [sS]quid/([-.\w+]+)\r\n|s 107 | self.setResponseCode(407, profile["status_reason"]) 108 | for name, value in profile["headers"]: 109 | self.responseHeaders.addRawHeader(name, value) 110 | 111 | self.responseHeaders.addRawHeader("Content-Type", "text/html") 112 | self.responseHeaders.addRawHeader( 113 | "Proxy-Authenticate", 'Basic realm="%s"' % prompt 114 | ) 115 | self.responseHeaders.addRawHeader("Content-Length", "{}".format(len(content))) 116 | 117 | self.write(content.encode("utf-8")) 118 | self.finish() 119 | 120 | 121 | class AlertProxy(HTTPChannel): 122 | requestFactory = AlertProxyRequest 123 | 124 | 125 | class HTTPProxyFactory(http.HTTPFactory): 126 | def buildProtocol(self, addr): 127 | return AlertProxy() 128 | 129 | 130 | class HTTPProxy(CanaryService): 131 | NAME = "httpproxy" 132 | 133 | def __init__(self, config=None, logger=None): 134 | CanaryService.__init__(self, config=config, logger=logger) 135 | self.port = int(config.getVal("httpproxy.port", default=8443)) 136 | self.banner = config.getVal("httpproxy.banner", "").encode("utf8") 137 | self.skin = config.getVal("httpproxy.skin", default="squid") 138 | self.skindir = os.path.join(HTTPProxy.resource_dir(), "skin", self.skin) 139 | self.logtype = logger.LOG_HTTPPROXY_LOGIN_ATTEMPT 140 | self.listen_addr = config.getVal("device.listen_addr", default="") 141 | 142 | authfilename = os.path.join(self.skindir, "auth.html") 143 | try: 144 | with open(authfilename, "r") as f: 145 | self.auth_template = Template(f.read()) 146 | except: # noqa: E722 147 | self.auth_template = Template("") 148 | 149 | def getService(self): 150 | AlertProxyRequest.FACTORY = self 151 | f = HTTPProxyFactory() 152 | return internet.TCPServer(self.port, f, interface=self.listen_addr) 153 | -------------------------------------------------------------------------------- /opencanary/modules/vnc.py: -------------------------------------------------------------------------------- 1 | from opencanary.modules import CanaryService 2 | 3 | from twisted.internet.protocol import Protocol 4 | from twisted.internet.protocol import Factory 5 | from twisted.application import internet 6 | 7 | from opencanary.modules.des import des 8 | 9 | import os 10 | 11 | RFB_33 = b"003.003" 12 | RFB_37 = b"003.007" 13 | RFB_38 = b"003.008" 14 | 15 | # states 16 | PRE_INIT = 1 17 | HANDSHAKE_SEND = 2 18 | SECURITY_SEND = 3 19 | AUTH_SEND = 4 20 | AUTH_OVER = 5 21 | 22 | # if one of these is used in the VNC authentication attempt, alert that 23 | # a common password was tried 24 | COMMON_PASSWORDS = [ 25 | "111111", 26 | "password", 27 | "123456", 28 | "111111", 29 | "1234", 30 | "administrator", 31 | "root", 32 | "passw0rd", 33 | ] 34 | 35 | 36 | class ProtocolError(Exception): 37 | pass 38 | 39 | 40 | class UnsupportedVersion(Exception): 41 | pass 42 | 43 | 44 | class VNCProtocol(Protocol): 45 | """ 46 | Implementation of VNC up to VNC authentication 47 | """ 48 | 49 | def __init__(self, version=RFB_38): 50 | self.serv_version = version 51 | self.state = PRE_INIT 52 | 53 | def _send_handshake( 54 | self, 55 | ): 56 | print("send handshake") 57 | version_string = "RFB {version}\n".format( 58 | version=self.serv_version.decode("utf-8") 59 | ) 60 | self.transport.write(version_string.encode("utf-8")) 61 | self.state = HANDSHAKE_SEND 62 | 63 | def _recv_handshake(self, data=None): 64 | print("got handshake") 65 | if len(data) != 12 or data[:3] != b"RFB": 66 | raise ProtocolError() 67 | client_ver = data[4:-1] 68 | 69 | # support single version for now 70 | if client_ver not in [RFB_33, RFB_37, RFB_38]: 71 | raise UnsupportedVersion() 72 | 73 | self._send_security(client_ver) 74 | 75 | def _send_security(self, client_ver): 76 | print("send security") 77 | if client_ver == RFB_33: 78 | self.transport.write(b"\x00\x00\x00\x02") # specify VNC auth using 4 bytes 79 | self._send_auth() 80 | else: 81 | self.transport.write(b"\x01\x02") # VNC authentication 82 | self.state = SECURITY_SEND 83 | 84 | def _recv_security(self, data=None): 85 | print("got security") 86 | if len(data) != 1 and data != "\x02": 87 | raise ProtocolError() 88 | self._send_auth() 89 | 90 | def _send_auth( 91 | self, 92 | ): 93 | print("send auth") 94 | self.challenge = os.urandom(16) 95 | self.transport.write(self.challenge) 96 | self.state = AUTH_SEND 97 | 98 | def _recv_auth(self, data=None): 99 | print("got auth") 100 | if len(data) != 16: 101 | raise ProtocolError() 102 | 103 | logdata = { 104 | "VNC Server Challenge": self.challenge.hex(), 105 | "VNC Client Response": data.hex(), 106 | } 107 | 108 | used_password = self._try_decrypt_response(response=data) 109 | if used_password: 110 | logdata["VNC Password"] = used_password 111 | else: 112 | logdata["VNC Password"] = "" 113 | self.factory.log(logdata, transport=self.transport) 114 | self._send_auth_failed() 115 | 116 | def connectionMade(self): 117 | if self.state != PRE_INIT: 118 | raise ProtocolError() 119 | self._send_handshake() 120 | 121 | def _send_auth_failed( 122 | self, 123 | ): 124 | self.transport.write( 125 | b"\x00\x00\x00\x01" 126 | + b"\x00\x00\x00\x16" # response code 127 | + b"Authentication failure" # message length 128 | ) # Message 129 | self.state = AUTH_OVER 130 | raise ProtocolError() 131 | 132 | def _try_decrypt_response(self, response=None): 133 | # attempt to decrypt each of the common passwords 134 | # really inefficient, but it means we don't have to rely on 135 | # a static challenge 136 | for password in COMMON_PASSWORDS: 137 | pw = password[:8] # vnc passwords are max 8 chars 138 | if len(pw) < 8: 139 | pw += "\x00" * (8 - len(pw)) 140 | 141 | pw = pw.encode("ascii") 142 | # VNC use of DES requires password bits to be mirrored 143 | values = bytearray() 144 | for x in pw: 145 | values.append(int("{:08b}".format(x)[::-1], 2)) 146 | desbox = des(values) 147 | 148 | decrypted_challenge = desbox.decrypt(response) 149 | if decrypted_challenge == self.challenge: 150 | return password 151 | return None 152 | 153 | def dataReceived(self, data): 154 | """ 155 | Received data is unbuffered so we buffer it for telnet. 156 | """ 157 | try: 158 | if self.state == HANDSHAKE_SEND: 159 | self._recv_handshake(data=data) 160 | elif self.state == SECURITY_SEND: 161 | self._recv_security(data=data) 162 | elif self.state == AUTH_SEND: 163 | self._recv_auth(data=data) 164 | except (UnsupportedVersion, ProtocolError): 165 | self.transport.loseConnection() 166 | return 167 | 168 | 169 | class CanaryVNC(Factory, CanaryService): 170 | NAME = "VNC" 171 | protocol = VNCProtocol 172 | 173 | def __init__(self, config=None, logger=None): 174 | CanaryService.__init__(self, config, logger) 175 | self.port = config.getVal("vnc.port", 5900) 176 | self.listen_addr = config.getVal("device.listen_addr", default="") 177 | self.logtype = logger.LOG_VNC 178 | 179 | def getService(self): 180 | return internet.TCPServer(self.port, self, interface=self.listen_addr) 181 | 182 | 183 | CanaryServiceFactory = CanaryVNC 184 | -------------------------------------------------------------------------------- /bin/opencanary.tac: -------------------------------------------------------------------------------- 1 | import traceback 2 | import warnings 3 | import sys 4 | from twisted.application import service 5 | from pkg_resources import iter_entry_points 6 | 7 | from opencanary.config import config, is_docker 8 | from opencanary.logger import getLogger 9 | from opencanary.modules.http import CanaryHTTP 10 | from opencanary.modules.https import CanaryHTTPS 11 | from opencanary.modules.ftp import CanaryFTP 12 | from opencanary.modules.ssh import CanarySSH 13 | from opencanary.modules.telnet import Telnet 14 | from opencanary.modules.httpproxy import HTTPProxy 15 | from opencanary.modules.mysql import CanaryMySQL 16 | from opencanary.modules.mssql import MSSQL 17 | from opencanary.modules.ntp import CanaryNtp 18 | from opencanary.modules.tftp import CanaryTftp 19 | from opencanary.modules.vnc import CanaryVNC 20 | from opencanary.modules.sip import CanarySIP 21 | from opencanary.modules.git import CanaryGit 22 | from opencanary.modules.redis import CanaryRedis 23 | from opencanary.modules.tcpbanner import CanaryTCPBanner 24 | from opencanary.modules.rdp import CanaryRDP 25 | 26 | 27 | def warn(*args, **kwargs): 28 | pass 29 | 30 | 31 | warnings.warn = warn 32 | 33 | 34 | # from opencanary.modules.example0 import CanaryExample0 35 | # from opencanary.modules.example1 import CanaryExample1 36 | 37 | ENTRYPOINT = "canary.usermodule" 38 | MODULES = [ 39 | CanaryFTP, 40 | CanaryGit, 41 | CanaryHTTP, 42 | CanaryHTTPS, 43 | CanaryMySQL, 44 | CanaryNtp, 45 | CanaryRDP, 46 | CanaryRedis, 47 | CanarySIP, 48 | CanarySSH, 49 | CanaryTCPBanner, 50 | CanaryTftp, 51 | CanaryVNC, 52 | HTTPProxy, 53 | MSSQL, 54 | Telnet, 55 | # CanaryExample0, 56 | # CanaryExample1, 57 | ] 58 | 59 | if config.moduleEnabled("snmp"): 60 | try: 61 | # Module need Scapy, but the rest of OpenCanary doesn't 62 | from opencanary.modules.snmp import CanarySNMP 63 | 64 | MODULES.append(CanarySNMP) 65 | except ImportError: 66 | print("Can't import SNMP. Please ensure you have Scapy installed.") 67 | pass 68 | 69 | if config.moduleEnabled("llmnr"): 70 | try: 71 | # Module needs Scapy, but the rest of OpenCanary doesn't 72 | from opencanary.modules.llmnr import CanaryLLMNR 73 | 74 | MODULES.append(CanaryLLMNR) 75 | except ImportError: 76 | print("Can't import LLMNR. Please ensure you have Scapy installed.") 77 | pass 78 | 79 | # NB: imports below depend on inotify, only available on linux 80 | if sys.platform.startswith("linux"): 81 | from opencanary.modules.samba import CanarySamba 82 | 83 | MODULES.append(CanarySamba) 84 | if config.moduleEnabled("portscan") and is_docker(): 85 | # Remove portscan if running in DOCKER (specified in Dockerfile) 86 | print("Can't use portscan in Docker. Portscan module disabled.") 87 | else: 88 | from opencanary.modules.portscan import CanaryPortscan 89 | 90 | MODULES.append(CanaryPortscan) 91 | 92 | 93 | logger = getLogger(config) 94 | 95 | 96 | def start_mod(application, klass): # noqa: C901 97 | try: 98 | obj = klass(config=config, logger=logger) 99 | except Exception: 100 | err = "Failed to instantiate instance of class %s in %s. %s" % ( 101 | klass.__name__, 102 | klass.__module__, 103 | traceback.format_exc(), 104 | ) 105 | logMsg({"logdata": err}) 106 | return 107 | 108 | if hasattr(obj, "startYourEngines"): 109 | try: 110 | obj.startYourEngines() 111 | msg = "Ran startYourEngines on class %s in %s" % ( 112 | klass.__name__, 113 | klass.__module__, 114 | ) 115 | logMsg({"logdata": msg}) 116 | 117 | except Exception: 118 | err = "Failed to run startYourEngines on %s in %s. %s" % ( 119 | klass.__name__, 120 | klass.__module__, 121 | traceback.format_exc(), 122 | ) 123 | logMsg({"logdata": err}) 124 | elif hasattr(obj, "getService"): 125 | try: 126 | service = obj.getService() 127 | if not isinstance(service, list): 128 | service = [service] 129 | for s in service: 130 | s.setServiceParent(application) 131 | msg = "Added service from class %s in %s to fake" % ( 132 | klass.__name__, 133 | klass.__module__, 134 | ) 135 | logMsg({"logdata": msg}) 136 | except Exception: 137 | err = "Failed to add service from class %s in %s. %s" % ( 138 | klass.__name__, 139 | klass.__module__, 140 | traceback.format_exc(), 141 | ) 142 | logMsg({"logdata": err}) 143 | else: 144 | err = "The class %s in %s does not have any required starting method." % ( 145 | klass.__name__, 146 | klass.__module__, 147 | ) 148 | logMsg({"logdata": err}) 149 | 150 | 151 | def logMsg(msg): 152 | data = {} 153 | data["logdata"] = {"msg": msg} 154 | logger.log(data, retry=False) 155 | 156 | 157 | application = service.Application("opencanaryd") 158 | 159 | # List of modules to start 160 | start_modules = [] 161 | 162 | # Add all custom modules 163 | # (Permanently enabled as they don't officially use settings yet) 164 | for ep in iter_entry_points(ENTRYPOINT): 165 | try: 166 | klass = ep.load(require=False) 167 | start_modules.append(klass) 168 | except Exception: 169 | err = "Failed to load class from the entrypoint: %s. %s" % ( 170 | str(ep), 171 | traceback.format_exc(), 172 | ) 173 | logMsg({"logdata": err}) 174 | 175 | # Add only enabled modules 176 | start_modules.extend(filter(lambda m: config.moduleEnabled(m.NAME), MODULES)) 177 | 178 | for klass in start_modules: 179 | start_mod(application, klass) 180 | 181 | msg = "Canary running!!!" 182 | logMsg({"logdata": msg}) 183 | -------------------------------------------------------------------------------- /opencanary/modules/__init__.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import warnings 3 | import os.path 4 | from pkg_resources import resource_filename 5 | from twisted.application import internet 6 | from twisted.internet.protocol import Factory 7 | from twisted.internet.protocol import DatagramProtocol 8 | 9 | from opencanary.honeycred import buildHoneyCredHook 10 | 11 | # Monkey-patch-replace Twisted Protocol with CanaryProtocol class 12 | from twisted.internet import protocol 13 | 14 | 15 | class CanaryProtocol(protocol.Protocol): 16 | """TCP protocols (ie. descedents of this class) gain a log method that be 17 | can be called with just the event data, as transport data is added here""" 18 | 19 | def log(self, *args, **kwargs): 20 | if hasattr(self, "factory") and hasattr(self.factory, "log"): 21 | kwargs["transport"] = self.transport 22 | return self.factory.log(*args, **kwargs) 23 | 24 | raise AttributeError( 25 | """Instance of %s does not have 'factory' attribute 26 | or factory does not have a log function.""" 27 | % self.__class__.__name__ 28 | ) 29 | 30 | 31 | protocol.Protocol = CanaryProtocol 32 | 33 | 34 | class CanaryService(object): 35 | NAME = "baseservice" 36 | 37 | def __init__(self, config=None, logger=None): 38 | self.config = config 39 | self.logger = logger 40 | self.logtype = None 41 | 42 | # if config contains honeycreds, create basic honeycreds class 43 | self.creds = config.getVal("%s.honeycreds" % self.NAME, []) 44 | if self.creds: 45 | self.honeyCredHook = buildHoneyCredHook(self.creds) 46 | 47 | @classmethod 48 | def resource_dir(klass): 49 | """Read-Only module resource directory""" 50 | path = os.path.join("data", klass.NAME) 51 | return resource_filename(__name__, path) 52 | 53 | @classmethod 54 | def resource_filename(klass, *args): 55 | """Access read-only data (installed with package)""" 56 | return os.path.join(klass.resource_dir(), *args) 57 | 58 | def log(self, logdata, **kwargs): 59 | """ 60 | Log a module event 61 | 62 | For brevity, protocols may pass in Twisted transport argument 63 | for logger to get the IPs and ports of the connection. 64 | """ 65 | data = {"logtype": self.logtype, "logdata": logdata} 66 | 67 | logtype = kwargs.pop("logtype", None) 68 | if logtype: 69 | msg = """Passing in the logtype to log is deprecated. (In future each module will have only only logtype.)""" 70 | warnings.warn(msg, DeprecationWarning) 71 | data["logtype"] = logtype 72 | 73 | transport = kwargs.pop("transport", None) 74 | if transport: 75 | us = transport.getHost() 76 | peer = transport.getPeer() 77 | data["src_host"] = peer.host 78 | data["src_port"] = peer.port 79 | data["dst_host"] = us.host 80 | data["dst_port"] = us.port 81 | 82 | # otherwise the module can include IPs and ports as kwargs 83 | data.update(kwargs) 84 | 85 | # run pre-log hooks 86 | if getattr(self, "honeyCredHook", None): 87 | username = logdata.get("USERNAME", None) 88 | password = logdata.get("PASSWORD", None) 89 | if username or password: 90 | data["honeycred"] = self.honeyCredHook(username, password) 91 | 92 | self.logger.log(data) 93 | 94 | def getService(self): 95 | """Return service to be run 96 | 97 | This handles the easy case where the CanaryService class is 98 | also the Factory/Datagram class. Subclasses should override 99 | this if more intricracy is needed. 100 | """ 101 | if isinstance(self, Factory): 102 | return internet.TCPServer(self.port, self) 103 | elif isinstance(self, DatagramProtocol): 104 | return internet.UDPServer(self.port, self) 105 | 106 | err = ( 107 | "The class %s does not inherit from either Factory or DatagramProtocol." 108 | % (self.__class__.__name__) 109 | ) 110 | raise Exception(err) 111 | 112 | 113 | if sys.platform.startswith("linux"): # noqa: C901 114 | from twisted.python import filepath 115 | from twisted.internet import inotify 116 | from twisted.python._inotify import INotifyError 117 | from twisted.internet.inotify import IN_CREATE 118 | import os 119 | 120 | class FileSystemWatcher(object): 121 | def __init__(self, fileName=None): 122 | self.path = fileName 123 | self.log_dir = os.path.dirname(os.path.realpath(self.path)) 124 | self.f = None 125 | 126 | def reopenFiles(self, skipToEnd=True): 127 | if self.f: 128 | self.f.close() 129 | 130 | try: 131 | self.f = open(self.path) 132 | if skipToEnd: 133 | self.f.seek(0, 2) 134 | except IOError: 135 | self.f = None 136 | 137 | self.notifier.startReading() 138 | try: 139 | self.notifier.ignore(filepath.FilePath(self.path)) 140 | except KeyError: 141 | pass 142 | 143 | try: 144 | self.notifier.watch( 145 | filepath.FilePath(self.path), callbacks=[self.onChange] 146 | ) 147 | except INotifyError: 148 | self.notifier.watch( 149 | filepath.FilePath(self.log_dir), 150 | mask=IN_CREATE, 151 | callbacks=[self.onDirChange], 152 | ) 153 | 154 | def start(self): 155 | self.notifier = inotify.INotify() 156 | self.reopenFiles() 157 | 158 | def handleLines(self, lines=None): 159 | pass 160 | 161 | def processAuditLines( 162 | self, 163 | ): 164 | if not self.f: 165 | return 166 | 167 | lines = self.f.read().strip().split("\n") 168 | 169 | self.handleLines(lines=lines) 170 | 171 | def onChange(self, watch, path, mask): 172 | # print path, 'changed', mask # or do something else! 173 | if mask != 2: 174 | self.reopenFiles() 175 | 176 | self.processAuditLines() 177 | 178 | def onDirChange(self, watch, path, mask): 179 | # print path, ' dir changed', mask # or do something else! 180 | # import pdb; pdb.set_trace() 181 | try: 182 | self.notifier.ignore(filepath.FilePath(self.log_dir)) 183 | except KeyError: 184 | pass 185 | 186 | if mask != 2: 187 | self.reopenFiles(skipToEnd=False) 188 | 189 | self.processAuditLines() 190 | -------------------------------------------------------------------------------- /opencanary/modules/mysql.py: -------------------------------------------------------------------------------- 1 | from opencanary.modules import CanaryService 2 | from opencanary.config import ConfigException 3 | 4 | from twisted.protocols.policies import TimeoutMixin 5 | from twisted.internet.protocol import Protocol 6 | from twisted.internet.protocol import Factory 7 | from twisted.application import internet 8 | from random import randint 9 | 10 | import struct 11 | import re 12 | import string 13 | import random 14 | 15 | UINT_MAX = 0xFFFFFFFF 16 | 17 | 18 | class MySQL(Protocol, TimeoutMixin): 19 | HEADER_LEN = 4 20 | ERR_CODE_ACCESS_DENIED = 1045 21 | ERR_CODE_PKT_ORDER = 1156 22 | SQL_STATE_ACCESS_DENIED = b"28000" 23 | SQL_STATE_PKT_ORDER = b"08S01" 24 | 25 | # https://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::Handshake 26 | def __init__(self, factory): 27 | self._busyReceiving = False 28 | self._buffer = b"" 29 | self.factory = factory 30 | self.threadid = factory.next_threadid() 31 | self.setTimeout(10) 32 | 33 | @staticmethod 34 | def build_packet(seq_id, data): 35 | data_len = len(data) 36 | if data_len > 0xFFFFFF or data_len <= 0: 37 | return None 38 | 39 | if seq_id > 0xFF or seq_id < 0: 40 | return None 41 | 42 | # chop to 3 byte int 43 | _length = struct.pack("