v2.2.0 — Full arsenal expansion: 16 new security modules
Add WiFi Audit, API Fuzzer, Cloud Scanner, Threat Intel, Log Correlator,
Steganography, Anti-Forensics, BLE Scanner, Forensics, RFID/NFC, Malware
Sandbox, Password Toolkit, Web Scanner, Report Engine, Net Mapper, and
C2 Framework. Each module includes CLI interface, Flask routes, and web
UI template. Also includes Go DNS server source + binary, IP Capture
service, SYN Flood, Gone Fishing mail server, and hack hijack modules
from v2.0 work.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 05:16:31 -08:00
|
|
|
{% extends "base.html" %}
|
|
|
|
|
{% block title %}Password Toolkit — AUTARCH{% endblock %}
|
|
|
|
|
{% block content %}
|
|
|
|
|
<div class="page-header">
|
|
|
|
|
<h1>Password Toolkit</h1>
|
|
|
|
|
<p class="text-muted">Hash identification, cracking, generation, and credential testing</p>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="tabs">
|
|
|
|
|
<button class="tab active" onclick="switchTab('identify')">Identify</button>
|
|
|
|
|
<button class="tab" onclick="switchTab('crack')">Crack</button>
|
|
|
|
|
<button class="tab" onclick="switchTab('generate')">Generate</button>
|
|
|
|
|
<button class="tab" onclick="switchTab('spray')">Spray</button>
|
|
|
|
|
<button class="tab" onclick="switchTab('wordlists')">Wordlists</button>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- Identify Tab -->
|
|
|
|
|
<div id="tab-identify" class="tab-content active">
|
|
|
|
|
<div class="card" style="max-width:800px">
|
|
|
|
|
<h3>Hash Identification</h3>
|
|
|
|
|
<div class="form-group">
|
|
|
|
|
<label>Hash (one per line for batch)</label>
|
|
|
|
|
<textarea id="id-hash" class="form-control" rows="3" placeholder="e3b0c44298fc1c149afbf4c8996fb924..."></textarea>
|
|
|
|
|
</div>
|
|
|
|
|
<button class="btn btn-primary" onclick="identifyHash()">Identify</button>
|
|
|
|
|
<div id="id-results" style="margin-top:1rem"></div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="card" style="margin-top:1rem;max-width:800px">
|
|
|
|
|
<h3>Hash a String</h3>
|
|
|
|
|
<div style="display:flex;gap:0.5rem;align-items:end">
|
|
|
|
|
<div class="form-group" style="flex:1;margin:0">
|
|
|
|
|
<label>Plaintext</label>
|
|
|
|
|
<input type="text" id="hash-plaintext" class="form-control" placeholder="text to hash">
|
|
|
|
|
</div>
|
|
|
|
|
<div class="form-group" style="width:140px;margin:0">
|
|
|
|
|
<label>Algorithm</label>
|
|
|
|
|
<select id="hash-algo" class="form-control">
|
|
|
|
|
<option value="md5">MD5</option>
|
|
|
|
|
<option value="sha1">SHA-1</option>
|
|
|
|
|
<option value="sha256" selected>SHA-256</option>
|
|
|
|
|
<option value="sha512">SHA-512</option>
|
|
|
|
|
</select>
|
|
|
|
|
</div>
|
|
|
|
|
<button class="btn btn-primary" onclick="hashString()" style="height:38px">Hash</button>
|
|
|
|
|
</div>
|
|
|
|
|
<div id="hash-result" style="margin-top:0.5rem;font-family:monospace;font-size:0.85rem;word-break:break-all"></div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- Crack Tab -->
|
|
|
|
|
<div id="tab-crack" class="tab-content" style="display:none">
|
|
|
|
|
<div class="card" style="max-width:800px">
|
|
|
|
|
<h3>Hash Cracker</h3>
|
|
|
|
|
<div class="form-group">
|
|
|
|
|
<label>Hash</label>
|
|
|
|
|
<input type="text" id="crack-hash" class="form-control" placeholder="hash to crack">
|
|
|
|
|
</div>
|
|
|
|
|
<div style="display:grid;grid-template-columns:1fr 1fr;gap:0.5rem">
|
|
|
|
|
<div class="form-group">
|
|
|
|
|
<label>Hash Type</label>
|
|
|
|
|
<select id="crack-type" class="form-control">
|
|
|
|
|
<option value="auto">Auto-detect</option>
|
|
|
|
|
<option value="MD5">MD5</option>
|
|
|
|
|
<option value="SHA-1">SHA-1</option>
|
|
|
|
|
<option value="SHA-256">SHA-256</option>
|
|
|
|
|
<option value="SHA-512">SHA-512</option>
|
|
|
|
|
<option value="NTLM">NTLM</option>
|
|
|
|
|
<option value="bcrypt">bcrypt</option>
|
|
|
|
|
<option value="SHA-512 Crypt">SHA-512 Crypt</option>
|
|
|
|
|
<option value="MySQL 4.1+">MySQL 4.1+</option>
|
|
|
|
|
</select>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="form-group">
|
|
|
|
|
<label>Attack Mode</label>
|
|
|
|
|
<select id="crack-mode" class="form-control">
|
|
|
|
|
<option value="dictionary">Dictionary</option>
|
|
|
|
|
<option value="brute_force">Brute Force</option>
|
|
|
|
|
<option value="mask">Mask</option>
|
|
|
|
|
<option value="hybrid">Hybrid</option>
|
|
|
|
|
</select>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="form-group">
|
|
|
|
|
<label>Tool</label>
|
|
|
|
|
<select id="crack-tool" class="form-control">
|
|
|
|
|
<option value="auto">Auto (hashcat → john → python)</option>
|
|
|
|
|
<option value="hashcat">hashcat</option>
|
|
|
|
|
<option value="john">John the Ripper</option>
|
|
|
|
|
</select>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="form-group">
|
|
|
|
|
<label>Mask (for mask/brute)</label>
|
|
|
|
|
<input type="text" id="crack-mask" class="form-control" placeholder="?a?a?a?a?a?a?a?a">
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<button class="btn btn-primary" onclick="startCrack()">Crack</button>
|
|
|
|
|
<div id="crack-status" style="margin-top:1rem"></div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="card" style="margin-top:1rem;max-width:800px">
|
|
|
|
|
<h3>Available Tools</h3>
|
|
|
|
|
<div id="tools-status" style="font-size:0.85rem">Loading...</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- Generate Tab -->
|
|
|
|
|
<div id="tab-generate" class="tab-content" style="display:none">
|
|
|
|
|
<div class="card" style="max-width:800px">
|
|
|
|
|
<h3>Password Generator</h3>
|
|
|
|
|
<div style="display:grid;grid-template-columns:1fr 1fr;gap:0.5rem">
|
|
|
|
|
<div class="form-group">
|
|
|
|
|
<label>Length</label>
|
|
|
|
|
<input type="number" id="gen-length" class="form-control" value="16" min="4" max="128">
|
|
|
|
|
</div>
|
|
|
|
|
<div class="form-group">
|
|
|
|
|
<label>Count</label>
|
|
|
|
|
<input type="number" id="gen-count" class="form-control" value="5" min="1" max="50">
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div style="display:flex;gap:1rem;margin:0.5rem 0;font-size:0.85rem;flex-wrap:wrap">
|
|
|
|
|
<label><input type="checkbox" id="gen-upper" checked> Uppercase</label>
|
|
|
|
|
<label><input type="checkbox" id="gen-lower" checked> Lowercase</label>
|
|
|
|
|
<label><input type="checkbox" id="gen-digits" checked> Digits</label>
|
|
|
|
|
<label><input type="checkbox" id="gen-symbols" checked> Symbols</label>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="form-group">
|
|
|
|
|
<label>Pattern (optional — ?u=upper ?l=lower ?d=digit ?s=symbol ?a=any)</label>
|
|
|
|
|
<input type="text" id="gen-pattern" class="form-control" placeholder="?u?l?l?l?l?d?d?s">
|
|
|
|
|
</div>
|
|
|
|
|
<button class="btn btn-primary" onclick="generatePw()">Generate</button>
|
|
|
|
|
<div id="gen-results" style="margin-top:1rem"></div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="card" style="margin-top:1rem;max-width:800px">
|
|
|
|
|
<h3>Password Strength Auditor</h3>
|
|
|
|
|
<div style="display:flex;gap:0.5rem;align-items:end">
|
|
|
|
|
<div class="form-group" style="flex:1;margin:0">
|
|
|
|
|
<input type="text" id="audit-pw" class="form-control" placeholder="password to audit" oninput="liveAudit()">
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div id="audit-result" style="margin-top:0.5rem"></div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- Spray Tab -->
|
|
|
|
|
<div id="tab-spray" class="tab-content" style="display:none">
|
|
|
|
|
<div class="card" style="max-width:800px">
|
|
|
|
|
<h3>Credential Spray</h3>
|
|
|
|
|
<div class="form-group">
|
|
|
|
|
<label>Targets (one per line: host:port:username)</label>
|
|
|
|
|
<textarea id="spray-targets" class="form-control" rows="4" placeholder="192.168.1.100:22:admin 192.168.1.101:22:root"></textarea>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="form-group">
|
|
|
|
|
<label>Passwords (one per line)</label>
|
|
|
|
|
<textarea id="spray-passwords" class="form-control" rows="4" placeholder="admin password 123456 root"></textarea>
|
|
|
|
|
</div>
|
|
|
|
|
<div style="display:grid;grid-template-columns:1fr 1fr;gap:0.5rem">
|
|
|
|
|
<div class="form-group">
|
|
|
|
|
<label>Protocol</label>
|
|
|
|
|
<select id="spray-proto" class="form-control">
|
|
|
|
|
<option value="ssh">SSH</option>
|
|
|
|
|
<option value="ftp">FTP</option>
|
|
|
|
|
<option value="smb">SMB</option>
|
|
|
|
|
</select>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="form-group">
|
|
|
|
|
<label>Delay (seconds)</label>
|
|
|
|
|
<input type="number" id="spray-delay" class="form-control" value="1" min="0" step="0.5">
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<button class="btn btn-primary" onclick="startSpray()">Start Spray</button>
|
|
|
|
|
<div id="spray-status" style="margin-top:1rem"></div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- Wordlists Tab -->
|
|
|
|
|
<div id="tab-wordlists" class="tab-content" style="display:none">
|
|
|
|
|
<div class="card" style="max-width:800px">
|
|
|
|
|
<h3>Wordlist Management</h3>
|
|
|
|
|
<div style="display:flex;gap:0.5rem;align-items:end;margin-bottom:1rem">
|
|
|
|
|
<input type="file" id="wl-upload" class="form-control" style="flex:1">
|
|
|
|
|
<button class="btn btn-primary" onclick="uploadWordlist()">Upload</button>
|
|
|
|
|
</div>
|
|
|
|
|
<div id="wl-list"></div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<style>
|
|
|
|
|
.strength-bar{height:6px;border-radius:3px;background:var(--bg-input);margin:4px 0;overflow:hidden}
|
|
|
|
|
.strength-fill{height:100%;border-radius:3px;transition:width 0.3s}
|
|
|
|
|
.str-very_weak .strength-fill{width:15%;background:#ef4444}
|
|
|
|
|
.str-weak .strength-fill{width:35%;background:#f59e0b}
|
|
|
|
|
.str-medium .strength-fill{width:55%;background:#eab308}
|
|
|
|
|
.str-strong .strength-fill{width:75%;background:#22c55e}
|
|
|
|
|
.str-very_strong .strength-fill{width:100%;background:#10b981}
|
|
|
|
|
.pw-row{display:flex;align-items:center;gap:0.5rem;padding:0.3rem 0;font-family:monospace;font-size:0.85rem}
|
|
|
|
|
.pw-row .copy-btn{cursor:pointer;color:var(--accent);font-size:0.75rem}
|
|
|
|
|
</style>
|
|
|
|
|
|
|
|
|
|
<script>
|
|
|
|
|
let crackPoll=null,sprayPoll=null;
|
|
|
|
|
|
|
|
|
|
function switchTab(name){
|
|
|
|
|
document.querySelectorAll('.tab').forEach((t,i)=>t.classList.toggle('active',
|
|
|
|
|
['identify','crack','generate','spray','wordlists'][i]===name));
|
|
|
|
|
document.querySelectorAll('.tab-content').forEach(c=>c.style.display='none');
|
Add Port Scanner, fix Hack Hijack SSE, fix debug console, fix tab layout bugs
- Add advanced Port Scanner with live SSE output, nmap integration, result export
- Add Port Scanner to sidebar nav and register blueprint
- Fix Hack Hijack scan: replace polling with SSE streaming, add live output box
and real-time port discovery table; add port_found_cb/status_cb to module
- Fix debug console: capture print()/stdout/stderr via _PrintCapture wrapper,
install handler at startup (not just on toggle), fix SSE stream history replay
- Add missing CSS: .card, .tabs, .btn-sm, .form-control, --primary, --surface
- Fix tab switching bug: style.display='' falls back to CSS display:none;
use explicit 'block' in hack_hijack, c2_framework, net_mapper, password_toolkit,
report_engine, social_eng, webapp_scanner
- Fix defense/linux layout: rewrite with card-based layout, remove slow
load_modules() call on every page request
- Fix sms_forge missing run() function warning on startup
- Fix port scanner JS: </style> was used instead of </script> closing tag
- Port scanner advanced options: remove collapsible toggle, show as always-visible bar
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-08 18:09:49 -07:00
|
|
|
document.getElementById('tab-'+name).style.display='block';
|
v2.2.0 — Full arsenal expansion: 16 new security modules
Add WiFi Audit, API Fuzzer, Cloud Scanner, Threat Intel, Log Correlator,
Steganography, Anti-Forensics, BLE Scanner, Forensics, RFID/NFC, Malware
Sandbox, Password Toolkit, Web Scanner, Report Engine, Net Mapper, and
C2 Framework. Each module includes CLI interface, Flask routes, and web
UI template. Also includes Go DNS server source + binary, IP Capture
service, SYN Flood, Gone Fishing mail server, and hack hijack modules
from v2.0 work.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 05:16:31 -08:00
|
|
|
if(name==='crack') loadTools();
|
|
|
|
|
if(name==='wordlists') loadWordlists();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function identifyHash(){
|
|
|
|
|
const text=document.getElementById('id-hash').value.trim();
|
|
|
|
|
if(!text) return;
|
|
|
|
|
const hashes=text.split('\n').map(h=>h.trim()).filter(Boolean);
|
|
|
|
|
const payload=hashes.length===1?{hash:hashes[0]}:{hashes};
|
|
|
|
|
fetch('/password-toolkit/identify',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(payload)})
|
|
|
|
|
.then(r=>r.json()).then(d=>{
|
|
|
|
|
const div=document.getElementById('id-results');
|
|
|
|
|
if(d.types){
|
|
|
|
|
div.innerHTML=d.types.length?d.types.map(t=>`<div style="padding:4px 0">
|
|
|
|
|
<span class="conf-${t.confidence}" style="display:inline-block;width:70px">${t.confidence.toUpperCase()}</span>
|
|
|
|
|
<strong>${t.name}</strong>
|
|
|
|
|
<span style="color:var(--text-muted);font-size:0.8rem;margin-left:0.5rem">hashcat: ${t.hashcat_mode} | john: ${t.john_format||'—'}</span>
|
|
|
|
|
</div>`).join(''):'<div style="color:var(--text-muted)">No matching hash types</div>';
|
|
|
|
|
} else if(d.results){
|
|
|
|
|
div.innerHTML=d.results.map(r=>`<div style="margin-bottom:0.5rem;border-bottom:1px solid var(--border);padding-bottom:0.5rem">
|
|
|
|
|
<code style="font-size:0.8rem">${esc(r.hash)}</code><br>
|
|
|
|
|
${r.types.length?r.types.map(t=>`<span class="conf-${t.confidence}">${t.confidence.toUpperCase()}</span> ${t.name} `).join(' | '):'<span style="color:var(--text-muted)">Unknown</span>'}
|
|
|
|
|
</div>`).join('');
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function hashString(){
|
|
|
|
|
const plaintext=document.getElementById('hash-plaintext').value;
|
|
|
|
|
const algo=document.getElementById('hash-algo').value;
|
|
|
|
|
fetch('/password-toolkit/hash',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({plaintext,algorithm:algo})})
|
|
|
|
|
.then(r=>r.json()).then(d=>{
|
|
|
|
|
document.getElementById('hash-result').innerHTML=d.ok?
|
|
|
|
|
`<strong>${d.algorithm}:</strong> ${d.hash} <span class="copy-btn" onclick="navigator.clipboard.writeText('${d.hash}')">[copy]</span>`
|
|
|
|
|
:`Error: ${d.error}`;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function startCrack(){
|
|
|
|
|
const hash=document.getElementById('crack-hash').value.trim();
|
|
|
|
|
if(!hash) return;
|
|
|
|
|
const payload={hash,hash_type:document.getElementById('crack-type').value,
|
|
|
|
|
attack_mode:document.getElementById('crack-mode').value,
|
|
|
|
|
tool:document.getElementById('crack-tool').value,
|
|
|
|
|
mask:document.getElementById('crack-mask').value};
|
|
|
|
|
const div=document.getElementById('crack-status');
|
|
|
|
|
div.innerHTML='<div class="spinner-inline"></div> Cracking...';
|
|
|
|
|
fetch('/password-toolkit/crack',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(payload)})
|
|
|
|
|
.then(r=>r.json()).then(d=>{
|
|
|
|
|
if(d.cracked){
|
|
|
|
|
div.innerHTML=`<div style="color:#22c55e;font-weight:700">CRACKED: ${esc(d.cracked)}</div>
|
|
|
|
|
${d.message?'<div>'+esc(d.message)+'</div>':''}`;
|
|
|
|
|
} else if(d.job_id){
|
|
|
|
|
div.innerHTML='<div class="spinner-inline"></div> '+esc(d.message);
|
|
|
|
|
if(crackPoll) clearInterval(crackPoll);
|
|
|
|
|
crackPoll=setInterval(()=>{
|
|
|
|
|
fetch('/password-toolkit/crack/'+d.job_id).then(r=>r.json()).then(s=>{
|
|
|
|
|
if(!s.done) return;
|
|
|
|
|
clearInterval(crackPoll);crackPoll=null;
|
|
|
|
|
if(s.cracked) div.innerHTML=`<div style="color:#22c55e;font-weight:700">CRACKED: ${esc(s.cracked)}</div>`;
|
|
|
|
|
else div.innerHTML=`<div style="color:var(--text-muted)">Not cracked. ${esc(s.message||'')}</div>`;
|
|
|
|
|
});
|
|
|
|
|
},2000);
|
|
|
|
|
} else {
|
|
|
|
|
div.innerHTML=`<div style="color:var(--text-muted)">${esc(d.message||d.error||'No result')}</div>`;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function loadTools(){
|
|
|
|
|
fetch('/password-toolkit/tools').then(r=>r.json()).then(d=>{
|
|
|
|
|
const div=document.getElementById('tools-status');
|
|
|
|
|
div.innerHTML=['hashcat','john','hydra','ncrack'].map(t=>{
|
|
|
|
|
const ok=d[t];
|
|
|
|
|
return `<span style="margin-right:1rem">${ok?'<span style="color:#22c55e">✓</span>':'<span style="color:var(--danger)">✗</span>'} ${t}</span>`;
|
|
|
|
|
}).join('');
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function generatePw(){
|
|
|
|
|
const payload={length:+document.getElementById('gen-length').value,
|
|
|
|
|
count:+document.getElementById('gen-count').value,
|
|
|
|
|
uppercase:document.getElementById('gen-upper').checked,
|
|
|
|
|
lowercase:document.getElementById('gen-lower').checked,
|
|
|
|
|
digits:document.getElementById('gen-digits').checked,
|
|
|
|
|
symbols:document.getElementById('gen-symbols').checked,
|
|
|
|
|
pattern:document.getElementById('gen-pattern').value};
|
|
|
|
|
fetch('/password-toolkit/generate',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(payload)})
|
|
|
|
|
.then(r=>r.json()).then(d=>{
|
|
|
|
|
if(!d.ok) return;
|
|
|
|
|
document.getElementById('gen-results').innerHTML=d.passwords.map(p=>`<div class="pw-row">
|
|
|
|
|
<code>${esc(p.password)}</code>
|
|
|
|
|
<span class="copy-btn" onclick="navigator.clipboard.writeText('${esc(p.password)}')">[copy]</span>
|
|
|
|
|
<span style="font-size:0.75rem;color:var(--text-muted)">${p.entropy} bits — ${p.strength}</span>
|
|
|
|
|
<div class="strength-bar str-${p.strength}" style="width:100px"><div class="strength-fill"></div></div>
|
|
|
|
|
</div>`).join('');
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let auditTimer=null;
|
|
|
|
|
function liveAudit(){
|
|
|
|
|
if(auditTimer) clearTimeout(auditTimer);
|
|
|
|
|
auditTimer=setTimeout(()=>{
|
|
|
|
|
const pw=document.getElementById('audit-pw').value;
|
|
|
|
|
if(!pw){document.getElementById('audit-result').innerHTML='';return}
|
|
|
|
|
fetch('/password-toolkit/audit',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({password:pw})})
|
|
|
|
|
.then(r=>r.json()).then(d=>{
|
|
|
|
|
if(!d.ok) return;
|
|
|
|
|
const colors={very_weak:'#ef4444',weak:'#f59e0b',medium:'#eab308',strong:'#22c55e',very_strong:'#10b981'};
|
|
|
|
|
document.getElementById('audit-result').innerHTML=`
|
|
|
|
|
<div style="display:flex;gap:1rem;align-items:center;margin-bottom:0.5rem">
|
|
|
|
|
<strong style="color:${colors[d.strength]}">${d.strength.replace('_',' ').toUpperCase()}</strong>
|
|
|
|
|
<span>${d.entropy} bits entropy</span>
|
|
|
|
|
<span>charset: ${d.charset_size}</span>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="strength-bar str-${d.strength}" style="width:200px"><div class="strength-fill"></div></div>
|
|
|
|
|
<div style="font-size:0.8rem;margin-top:0.5rem">${Object.entries(d.checks).map(([k,v])=>
|
|
|
|
|
`<span style="margin-right:0.75rem">${v?'<span style="color:#22c55e">✓</span>':'<span style="color:var(--danger)">✗</span>'} ${k.replace(/_/g,' ')}</span>`
|
|
|
|
|
).join('')}</div>`;
|
|
|
|
|
});
|
|
|
|
|
},300);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function startSpray(){
|
|
|
|
|
const targets=document.getElementById('spray-targets').value.trim().split('\n').filter(Boolean).map(l=>{
|
|
|
|
|
const p=l.split(':');return{host:p[0],port:+(p[1]||22),username:p[2]||'admin'}});
|
|
|
|
|
const passwords=document.getElementById('spray-passwords').value.trim().split('\n').filter(Boolean);
|
|
|
|
|
const payload={targets,passwords,protocol:document.getElementById('spray-proto').value,
|
|
|
|
|
delay:+document.getElementById('spray-delay').value};
|
|
|
|
|
const div=document.getElementById('spray-status');
|
|
|
|
|
div.innerHTML='<div class="spinner-inline"></div> Starting spray...';
|
|
|
|
|
fetch('/password-toolkit/spray',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(payload)})
|
|
|
|
|
.then(r=>r.json()).then(d=>{
|
|
|
|
|
if(!d.ok){div.innerHTML='Error: '+esc(d.error);return}
|
|
|
|
|
if(sprayPoll) clearInterval(sprayPoll);
|
|
|
|
|
sprayPoll=setInterval(()=>{
|
|
|
|
|
fetch('/password-toolkit/spray/'+d.job_id).then(r=>r.json()).then(s=>{
|
|
|
|
|
let html=`<div>Progress: ${s.tested}/${s.total}</div>`;
|
|
|
|
|
if(s.found&&s.found.length) html+=`<div style="color:#22c55e;font-weight:700;margin-top:0.5rem">Found credentials:</div>`+
|
|
|
|
|
s.found.map(c=>`<div style="font-family:monospace">${c.protocol}://${esc(c.username)}:${esc(c.password)}@${esc(c.host)}:${c.port}</div>`).join('');
|
|
|
|
|
if(s.done){clearInterval(sprayPoll);sprayPoll=null;html+='<div style="margin-top:0.5rem;color:var(--text-muted)">Spray complete.</div>'}
|
|
|
|
|
else html='<div class="spinner-inline"></div> '+html;
|
|
|
|
|
div.innerHTML=html;
|
|
|
|
|
});
|
|
|
|
|
},2000);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function loadWordlists(){
|
|
|
|
|
fetch('/password-toolkit/wordlists').then(r=>r.json()).then(d=>{
|
|
|
|
|
const div=document.getElementById('wl-list');
|
|
|
|
|
const wls=d.wordlists||[];
|
|
|
|
|
if(!wls.length){div.innerHTML='<div style="color:var(--text-muted)">No wordlists found. Upload one or install rockyou.txt.</div>';return}
|
|
|
|
|
div.innerHTML='<table class="data-table"><thead><tr><th>Name</th><th>Size</th><th>Lines</th><th></th></tr></thead><tbody>'+
|
|
|
|
|
wls.map(w=>`<tr><td>${esc(w.name)}${w.system?' <span style="color:var(--text-muted);font-size:0.75rem">[system]</span>':''}</td>
|
|
|
|
|
<td>${w.size_human}</td><td>${w.lines>=0?w.lines.toLocaleString():'—'}</td>
|
|
|
|
|
<td>${w.system?'':'<button class="btn btn-sm" style="color:var(--danger)" onclick="deleteWordlist(\''+esc(w.name)+'\')">Delete</button>'}</td></tr>`).join('')+
|
|
|
|
|
'</tbody></table>';
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function uploadWordlist(){
|
|
|
|
|
const input=document.getElementById('wl-upload');
|
|
|
|
|
if(!input.files.length) return;
|
|
|
|
|
const fd=new FormData();fd.append('file',input.files[0]);
|
|
|
|
|
fetch('/password-toolkit/wordlists',{method:'POST',body:fd})
|
|
|
|
|
.then(r=>r.json()).then(d=>{
|
|
|
|
|
if(d.ok) loadWordlists();
|
|
|
|
|
else alert(d.error);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function deleteWordlist(name){
|
|
|
|
|
if(!confirm('Delete wordlist: '+name+'?')) return;
|
|
|
|
|
fetch('/password-toolkit/wordlists/'+encodeURIComponent(name),{method:'DELETE'})
|
|
|
|
|
.then(r=>r.json()).then(()=>loadWordlists());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function esc(s){return s?String(s).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"').replace(/'/g,'''):''}
|
|
|
|
|
</script>
|
|
|
|
|
{% endblock %}
|