SmartPenTest

OWASP Vulnerability Scanner — AI Analysis

Scan Configuration

mqtt: connecting...

Scan Scenario

Scan Progress

Ready to scan

Severity Distribution

Vulnerabilities Found

กด Start Scan เพื่อเริ่มสแกน

Scan Statistics

0
Total Vulns
0
Critical
0
High
0
Medium
0
Pages Crawled
0
Risk Score

AI Security Analysis

🤖 AI Security Advisor
เริ่มสแกนเพื่อรับการวิเคราะห์จาก AI

OWASP Top 10 Coverage

A01 Broken Access Control — -
A02 Cryptographic Failures — -
A03 Injection — -
A04 Insecure Design — -
A05 Security Misconfiguration — -
A06 Vulnerable Components — -
A07 Auth Failures — -
A08 Data Integrity — -
A09 Logging Failures — -
A10 SSRF — -
' }, { severity: 'critical', category: 'A03', title: 'Stored XSS — Comment Section', desc: 'พบ Stored XSS ที่ช่องแสดงความคิดเห็น script จะทำงานกับผู้ใช้ทุกคนที่เข้าชมหน้านี้', url: '/post/123#comments' }, { severity: 'high', category: 'A03', title: 'DOM-based XSS — URL Fragment', desc: 'พบ DOM XSS ผ่าน URL fragment ที่ถูกใส่เข้า innerHTML โดยตรง', url: '/page#' }, { severity: 'medium', category: 'A05', title: 'Missing CSP Header', desc: 'ไม่มี Content-Security-Policy header ทำให้ XSS สามารถโหลด external scripts ได้', url: '/ (Response headers)' }, { severity: 'medium', category: 'A03', title: 'HTML Injection — Profile Name', desc: 'สามารถใส่ HTML tags ในชื่อโปรไฟล์ แสดงผลบนหน้าอื่นโดยไม่ escape', url: '/profile/edit' }, { severity: 'low', category: 'A05', title: 'HttpOnly Flag Missing on Session Cookie', desc: 'Cookie ไม่มี HttpOnly flag ทำให้ XSS สามารถอ่าน session cookie ได้', url: '/ (Set-Cookie header)' }, ], clean: [ { severity: 'info', category: 'A05', title: 'Server Fingerprint', desc: 'ตรวจพบ web server เป็น Nginx แต่ไม่ได้เปิดเผยเวอร์ชัน', url: '/ (Server header)' }, { severity: 'low', category: 'A09', title: 'Strict-Transport-Security Missing on Subdomain', desc: 'Subdomain บางตัวไม่มี HSTS header แต่ main domain มีแล้ว', url: 'cdn.testsite.com' }, ], overloaded: [ { severity: 'high', category: 'A05', title: 'Server 503 — Service Unavailable', desc: 'เซิร์ฟเวอร์ตอบ 503 ระหว่างการสแกน อาจมี rate limiting หรือ server overloaded', url: '/ (HTTP 503)' }, { severity: 'medium', category: 'A05', title: 'Connection Timeout on Deep Paths', desc: 'หลาย URL ตอบช้าเกิน 30 วินาที สแกนไม่สมบูรณ์', url: '/api/admin/*' }, { severity: 'info', category: 'A05', title: 'WAF Detected — Cloudflare', desc: 'ตรวจพบ Web Application Firewall (Cloudflare) อาจบล็อกบาง scan requests', url: '/ (cf-ray header)' }, ], }; // ===== AI EXPLANATIONS ===== const AI_EXPLANATIONS = { normal: 'จากการสแกนพบช่องโหว่หลายจุด ที่สำคัญที่สุดคือ Default Admin Credentials (Critical) — ต้องเปลี่ยนรหัสผ่าน admin ทันที เพราะผู้โจมตีสามารถเข้าถึงระบบได้ง่ายมาก\n\nSQL Injection ที่หน้า login ก็อันตรายมาก แนะนำให้ใช้ Prepared Statements แทน string concatenation\n\nสำหรับ IDOR ที่ /api/users ให้เพิ่ม authorization check ทุกครั้งที่เข้าถึงข้อมูลผู้ใช้', sqli: 'พบช่องโหว่ SQL Injection ร้ายแรงหลายจุด! นี่คือสถานการณ์ฉุกเฉิน\n\nBlind SQLi + Union SQLi หมายความว่าผู้โจมตีสามารถ:\n- ดึงข้อมูลทั้ง database (username, password, ข้อมูลส่วนตัว)\n- แก้ไข/ลบข้อมูล\n- อาจเข้าถึง OS ของเซิร์ฟเวอร์ได้\n\nวิธีแก้เร่งด่วน:\n1. ใช้ Prepared Statements / Parameterized Queries ทุกจุด\n2. ใช้ ORM แทน raw SQL\n3. ปิด error messages ใน production\n4. Hash รหัสผ่านด้วย bcrypt ทันที', xss: 'พบ Cross-Site Scripting (XSS) หลายประเภท — โดยเฉพาะ Stored XSS ที่อันตรายมาก!\n\nStored XSS หมายความว่าผู้โจมตีฝัง script ไว้ใน database แล้ว script จะทำงานกับผู้ใช้ทุกคน สามารถ:\n- ขโมย session cookie → เข้าบัญชีผู้ใช้\n- Redirect ไปหน้า phishing\n- ติดตั้ง keylogger บนหน้าเว็บ\n\nวิธีแก้:\n1. Escape HTML output ทุกจุด (ใช้ library เช่น DOMPurify)\n2. เพิ่ม Content-Security-Policy header\n3. เพิ่ม HttpOnly flag บน session cookie\n4. ใช้ template engine ที่ auto-escape', clean: 'สแกนเสร็จสมบูรณ์ ผลลัพธ์ดีมาก!\n\nพบเพียงข้อสังเกตเล็กน้อย ไม่มีช่องโหว่ร้ายแรง เว็บไซต์นี้มีการป้องกันที่ดี มี security headers ครบถ้วน และไม่มี injection vulnerabilities\n\nแนะนำเพิ่มเติม: เพิ่ม HSTS header ให้ครบทุก subdomain', overloaded: 'การสแกนไม่สมบูรณ์เนื่องจากเซิร์ฟเวอร์ตอบสนองช้า/ล่ม\n\nอาจเกิดจาก:\n1. Rate limiting / WAF บล็อกการสแกน\n2. เซิร์ฟเวอร์ overloaded จริง\n3. ทรัพยากรไม่เพียงพอ\n\nแนะนำ:\n- ลดความเร็วในการสแกน\n- ขอ whitelist IP จากผู้ดูแลระบบ\n- สแกนนอกเวลาใช้งาน peak', }; const AI_EXTRA = [ 'เพิ่มเติม: ควรทำ penetration test อย่างน้อยปีละ 2 ครั้ง และหลังจากอัปเดตระบบทุกครั้ง', 'แนะนำให้ทีมพัฒนาเรียนรู้ OWASP Top 10 ทุกคน เพราะ security เป็นหน้าที่ของทุกคนในทีม ไม่ใช่แค่ security team', 'ควรตั้ง Security Champions ในแต่ละทีมพัฒนา เพื่อให้มีคนรับผิดชอบเรื่อง security โดยเฉพาะ', 'ลองใช้ SAST (Static Application Security Testing) เช่น SonarQube ร่วมกับ CI/CD pipeline เพื่อตรวจจับช่องโหว่ตั้งแต่ขั้นตอนเขียนโค้ด', 'สำหรับ API ควรเพิ่ม rate limiting, input validation, และ authentication ให้ครบทุก endpoint', ]; // ===== SCENARIO BUTTONS ===== document.getElementById('scenario-grid').addEventListener('click', e => { const btn = e.target.closest('.glitch-btn'); if (!btn) return; document.querySelectorAll('.glitch-btn').forEach(b => b.classList.remove('active')); btn.classList.add('active'); scenario = btn.dataset.scenario; }); // ===== CHART SETUP ===== const ctx = document.getElementById('chart').getContext('2d'); const chart = new Chart(ctx, { type: 'doughnut', data: { labels: ['Critical', 'High', 'Medium', 'Low', 'Info'], datasets: [{ data: [0, 0, 0, 0, 0], backgroundColor: ['#f87171', '#f0883e', '#fbbf24', '#58a6ff', '#8b949e'], borderColor: '#161b22', borderWidth: 3, }], }, options: { responsive: true, maintainAspectRatio: false, cutout: '60%', plugins: { legend: { position: 'bottom', labels: { color: '#8b949e', font: { size: 10 }, boxWidth: 12, padding: 8 } }, }, }, }); // ===== SCAN PHASES ===== const PHASES = [ { label: 'Reconnaissance — สำรวจเป้าหมาย', duration: 1500 }, { label: 'Spider — ค้นหา URL ทั้งหมด', duration: 2000 }, { label: 'Active Scan — ทดสอบช่องโหว่', duration: 3000 }, { label: 'Analysis — วิเคราะห์ผลลัพธ์', duration: 1500 }, ]; // ===== START SCAN ===== window.startScan = async function() { if (scanning) return; scanning = true; const btn = document.getElementById('btn-scan'); btn.textContent = 'Scanning...'; btn.className = 'start-btn on'; btn.disabled = true; // Reset state foundVulns = []; stats = { total: 0, critical: 0, high: 0, medium: 0, low: 0, info: 0, pages: 0, risk: 0 }; updateStats(); chart.data.datasets[0].data = [0, 0, 0, 0, 0]; chart.update(); document.getElementById('vuln-list').innerHTML = ''; document.getElementById('ai-content').innerHTML = 'Scanning...'; document.getElementById('btn-ask-ai').disabled = true; // Reset OWASP coverage for (let i = 1; i <= 10; i++) { document.getElementById('ow-a' + (i < 10 ? '0' + i : i)).textContent = '-'; document.getElementById('ow-a' + (i < 10 ? '0' + i : i)).style.color = '#484f58'; } const vulns = VULN_DB[scenario] || VULN_DB.normal; let progress = 0; const totalDuration = PHASES.reduce((a, p) => a + p.duration, 0); // Run phases for (const phase of PHASES) { document.getElementById('phase-label').textContent = phase.label; const steps = 20; const stepDur = phase.duration / steps; const stepPct = (phase.duration / totalDuration * 100) / steps; for (let i = 0; i < steps; i++) { progress += stepPct; document.getElementById('progress-fill').style.width = Math.min(progress, 100) + '%'; document.getElementById('progress-fill').textContent = Math.round(progress) + '%'; // Randomly add pages crawled if (Math.random() < 0.3) { stats.pages += Math.floor(Math.random() * 3) + 1; updateStats(); } await sleep(stepDur); } // Add vulns during Active Scan phase if (phase.label.includes('Active Scan')) { for (let v = 0; v < vulns.length; v++) { await sleep(300 + Math.random() * 400); addVuln(vulns[v]); } } } // Complete document.getElementById('progress-fill').style.width = '100%'; document.getElementById('progress-fill').textContent = '100%'; document.getElementById('phase-label').textContent = 'Scan complete'; // Calculate risk score stats.risk = Math.min(100, stats.critical * 30 + stats.high * 15 + stats.medium * 5 + stats.low * 1); updateStats(); // Show AI analysis await typeAI(AI_EXPLANATIONS[scenario] || AI_EXPLANATIONS.normal); document.getElementById('btn-ask-ai').disabled = false; // Publish summary via MQTT if (mqttClient?.connected) { const scanId = document.getElementById('scan-id').value; mqttClient.publish('pentest/' + scanId + '/summary', JSON.stringify({ url: document.getElementById('target-url').value, scenario, total: stats.total, critical: stats.critical, high: stats.high, medium: stats.medium, risk: stats.risk, })); } btn.textContent = 'Start Scan'; btn.className = 'start-btn off'; btn.disabled = false; scanning = false; }; function addVuln(vuln) { foundVulns.push(vuln); stats.total++; stats[vuln.severity]++; // Update chart const sevMap = { critical: 0, high: 1, medium: 2, low: 3, info: 4 }; chart.data.datasets[0].data[sevMap[vuln.severity]]++; chart.update(); // Update OWASP coverage const owNum = vuln.category.replace('A', ''); const owEl = document.getElementById('ow-a' + owNum); if (owEl) { const sevColors = { critical: '#f87171', high: '#f0883e', medium: '#fbbf24', low: '#58a6ff', info: '#8b949e' }; owEl.textContent = vuln.severity.toUpperCase(); owEl.style.color = sevColors[vuln.severity]; } // Add card const list = document.getElementById('vuln-list'); if (stats.total === 1) list.innerHTML = ''; const card = document.createElement('div'); card.className = 'vuln-card'; card.innerHTML = '
' + '' + vuln.severity + '' + '' + vuln.category + '' + '' + vuln.title + '' + '
' + '
' + vuln.desc + '
' + '
' + escapeHtml(vuln.url) + '
'; list.appendChild(card); // Publish via MQTT if (mqttClient?.connected) { const scanId = document.getElementById('scan-id').value; mqttClient.publish('pentest/' + scanId + '/result', JSON.stringify({ url: document.getElementById('target-url').value, severity: vuln.severity, category: vuln.category, description: vuln.title, })); } updateStats(); } function escapeHtml(text) { const d = document.createElement('div'); d.textContent = text; return d.innerHTML; } // ===== AI TYPING ===== async function typeAI(text) { const el = document.getElementById('ai-content'); el.innerHTML = ''; const lines = text.split('\n'); let fullHtml = ''; for (const line of lines) { for (let i = 0; i < line.length; i++) { fullHtml += line[i]; el.innerHTML = fullHtml + ''; await sleep(15 + Math.random() * 15); } fullHtml += '
'; el.innerHTML = fullHtml + ''; await sleep(100); } el.innerHTML = fullHtml; } window.askAI = async function() { const btn = document.getElementById('btn-ask-ai'); btn.disabled = true; const extra = AI_EXTRA[Math.floor(Math.random() * AI_EXTRA.length)]; await typeAI(extra); btn.disabled = false; }; function updateStats() { document.getElementById('s-total').textContent = stats.total; document.getElementById('s-critical').textContent = stats.critical; document.getElementById('s-high').textContent = stats.high; document.getElementById('s-medium').textContent = stats.medium; document.getElementById('s-pages').textContent = stats.pages; document.getElementById('s-risk').textContent = stats.risk; } function sleep(ms) { return new Promise(r => setTimeout(r, ms)); } // ===== MQTT ===== function initMQTT() { mqttClient = mqtt.connect(MQTT_BROKER); mqttClient.on('connect', () => { document.getElementById('dot-mqtt').className = 'dot on'; document.getElementById('status-mqtt').textContent = 'mqtt: connected'; }); mqttClient.on('offline', () => { document.getElementById('dot-mqtt').className = 'dot off'; document.getElementById('status-mqtt').textContent = 'mqtt: offline'; }); } // ===== INIT ===== initMQTT();