├── README.md ├── add_cowrie_user.sh ├── add_dionaea_user.sh ├── broker ├── Dockerfile └── mongodb.conf ├── cowrie ├── Dockerfile └── run.sh ├── dionaea ├── Dockerfile ├── dionaea.conf └── supervisor-dionaea.conf └── docs └── data-flow-diagram.png /README.md: -------------------------------------------------------------------------------- 1 | # mhn-core-docker 2 | 3 | ## What this is 4 | 5 | 1. It's a subset of the [Modern Honey Network project](https://github.com/threatstream/mhn) that's set up to run in docker. 6 | 2. The "broker" image runs an hpfeeds broker. The broker allows clients to publish to channels or subscribe to channels. 7 | 3. The "cowrie" image runs the cowrie honeypot. It connects to the broker and publishes events to it. 8 | 4. The "dionaea" image runs the dionaea honeypot. It connects to the broker and publishes events to it, and it stores captured binaries. 9 | 5. In the broker container, an application called "geoloc" subscribes to the cowrie channel events and publishes a second channel with geolocation info added. 10 | 6. Also in the broker container, an application called "honeymap" subscribes to the geoloc channel and makes a pretty map. It listens on port 3000. 11 | 12 | ![Data Flow Diagram](https://mattcarothers.github.io/mhn-core-docker/data-flow-diagram.png) 13 | 14 | ## Steps to make this work 15 | 16 | Create a docker network so you can statically IP your containers: 17 | ``` 18 | docker network create --subnet 192.168.0.0/24 honeynet 19 | ``` 20 | 21 | Clone the repository, change to the broker directory, and build the docker image. 22 | ``` 23 | git clone https://github.com/MattCarothers/mhn-core-docker 24 | cd broker 25 | docker build -t broker . 26 | ``` 27 | 28 | Start the broker image. Your host OS will now be listening on port 3000 for http requests into 29 | honeymap. If you prefer to forward ports with iptables or use a reverse proxy, leave out the 30 | -p flag. Events from hpfeeds will be written to /var/log/broker/mhn-json.log. 31 | ``` 32 | docker run --name broker -v /var/log/broker:/var/log/mhn -d \ 33 | --restart unless-stopped \ 34 | -p 3000:3000 \ 35 | --net honeynet --ip 192.168.0.2 broker 36 | ``` 37 | 38 | Add an hpfeeds auth key for the cowrie honeypot by inserting it into the mongo 39 | database. You should edit this script and change the key. Especially if you plan to expose 40 | hpfeeds outside of your host. You'll need to change it in cowrie/Dockerfile 41 | too. 42 | ``` 43 | cd .. 44 | ./add_cowrie_user.sh 45 | ``` 46 | 47 | Optional: create a honeypot user on the host OS to own the cowrie log 48 | directory. Set the uid of the new user in cowrie/Dockerfile. 49 | 50 | Create the honeypot image. 51 | ``` 52 | cd cowrie 53 | docker build -t cowrie . 54 | ``` 55 | 56 | Create a log directory for the honeypot. Change ownership to uid 1000 (default) 57 | or whatever your honeypot user is if you created one. Creating this directory 58 | isn't strictly necessary, but it's helpful for troubleshooting. 59 | ``` 60 | mkdir /var/log/cowrie 61 | chown 1000 /var/log/cowrie 62 | ``` 63 | 64 | Start the honeypot. Your host will now be listening on 22 and 23. If you're 65 | forwarding ports with iptables, leave out the -p flags. NB: If your host has 66 | ssh running on port 22 already, docker won't be able to bind to it. 67 | ``` 68 | docker run -d --name cowrie -v /var/log/cowrie:/opt/cowrie/log \ 69 | --restart unless-stopped \ 70 | --net honeynet --ip 192.168.0.3 --link broker \ 71 | -p 22:22 -p 23:23 \ 72 | cowrie 73 | ``` 74 | 75 | Add an hpfeeds auth key for the dionaea honeypot by inserting it into the 76 | mongo database. You should edit this script and change the key. Especially if you plan to expose 77 | hpfeeds outside of your host. You'll need to change it in dionaea/Dockerfile 78 | too. 79 | ``` 80 | cd .. 81 | ./add_dionaea_user.sh 82 | ``` 83 | 84 | Optional: edit the dionaea config file and set any options you want. 85 | ``` 86 | vi dionaea/dionaea.conf 87 | ``` 88 | 89 | Optional: create a honeypot user on the host OS to own the dionaea log 90 | directory. Set the uid of the new user in dionaea/Dockerfile. 91 | 92 | Create the honeypot image. 93 | ``` 94 | cd dionaea 95 | docker build -t dionaea . 96 | ``` 97 | 98 | Create a log directory for the honeypot. Change ownership to uid 1000 99 | (default) or whatever your honeypot user is if you created one. You'll 100 | want to map a directory on the host OS if you're storing binaries, sqllite 101 | logs, or other stuff you want to access. The default config stores binaries 102 | and sends events via hpfeeds to the broker. 103 | ``` 104 | mkdir /var/log/dionaea 105 | chown 1000 /var/log/dionaea 106 | ``` 107 | 108 | Start the honeypot. Your host will now be listening on a bunch of ports. 109 | If you're forwarding ports with iptables, leave out the -p flags. 110 | ``` 111 | docker run -d --name dionaea -v /var/log/dionaea:/opt/dionaea/var/dionaea \ 112 | --net honeynet --ip 192.168.0.4 --link broker \ 113 | --restart unless-stopped \ 114 | -p 21:21 -p 42:42 -p 80:80 -p 135:135 -p 443:443 -p 445:445 -p 1433:1433 \ 115 | -p 1723:1723 -p 1883:1883 -p 3306:3306 -p 5060:5060 -p 5061:5061 \ 116 | -p 69:69/udp -p 1900:1900/udp -p 5060:5060/udp \ 117 | dionaea 118 | ``` 119 | 120 | ## iptables configuration 121 | 122 | If you have a dark subnet routed to your host, you'll need to perform some additional configuration 123 | in order to get packets to the honeypot. 124 | 125 | ``` 126 | # Clear existing rules 127 | iptables -F 128 | iptables -F -t nat 129 | 130 | # Permit docker containers to NAT 131 | iptables -A FORWARD -s 172.17.0.0/16 -j ACCEPT 132 | iptables -A FORWARD -s 192.168.0.0/24 -j ACCEPT 133 | iptables -A FORWARD -m state --state ESTABLISHED -j ACCEPT 134 | 135 | # Permit specific hosts to reach exposed docker container ports (e.g. 136 | # honeymap or hpfeeds) 137 | iptables -A FORWARD -s YOUR_TRUSTED_SOURCE_IP -d 172.17.0.0/16 -j ACCEPT 138 | iptables -A FORWARD -s YOUR_TRUSTED_SOURCE_IP -d 192.168.0.0/24 -j ACCEPT 139 | 140 | # Permit locahost 141 | iptables -A FORWARD -s 127.0.0.0/8 -j ACCEPT 142 | iptables -A FORWARD -d 127.0.0.0/8 -j ACCEPT 143 | 144 | # Allow traffic to honeypots on the ports they need 145 | # Cowrie 146 | iptables -A FORWARD -d 192.168.0.3 -p tcp --destination-port 22 -j ACCEPT 147 | iptables -A FORWARD -d 192.168.0.3 -p tcp --destination-port 23 -j ACCEPT 148 | 149 | # Dionaea 150 | iptables -A FORWARD -d 192.168.0.4 -p tcp --destination-port 21 -j ACCEPT 151 | iptables -A FORWARD -d 192.168.0.4 -p tcp --destination-port 42 -j ACCEPT 152 | iptables -A FORWARD -d 192.168.0.4 -p tcp --destination-port 80 -j ACCEPT 153 | iptables -A FORWARD -d 192.168.0.4 -p tcp --destination-port 135 -j ACCEPT 154 | iptables -A FORWARD -d 192.168.0.4 -p tcp --destination-port 443 -j ACCEPT 155 | iptables -A FORWARD -d 192.168.0.4 -p tcp --destination-port 445 -j ACCEPT 156 | iptables -A FORWARD -d 192.168.0.4 -p tcp --destination-port 1433 -j ACCEPT 157 | iptables -A FORWARD -d 192.168.0.4 -p tcp --destination-port 1723 -j ACCEPT 158 | iptables -A FORWARD -d 192.168.0.4 -p tcp --destination-port 1883 -j ACCEPT 159 | iptables -A FORWARD -d 192.168.0.4 -p tcp --destination-port 3306 -j ACCEPT 160 | iptables -A FORWARD -d 192.168.0.4 -p tcp --destination-port 5060 -j ACCEPT 161 | iptables -A FORWARD -d 192.168.0.4 -p tcp --destination-port 5061 -j ACCEPT 162 | 163 | iptables -A FORWARD -d 192.168.0.4 -p udp --destination-port 69 -j ACCEPT 164 | iptables -A FORWARD -d 192.168.0.4 -p udp --destination-port 1900 -j ACCEPT 165 | iptables -A FORWARD -d 192.168.0.4 -p udp --destination-port 5060 -j ACCEPT 166 | 167 | # Don't forward any other packets. It's very important that you enable this rule before you 168 | # turn on ip forwarding. Otherwise you create a routing loop. 169 | iptables -P FORWARD DROP 170 | 171 | # Permit traffic to the host OS from approved sources 172 | iptables -A INPUT -m state --state ESTABLISHED -j ACCEPT 173 | iptables -A INPUT -s YOUR_TRUSTED_SOURCE_IP -j ACCEPT 174 | 175 | # Don't accept any other connections 176 | iptables -P INPUT DROP 177 | 178 | # NAT specific ports on specific destination IPs to docker containers 179 | iptables -t nat -A PREROUTING -i eth0 -j DNAT -d YOUR_DARK_IP --to-destination 192.168.0.3 180 | iptables -t nat -A PREROUTING -i eth0 -j DNAT -d YOUR_DARK_IP --to-destination 192.168.0.4 181 | 182 | # In practice you'll probably want to script that: 183 | HOSTS=`cat /etc/mhn/ssh-honeypots` 184 | for host in $HOSTS; do 185 | echo $host '->' 192.168.0.3 186 | iptables -t nat -A PREROUTING -i eth0 -j DNAT -d $host --to-destination 192.168.0.3 187 | done 188 | 189 | HOSTS=`cat /etc/mhn/dionaea-honeypots` 190 | for host in $HOSTS; do 191 | echo $host '->' 192.168.0.4 192 | iptables -t nat -A PREROUTING -i eth0 -j DNAT -d $host --to-destination 192.168.0.4 193 | done 194 | 195 | # And here's a script to clear out the honeypot nat rules: 196 | RULES=`iptables -t nat -nL PREROUTING --line-numbers | grep '192.168.0.[3456789]' | awk '{print $1}' | sort -rn` 197 | 198 | for rule in $RULES; do 199 | echo iptables -t nat -D PREROUTING $rule 200 | iptables -t nat -D PREROUTING $rule 201 | done 202 | ``` 203 | -------------------------------------------------------------------------------- /add_cowrie_user.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | docker exec broker /opt/hpfeeds/env/bin/python /opt/hpfeeds/broker/add_user.py cowrie 7919ea5eb8ab8cc475e64dd074723b0b cowrie.sessions "" 4 | -------------------------------------------------------------------------------- /add_dionaea_user.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | docker exec broker /opt/hpfeeds/env/bin/python /opt/hpfeeds/broker/add_user.py \ 4 | dionaea b64c2e86d0eb546e5b2757508df50222 \ 5 | dionaea.connections,dionaea.dcerpcrequests,dionaea.shellcodeprofiles,dionaea.capture "" 6 | -------------------------------------------------------------------------------- /broker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:18.04 2 | 3 | RUN apt-get update 4 | RUN apt-get install -y git wget supervisor sudo lsb-core 5 | 6 | WORKDIR /usr/src 7 | RUN git clone https://github.com/MattCarothers/mhn 8 | 9 | # Mongo needs to be running before we can install anything else. 10 | # install_mongo also runs from install_hpfeeds, but it doesn't 11 | # start the daemon, so we have to run it alone first. 12 | COPY mongodb.conf /etc/supervisor/conf.d/ 13 | WORKDIR /usr/src/mhn/scripts 14 | RUN ./install_mongo.sh ; \ 15 | mkdir -p /var/log/mhn ; \ 16 | /etc/init.d/supervisor start ; \ 17 | ./install_hpfeeds.sh ; \ 18 | ./install_honeymap.sh ; \ 19 | ./install_hpfeeds-logger-json.sh ; \ 20 | apt-get -y purge '.*-dev' ; \ 21 | rm -rf /usr/share/go 22 | 23 | EXPOSE 3000 24 | EXPOSE 10000 25 | 26 | WORKDIR / 27 | CMD ["/usr/bin/supervisord", "-n", "-c", "/etc/supervisor/supervisord.conf"] 28 | -------------------------------------------------------------------------------- /broker/mongodb.conf: -------------------------------------------------------------------------------- 1 | [program:mongod] 2 | command=/usr/bin/mongod --smallfiles --config /etc/mongodb.conf 3 | autostart=true 4 | autorestart=true 5 | priority=1 6 | stdout_logfile=/var/log/mhn/mongod.log 7 | stderr_logfile=/var/log/mhn/mongod.err 8 | -------------------------------------------------------------------------------- /cowrie/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:16.04 2 | 3 | # Authentication information for hpfeeds in the broker container. 4 | # Example command to add the credentials to the broker: 5 | # 6 | # docker exec broker /opt/hpfeeds/env/bin/python /opt/hpfeeds/broker/add_user.py \ 7 | # cowrie 7919ea5eb8ab8cc475e64dd074723b0b cowrie.sessions "" 8 | ENV HPF_HOST=broker 9 | ENV HPF_PORT=10000 10 | ENV HPF_IDENT=cowrie 11 | ENV HPF_SECRET=7919ea5eb8ab8cc475e64dd074723b0b 12 | 13 | # You may want to change the cowrie user id inside the container if 14 | # you're going to mount an external log directory. The internal uid 15 | # needs write permissions to the external volume. 16 | # 17 | # E.g. to save cowrie logs to /var/log/cowrie on the host OS, run docker with ... 18 | # 19 | # -v /var/log/cowrie:/opt/cowrie/log 20 | # 21 | # ... and make sure /var/log/cowrie is writable by the cowrie uid inside the container. 22 | ENV COWRIE_UID=1000 23 | 24 | # Install packages 25 | RUN apt-get update && apt-get install -y git supervisor 26 | 27 | # Create the cowrie user 28 | RUN useradd -u ${COWRIE_UID} -s /bin/false cowrie 29 | 30 | # Download the MHN distro 31 | WORKDIR /usr/src 32 | RUN git clone https://github.com/threatstream/mhn 33 | 34 | # Run the install script. The script will generate a bunch of errors, but we don't care. 35 | WORKDIR /usr/src/mhn/scripts 36 | RUN sed -i -e 's/set -e/#set -e/' deploy_cowrie.sh ; \ 37 | # Cowrie has deprecated start/stop.sh \ 38 | sed -i -e 's/start.sh env/bin\/cowrie start/' deploy_cowrie.sh ; \ 39 | sed -i -e 's/start.sh/bin\/cowrie/' deploy_cowrie.sh ; \ 40 | sed -i -e 's/ env/ cowrie-env/' deploy_cowrie.sh ; \ 41 | bash deploy_cowrie.sh foo bar ; \ 42 | apt-get -y purge '.*-dev' 43 | 44 | # Disable the json log and enable telnet 45 | RUN sed -i -e 's/logfile = log\/cowrie.json/#logfile = log\/cowrie.json/' \ 46 | /opt/cowrie/cowrie.cfg ; \ 47 | sed -i -e 's/^enabled = false/enabled = true/' \ 48 | /opt/cowrie/cowrie.cfg ; \ 49 | sed -i -e 's/^listen_endpoints = tcp:2222/listen_endpoints = tcp:22/' \ 50 | /opt/cowrie/cowrie.cfg ; \ 51 | sed -i -e 's/^listen_endpoints = tcp:2223/listen_endpoints = tcp:23/' \ 52 | /opt/cowrie/cowrie.cfg ; \ 53 | touch /etc/authbind/byport/23; \ 54 | chown cowrie /etc/authbind/byport/23; \ 55 | chmod 770 /etc/authbind/byport/23; 56 | 57 | EXPOSE 22 58 | EXPOSE 23 59 | 60 | COPY run.sh / 61 | 62 | WORKDIR /opt/cowrie 63 | CMD ["/run.sh"] 64 | 65 | # How to run the container: 66 | # 67 | # docker run --rm --name cowrie --link broker cowrie 68 | # 69 | # To log outside the container: 70 | # 71 | # mkdir /var/log/cowrie 72 | # chown 1000 /var/log/cowrie 73 | # docker run --rm --name cowrie -v /var/log/cowrie:/opt/cowrie/log --link broker cowrie 74 | -------------------------------------------------------------------------------- /cowrie/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # The tty directory needs to exist in order to log terminal sessions 4 | if [ ! -d /opt/cowrie/log/tty ]; then 5 | mkdir -p /opt/cowrie/log/tty 6 | chown cowrie /opt/cowrie/log/tty 7 | fi 8 | 9 | /usr/bin/supervisord -n -c /etc/supervisor/supervisord.conf 10 | -------------------------------------------------------------------------------- /dionaea/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:16.04 2 | 3 | # Authentication information for hpfeeds in the broker container. 4 | # Example command to add the credentials to the broker: 5 | # 6 | # docker exec broker /opt/hpfeeds/env/bin/python /opt/hpfeeds/broker/add_user.py \ 7 | # dionaea b64c2e86d0eb546e5b2757508df50222 dionaea.connections "" 8 | # docker exec broker /opt/hpfeeds/env/bin/python /opt/hpfeeds/broker/add_user.py \ 9 | # dionaea b64c2e86d0eb546e5b2757508df50222 dionaea.dcerpcrequests "" 10 | # docker exec broker /opt/hpfeeds/env/bin/python /opt/hpfeeds/broker/add_user.py \ 11 | # dionaea b64c2e86d0eb546e5b2757508df50222 dionaea.shellcodeprofiles "" 12 | # docker exec broker /opt/hpfeeds/env/bin/python /opt/hpfeeds/broker/add_user.py \ 13 | # dionaea b64c2e86d0eb546e5b2757508df50222 dionaea.capture "" 14 | ENV HPF_HOST=broker 15 | ENV HPF_PORT=10000 16 | ENV HPF_IDENT=dionaea 17 | ENV HPF_SECRET=b64c2e86d0eb546e5b2757508df50222 18 | 19 | # You may want to change the dionaea user id inside the container if 20 | # you're going to mount an external log directory. The internal uid 21 | # needs write permissions to the external volume. 22 | # 23 | # E.g. to save dionaea logs to /var/log/dionaea on the host OS, run docker with ... 24 | # 25 | # -v /var/log/dionaea:/opt/dionaea/log 26 | # 27 | # ... and make sure /var/log/dionaea is writable by the dionaea uid inside the container. 28 | ENV DIONAEA_UID=1000 29 | 30 | # Install packages 31 | RUN apt-get update && apt-get install -y supervisor autoconf automake \ 32 | build-essential git htop libcurl4-openssl-dev libemu-dev libgc-dev \ 33 | libev-dev libglib2.0-dev libloudmouth1-dev libnetfilter-queue-dev \ 34 | libpcap-dev libreadline-dev libsqlite3-dev libssl-dev libtool libudns-dev \ 35 | pkg-config sqlite3 subversion python3 cython3 python3-pip 36 | 37 | # Create the dionaea user 38 | RUN useradd -u ${DIONAEA_UID} -s /bin/false dionaea 39 | 40 | # Download dionaea and compile it 41 | RUN \ 42 | cd /usr/src && \ 43 | git clone https://github.com/ThomasAdam/liblcfg.git && \ 44 | cd liblcfg/code && \ 45 | autoreconf -vi && \ 46 | ./configure --prefix=/opt/dionaea && \ 47 | make install && \ 48 | cd /usr/src && \ 49 | git clone https://github.com/threatstream/mhn && \ 50 | git clone https://github.com/gento/dionaea.git dionaea && \ 51 | cp mhn/server/mhn/static/hpfeeds.py dionaea/modules/python/scripts/ && \ 52 | cd dionaea && \ 53 | autoreconf -vi && \ 54 | ln -s /usr/bin/python3 /usr/bin/python3.2 && \ 55 | ln -s /usr/bin/cython3 /usr/bin/cython && \ 56 | pip3 install -e git+https://github.com/HurricaneLabs/pyev.git#egg=pyev && \ 57 | ./configure --disable-werror --prefix=/opt/dionaea \ 58 | --with-lcfg-include=/opt/dionaea/include/ \ 59 | --with-lcfg-lib=/opt/dionaea/lib/ && \ 60 | sed -i -e 's/-Werror//' modules/nfq/Makefile && \ 61 | make LDFLAGS=-lcrypto && \ 62 | make install && \ 63 | # Format string update for Python 3.4+ \ 64 | sed -i -e 's/{:s}/{!s:s}/g' /opt/dionaea/lib/dionaea/python/dionaea/sip/__init__.py && \ 65 | sed -i -e 's/{:/{!s:/g' /opt/dionaea/lib/dionaea/python/dionaea/mssql/mssql.py && \ 66 | chown $DIONAEA_UID /opt/dionaea/var/dionaea 67 | 68 | COPY dionaea.conf /opt/dionaea/etc/dionaea/ 69 | COPY supervisor-dionaea.conf /etc/supervisor/conf.d/dionaea.conf 70 | 71 | RUN \ 72 | sed -i -e "s/HPF_HOST/$HPF_HOST/" /opt/dionaea/etc/dionaea/dionaea.conf && \ 73 | sed -i -e "s/HPF_PORT/$HPF_PORT/" /opt/dionaea/etc/dionaea/dionaea.conf && \ 74 | sed -i -e "s/HPF_IDENT/$HPF_IDENT/" /opt/dionaea/etc/dionaea/dionaea.conf && \ 75 | sed -i -e "s/HPF_SECRET/$HPF_SECRET/" /opt/dionaea/etc/dionaea/dionaea.conf 76 | 77 | EXPOSE 21 78 | EXPOSE 42 79 | EXPOSE 80 80 | EXPOSE 135 81 | EXPOSE 443 82 | EXPOSE 445 83 | EXPOSE 1433 84 | EXPOSE 1723 85 | EXPOSE 1883 86 | EXPOSE 3306 87 | EXPOSE 5060 88 | EXPOSE 5061 89 | 90 | EXPOSE 69/udp 91 | EXPOSE 1900/udp 92 | EXPOSE 5060/udp 93 | 94 | WORKDIR /opt/dionaea 95 | CMD ["/usr/bin/supervisord", "-n", "-c", "/etc/supervisor/supervisord.conf"] 96 | 97 | # How to run the container: 98 | # 99 | # docker run --rm --name dionaea --link broker dionaea 100 | # 101 | # To log outside the container: 102 | # 103 | # mkdir /var/log/dionaea 104 | # chown 1000 /var/log/dionaea 105 | # docker run --rm --name dionaea -v /var/log/dionaea:/opt/dionaea/log --link broker dionaea 106 | -------------------------------------------------------------------------------- /dionaea/dionaea.conf: -------------------------------------------------------------------------------- 1 | logging = { 2 | default = { 3 | // file not starting with / is taken relative to LOCALESTATEDIR (e.g. /opt/dionaea/var) 4 | file = "log/dionaea.log" 5 | levels = "all" 6 | domains = "*" 7 | } 8 | 9 | errors = { 10 | // file not starting with / is taken relative to LOCALESTATEDIR (e.g. /opt/dionaea/var) 11 | file = "log/dionaea-errors.log" 12 | levels = "warning,error" 13 | domains = "*" 14 | } 15 | } 16 | 17 | processors = 18 | { 19 | filter-emu = 20 | { 21 | config = { 22 | allow = [{ protocol = ["smbd","epmapper","nfqmirrord","mssqld"] }] 23 | } 24 | next = { 25 | emu = 26 | { 27 | config = { 28 | emulation = { 29 | limits = { 30 | files = "3" 31 | filesize = "524288" // 512 * 1024 32 | sockets = "3" 33 | sustain = "120" 34 | idle = "30" 35 | listen = "30" 36 | cpu = "120" 37 | steps = "1073741824" // 1024 * 1024 * 1024 38 | } 39 | 40 | /** 41 | * api default arguments for development 42 | * disabled by default 43 | * not working yet 44 | */ 45 | api = { 46 | connect = { 47 | host = "127.0.0.1" 48 | port = "4444" 49 | } 50 | } 51 | } 52 | } 53 | } 54 | } 55 | } 56 | 57 | /* 58 | filter-streamdumper = 59 | { 60 | config = { 61 | allow = [ 62 | { type = ["accept"] } 63 | { type = ["connect"] protocol=["ftpctrl"] } 64 | ] 65 | deny = [ 66 | { protocol = ["ftpdata", "ftpdatacon","xmppclient"] } 67 | ] 68 | } 69 | next = { 70 | streamdumper = { 71 | config = { 72 | path = "var/dionaea/bistreams/%Y-%m-%d/" 73 | } 74 | } 75 | } 76 | } 77 | */ 78 | 79 | /* filter-sessions = 80 | { 81 | config = { 82 | allow = [ { protocol = ["ftpctrl","remoteshell"] } ] 83 | } 84 | next = { 85 | python = { 86 | incident = "true" 87 | } 88 | } 89 | } 90 | */ 91 | } 92 | 93 | downloads = 94 | { 95 | dir = "var/dionaea/binaries" 96 | tmp-suffix = ".tmp" 97 | } 98 | 99 | /* 100 | bistreams = 101 | { 102 | python = 103 | { 104 | dir = "var/dionaea/bistreams" 105 | } 106 | } 107 | */ 108 | 109 | 110 | submit = 111 | { 112 | /* 113 | defaults = { 114 | urls = ["http://anubis.iseclab.org/nepenthes_action.php", 115 | "http://onlineanalyzer.norman.com/nepenthes_upload.php", 116 | "http://luigi.informatik.uni-mannheim.de/submit.php?action=verify"] 117 | email = "nepenthesdev@gmail.com" 118 | file_fieldname = "upfile" 119 | MAX_FILE_SIZE = "1500000" 120 | submit = "Submit for analysis" 121 | } 122 | */ 123 | 124 | /** 125 | * joebox is special, due to the TOS you can lookup here 126 | * http://www.joebox.org/resources/service%20terms.txt 127 | * therefore untested and disabled by default 128 | */ 129 | /* 130 | joebox = { 131 | urls = ["http://analysis.joebox.org/submit"] 132 | email = "nepenthesdev@gmail.com" 133 | file_fieldname = "upfile" 134 | MAX_FILE_SIZE = "1500000" 135 | submit = "Submit for analysis" 136 | service = "agree" 137 | xp = "1" 138 | vista = "1" 139 | w7 = "1" 140 | pcap = "1" 141 | } 142 | */ 143 | 144 | /* 145 | yoursection = 146 | { 147 | urls = ["http://127.0.0.1/submit"] 148 | email = "yourmail" 149 | user = "yourusername" 150 | pass = "yourpassword" 151 | } 152 | */ 153 | } 154 | 155 | listen = 156 | { 157 | /* basically we have 3 modes 158 | - getifaddrs - auto 159 | will get a list of all ips and bind a service to each ip 160 | - manual - your decision 161 | addrs has to be provided, and should look like this 162 | addrs = { eth0 = ["1.1.1.1", "1.1.1.2"], eth1 = ["2.1.1.1", "2.1.1.2"] } 163 | you get the idea ... 164 | for most cases with more than one address 165 | addrs = { eth0 = ["0.0.0.0"] } 166 | will do the trick 167 | if you want to throw in ipv6 support as well ... 168 | addrs = { eth0 = ["::"] } 169 | note: ipv6 does not work with surfids yet, 170 | as ipv6 addresses are mapped to ipv4 and surfids fails to retrieve the sensor id for ::ffff:1.2.3.4 171 | - nl, will require a list of interfaces 172 | fnmatch is possible like 173 | interfaces = ["ppp*","tun*"] 174 | and loading the nl module AFTER the python module in the modules section below 175 | nl will use the kernel netlink interface to figure out which addresses exist 176 | at runtime, and start/stop services dynamically per address per interface 177 | */ 178 | 179 | mode = "manual" 180 | addrs = { eth0 = ["0.0.0.0"] } 181 | } 182 | 183 | modules = { 184 | 185 | curl = 186 | { 187 | protocol = "http" 188 | } 189 | 190 | emu = { 191 | detect = "1" 192 | profile = "1" 193 | } 194 | 195 | pcap = 196 | { 197 | /** 198 | * libpcap 1.0.0 199 | * 200 | * "Arithmetic expression against transport layer headers, like 201 | * tcp[0], does not work against IPv6 packets. It only looks 202 | * at IPv4 packets." 203 | * 204 | * As a consequence, the default filter can not match 205 | * ipv6 tcp rst packets. 206 | * 207 | * If you want to go for rejected ipv6, remove the tcp matching part of the filter 208 | * The code is capable to checking the tcp-rst flag and seq number itself, but 209 | * matching every packet in userspace is expensive. 210 | * Therefore you'll have to hack the code if you want to track ipv6 rejected connections 211 | * 212 | * Format is IFACE = { addrs = MODE } 213 | * currently mode is ignored 214 | */ 215 | 216 | any = { 217 | addrs = "auto" 218 | } 219 | } 220 | 221 | nfq = 222 | { 223 | /** 224 | * queue has to be the nfqueue num 225 | * refer to http://dionaea.carnivore.it/#nfq_python 226 | * if you do not specify a queue-num with iptables, 0 is the default 227 | */ 228 | queue = "0" 229 | } 230 | 231 | python = { 232 | // default expands to PREFIX/lib/dionaea/python/ 233 | // ordering is granted 234 | // useful for development 235 | // simply add your devel directory to the list, avoids a make install for new python code 236 | sys_path = ["default"] 237 | 238 | // python imports 239 | imports = [ "log", 240 | "services", 241 | "ihandlers"] 242 | ftp = { 243 | root = "var/dionaea/wwwroot" 244 | 245 | /* ftp client section 246 | */ 247 | 248 | /* ports for active ftp 249 | * string indicating a range 250 | */ 251 | active-ports = "63001-64000" 252 | 253 | /* host for active ftp via NAT 254 | * 0.0.0.0 - the initiating connection ip is used for active ftp 255 | * not 0.0.0.0 - gets resolved as hostname and used 256 | */ 257 | active-host = "0.0.0.0" 258 | } 259 | tftp = { 260 | root = "var/dionaea/wwwroot" 261 | } 262 | http = { 263 | root = "var/dionaea/wwwroot" 264 | max-request-size = "32768" // maximum size in kbytes of the request (32MB) 265 | } 266 | upnp = { 267 | root = "var/dionaea/wwwroot" 268 | max-request-size = "32768" // maximum size in kbytes of the request (32MB) 269 | personalities-enable = "default" 270 | personalities = { 271 | default = { 272 | cache = "CACHE-CONTROL: max-age=120\r\n" 273 | st = "ST: upnp:rootdevice\r\n" 274 | usn = "USN: uuid:Upnp-IPMI-1_0-1234567890001::upnp:rootdevice\r\n" 275 | server = "SERVER: Linux/2.6.17.WB_WPCM450.1.3 UPnP/1.0, Intel SDK for UPnP devices/1.3.1\r\n" 276 | location = "LOCATION: http://192.168.0.1:49152/IPMIdevicedesc.xml\r\n" 277 | opt = "OPT: http://schemas.upnp.org/upnp/1/0/\r\n" 278 | } 279 | 280 | samsung-tv = { 281 | cache = "CACHE-CONTROL: max-age=900\r\n" 282 | st = "ST: uuid:c1fd12b2-d954-4dba-9e92-a697e1558fb4\r\n" 283 | usn = "USN: uuid:c1fd12b2-d954-4dba-9e92-a697e1558fb4\r\n" 284 | server = "SERVER: SHP, UPnP/1.0, Samsung UPnP SDK/1.0\r\n" 285 | location = "LOCATION: http://192.168.0.10:7677/MainTVServer2\r\n" 286 | opt = "OPT: http://schemas.upnp.org/upnp/1/0/\r\n" 287 | } 288 | 289 | xbox360 = { 290 | cache = "CACHE-CONTROL: max-age=1800\r\n" 291 | st = "ST: urn:microsoft.com:service:X_MS_MediaReceiverRegistrar:1\r\n" 292 | usn = "USN: uuid:531c567a-8c46-4201-bcd4-09afa554d859::urn:microsoft.com:service:X_MS_MediaReceiverRegistrar:1\r\n" 293 | server = "SERVER: Microsoft-Windows/6.3 UPnP/1.0 UPnP-Device-Host/1.0\r\n" 294 | location = "LOCATION: http://192.168.0.10:1055/upnphost/udhisapi.dll?content=uuid:531c567a-8c46-4201-bcd4-09afa554d859\r\n" 295 | opt = "OPT: http://schemas.upnp.org/upnp/1/0/\r\n" 296 | } 297 | } 298 | } 299 | sip = { 300 | udp = { 301 | port = "5060" 302 | } 303 | tcp = { 304 | port = "5060" 305 | } 306 | tls = { 307 | port = "5061" 308 | } 309 | users = "var/dionaea/sipaccounts.sqlite" 310 | rtp = { 311 | enable = "yes" 312 | /* how to dump the rtp stream 313 | bistream = dump as bistream 314 | */ 315 | mode = ["bistream", "pcap"] 316 | 317 | pcap = { 318 | path = "var/dionaea/rtp/{personality}/%Y-%m-%d/" 319 | filename = "%H:%M:%S_{remote_host}_{remote_port}_in.pcap" 320 | } 321 | } 322 | personalities = { 323 | default = { 324 | domain = "localhost" 325 | name = "softphone" 326 | personality = "generic" 327 | } 328 | /* 329 | next-server = { 330 | domain = "my-domain" 331 | name = "my server" 332 | personality = "generic" 333 | serve = ["10.0.0.1"] 334 | default_sdp = "default" 335 | handle = ["REGISTER", "INVITE", "BYE", "CANCEL", "ACK"] 336 | } 337 | 338 | */ 339 | } 340 | actions = { 341 | bank-redirect = { 342 | do = "redirect" 343 | params = { 344 | } 345 | } 346 | play-hello = { 347 | do = "play" 348 | params = { 349 | file = "var/dionaea/.../file.ext" 350 | } 351 | } 352 | } 353 | } 354 | surfids = { 355 | sslmode = "require" 356 | host = "surfids.example.com" // change this 357 | port = "5432" // maybe this 358 | username = "surfids" // this 359 | password = "secret" // and this 360 | dbname = "idsserver" 361 | } 362 | virustotal = { 363 | apikey = "........." // grab it from your virustotal account at My account -> Inbox -> Public API 364 | file = "var/dionaea/vtcache.sqlite" 365 | } 366 | mwserv = { // ask your mwserv backend provider for needed values 367 | url = "" // the url to send the submission requests to 368 | maintainer = "" // username of the maintainer of this sensor 369 | guid = "" // guid of this sensor, as generated serverside; typically 8 chars 370 | secret = "" // shared secret used for authentication aka password; typically 48 chars 371 | } 372 | mysql = { 373 | databases = { 374 | information_schema = { 375 | path = ":memory:" 376 | } 377 | 378 | // example how to extend this 379 | // just provide a databasename and path to the database 380 | // the database can be altered by attackers, so ... better use a copy 381 | // psn = { 382 | // path = "/path/to/cc_info.sqlite" 383 | // } 384 | 385 | } 386 | } 387 | submit_http = { // ask your submit_http backend provider for needed values 388 | url = "" // the url to send the submission requests to 389 | email = "" // optional 390 | user = "" // username (optional) 391 | pass = "" // password (optional) 392 | } 393 | hpfeeds = { 394 | hp1 = { 395 | server = "HPF_HOST" 396 | port = "HPF_PORT" 397 | ident = "HPF_IDENT" 398 | secret = "HPF_SECRET" 399 | // dynip_resolve: enable to lookup the sensor ip through a webservice 400 | // dynip_resolve = "http://hpfriends.honeycloud.net/ip" 401 | } 402 | } 403 | logsql = { 404 | mode = "sqlite" // so far there is only sqlite 405 | sqlite = { 406 | file = "var/dionaea/logsql.sqlite" 407 | } 408 | } 409 | logxmpp = { 410 | /** 411 | * this section defines a single xmpp logging target 412 | * you can have multiple 413 | */ 414 | carnivore = { 415 | server = "sensors.carnivore.it" 416 | 417 | /** 418 | * as dionaea does not support starttls (xmpp on port 5223), 419 | * we rely on 'legacy ssl' for the xmpp connection (port 5222) 420 | */ 421 | port = "5223" 422 | muc = "dionaea.sensors.carnivore.it" 423 | 424 | /** 425 | * if the server exists, this is a valid account 426 | */ 427 | username = "anonymous@sensors.carnivore.it" 428 | password = "anonymous" 429 | 430 | /** 431 | * setting a resource is possible, but you should not do it 432 | * the default resource is a random string of 8 chars 433 | */ 434 | // resource = "theresource" 435 | config = 436 | { 437 | /** 438 | * this defines a muc channel 439 | */ 440 | anon-events = 441 | { 442 | /** 443 | * incidents matching these events will get relayed to the channel 444 | */ 445 | events = ["^dionaea\x5c.connection\x5c..*", 446 | "^dionaea\x5c.modules\x5c.python\x5c.smb.dcerpc\x5c.*", 447 | "^dionaea\x5c.download\x5c.offer$", 448 | "^dionaea\x5c.download\x5c.complete\x5c.hash$", 449 | "^dionaea\x5c.module\x5c.emu\x5c.profile$", 450 | "^dionaea\x5c.modules\x5c.python\x5c.mysql\x5c.*", 451 | "^dionaea\x5c.modules\x5c.python\x5c.sip\x5c.*", 452 | "^dionaea\x5c.modules\x5c.python\x5c.p0f\x5c.*", 453 | "^dionaea\x5c.modules\x5c.python\x5c.virustotal\x5creport", 454 | ] 455 | 456 | /** 457 | * anonymous removes the local host information from all connection messages 458 | * so you can report without getting identified 459 | */ 460 | anonymous = "yes" 461 | } 462 | 463 | anon-files = 464 | { 465 | events = ["^dionaea\x5c.download\x5c.complete\x5c.unique"] 466 | } 467 | } 468 | } 469 | } 470 | nfq = { 471 | /** 472 | * nfq can intercept incoming tcp connections during the tcp handshake 473 | * giving your honeypot the possibility to provide service on 474 | * ports which are not served by default. 475 | * refer to the documentation (http://dionaea.carnivore.it/#nfq_python) 476 | * BEFORE using this 477 | */ 478 | 479 | nfaction = "0" // DROP 480 | 481 | throttle = { 482 | window = "30" 483 | limits = { 484 | total = "30" 485 | slot = "30" 486 | } 487 | } 488 | 489 | timeouts = { 490 | server = { 491 | listen = "5" 492 | } 493 | client = { 494 | idle = "10" 495 | sustain = "240" 496 | } 497 | } 498 | } 499 | p0f = { 500 | /** 501 | * start p0f with 502 | * sudo p0f -i any -u root -Q /tmp/p0f.sock -q -l 503 | */ 504 | path = "un:///tmp/p0f.sock" 505 | } 506 | 507 | fail2ban = { 508 | downloads = "var/dionaea/downloads.f2b" 509 | offers = "var/dionaea/offers.f2b" 510 | } 511 | 512 | ihandlers = { 513 | handlers = ["ftpdownload", "tftpdownload", "emuprofile", "cmdshell", "store", "uniquedownload", 514 | // "logsql", 515 | // "virustotal", 516 | // "mwserv", 517 | // "submit_http", 518 | "hpfeeds", 519 | // "logxmpp", 520 | // "nfq", 521 | // "p0f", 522 | // "surfids", 523 | // "fail2ban" 524 | ] 525 | } 526 | 527 | services = { 528 | serve = ["http", "https", "tftp", "ftp", "mirror", "smb", "epmap", "sip","mssql", "mysql", "pptp", "mqtt", "upnp"] 529 | } 530 | 531 | } 532 | 533 | nl = 534 | { 535 | lookup_ethernet_addr = "no" // set to yes in case you are interested in the mac address of the remote (only works for lan) 536 | 537 | } 538 | 539 | 540 | /* nc is a test module */ 541 | /* nc = 542 | { 543 | services = [ 544 | { 545 | proto = "redir" 546 | type = "tcp" 547 | host = "::" 548 | port = "4711" 549 | }, 550 | { 551 | proto = "redir" 552 | type = "tcp" 553 | host = "::" 554 | port = "12344" 555 | }, 556 | { 557 | proto = "sink" 558 | type = "tcp" 559 | host = "::" 560 | port = "12345" 561 | throttle = { 562 | in = "8192" 563 | } 564 | timeout = { 565 | listen = "15" 566 | connect = "15" 567 | } 568 | }, 569 | { 570 | proto = "source" 571 | type = "tcp" 572 | host = "::" 573 | port = "12346" 574 | throttle = { 575 | out = "8192" 576 | } 577 | timeout = { 578 | listen = "15" 579 | connect = "15" 580 | } 581 | }, 582 | { 583 | proto = "redir" 584 | type = "tcp" 585 | host = "::" 586 | port = "12347" 587 | throttle = { 588 | in = "8192" 589 | out = "8192" 590 | } 591 | timeout = { 592 | listen = "15" 593 | connect = "15" 594 | } 595 | }, 596 | { 597 | proto = "redir" 598 | type = "tls" 599 | host = "::" 600 | port = "12444" 601 | timeout = { 602 | listen = "15" 603 | connect = "15" 604 | } 605 | }, 606 | 607 | { 608 | proto = "sink" 609 | type = "tls" 610 | host = "::" 611 | port = "12445" 612 | throttle = { 613 | in = "8192" 614 | } 615 | timeout = { 616 | listen = "15" 617 | connect = "5" 618 | } 619 | }, 620 | { 621 | proto = "source" 622 | type = "tls" 623 | host = "::" 624 | port = "12446" 625 | throttle = { 626 | out = "8192" 627 | } 628 | timeout = { 629 | listen = "15" 630 | connect = "15" 631 | } 632 | }, 633 | { 634 | proto = "redir" 635 | type = "tls" 636 | host = "::" 637 | port = "12447" 638 | throttle = { 639 | in = "8192" 640 | out = "8192" 641 | } 642 | timeout = { 643 | listen = "15" 644 | connect = "15" 645 | } 646 | }, 647 | { 648 | proto = "source" 649 | type = "udp" 650 | host = "::" 651 | port = "12544" 652 | timeout = { 653 | connect = "15" 654 | } 655 | }, 656 | { 657 | proto = "sink" 658 | type = "udp" 659 | host = "::" 660 | port = "12545" 661 | timeout = { 662 | connect = "15" 663 | } 664 | }, 665 | { 666 | proto = "redir" 667 | type = "udp" 668 | host = "::" 669 | port = "12546" 670 | timeout = { 671 | connect = "15" 672 | } 673 | } 674 | ] 675 | 676 | clients = [ 677 | { 678 | proto = "source" 679 | type = "tcp" 680 | host = "127.0.0.1" 681 | port = "13344" 682 | timeout = { 683 | connecting = "5" 684 | connect = "15" 685 | reconnect = "5" 686 | } 687 | }, 688 | { 689 | proto = "redir" 690 | type = "tcp" 691 | host = "ip6-localhost" 692 | port = "13345" 693 | timeout = { 694 | connecting = "5" 695 | connect = "15" 696 | reconnect = "5" 697 | } 698 | }, 699 | { 700 | proto = "redir" 701 | type = "tls" 702 | host = "localhost" 703 | port = "13346" 704 | timeout = { 705 | connecting = "5" 706 | connect = "15" 707 | reconnect = "5" 708 | } 709 | }, 710 | { 711 | proto = "source" 712 | type = "tls" 713 | host = "ip6-localhost" 714 | port = "12445" 715 | timeout = { 716 | reconnect = "1" 717 | connect = "1" 718 | } 719 | } 720 | ] 721 | } 722 | */ 723 | } 724 | -------------------------------------------------------------------------------- /dionaea/supervisor-dionaea.conf: -------------------------------------------------------------------------------- 1 | [program:dionaea] 2 | command=/opt/dionaea/bin/dionaea -u dionaea -g dionaea 3 | stdout_logfile=/var/log/dionaea.out 4 | stderr_logfile=/var/log/dionaea.err 5 | autostart=true 6 | autorestart=true 7 | redirect_stderr=true 8 | stopsignal=QUIT 9 | -------------------------------------------------------------------------------- /docs/data-flow-diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MattCarothers/mhn-core-docker/c21f762079f2e4a89343892c4959e35c79fd8fe2/docs/data-flow-diagram.png --------------------------------------------------------------------------------