modified krawl template for single page visualization
This commit is contained in:
@@ -156,11 +156,35 @@ def generate_dashboard(stats: dict) -> str:
|
|||||||
background: #1c1917;
|
background: #1c1917;
|
||||||
border-left: 4px solid #f85149;
|
border-left: 4px solid #f85149;
|
||||||
}}
|
}}
|
||||||
|
th.sortable {{
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
position: relative;
|
||||||
|
padding-right: 24px;
|
||||||
|
}}
|
||||||
|
th.sortable:hover {{
|
||||||
|
background: #1c2128;
|
||||||
|
}}
|
||||||
|
th.sortable::after {{
|
||||||
|
content: '⇅';
|
||||||
|
position: absolute;
|
||||||
|
right: 8px;
|
||||||
|
opacity: 0.5;
|
||||||
|
font-size: 12px;
|
||||||
|
}}
|
||||||
|
th.sortable.asc::after {{
|
||||||
|
content: '▲';
|
||||||
|
opacity: 1;
|
||||||
|
}}
|
||||||
|
th.sortable.desc::after {{
|
||||||
|
content: '▼';
|
||||||
|
opacity: 1;
|
||||||
|
}}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h1>🕷️ Krawl Dashboard</h1>
|
<h1>Krawl Dashboard</h1>
|
||||||
|
|
||||||
<div class="stats-grid">
|
<div class="stats-grid">
|
||||||
<div class="stat-card">
|
<div class="stat-card">
|
||||||
@@ -190,13 +214,13 @@ def generate_dashboard(stats: dict) -> str:
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="table-container alert-section">
|
<div class="table-container alert-section">
|
||||||
<h2>🍯 Honeypot Triggers by IP</h2>
|
<h2>Honeypot Triggers by IP</h2>
|
||||||
<table>
|
<table id="honeypot-table">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>IP Address</th>
|
<th class="sortable" data-sort="ip">IP Address</th>
|
||||||
<th>Accessed Paths</th>
|
<th>Accessed Paths</th>
|
||||||
<th>Count</th>
|
<th class="sortable" data-sort="count">Count</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@@ -206,7 +230,7 @@ def generate_dashboard(stats: dict) -> str:
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="table-container alert-section">
|
<div class="table-container alert-section">
|
||||||
<h2>⚠️ Recent Suspicious Activity</h2>
|
<h2>Recent Suspicious Activity</h2>
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
@@ -223,7 +247,7 @@ def generate_dashboard(stats: dict) -> str:
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="table-container alert-section">
|
<div class="table-container alert-section">
|
||||||
<h2>🔑 Captured Credentials</h2>
|
<h2>Captured Credentials</h2>
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
@@ -241,7 +265,7 @@ def generate_dashboard(stats: dict) -> str:
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="table-container alert-section">
|
<div class="table-container alert-section">
|
||||||
<h2>😈 Detected Attack Types</h2>
|
<h2>Detected Attack Types</h2>
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
@@ -306,6 +330,64 @@ def generate_dashboard(stats: dict) -> str:
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<script>
|
||||||
|
// Add sorting functionality to tables
|
||||||
|
document.querySelectorAll('th.sortable').forEach(header => {{
|
||||||
|
header.addEventListener('click', function() {{
|
||||||
|
const table = this.closest('table');
|
||||||
|
const tbody = table.querySelector('tbody');
|
||||||
|
const rows = Array.from(tbody.querySelectorAll('tr'));
|
||||||
|
const sortType = this.getAttribute('data-sort');
|
||||||
|
const columnIndex = Array.from(this.parentElement.children).indexOf(this);
|
||||||
|
|
||||||
|
// Determine sort direction
|
||||||
|
const isAscending = this.classList.contains('asc');
|
||||||
|
|
||||||
|
// Remove sort classes from all headers in this table
|
||||||
|
table.querySelectorAll('th.sortable').forEach(th => {{
|
||||||
|
th.classList.remove('asc', 'desc');
|
||||||
|
}});
|
||||||
|
|
||||||
|
// Add appropriate class to clicked header
|
||||||
|
this.classList.add(isAscending ? 'desc' : 'asc');
|
||||||
|
|
||||||
|
// Sort rows
|
||||||
|
rows.sort((a, b) => {{
|
||||||
|
let aValue = a.cells[columnIndex].textContent.trim();
|
||||||
|
let bValue = b.cells[columnIndex].textContent.trim();
|
||||||
|
|
||||||
|
// Handle numeric sorting
|
||||||
|
if (sortType === 'count') {{
|
||||||
|
aValue = parseInt(aValue) || 0;
|
||||||
|
bValue = parseInt(bValue) || 0;
|
||||||
|
return isAscending ? bValue - aValue : aValue - bValue;
|
||||||
|
}}
|
||||||
|
|
||||||
|
// Handle IP address sorting
|
||||||
|
if (sortType === 'ip') {{
|
||||||
|
const ipToNum = ip => {{
|
||||||
|
const parts = ip.split('.');
|
||||||
|
if (parts.length !== 4) return 0;
|
||||||
|
return parts.reduce((acc, part, i) => acc + (parseInt(part) || 0) * Math.pow(256, 3 - i), 0);
|
||||||
|
}};
|
||||||
|
const aNum = ipToNum(aValue);
|
||||||
|
const bNum = ipToNum(bValue);
|
||||||
|
return isAscending ? bNum - aNum : aNum - bNum;
|
||||||
|
}}
|
||||||
|
|
||||||
|
// Default string sorting
|
||||||
|
if (isAscending) {{
|
||||||
|
return bValue.localeCompare(aValue);
|
||||||
|
}} else {{
|
||||||
|
return aValue.localeCompare(bValue);
|
||||||
|
}}
|
||||||
|
}});
|
||||||
|
|
||||||
|
// Re-append sorted rows
|
||||||
|
rows.forEach(row => tbody.appendChild(row));
|
||||||
|
}});
|
||||||
|
}});
|
||||||
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -9,40 +9,64 @@
|
|||||||
background-color: #0d1117;
|
background-color: #0d1117;
|
||||||
color: #c9d1d9;
|
color: #c9d1d9;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 40px 20px;
|
padding: 0;
|
||||||
min-height: 100vh;
|
height: 100vh;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
overflow: hidden;
|
||||||
}}
|
}}
|
||||||
.container {{
|
.container {{
|
||||||
max-width: 1200px;
|
max-width: 1200px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
padding: 20px;
|
||||||
|
box-sizing: border-box;
|
||||||
}}
|
}}
|
||||||
h1 {{
|
h1 {{
|
||||||
color: #f85149;
|
color: #f85149;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 48px;
|
font-size: 36px;
|
||||||
margin: 60px 0 30px;
|
margin: 40px 0 20px 0;
|
||||||
|
flex-shrink: 0;
|
||||||
}}
|
}}
|
||||||
.counter {{
|
.counter {{
|
||||||
color: #f85149;
|
color: #f85149;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 56px;
|
font-size: 32px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
margin-bottom: 60px;
|
margin: 0 0 30px 0;
|
||||||
|
flex-shrink: 0;
|
||||||
}}
|
}}
|
||||||
.links-container {{
|
.links-container {{
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 20px;
|
gap: 10px;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
overflow-y: auto;
|
||||||
|
flex: 1;
|
||||||
|
padding-top: 10px;
|
||||||
|
}}
|
||||||
|
.links-container::-webkit-scrollbar {{
|
||||||
|
width: 8px;
|
||||||
|
}}
|
||||||
|
.links-container::-webkit-scrollbar-track {{
|
||||||
|
background: #0d1117;
|
||||||
|
}}
|
||||||
|
.links-container::-webkit-scrollbar-thumb {{
|
||||||
|
background: #30363d;
|
||||||
|
border-radius: 4px;
|
||||||
|
}}
|
||||||
|
.links-container::-webkit-scrollbar-thumb:hover {{
|
||||||
|
background: #484f58;
|
||||||
}}
|
}}
|
||||||
.link-box {{
|
.link-box {{
|
||||||
background: #161b22;
|
background: #161b22;
|
||||||
border: 1px solid #30363d;
|
border: 1px solid #30363d;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
padding: 15px 30px;
|
padding: 10px 20px;
|
||||||
min-width: 300px;
|
min-width: 300px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
transition: all 0.3s ease;
|
transition: all 0.3s ease;
|
||||||
@@ -56,7 +80,7 @@
|
|||||||
a {{
|
a {{
|
||||||
color: #58a6ff;
|
color: #58a6ff;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
font-size: 20px;
|
font-size: 16px;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
}}
|
}}
|
||||||
a:hover {{
|
a:hover {{
|
||||||
@@ -66,21 +90,21 @@
|
|||||||
background: #1c1917;
|
background: #1c1917;
|
||||||
border: 2px solid #f85149;
|
border: 2px solid #f85149;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
padding: 30px 50px;
|
padding: 20px 30px;
|
||||||
margin: 40px auto;
|
margin: 20px auto;
|
||||||
max-width: 800px;
|
max-width: 800px;
|
||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
}}
|
}}
|
||||||
.canary-token a {{
|
.canary-token a {{
|
||||||
color: #f85149;
|
color: #f85149;
|
||||||
font-size: 18px;
|
font-size: 14px;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}}
|
}}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h1>Krawl me! 🕸</h1>
|
<h1>Krawl me!</h1>
|
||||||
<div class="counter">{counter}</div>
|
<div class="counter">{counter}</div>
|
||||||
|
|
||||||
<div class="links-container">
|
<div class="links-container">
|
||||||
|
|||||||
@@ -125,6 +125,7 @@ class Wordlists:
|
|||||||
def server_errors(self):
|
def server_errors(self):
|
||||||
return self._data.get("server_errors", {})
|
return self._data.get("server_errors", {})
|
||||||
|
|
||||||
|
@property
|
||||||
def server_headers(self):
|
def server_headers(self):
|
||||||
return self._data.get("server_headers", [])
|
return self._data.get("server_headers", [])
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user