├── README.md └── cowmilk.py /README.md: -------------------------------------------------------------------------------- 1 | # Cowmilk 2 | Cowmilk is a simple web app for fetching and displaying cowrie data in your browser. 3 | 4 | ## Usage 5 | It's important to edit the database variables and point it to your cowrie instance. After that, just run the script and go to http://ip-address:8080 in your browser. 6 | -------------------------------------------------------------------------------- /cowmilk.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bdwit" 4 | __description__ = "A simple web app to fetch and visualize your cowrie ssh honeypot data" 5 | 6 | """ 7 | Requirements (pip install ): 8 | * bottle 9 | * mysql-python 10 | * tabulate 11 | * requests 12 | 13 | Todo: 14 | * More/better sql queries 15 | * IP (geo)lookups 16 | * Hash lookups 17 | * Fancy template 18 | """ 19 | 20 | from bottle import get, post, run, template, request 21 | from tabulate import tabulate 22 | import requests 23 | import MySQLdb as db 24 | import re 25 | import sys 26 | 27 | # Database settings, edit to your needs 28 | DB_HOST = "" 29 | DB_USER = "" 30 | DB_PASS = "" 31 | DB_NAME = "" 32 | 33 | # Connect to database 34 | connection = db.connect(DB_HOST, DB_USER, DB_PASS, DB_NAME); 35 | 36 | @get("/attacks") 37 | def attack_stats(): 38 | # Attack statistics pivot page 39 | attacks = "
"
 40 |     attacks += "

Attacker Statistics

" 41 | 42 | sql = [] 43 | sql.append({"title":"Login attempts last 28 days", 44 | "sql":" SELECT date(timestamp) AS dateins,COUNT(session) AS occ\ 45 | FROM auth GROUP BY DATE(timestamp)\ 46 | ORDER BY timestamp DESC LIMIT 28", 47 | "columns":"Date,Amount" 48 | }) 49 | sql.append({"title":"Top 25 SSH clients", 50 | "sql":" SELECT clients.version, COUNT(client)\ 51 | FROM sessions INNER JOIN clients ON sessions.client = clients.id\ 52 | GROUP BY sessions.client\ 53 | ORDER BY COUNT(client) DESC\ 54 | LIMIT 25", 55 | "columns":"Client,Amount" 56 | }) 57 | sql.append({"title":"Usernames used yesterday", 58 | "sql":" SELECT username,COUNT(username) AS occ\ 59 | FROM auth\ 60 | WHERE username <> '' AND DATE(timestamp) = SUBDATE(CURDATE(),1)\ 61 | GROUP BY username ORDER BY COUNT(username) DESC", 62 | "columns":"Username,Amount" 63 | }) 64 | sql.append({"title":"Passwords used yesterday", 65 | "sql":" SELECT password,COUNT(password) AS occ\ 66 | FROM auth\ 67 | WHERE password <> '' AND DATE(timestamp) = SUBDATE(CURDATE(),1)\ 68 | GROUP BY password ORDER BY COUNT(password) DESC", 69 | "columns":"Password,Amount" 70 | }) 71 | sql.append({"title":"User/pass combinations yesterday", 72 | "sql":" SELECT username, password, COUNT(username) AS occ\ 73 | FROM auth\ 74 | WHERE username <> '' AND password <> '' AND DATE(timestamp) = SUBDATE(CURDATE(),1)\ 75 | GROUP BY username, password ORDER BY COUNT(username) DESC", 76 | "columns":"Username,Password,Amount" 77 | }) 78 | 79 | # Get and present data 80 | with connection: 81 | for key in sql: 82 | cursor = connection.cursor() 83 | cursor.execute(key["sql"]) 84 | rows = cursor.fetchall() 85 | columns = key["columns"].split(",") 86 | data = tabulate(rows, columns, tablefmt="rst") 87 | attacks += "

{0}

".format(key["title"]) 88 | attacks += data + "
" 89 | 90 | attacks += "
" 91 | return attacks 92 | 93 | @get("/tty") 94 | def tty_input(): 95 | # Behaviour analysis pivot page 96 | cmd = "
"
 97 |     cmd += "

Behaviour Statistics

" 98 | 99 | sql = [] 100 | sql.append({"title":"CLI input today", 101 | "sql":" SELECT timestamp,input,success\ 102 | FROM input\ 103 | WHERE DATE(timestamp) = CURDATE()\ 104 | ORDER BY timestamp DESC", 105 | "columns":"Timestamp,Command,Successful" 106 | }) 107 | sql.append({"title":"CLI input yesterday", 108 | "sql":" SELECT timestamp,input,success\ 109 | FROM input\ 110 | WHERE DATE(timestamp) = SUBDATE(CURDATE(),1)\ 111 | ORDER BY timestamp DESC", 112 | "columns":"Timestamp,Command,Successful" 113 | }) 114 | sql.append({"title":"Interesting commands", 115 | "sql":" SELECT timestamp, input, success\ 116 | FROM input\ 117 | WHERE (input like '%cat%' OR input like '%dev%' OR input like '%man%' OR input like '%gpg%'\ 118 | OR input like '%ping%' OR input like '%ssh%' OR input like '%scp%' OR input like '%whois%'\ 119 | OR input like '%unset%' OR input like '%kill%' OR input like '%ifconfig%' OR input like '%iwconfig%' OR input like '%iptables%'\ 120 | OR input like '%traceroute%' OR input like '%screen%' OR input like '%user%')\ 121 | AND input NOT like '%wget%' AND input NOT like '%apt-get%'\ 122 | GROUP BY input\ 123 | ORDER BY timestamp DESC", 124 | "columns":"Timestamp,Command,Successful" 125 | }) 126 | 127 | # Get and present data 128 | with connection: 129 | for key in sql: 130 | cursor = connection.cursor() 131 | cursor.execute(key["sql"]) 132 | rows = cursor.fetchall() 133 | columns = key["columns"].split(",") 134 | data = tabulate(rows, columns, tablefmt="rst") 135 | cmd += "

{0}

".format(key["title"]) 136 | cmd += data + "
" 137 | 138 | cmd += "
" 139 | return cmd 140 | 141 | @get("/intel") 142 | def ip_intelligence(): 143 | # IP intelligence pivot page 144 | intel = "
"
145 |     intel += "

IP Intelligence

" 146 | 147 | sql = [] 148 | sql.append({"title":"Number of connections per IP today", 149 | "sql":" SELECT ip,COUNT(ip) AS occ\ 150 | FROM sessions\ 151 | WHERE DATE(starttime) = CURDATE()\ 152 | GROUP BY ip ORDER BY COUNT(ip) DESC", 153 | "columns":"IP address,Amount" 154 | }) 155 | sql.append({"title":"Number of connections per IP yesterday", 156 | "sql":" SELECT ip,COUNT(ip) AS occ\ 157 | FROM sessions\ 158 | WHERE DATE(starttime) = SUBDATE(CURDATE(),1)\ 159 | GROUP BY ip ORDER BY COUNT(ip) DESC", 160 | "columns":"IP address,Amount" 161 | }) 162 | sql.append({"title":"Overall IP activity", 163 | "sql":" SELECT A.*, B.success\ 164 | FROM (SELECT ip, MAX(starttime) as starttime, COUNT(DISTINCT sessions.id) as sessions FROM sessions GROUP BY ip) A LEFT JOIN (SELECT sessions.ip, MAX(success) as success FROM sessions, auth\ 165 | WHERE sessions.id = auth.session\ 166 | GROUP BY ip) B on A.ip = B.ip ORDER BY starttime DESC", 167 | "columns":"IP Address,Last Seen,Sessions,Successful" 168 | }) 169 | 170 | # Get and present data 171 | with connection: 172 | for key in sql: 173 | cursor = connection.cursor() 174 | cursor.execute(key["sql"]) 175 | rows = cursor.fetchall() 176 | columns = key["columns"].split(",") 177 | data = tabulate(rows, columns, tablefmt="rst") 178 | intel += "

{0}

".format(key["title"]) 179 | intel += data + "
" 180 | 181 | intel += "
" 182 | return intel 183 | 184 | @get("/malwr") 185 | def malware_analysis(): 186 | # Malware analysis pivot page 187 | malwr = "
"
188 |     malwr += "

Malware Analysis

" 189 | 190 | sql = [] 191 | sql.append({"title":"Succesful downloads today", 192 | "sql":" SELECT timestamp, input, TRIM(LEADING 'wget' FROM input) as file\ 193 | FROM input\ 194 | WHERE input LIKE '%wget%' AND input NOT LIKE 'wget' AND DATE(timestamp) = CURDATE()\ 195 | ORDER BY timestamp DESC", 196 | "columns":"Timestamp,Input,Location" 197 | }) 198 | sql.append({"title":"Executed scripts today", 199 | "sql":" SELECT timestamp, input\ 200 | FROM input\ 201 | WHERE input LIKE '%./%' AND DATE(timestamp) = CURDATE()\ 202 | ORDER BY timestamp DESC", 203 | "columns":"Timestamp,Input" 204 | }) 205 | sql.append({"title":"Succesful downloads yesterday", 206 | "sql":" SELECT timestamp, input, TRIM(LEADING 'wget' FROM input) as file\ 207 | FROM input\ 208 | WHERE input LIKE '%wget%' AND input NOT LIKE 'wget' AND DATE(timestamp) = SUBDATE(CURDATE(),1)\ 209 | ORDER BY timestamp DESC", 210 | "columns":"Timestamp,Input,Location" 211 | }) 212 | sql.append({"title":"Executed scripts yesterday", 213 | "sql":" SELECT timestamp, input\ 214 | FROM input\ 215 | WHERE input LIKE '%./%' AND DATE(timestamp) = SUBDATE(CURDATE(),1)\ 216 | ORDER BY timestamp DESC", 217 | "columns":"Timestamp,Input" 218 | }) 219 | 220 | # Get and present data 221 | with connection: 222 | for key in sql: 223 | cursor = connection.cursor() 224 | cursor.execute(key["sql"]) 225 | rows = cursor.fetchall() 226 | columns = key["columns"].split(",") 227 | data = tabulate(rows, columns, tablefmt="rst") 228 | malwr += "

{0}

".format(key["title"]) 229 | malwr += data + "
" 230 | 231 | malwr += "
" 232 | return malwr 233 | 234 | # @get("/proxy") 235 | # def proxy_abuse(): 236 | # # Proxy abuse pivot page 237 | # proxy = "
"
238 | #     proxy += "

SSH Proxy Abuse

" 239 | # proxy += "
" 240 | # return proxy 241 | 242 | # Main page 243 | @get("/") 244 | def main(): 245 | main = "
" 246 | main += "

Cowrie SSH Honeypot Analytics

" 247 | main += "

Attack Statistics

" 248 | main += "

Behaviour Statistics

" 249 | #main += "

Proxy Abuse

" 250 | main += "

IP Intelligence

" 251 | main += "

Malware Analysis

" 252 | main += "

" 253 | return main 254 | 255 | 256 | # Run the webpage on port 8080 257 | run(host='localhost', port=8080) --------------------------------------------------------------------------------