├── docker-compose.yml ├── cowrie └── Dockerfile ├── README.md └── config └── cowrie-config └── cowrie.cfg /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | services: 3 | cowrie: 4 | image: rayson/cowrie:20160907-1 5 | build: cowrie 6 | user: cowrie 7 | ports: 8 | - "22:2222/tcp" 9 | volumes: 10 | - ./config/cowrie-config/cowrie.cfg:/opt/cowrie/cowrie.cfg:Z 11 | - cowrie-data:/opt/cowrie/data:Z 12 | - cowrie-log:/opt/cowrie/log:Z 13 | volumes: 14 | cowrie-data: 15 | cowrie-log: 16 | -------------------------------------------------------------------------------- /cowrie/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:3.4 2 | MAINTAINER Rayson Zhu 3 | 4 | EXPOSE 2222 5 | CMD ["twistd", "-n", "-l", "log/cowrie.log", "--umask", "0077", "cowrie"] 6 | 7 | RUN apk add --no-cache ca-certificates wget python py-pip py-twisted py-cryptography \ 8 | py-openssl py-enum34 py-six py-asn1 py-ipaddress py-cffi py-idna && \ 9 | pip install service_identity && \ 10 | adduser -D cowrie && \ 11 | wget -O /tmp/cowrie.zip https://github.com/micheloosterhof/cowrie/archive/3d8085e86a13332311949e206c5a15b514db1d90.zip && \ 12 | mkdir -p /opt && \ 13 | unzip -d /opt /tmp/cowrie.zip && mv /opt/cowrie-* /opt/cowrie && \ 14 | rm /tmp/cowrie.zip && \ 15 | chown -R cowrie: /opt/cowrie && \ 16 | cp -a /opt/cowrie/cowrie.cfg.dist /opt/cowrie/cowrie.cfg && \ 17 | apk del ca-certificates wget 18 | 19 | WORKDIR /opt/cowrie 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #docker-cowrie 2 | 3 | This repo contains Dockerfile and Docker compose file that help you 4 | run [Cowrie][] in Docker containers. 5 | 6 | [Cowrie][] is a medium interaction SSH and Telnet honeypot designed 7 | to log brute force attacks and the shell interaction performed by the attacker. 8 | 9 | ## Usage 10 | 11 | ### Step 1: Install Docker Engine and Docker Compose 12 | 13 | Please make sure you have Docker Engine and Docker Compose installed. 14 | 15 | If not, see 16 | and . 17 | 18 | ### Step 2: Clone This Repo 19 | 20 | ``` sh 21 | cd /path/you/like 22 | git clone https://github.com/vfreex/docker-cowrie.git && cd docker-cowrie 23 | 24 | ``` 25 | 26 | ### Step 3: Prepare Your Cowrie Docker Image 27 | 28 | You can either build the Docker image from the Dockerfile in this repo, 29 | or pull the prebuilt image from Docker Hub: 30 | 31 | #### Build by Yourself 32 | 33 | Just build it using `docker-compose build`. 34 | The Dockerfile is located at `cowrie/Dockerfile`. Edit it if necessary. 35 | 36 | ``` sh 37 | 38 | docker-compose build 39 | 40 | ``` 41 | 42 | #### Pull from Docker Hub 43 | 44 | If you don't want to build by yourself, just pull my prebuilt image 45 | from Docker Hub. The repo homepage is at . 46 | 47 | ``` sh 48 | docker-compose pull 49 | ``` 50 | 51 | ### Step 4: Run 52 | 53 | Before starting a Cowrie container, you may want to edit Cowrie's configuration 54 | file. It is `config/cowrie-config/cowrie.cfg` and will be mounted as 55 | a Docker volume when you start the container. 56 | 57 | ``` sh 58 | # edit config/cowrie-config/conrie.cfg if necessary 59 | # edit docker-compose.yml to change the port number you want to map 60 | 61 | # run in the background 62 | docker-compose up -d 63 | 64 | # run in the foreground 65 | # docker-compose up 66 | ``` 67 | To stop and destroy the container that runs in the background: 68 | 69 | ``` sh 70 | docker-compose down 71 | ``` 72 | 73 | ## Inspect Your Cowrie Container 74 | 75 | ### Display the status of our container 76 | 77 | ``` bash 78 | # get container's name and port mapping 79 | docker-compose ps 80 | # get container's detailed information 81 | docker inspect `docker-compose ps -q` 82 | ``` 83 | 84 | ### Inspect log and data files 85 | 86 | [Cowrie]'s `data` and `log` directorires contain all data 87 | that you are insterested in. 88 | They are mounted as Docker named volumes. 89 | 90 | Before inspecting files in those directories, 91 | you should figure out the names of those volumes by running `docker volume ls`: 92 | 93 | ``` bash 94 | $ docker volume ls 95 | DRIVER VOLUME NAME 96 | local cowrie_cowrie-log 97 | local cowrie_cowrie-data 98 | ``` 99 | 100 | Then obtain the pysical path of your desired volume by ruuning 101 | `docker volume inspect `: 102 | 103 | ``` bash 104 | $ docker volume inspect cowrie_cowrie-log 105 | [ 106 | { 107 | "Name": "cowrie_cowrie-log", 108 | "Driver": "local", 109 | "Mountpoint": "/var/lib/docker/volumes/cowrie_cowrie-log/_data" 110 | } 111 | ] 112 | ``` 113 | 114 | The "Mountpoint" above is the physical path of the volume. 115 | All files you need are just there. 116 | 117 | ## Cleanup 118 | 119 | If you don't want to use the Docker image anymore, 120 | you can delete the Docker image: 121 | 122 | ``` sh 123 | docker-compose down --rmi all # will not delete your data volumes 124 | 125 | # Be careful: delete all the data volumes (the storage for cowrie logs and data) either 126 | # docker-compose down -v --rmi all 127 | ``` 128 | 129 | ## Troubleshoot 130 | 131 | ### Error occurs when executing `docker-compose`: 132 | 133 | ``` 134 | ERROR: In file './docker-compose.yml' service 'version' doesn't have any configuration options. All top level keys in your docker-compose.yml must map to a dictionary of configuration options. 135 | ``` 136 | _Solution_ 137 | 138 | Upgrade your docker-compose to 1.6.0+: 139 | 140 | ``` sh 141 | # Make sure you have pip installed. If not, please install pip: 142 | # apt install python-pip # Debian/Ubuntu 143 | # dnf install python-pip # Fedora 144 | # yum install python-pip # RHEL/CentOS with EPEL 145 | 146 | $ pip install -U docker-compose 147 | ``` 148 | 149 | [Cowrie]: https://github.com/micheloosterhof/cowrie 150 | -------------------------------------------------------------------------------- /config/cowrie-config/cowrie.cfg: -------------------------------------------------------------------------------- 1 | # 2 | # Cowrie configuration file (cowrie.cfg) 3 | # 4 | 5 | # ============================================================================ 6 | # General Honeypot Options 7 | # ============================================================================ 8 | [honeypot] 9 | 10 | # Sensor name is used to identify this Cowrie instance. Used by the database 11 | # logging modules such as mysql. 12 | # 13 | # If not specified, the logging modules will instead use the IP address of the 14 | # server as the sensor name. 15 | # 16 | # (default: not specified) 17 | #sensor_name=myhostname 18 | 19 | # Hostname for the honeypot. Displayed by the shell prompt of the virtual 20 | # environment 21 | # 22 | # (default: svr04) 23 | hostname = server 24 | 25 | 26 | # Directory where to save log files in. 27 | # 28 | # (default: log) 29 | log_path = log 30 | 31 | 32 | # Directory where to save downloaded artifacts in. 33 | # 34 | # (default: dl) 35 | download_path = dl 36 | 37 | 38 | # Directory for miscellaneous data files, such as the password database. 39 | # 40 | # (default: data_path) 41 | data_path = data 42 | 43 | 44 | # Directory where virtual file contents are kept in. 45 | # 46 | # This is only used by commands like 'cat' to display the contents of files. 47 | # Adding files here is not enough for them to appear in the honeypot - the 48 | # actual virtual filesystem is kept in filesystem_file (see below) 49 | # 50 | # (default: honeyfs) 51 | contents_path = honeyfs 52 | 53 | 54 | # File in the python pickle format containing the virtual filesystem. 55 | # 56 | # This includes the filenames, paths, permissions for the Cowrie filesystem, 57 | # but not the file contents. This is created by the bin/createfs utility from 58 | # a real template linux installation. 59 | # 60 | # (default: fs.pickle) 61 | filesystem_file = data/fs.pickle 62 | 63 | 64 | # Directory for creating simple commands that only output text. 65 | # 66 | # The command must be placed under this directory with the proper path, such 67 | # as: 68 | # txtcmds/usr/bin/vi 69 | # The contents of the file will be the output of the command when run inside 70 | # the honeypot. 71 | # 72 | # In addition to this, the file must exist in the virtual filesystem 73 | # 74 | # (default: txtcmds) 75 | txtcmds_path = txtcmds 76 | 77 | 78 | # Maximum file size (in bytes) for downloaded files to be stored in 'download_path'. 79 | # A value of 0 means no limit. If the file size is known to be too big from the start, 80 | # the file will not be stored on disk at all. 81 | # 82 | # (default: 0) 83 | #download_limit_size = 10485760 84 | 85 | 86 | # Session management interface. 87 | # 88 | # This is a telnet based service that can be used to interact with active 89 | # sessions. Disabled by default. The interact feature is only available on 90 | # the loopback interface. 91 | # 92 | # (default: false) 93 | interact_enabled = false 94 | # (default: 5123) 95 | interact_port = 5123 96 | 97 | 98 | # ============================================================================ 99 | # Network Specific Options 100 | # ============================================================================ 101 | 102 | 103 | # IP address to bind to when opening outgoing connections. Used by wget and 104 | # curl commands. 105 | # 106 | # (default: not specified) 107 | #out_addr = 0.0.0.0 108 | 109 | 110 | # Fake address displayed as the address of the incoming connection. 111 | # This doesn't affect logging, and is only used by honeypot commands such as 112 | # 'w' and 'last' 113 | # 114 | # If not specified, the actual IP address is displayed instead (default 115 | # behaviour). 116 | # 117 | # (default: not specified) 118 | #fake_addr = 192.168.66.254 119 | 120 | 121 | # The IP address on which this machine is reachable on from the internet. 122 | # Useful if you use portforwarding or other mechanisms. If empty, Cowrie 123 | # will determine by itself. Used in 'netstat' output 124 | # 125 | #internet_facing_ip = 9.9.9.9 126 | 127 | 128 | # Enable to log the public IP of the honeypot (useful if listening on 127.0.0.1) 129 | # IP address is obtained by querying http://myip.threatstream.com 130 | #report_public_ip = true 131 | 132 | 133 | 134 | # ============================================================================ 135 | # Authentication Specific Options 136 | # ============================================================================ 137 | 138 | 139 | # Class that implements the checklogin() method. 140 | # 141 | # Class must be defined in cowrie/core/auth.py 142 | # Default is the 'UserDB' class which uses the password database. 143 | # 144 | # Alternatively the 'AuthRandom' class can be used, which will let 145 | # a user login after a random number of attempts. 146 | # It will also cache username/password combinations that allow login. 147 | # 148 | # auth_class = UserDB 149 | 150 | # When AuthRandom is used also set the 151 | # auth_class_parameters: , , 152 | # for example: 2, 5, 10 = allows access after randint(2,5) attempts 153 | # and cache 10 combinations. 154 | # 155 | auth_class = AuthRandom 156 | auth_class_parameters = 2, 5, 10 157 | 158 | 159 | # No authentication checking at all 160 | # enabling 'auth_none' will enable the ssh2 'auth_none' authentication method 161 | # this allows the requested user in without any verification at all 162 | # 163 | # (default: false) 164 | #auth_none_enabled = false 165 | 166 | 167 | 168 | # ============================================================================ 169 | # SSH Specific Options 170 | # ============================================================================ 171 | 172 | 173 | # IP addresses to listen for incoming SSH connections. 174 | # 175 | # (default: 0.0.0.0) = any IPv4 address 176 | #listen_addr = 0.0.0.0 177 | # (use :: for listen to all IPv6 and IPv4 addresses) 178 | #listen_addr = :: 179 | 180 | 181 | # Port to listen for incoming SSH connections. 182 | # 183 | # (default: 2222) 184 | #listen_port = 2222 185 | 186 | 187 | # SSH Version String 188 | # 189 | # Use these to disguise your honeypot from a simple SSH version scan 190 | # Examples: 191 | # SSH-2.0-OpenSSH_5.1p1 Debian-5 192 | # SSH-1.99-OpenSSH_4.3 193 | # SSH-1.99-OpenSSH_4.7 194 | # SSH-1.99-Sun_SSH_1.1 195 | # SSH-2.0-OpenSSH_4.2p1 Debian-7ubuntu3.1 196 | # SSH-2.0-OpenSSH_4.3 197 | # SSH-2.0-OpenSSH_4.6 198 | # SSH-2.0-OpenSSH_5.1p1 Debian-5 199 | # SSH-2.0-OpenSSH_5.1p1 FreeBSD-20080901 200 | # SSH-2.0-OpenSSH_5.3p1 Debian-3ubuntu5 201 | # SSH-2.0-OpenSSH_5.3p1 Debian-3ubuntu6 202 | # SSH-2.0-OpenSSH_5.3p1 Debian-3ubuntu7 203 | # SSH-2.0-OpenSSH_5.5p1 Debian-6 204 | # SSH-2.0-OpenSSH_5.5p1 Debian-6+squeeze1 205 | # SSH-2.0-OpenSSH_5.5p1 Debian-6+squeeze2 206 | # SSH-2.0-OpenSSH_5.8p2_hpn13v11 FreeBSD-20110503 207 | # SSH-2.0-OpenSSH_5.9p1 Debian-5ubuntu1 208 | # SSH-2.0-OpenSSH_6.0p1 Debian-4+deb7u2 209 | # SSH-2.0-OpenSSH_5.9 210 | # 211 | # (default: "SSH-2.0-SSH-2.0-OpenSSH_6.0p1 Debian-4+deb7u2") 212 | ssh_version_string = SSH-2.0-OpenSSH_6.0p1 Debian-4+deb7u2 213 | 214 | 215 | # Source Port to report in logs (useful if you use iptables to forward ports to Cowrie) 216 | #reported_ssh_port = 22 217 | 218 | 219 | # Public and private SSH key files. If these don't exist, they are created 220 | # automatically. 221 | rsa_public_key = data/ssh_host_rsa_key.pub 222 | rsa_private_key = data/ssh_host_rsa_key 223 | dsa_public_key = data/ssh_host_dsa_key.pub 224 | dsa_private_key = data/ssh_host_dsa_key 225 | 226 | 227 | # sftp_enabled enables the sftp subsystem 228 | sftp_enabled = true 229 | 230 | 231 | # SSH forwarding 232 | # Useful for forwarding protocols to other honeypots 233 | 234 | # This enables redirecting forwarding requests to another address 235 | ssh_forward_redirect = false 236 | # (default: false) 237 | 238 | # forward_redirect_ = : 239 | forward_redirect_80 = 127.0.0.1:8080 240 | forward_redirect_443 = 127.0.0.1:8443 241 | # If you want to record SMTP traffic, install SMTP honeypoint. 242 | # (e.g https://github.com/awhitehatter/mailoney), run 243 | # python mailoney.py -s yahoo.com -t schizo_open_relay -p 12525 244 | forward_redirect_25 = 127.0.0.1:12525 245 | forward_redirect_587 = 127.0.0.1:12525 246 | 247 | 248 | # ============================================================================ 249 | # Telnet Specific Options 250 | # ============================================================================ 251 | [telnet] 252 | 253 | # Enable Telnet support, disabled by default 254 | enabled = false 255 | 256 | # IP addresses to listen for incoming Telnet connections. 257 | # 258 | # (default: 0.0.0.0) = any IPv4 address 259 | #listen_addr = 0.0.0.0 260 | # (use :: for listen to all IPv6 and IPv4 addresses) 261 | #listen_addr = :: 262 | 263 | 264 | # Port to listen for incoming Telnet connections. 265 | # 266 | # (default: 2223) 267 | #listen_port = 2223 268 | 269 | # Source Port to report in logs (useful if you use iptables to forward ports to Cowrie) 270 | #reported_port = 23 271 | 272 | 273 | # ============================================================================ 274 | # Database logging Specific Options 275 | # ============================================================================ 276 | 277 | # XMPP Logging 278 | # Log to an xmpp server. 279 | # 280 | #[database_xmpp] 281 | #server = sensors.carnivore.it 282 | #user = anonymous@sensors.carnivore.it 283 | #password = anonymous 284 | #muc = dionaea.sensors.carnivore.it 285 | #signal_createsession = cowrie-events 286 | #signal_connectionlost = cowrie-events 287 | #signal_loginfailed = cowrie-events 288 | #signal_loginsucceeded = cowrie-events 289 | #signal_command = cowrie-events 290 | #signal_clientversion = cowrie-events 291 | #debug=true 292 | 293 | 294 | 295 | # ============================================================================ 296 | # Output Plugins 297 | # These provide an extensible mechanism to send audit log entries to third 298 | # parties. The audit entries contain information on clients connecting to 299 | # the honeypot. 300 | # ============================================================================ 301 | 302 | 303 | # JSON based logging module 304 | # 305 | [output_jsonlog] 306 | logfile = log/cowrie.json 307 | 308 | 309 | # Supports logging to Elasticsearch 310 | # This is a simple early release 311 | # 312 | #[output_elasticsearch] 313 | #host = localhost 314 | #port = 9200 315 | #index = cowrie 316 | #type = cowrie 317 | 318 | 319 | # Send login attemp information to SANS DShield 320 | # See https://isc.sans.edu/ssh.html 321 | # You must signup for an api key. 322 | # Once registered, find your details at: https://isc.sans.edu/myaccount.html 323 | # 324 | #[output_dshield] 325 | #userid = userid_here 326 | #auth_key = auth_key_here 327 | #batch_size = 100 328 | 329 | 330 | # Local Syslog output module 331 | # 332 | # This sends log messages to the local syslog daemon. 333 | # Facility can be: 334 | # KERN, USER, MAIL, DAEMON, AUTH, LPR, NEWS, UUCP, CRON, SYSLOG and LOCAL0 to LOCAL7. 335 | # 336 | # Format can be: 337 | # text, cef 338 | # 339 | #[output_localsyslog] 340 | #facility = USER 341 | #format = text 342 | 343 | 344 | # Text output 345 | # This writes audit log entries to a text file 346 | # 347 | # Format can be: 348 | # text, cef 349 | # 350 | #[output_textlog] 351 | #logfile = log/audit.log 352 | #format = text 353 | 354 | 355 | # MySQL logging module 356 | # Identical functionality as [database_mysql] but with different internals 357 | # Database structure for this module is supplied in doc/sql/mysql.sql 358 | # 359 | #[output_mysql] 360 | #host = localhost 361 | #database = cowrie 362 | #username = cowrie 363 | #password = secret 364 | #port = 3306 365 | 366 | 367 | # SQLite3 logging module 368 | # 369 | # Logging to SQLite3 database. To init the database, use the script 370 | # doc/sql/sqlite3.sql: 371 | # sqlite3 < doc/sql/sqlite3.sql 372 | # 373 | #[output_sqlite] 374 | #db_file = cowrie.db 375 | 376 | 377 | # Splunk SDK output module - Legacy. Requires Splunk API installed 378 | # This sends logs directly to Splunk using the Python REST SDK 379 | # 380 | #[output_splunklegacy] 381 | #host = localhost 382 | #port = 8889 383 | #username = admin 384 | #password = password 385 | #index = cowrie 386 | 387 | 388 | # Splunk HTTP Event Collector (HEC) output module 389 | # Sends JSON directly to Splunk over HTTPS 390 | # mandatory fields: url, token 391 | # optional fields: index, source, sourcetype, host 392 | # 393 | #[output_splunk] 394 | #url = https://localhost:8088/services/collector/event 395 | #token = 6A0EA6C6-8006-4E39-FC44-C35FF6E561A8 396 | #index = cowrie 397 | #sourcetype = cowrie 398 | #source = cowrie 399 | 400 | 401 | # HPFeeds 402 | # 403 | #[database_hpfeeds] 404 | #server = hpfeeds.mysite.org 405 | #port = 10000 406 | #identifier = abc123 407 | #secret = secret 408 | #debug=false 409 | 410 | 411 | # VirusTotal output module 412 | # You must signup for an api key. 413 | # 414 | #[output_virustotal] 415 | #api_key = 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef 416 | # 417 | 418 | --------------------------------------------------------------------------------