aboutsummaryrefslogtreecommitdiff
path: root/cowrieder.py
diff options
context:
space:
mode:
authorAda Isopods <me@bathynomus.xyz>2025-05-16 06:21:20 -0600
committerAda Isopods <me@bathynomus.xyz>2026-10-21 23:04:28 -0600
commit0deb8ecec9b874d58f6c46f6351d401464d1c061 (patch)
tree00b69f38534afd14381b85e5fd7d8872428ed3c2 /cowrieder.py
parentd38e608b315ec391a7a5fe2775ce3e5b63a54b1f (diff)
you don't need to see my wacky internal terminology for a simple log analyzing tool
Diffstat (limited to 'cowrieder.py')
-rw-r--r--cowrieder.py34
1 files changed, 17 insertions, 17 deletions
diff --git a/cowrieder.py b/cowrieder.py
index db549bc..75be8c1 100644
--- a/cowrieder.py
+++ b/cowrieder.py
@@ -36,7 +36,7 @@ def ttylog(mystring): #mystring
if(os.isatty(1)):
print(mystring)
-def ppip(addr, spacing = False, ttycolor = False): # Pretty-print an address with colour and, if it's IPv4, a consistent width
+def ppip(addr, spacing = False, ttycolor = False): # Pretty-print an address with colour and, if it's IPv4 or hashed, a consistent width
rs = addr
if(ttycolor):
rs = ccgen(rs) + rs + ccgen()
@@ -49,6 +49,8 @@ def hashgen(seed, length=16):
raise Warning("Due to strange behaviour on the part of the hexdigest() function, length should be a multiple of 2")
return hashlib.shake_256(str(seed).encode("utf-8")).hexdigest(int(length / 2))
+cmdping_commands = ['uname', 'nproc', 'echo'] # List of commands that, if used exclusively, qualify a session as a "command ping"
+
# ArgParse crap coming in hot
parser = argparse.ArgumentParser(
@@ -61,11 +63,11 @@ parser.add_argument('-v', '--verbose', action='store_true', help="Make the outpu
parser.add_argument('-V', '--verboser', action='store_true', help="Make the output even more verbose (print timestamp, event id, and message (if applicable) for all events)")
parser.add_argument('-W', '--verbosest', action='store_true', help="Make the output even more verboserer (just group the input log by session id and dump it to pretty-printed JSON)")
-parser.add_argument('-P', '--pings', action='store_true', help='Print only "empty pings"')
-parser.add_argument('-F', '--fails', action='store_true', help='Print only failed logins')
-parser.add_argument('-L', '--logins', action='store_true', help='Print only "login pings"')
-parser.add_argument('-C', '--commands', action='store_true', help='Print only "command pings"')
-parser.add_argument('-E', '--eventful', action='store_true', help='Print only the cool interesting sessions that aren\'t any of that other stuff.')
+parser.add_argument('-P', '--pings', action='store_true', help='Include only connections where no authentication attempt was made')
+parser.add_argument('-F', '--fails', action='store_true', help='Include only failed logins')
+parser.add_argument('-L', '--logins', action='store_true', help='Include only successful logins where no commands were run')
+parser.add_argument('-C', '--commands', action='store_true', help='Include only logins where only this list of basic test commands were run: ' + str(cmdping_commands))
+parser.add_argument('-E', '--eventful', action='store_true', help='Include only the cool interesting sessions that aren\'t any of that other stuff')
parser.add_argument('-r', '--redact-ip', action='store_true', help='Redact IP addresses by converting them to 16-character hashes')
parser.add_argument('-i', '--filter-ip', help='Filter data to a specific IP or censored hash thereof')
@@ -129,9 +131,9 @@ def session_cred_combos(session): # List passwords used in login attempt
for event in session:
if(event['eventid'] == "cowrie.login.failed" or event['eventid'] == "cowrie.login.success"):
if('password' in event):
- ra.append([event['username'], event['password']])
+ ra.append((event['username'], event['password']))
elif('key' in event):
- ra.append([event['username'], []])
+ ra.append((event['username'], []))
return ra
def session_ran_command(session): # Was a command run during the session
@@ -146,8 +148,6 @@ def session_saved_file(session):
return True
return False
-cmdping_commands = ['uname', 'nproc', 'echo'] # List of commands that, if used exclusively, qualify a session as a "command ping"
-
def session_is_cmdping(session): # Determine if a session qualifies as a "command ping"
if(session_ran_command(session)):
for event in session:
@@ -177,7 +177,7 @@ def session_pingcmds(session): # Return array of all "command ping" commands use
-with open(filepath, "r") as logfile: # Load da file and collect all possible relevant data about it
+with open(filepath, "r") as logfile: # Load da file and populate da master array
for line in logfile:
entry = json.loads(line)
@@ -226,7 +226,7 @@ if(verbosity == 2): # High verbosity mode: print timestamp, event type and messa
else:
print(entry["timestamp"] + " > " + eventid + (" " * (29 - len(eventid))) + ": " + entry['message'])
-elif(verbosity == 3): # Maximum verbosity: literally just pretty print the now-sorted-by-session logs
+elif(verbosity == 3): # Maximum verbosity: literally just dump the now-sorted-by-session logs as pretty-printed JSON
print(json.dumps(sessions, indent=4))
else: # Default (low) verbosity: just the good stuff
@@ -236,20 +236,20 @@ else: # Default (low) verbosity: just the good stuff
session = sessions[session_id]
ip = session_ip(session)
timestamp = session_timestamp(session)[:22].replace("T", " ") # clean up the timestamp text all pretty like
- durationstring = " closed after " + str(session_duration(session)) + "s"
+ durationstring = "closed after " + str(session_duration(session)) + "s"
if(session_duration(session) < 0):
durationstring = "active as of processing"
if(not session_attempted_login(session)): # Printing empty pings
- print(timestamp + " > " + ppip(ip, True, True) + " > " + ccgen("PURPLE") + "Empty ping" + ccgen() + durationstring)
+ print(timestamp + " > " + ppip(ip, True, True) + " > Connection opened and " + durationstring)
elif(session_attempted_login(session) and not session_login_succeeded(session)): # Printing failed logins
- print(timestamp + " > " + ppip(ip, True, True) + " > " + ccgen("RED") +"Failed login" + ccgen() + ": " + str(session_cred_combos(session)))
+ print(timestamp + " > " + ppip(ip, True, True) + " > " + ccgen("RED") +"Failed login" + ccgen() + " with credentials: " + str(session_cred_combos(session)))
elif(session_ran_command(session)): # Printing logic for sessions in which a command was run
if(not verbosity == 1 and session_is_cmdping(session)): # If -v is not enabled, collapse "command pings" to one-liners
- print(timestamp + " > " + ppip(ip, True, True) + " > " + ccgen("BLUE") + "Command ping" + ccgen() + ": " + str(session_cred_combos(session)) + " > " + str(session_pingcmds(session)))
+ print(timestamp + " > " + ppip(ip, True, True) + " > " + ccgen("GREEN") + "Login" + ccgen() + " with credentials: " + str(session_cred_combos(session)) + ccgen("BLUE") + " ran commands " + ccgen() + str(session_pingcmds(session)))
else: # Printing logic for un-collapsed sessions where commands were run
print(timestamp + " > " + ppip(ip, True, True) + " > " + ccgen("CYAN") + "Session" + ccgen() + ":")
@@ -277,7 +277,7 @@ else: # Default (low) verbosity: just the good stuff
print(" X Session " + durationstring)
else: # Printing logic for successful logins in which no commands were run
- print(timestamp + " > " + ppip(ip, True, True) + " > " + ccgen("GREEN") + "Login ping" + ccgen() + ": " + str(session_cred_combos(session)))
+ print(timestamp + " > " + ppip(ip, True, True) + " > " + ccgen("GREEN") + "Login" + ccgen() + " with credentials: " + str(session_cred_combos(session)))
if(args.stats):
print("Aggregate statistics TODO") \ No newline at end of file