aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAda Isopods <me@bathynomus.xyz>2025-05-31 06:50:54 -0600
committerAda Isopods <me@bathynomus.xyz>2026-10-21 23:04:42 -0600
commit791eab614ded59048e0ffd65660b14e1e6804c27 (patch)
tree5ef723558547a680fd0dff79c5481e91f15e572d
parent987780503bfd69b8d8759d58ba1273a135fe3b1a (diff)
HTML webpage output. I know the code sucks don't @ me
-rw-r--r--.gitignore7
-rw-r--r--README.md6
-rw-r--r--cowrieder.py500
3 files changed, 503 insertions, 10 deletions
diff --git a/.gitignore b/.gitignore
index 18ab1f7..18d2db3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,2 @@
-*.json
-*.json.*
-*.log
-*.log.*
-*.txt
+output/
+cowrie/ \ No newline at end of file
diff --git a/README.md b/README.md
index fd73709..36a2205 100644
--- a/README.md
+++ b/README.md
@@ -12,7 +12,7 @@ cowrieder.py <options> /var/log/cowrie/
Options:
```
--h, --help show this help message and exit
+-h -h, --help show this help message and exit
-v, --verbose Make the output more verbose (do less to collapse less-interesting information)
-V, --verboser Make the output even more verbose (one line per event)
-W, --verbosest Make the output even more verboserer (dump as much information as possible as pretty-printed JSON)
@@ -33,8 +33,8 @@ Options:
-c, --no-color Don't color-code terminal output
-s, --stats Print aggregated statistics
-S, --only-stats Print only aggregated statistics
+-m, --html Output an overview as an HTML webpage, GoAccess-style. Ignores previous two options.
```
# TODO
-- Filter by regex?
-- HTML output option \ No newline at end of file
+- Filter by regex? \ No newline at end of file
diff --git a/cowrieder.py b/cowrieder.py
index 4162a40..85c2485 100644
--- a/cowrieder.py
+++ b/cowrieder.py
@@ -46,6 +46,7 @@ parser.add_argument('-c', '--no-color', action='store_true', help="Don't color-c
parser.add_argument('-s', '--stats', action='store_true', help='Print aggregated statistics')
parser.add_argument('-S', '--only-stats', action='store_true', help='Print only aggregated statistics')
+parser.add_argument('-m', '--html', action='store_true', help="Output an overview as an HTML webpage, GoAccess-style. Ignores previous two options.")
def ccgen(seed=""): # Color code generator
if(not os.isatty(1) or args.no_color): # Do not output color code at all if output is not a TTY that can accept them
@@ -510,7 +511,7 @@ elif(verbosity == 2): # High verbosity mode: print timestamp, event type and mes
-else: # Default (low) verbosity: just the good stuff
+elif(not args.html): # Default (low) verbosity: just the good stuff
if(not args.only_stats):
for session_id in sessions:
@@ -586,4 +587,499 @@ else: # Default (low) verbosity: just the good stuff
print("\n--- Top IPs with credential combos tried: ---")
print_dict_of_lists(login_combos_by_ip, truncate=7, limit = 20, key_is_ip=True)
print_percentage_stats()
- print("---\nTook {}s to parse {} of logs".format(str(log_parsing_time)[:4], sizeof_fmt(total_filesize))) \ No newline at end of file
+ print("---\nTook {}s to parse {} of logs".format(str(log_parsing_time)[:4], sizeof_fmt(total_filesize)))
+
+elif(args.html):
+ # This is a bad way to do it but it's the way I'm gonna. fuck you
+ print('<!DOCTYPE html>')
+ print('<head>')
+ print(' <meta charset="utf-8">')
+ print(' <meta name="viewport" content="width=device-width, initial-scale=1">')
+ print(' <title>Cowrie Stats</title>')
+ print(' <style>')
+ print(' :root {')
+ print(' --black: #181a1c;')
+ print(' --bg_dim: #252630;')
+ print(' --bg0: #2b2d3a;')
+ print(' --bg1: #333648;')
+ print(' --bg2: #363a4e;')
+ print(' --bg3: #393e53;')
+ print(' --bg4: #3f445b;')
+ print(' --gray_dim: #5a5e7a;')
+ print(' --gray: #7e8294;')
+ print(' --fg: #e1e3e4;')
+ print(' --red: #fb617e;')
+ print(' --orange: #f89860;')
+ print(' --yellow: #edc763;')
+ print(' --green: #9ed06c;')
+ print(' --blue: #6dcae8;')
+ print(' --purple: #bb97ee;')
+ print('')
+ print(' --bg: var(--bg0);')
+ print(' --fontcolor: var(--fg);')
+ print(' --linkcolor: var(--red);')
+ print(' --linkhover: var(--blue);')
+ print('')
+ print(' --pc1: var(--red);')
+ print(' --pc2: var(--orange);')
+ print(' --pc3: var(--green);')
+ print(' --pc4: var(--blue);')
+ print(' --pc5: var(--purple);')
+ print('')
+ print('')
+ print(' --stdpadding: 1rem;')
+ print(' }')
+ print(' body {')
+ print(' background-color: var(--bg);')
+ print(' font-family: sans-serif;')
+ print(' color: var(--fontcolor);')
+ print(' padding: var(--stdpadding);')
+ print(' margin: 0;')
+ print(' box-sizing: border-box;')
+ print(' min-height: 100vh;')
+ print(' display: flex;')
+ print(' flex-direction: column;')
+ print(' }')
+ print(' header {')
+ print(' display: flex;')
+ print(' padding: var(--stdpadding);')
+ print(' align-items: center;')
+ print(' }')
+ print(' header div {')
+ print(' margin-left: var(--stdpadding);')
+ print(' }')
+ print(' header div h1, header div p {')
+ print(' margin: 0')
+ print(' }')
+ print(' footer {')
+ print(' display: flex;')
+ print(' margin-top: var(--stdpadding);')
+ print(' gap: var(--stdpadding);')
+ print(' flex-wrap: wrap;')
+ print(' }')
+ print(' main {')
+ print(' flex: 1;')
+ print(' }')
+ print(' a {')
+ print(' color: var(--linkcolor);')
+ print(' }')
+ print(' a:hover {')
+ print(' color: var(--linkhover);')
+ print(' }')
+ print(' section {')
+ print(' margin: var(--stdpadding) 0;')
+ print(' }')
+ print(' .smallstats {')
+ print(' display: flex;')
+ print(' gap: var(--stdpadding);')
+ print(' flex-wrap: wrap;')
+ print(' }')
+ print(' .smallstats article {')
+ print(' padding: var(--stdpadding);')
+ print(' flex: 1;')
+ print(' background-color: #fff2;')
+ print(' border-left: 3px solid var(--fontcolor);')
+ print(' }')
+ print(' .smallstats article h5 {')
+ print(' margin: 0;')
+ print(' font-weight: normal;')
+ print(' }')
+ print('')
+ print(' .bigstats {')
+ print(' display: flex;')
+ print(' gap: var(--stdpadding);')
+ print(' flex-wrap: wrap;')
+ print(' }')
+ print(' .bigstats p {')
+ print(' margin: 0;')
+ print(' }')
+ print(' .bigstats article {')
+ print(' padding: var(--stdpadding);')
+ print(' flex: 1;')
+ print(' background-color: var(--bg_dim);')
+ print(' box-shadow: 0 0 calc(var(--stdpadding) / 2) black inset;')
+ print(' border-left: 3px solid var(--fontcolor);')
+ print(' display: flex;')
+ print(' flex-direction: column;')
+ print(' justify-content: center;')
+ print(' align-items: center;')
+ print(' min-width: min(30rem, calc(100% - (var(--stdpadding) * 2) - 3px));')
+ print(' }')
+ print(' .bigstats article h3 {')
+ print(' margin-top: 0;')
+ print(' }')
+ print(' .bigstats article > ul {')
+ print(' overflow-y: scroll;')
+ print(' max-height: 30rem;')
+ print(' padding-left: 0;')
+ print(' width: 100%;')
+ print(' margin: 0;')
+ print(' }')
+ print(' .bigstats article > ul > li {')
+ print(' list-style-type: none;')
+ print(' background-color: var(--bg0);')
+ print(' padding: var(--stdpadding);')
+ print(' margin: var(--stdpadding);')
+ print(' }')
+ print(' .bigstats article > ul > li > details > ul {')
+ print(' display: flex;')
+ print(' flex-wrap: wrap;')
+ print(' gap: calc(var(--stdpadding)/2);')
+ print(' overflow-y: scroll;')
+ print(' max-height: 20rem;')
+ print(' padding-left: 0;')
+ print(' margin-top: var(--stdpadding);')
+ print(' }')
+ print(' .bigstats article > ul > li > details > ul > li {')
+ print(' list-style-type: none;')
+ print(' padding: .5rem;')
+ print(' background-color: var(--bg2);')
+ print(' }')
+ print('')
+ print(' .bigstats article > ul > li > ul {')
+ print(' list-style-type: none;')
+ print(' padding-left: 0;')
+ print(' display: flex;')
+ print(' flex-direction: column;')
+ print(' gap: calc(var(--stdpadding) / 2);')
+ print(' margin-top: calc(var(--stdpadding) / 2);')
+ print(' }')
+ print(' .bigstats article > ul > li > ul > li {')
+ print(' padding: calc(var(--stdpadding) / 2);')
+ print(' background-color: var(--bg2);')
+ print(' display: flex;')
+ print(' align-items: center;')
+ print(' gap: calc(var(--stdpadding) / 2);')
+ print(' }')
+ print(' .bigstats article > ul > li > ul > li svg {')
+ print(' max-width: 1.5em;')
+ print(' min-width: 1.5em;')
+ print(' }')
+ print(' .slfail svg, .slend svg {')
+ print(' color: var(--red);')
+ print(' }')
+ print(' .slsuccess svg {')
+ print(' color: var(--green);')
+ print(' }')
+ print(' .slsave svg {')
+ print(' color: var(--blue);')
+ print(' }')
+ print('')
+ print(' .piecontainer {')
+ print(' display: flex;')
+ print(' gap: var(--stdpadding);')
+ print(' align-items: center;')
+ print(' --sliceangle1: 72deg;')
+ print(' --sliceangle2: 144deg;')
+ print(' --sliceangle3: 216deg;')
+ print(' --sliceangle4: 288deg;')
+ print(' }')
+ print(' .piechart {')
+ print(' border-radius: 100%;')
+ print(' width: min(20rem, 70vw);')
+ print(' aspect-ratio: 1;')
+ print(' display: flex;')
+ print(' justify-content: center;')
+ print(' align-items: center;')
+ print(' filter: drop-shadow(2px 2px 2px #0004);')
+ print(' background: conic-gradient(var(--pc1) 0deg 360deg);')
+ print(' }')
+ print(' .piechart > .piechart {')
+ print(' background: conic-gradient(#0000 0deg var(--sliceangle1), var(--pc2) var(--sliceangle1) 360deg);')
+ print(' }')
+ print(' .piechart > .piechart > .piechart {')
+ print(' background: conic-gradient(#0000 0deg var(--sliceangle2), var(--pc3) var(--sliceangle2) 360deg);')
+ print(' }')
+ print(' .piechart > .piechart > .piechart > .piechart {')
+ print(' background: conic-gradient(#0000 0deg var(--sliceangle3), var(--pc4) var(--sliceangle3) 360deg);')
+ print(' }')
+ print(' .piechart > .piechart > .piechart > .piechart > .piechart {')
+ print(' background: conic-gradient(#0000 0deg var(--sliceangle4), var(--pc5) var(--sliceangle4) 360deg);')
+ print(' }')
+ print(' .pielabel1::marker {')
+ print(' content: "■ ";')
+ print(' color: var(--pc1);')
+ print(' }')
+ print(' .pielabel2::marker {')
+ print(' content: "■ ";')
+ print(' color: var(--pc2);')
+ print(' }')
+ print(' .pielabel3::marker {')
+ print(' content: "■ ";')
+ print(' color: var(--pc3);')
+ print(' }')
+ print(' .pielabel4::marker {')
+ print(' content: "■ ";')
+ print(' color: var(--pc4);')
+ print(' }')
+ print(' .pielabel5::marker {')
+ print(' content: "■ ";')
+ print(' color: var(--pc5);')
+ print(' }')
+ print('')
+ print(' @media screen and (max-width: 100vh) {')
+ print(' .smallstats {')
+ print(' flex-direction: column;')
+ print(' }')
+ print(' .piecontainer {')
+ print(' flex-direction: column;')
+ print(' }')
+ print(' }')
+ print(' </style>')
+ print('</head>')
+ print('<body>')
+ print(' <header>')
+ print(' <svg fill="gainsboro" height="3rem" viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg"><g id="am"><path d="M57.13,42.78c-4.63-10.07-9.17-20.1-14.56-32.06-.38-.85-1.32-1.5-2.26-1.61l-.61-2.03c-.3-1.02-1.14-1.79-2.17-2.01l-4.21-.92c-.86-.19-1.77-.19-2.64,0l-4.21,.92c-1.04,.23-1.87,1-2.17,2.01l-.61,2.03c-.94,.1-1.88,.76-2.26,1.61-4.24,9.46-8.62,19.05-12.86,28.33l-1.71,3.73c-.21,.47-.27,1.02-.16,1.57,.11,.54,.38,1.03,.76,1.38l15.18,13.85c.44,.4,1.06,.53,1.61,.34,.56-.19,.98-.66,1.09-1.24l.99-5.11,4.17,2.54c.92,.56,2.05,.56,2.97,0l4.17-2.54,.99,5.11c.11,.58,.53,1.06,1.09,1.24,.17,.06,.34,.08,.51,.08,.4,0,.8-.15,1.1-.43l15.18-13.85c.78-.71,1.04-1.98,.6-2.94Zm-28.49-1.55l1.08-5.81h4.56l1.08,5.81h-6.72Zm7.09,2l.71,3.85h-8.89l.71-3.85h7.46Zm-2.53-13.66l.71,3.85h-3.82l.71-3.85h2.39Zm-2.02-2l.83-4.45,.82,4.45h-1.65Zm2.03-8.93h10.74c3.63,8.05,6.95,15.35,10.26,22.56l-19.71-15.6-1.29-6.96Zm-6.31-11.62l4.21-.92c.58-.13,1.2-.13,1.78,0l4.21,.92c.33,.07,.59,.31,.68,.63l.43,1.44h-12.44l.43-1.44c.1-.32,.36-.56,.68-.63Zm-3.64,4.52c.09-.21,.45-.44,.68-.44h16.12c.23,0,.59,.23,.68,.44,.8,1.77,1.54,3.41,2.3,5.1H20.95c.77-1.7,1.55-3.41,2.31-5.1Zm-3.21,7.1h10.75l-1.29,6.96-19.73,15.61,.61-1.34c3.18-6.96,6.43-14.1,9.66-21.24Zm3.47,39.02l-14.54-13.26,19.98-15.81-5.44,29.06Zm8.93-3.26c-.27,.17-.62,.17-.89,0l-4.81-2.93,.44-2.39h9.63l.44,2.39-4.81,2.93Zm8.04,3.26l-5.43-29.06,19.97,15.8-14.54,13.26Z" /></g></svg>')
+ print(' <div>')
+ print(' <h1>Cowrie Stats</h1>')
+ print(' <p>' + session_timestamp(sessions[next(iter(sessions))])[:10] + ' &ndash; ' + session_timestamp(sessions[next(reversed(sessions))])[:10] + '</p>')
+ print(' </div>')
+ print(' </header>')
+ print(' <main>')
+ print(' <section class="smallstats">')
+ print(' <article>')
+ print(' <h5>Total Sessions</h5>')
+ print(' '+str(len(sessions)))
+ print(' </article>')
+ print(' <article>')
+ print(' <h5>Distinct Visitors</h5>')
+ print(' '+str(len(attempt_counts_by_ip)))
+ print(' </article>')
+ print(' <article>')
+ print(' <h5>Files Saved</h5>')
+ print(' '+str(cnt_filessaved))
+ print(' </article>')
+ print(' <article>')
+ print(' <h5>Log Parsing Time</h5>')
+ print(' '+str(log_parsing_time)[:4]+'s')
+ print(' </article>')
+ print(' <article>')
+ print(' <h5>Total Log Size</h5>')
+ print(' '+sizeof_fmt(total_filesize))
+ print(' </article>')
+ print(' <article>')
+ print(' <h5>Updated</h5>')
+ print(' '+time.strftime("%Y-%m-%d %H:%M:%S%z"))
+ print(' </article>')
+ print(' </section>')
+
+ if(args.pings or args.fails or args.logins or args.commands or args.eventful or args.filter_username or args.filter_password or args.filter_sensor or args.filter_ip):
+ print(' <h2>Active Filters</h2>')
+ print(' <section class="smallstats">')
+ if(args.filter_ip):
+ print(' <article>')
+ print(' <h5>By IP</h5>')
+ print(' '+args.filter_ip)
+ print(' </article>')
+ if(args.filter_username):
+ print(' <article>')
+ print(' <h5>By Username Used</h5>')
+ print(' '+args.filter_username)
+ print(' </article>')
+ if(args.filter_password):
+ print(' <article>')
+ print(' <h5>By Password Used</h5>')
+ print(' '+args.filter_password)
+ print(' </article>')
+ if(args.filter_sensor):
+ print(' <article>')
+ print(' <h5>By Sensor</h5>')
+ print(' '+args.filter_sensor)
+ print(' </article>')
+ if(args.pings or args.fails or args.logins or args.commands or args.eventful):
+ print(' <article>')
+ print(' <h5>By Session Type</h5>')
+ h_typefilters = ' '
+ h_typefiltercnt = 0
+ if(args.pings):
+ h_typefilters += 'NoLogin'
+ h_typefiltercnt += 1
+ if(args.fails):
+ if(h_typefiltercnt > 0):
+ h_typefilters += ', '
+ h_typefilters += 'Failed'
+ h_typefiltercnt += 1
+ if(args.logins):
+ if(h_typefiltercnt > 0):
+ h_typefilters += ', '
+ h_typefilters += 'NoCommands'
+ h_typefiltercnt += 1
+ if(args.commands):
+ if(h_typefiltercnt > 0):
+ h_typefilters += ', '
+ h_typefilters += 'Commands'
+ h_typefiltercnt += 1
+ if(args.eventful):
+ if(h_typefiltercnt > 0):
+ h_typefilters += ', '
+ h_typefilters += 'Eventful'
+ print(h_typefilters)
+ print(' </article>')
+ print(' </section>')
+ print(' <section class="bigstats">')
+ print(' <article>')
+ print(' <h3>Sessions by Source IP</h3>')
+ print(' <div class="piecontainer" style="')
+ print(' --sliceangle1: '+str(1 - (top_n_percent_of_ips_session_percent(0.5)) / 100)+'turn;')
+ print(' --sliceangle2: '+str(1 - (top_n_percent_of_ips_session_percent(0.1)) / 100)+'turn;')
+ print(' --sliceangle3: '+str(1 - (top_n_percent_of_ips_session_percent(0.01)) / 100)+'turn;')
+ print(' --sliceangle4: '+str(1 - (percent_of_all_sessions(attempt_counts_by_ip[next(iter(attempt_counts_by_ip))])) / 100)+'turn;')
+ print(' ">')
+ print(' <div class="piechart">')
+ print(' <div class="piechart">')
+ print(' <div class="piechart" style="width: 95%;">')
+ print(' <div class="piechart" style="width: 95%;">')
+ print(' <div class="piechart" style="width: 95%;">')
+ print('')
+ print(' </div>')
+ print(' </div>')
+ print(' </div>')
+ print(' </div>')
+ print(' </div>')
+ print(' <div>')
+ print(' <ul>')
+ print(' <li class="pielabel1">'+str(100 - top_n_percent_of_ips_session_percent(0.5))+'% &ndash; Bottom 50%</li>')
+ print(' <li class="pielabel2">'+str(top_n_percent_of_ips_session_percent(0.5))+'% &ndash; Top 50%</li>')
+ print(' <li class="pielabel3">'+str(top_n_percent_of_ips_session_percent(0.1))+'% &ndash; Top 10%</li>')
+ print(' <li class="pielabel4">'+str(top_n_percent_of_ips_session_percent(0.01))+'% &ndash; Top 1%</li>')
+ print(' <li class="pielabel5">'+str(percent_of_all_sessions(attempt_counts_by_ip[next(iter(attempt_counts_by_ip))]))+'% &ndash; Top 1 ('+next(iter(attempt_counts_by_ip))+')</li>')
+ print(' </ul>')
+ print(' </div>')
+ print(' </div>')
+ print(' </article>')
+ print(' <article>')
+ print(' <h3>Sessions by Type</h3>')
+ print(' <div class="piecontainer" style="')
+ print(' --sliceangle1: '+str(1 - (percent_of_all_sessions(cnt_fails + cnt_lping + cnt_cmdping + cnt_eventful) / 100))+'turn;')
+ print(' --sliceangle2: '+str(1 - (percent_of_all_sessions(cnt_lping + cnt_cmdping + cnt_eventful) / 100))+'turn;')
+ print(' --sliceangle3: '+str(1 - (percent_of_all_sessions(cnt_cmdping + cnt_eventful) / 100))+'turn;')
+ print(' --sliceangle4: '+str(1 - (percent_of_all_sessions(cnt_eventful) / 100))+'turn;')
+ print(' ">')
+ print(' <div class="piechart">')
+ print(' <div class="piechart">')
+ print(' <div class="piechart">')
+ print(' <div class="piechart" style="width: 95%;">')
+ print(' <div class="piechart" style="width: 95%;">')
+ print('')
+ print(' </div>')
+ print(' </div>')
+ print(' </div>')
+ print(' </div>')
+ print(' </div>')
+ print(' <div>')
+ print(' <ul>')
+ print(' <li class="pielabel1">'+str(percent_of_all_sessions(cnt_pings))+'% &ndash; No attempt to log in</li>')
+ print(' <li class="pielabel2">'+str(percent_of_all_sessions(cnt_fails))+'% &ndash; Failed logins</li>')
+ print(' <li class="pielabel3">'+str(percent_of_all_sessions(cnt_lping + cnt_cmdping + cnt_eventful))+'% &ndash; Successful logins</li>')
+ print(' <li class="pielabel4">'+str(percent_of_all_sessions(cnt_cmdping + cnt_eventful))+'% &ndash; Logins that ran commands</li>')
+ print(' <li class="pielabel5">'+str(percent_of_all_sessions(cnt_eventful))+'% &ndash; Logins that ran unusual* commands</li>')
+ print(' </ul>')
+ print(' <p>*Not a subset of <code>'+str(cmdping_commands)+'</code></p>')
+ print(' </div>')
+ print(' </div>')
+ print(' </article>')
+ print(' </section>')
+ print(' <section class="bigstats">')
+ print(' <article>')
+ print(' <h3>Attempts by username</h3>')
+ print(' <p>Expand to show corresponding passwords</p>')
+ print(' <ul>')
+ for uname in passwords_by_username:
+ print(' <li>')
+ print(' <details>')
+ print(' <summary>'+uname+' &ndash; '+str(attempt_counts_by_username[uname])+' Attempts</summary>')
+ print(' <ul>')
+ for pw in passwords_by_username[uname]:
+ print(' <li>'+pw+'</li>')
+ print(' </ul>')
+ print(' </details>')
+ print(' </li>')
+ print(' </ul>')
+ print(' </article>')
+ print(' <article>')
+ print(' <h3>Attempts by IP</h3>')
+ print(' <p>Expand to show corresponding credential combos</p>')
+ print(' <ul>')
+ for ip in login_combos_by_ip:
+ print(' <li>')
+ print(' <details>')
+ print(' <summary>'+ip+' &ndash; '+str(attempt_counts_by_ip[ip])+' Attempts</summary>')
+ print(' <ul>')
+ for combo in login_combos_by_ip[ip]:
+ print(' <li>'+combo[0]+' : '+combo[1]+'</li>')
+ print(' </ul>')
+ print(' </details>')
+ print(' </li>')
+ print(' </ul>')
+ print(' </article>')
+ print(' <article>')
+ print(' <h3>Total Attempts Per Password</h3>')
+ print(' <ul>')
+ for pw in attempt_counts_by_password:
+ if(pw =='[SSH_PUBKEY_ATTEMPT]'):
+ print(' <li style="display: flex; align-items: center; gap: calc(var(--stdpadding) / 2)"><svg style="width: 1.5em;" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="size-6"><path fill-rule="evenodd" d="M15.75 1.5a6.75 6.75 0 0 0-6.651 7.906c.067.39-.032.717-.221.906l-6.5 6.499a3 3 0 0 0-.878 2.121v2.818c0 .414.336.75.75.75H6a.75.75 0 0 0 .75-.75v-1.5h1.5A.75.75 0 0 0 9 19.5V18h1.5a.75.75 0 0 0 .53-.22l2.658-2.658c.19-.189.517-.288.906-.22A6.75 6.75 0 1 0 15.75 1.5Zm0 3a.75.75 0 0 0 0 1.5A2.25 2.25 0 0 1 18 8.25a.75.75 0 0 0 1.5 0 3.75 3.75 0 0 0-3.75-3.75Z" clip-rule="evenodd" /></svg> (SSH Public Key) × '+str(attempt_counts_by_password[pw])+'</li>')
+ else:
+ print(' <li>'+pw+' × '+str(attempt_counts_by_password[pw])+'</li>')
+ print(' </ul>')
+ print(' </article>')
+ if(cnt_eventful > 0):
+ print(' <article>')
+ print(' <h3>')
+ print(' <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="size-6" style="color: var(--pc5); height: 1.2em;">')
+ print(' <path fill-rule="evenodd" d="M2.25 13.5a8.25 8.25 0 0 1 8.25-8.25.75.75 0 0 1 .75.75v6.75H18a.75.75 0 0 1 .75.75 8.25 8.25 0 0 1-16.5 0Z" clip-rule="evenodd" />')
+ print(' <path fill-rule="evenodd" d="M12.75 3a.75.75 0 0 1 .75-.75 8.25 8.25 0 0 1 8.25 8.25.75.75 0 0 1-.75.75h-7.5a.75.75 0 0 1-.75-.75V3Z" clip-rule="evenodd" />')
+ print(' </svg>')
+ print(' Sessions of Particular Note')
+ print(' </h3>')
+ print(' <ul>')
+ for s_id in sessions:
+ session = sessions[s_id]
+ if(session_ran_command(session) and not session_is_cmdping(session)):
+ print(' <li>')
+ print(' '+session_ip(session)+' @ '+session_timestamp(session)[:19].replace('T', ' ')+':')
+ print(' <ul class="sessionlog">')
+ for entry in session:
+ match(entry["eventid"]):
+ case "cowrie.login.failed":
+ print(' <li class="slfail">')
+ print(' <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="size-6"><path fill-rule="evenodd" d="M12 2.25c-5.385 0-9.75 4.365-9.75 9.75s4.365 9.75 9.75 9.75 9.75-4.365 9.75-9.75S17.385 2.25 12 2.25Zm-1.72 6.97a.75.75 0 1 0-1.06 1.06L10.94 12l-1.72 1.72a.75.75 0 1 0 1.06 1.06L12 13.06l1.72 1.72a.75.75 0 1 0 1.06-1.06L13.06 12l1.72-1.72a.75.75 0 1 0-1.06-1.06L12 10.94l-1.72-1.72Z" clip-rule="evenodd" /></svg>')
+ pw = entry['password']
+ if(pw =='[SSH_PUBKEY_ATTEMPT]'):
+ pw = '<svg style="width: 1.5em;" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="size-6"><path fill-rule="evenodd" d="M15.75 1.5a6.75 6.75 0 0 0-6.651 7.906c.067.39-.032.717-.221.906l-6.5 6.499a3 3 0 0 0-.878 2.121v2.818c0 .414.336.75.75.75H6a.75.75 0 0 0 .75-.75v-1.5h1.5A.75.75 0 0 0 9 19.5V18h1.5a.75.75 0 0 0 .53-.22l2.658-2.658c.19-.189.517-.288.906-.22A6.75 6.75 0 1 0 15.75 1.5Zm0 3a.75.75 0 0 0 0 1.5A2.25 2.25 0 0 1 18 8.25a.75.75 0 0 0 1.5 0 3.75 3.75 0 0 0-3.75-3.75Z" clip-rule="evenodd" /></svg> (SSH Public Key)'
+ print(' ' + entry["username"] + ' : ' + pw)
+ print(' </li>')
+ case "cowrie.login.success":
+ print(' <li class="slsuccess">')
+ print(' <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="size-6"><path fill-rule="evenodd" d="M2.25 12c0-5.385 4.365-9.75 9.75-9.75s9.75 4.365 9.75 9.75-4.365 9.75-9.75 9.75S2.25 17.385 2.25 12Zm13.36-1.814a.75.75 0 1 0-1.22-.872l-3.236 4.53L9.53 12.22a.75.75 0 0 0-1.06 1.06l2.25 2.25a.75.75 0 0 0 1.14-.094l3.75-5.25Z" clip-rule="evenodd" /></svg>')
+ pw = entry['password']
+ if(pw =='[SSH_PUBKEY_ATTEMPT]'):
+ pw = '<svg style="width: 1.5em;" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="size-6"><path fill-rule="evenodd" d="M15.75 1.5a6.75 6.75 0 0 0-6.651 7.906c.067.39-.032.717-.221.906l-6.5 6.499a3 3 0 0 0-.878 2.121v2.818c0 .414.336.75.75.75H6a.75.75 0 0 0 .75-.75v-1.5h1.5A.75.75 0 0 0 9 19.5V18h1.5a.75.75 0 0 0 .53-.22l2.658-2.658c.19-.189.517-.288.906-.22A6.75 6.75 0 1 0 15.75 1.5Zm0 3a.75.75 0 0 0 0 1.5A2.25 2.25 0 0 1 18 8.25a.75.75 0 0 0 1.5 0 3.75 3.75 0 0 0-3.75-3.75Z" clip-rule="evenodd" /></svg> (SSH Public Key)'
+ print(' ' + entry["username"] + ' : ' + pw)
+ print(' </li>')
+ case "cowrie.command.input":
+ print(' <li class="slcmd">')
+ print(' <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="size-6"><path fill-rule="evenodd" d="M2.25 6a3 3 0 0 1 3-3h13.5a3 3 0 0 1 3 3v12a3 3 0 0 1-3 3H5.25a3 3 0 0 1-3-3V6Zm3.97.97a.75.75 0 0 1 1.06 0l2.25 2.25a.75.75 0 0 1 0 1.06l-2.25 2.25a.75.75 0 0 1-1.06-1.06l1.72-1.72-1.72-1.72a.75.75 0 0 1 0-1.06Zm4.28 4.28a.75.75 0 0 0 0 1.5h3a.75.75 0 0 0 0-1.5h-3Z" clip-rule="evenodd" /></svg>')
+ print(' <code>'+entry['input']+'</code>')
+ print(' </li>')
+ case "cowrie.session.file_download":
+ df = "file"
+ if("url" in entry):
+ df = entry["url"]
+ elif("destfile" in entry):
+ df = entry["destfile"]
+ print(' <li class="slsave">')
+ print(' <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="size-6"><path fill-rule="evenodd" d="M12 2.25a.75.75 0 0 1 .75.75v11.69l3.22-3.22a.75.75 0 1 1 1.06 1.06l-4.5 4.5a.75.75 0 0 1-1.06 0l-4.5-4.5a.75.75 0 1 1 1.06-1.06l3.22 3.22V3a.75.75 0 0 1 .75-.75Zm-9 13.5a.75.75 0 0 1 .75.75v2.25a1.5 1.5 0 0 0 1.5 1.5h13.5a1.5 1.5 0 0 0 1.5-1.5V16.5a.75.75 0 0 1 1.5 0v2.25a3 3 0 0 1-3 3H5.25a3 3 0 0 1-3-3V16.5a.75.75 0 0 1 .75-.75Z" clip-rule="evenodd" /></svg>')
+ print(' Saved '+df+' to '+entry["outfile"][:50]+'...')
+ print(' </li>')
+ print(' <li class="slend">')
+ print(' <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="size-6"><path fill-rule="evenodd" d="M5.47 5.47a.75.75 0 0 1 1.06 0L12 10.94l5.47-5.47a.75.75 0 1 1 1.06 1.06L13.06 12l5.47 5.47a.75.75 0 1 1-1.06 1.06L12 13.06l-5.47 5.47a.75.75 0 0 1-1.06-1.06L10.94 12 5.47 6.53a.75.75 0 0 1 0-1.06Z" clip-rule="evenodd" /></svg>')
+ print(' Closed after '+str(session_duration(session))+'s')
+ print(' </li>')
+ print(' </ul>')
+ print(' </li>')
+ print(' </ul>')
+ print(' </article>')
+ print(' </section>')
+ print(' </main>')
+ print(' <footer><span>Generated by Cowrieder</span> <a href="https://git.isopod.cool/root/cowrieder">Source</a> <a href="https://www.cowrie.org/">Cowrie</a> <a href="https://www.svgrepo.com/svg/423906/bee-origami-paper">Bee</a> <a href="https://heroicons.com/solid">Other Icons</a> <a href="https://github.com/sainnhe/sonokai">Colours</a> <span style="text-align: right; flex: 1;">🏳️‍⚧️ 🇵🇸</span></footer>')
+ print('</body>') \ No newline at end of file