ASDA is a distributed system for detecting, blocking, and sharing information about SSH brute force attacks automatically between servers using Fail2Ban and WebSockets.
server/
βββ server.js # WebSocket server, REST API and dashboard backend
βββ .env # Environment configuration
βββ package.json # Dependencies
βββ logs/ # Server logs
β βββ server_log.csv # All forwarded IPs
β βββ received_ips.log # All received IPs
βββ public/ # Admin dashboard files
βββ index.html # Dashboard UI
βββ login.html # Authentication login page
βββ style.css # Dashboard styling
βββ script.js # Dashboard functionality and API integration
client/
βββ client.js # WebSocket client
βββ .env # Environment configuration
βββ package.json # Dependencies
βββ block_from_server.sh # Script to block IPs
βββ unblock_from_server.sh # Script to unblock IPs
βββ fail2ban-trigger.sh # Called by Fail2Ban on ban
βββ .ip_queue # Queue file for IPs to send
βββ logs/ # Client logs
βββ actions.log # Human-readable log
βββ block_log.csv # CSV log of all actions
install/
βββ install.sh # Installation script
βββ asda-client.service # Systemd service for client
βββ asda-server.service # Systemd service for server
βββ asda-notify.conf # Fail2Ban action config
βββ sshd-asda.conf # Fail2Ban jail config
-
Backend:
- Node.js (v16+)
- Express.js (for REST API and admin dashboard)
- WebSocket (
ws
package for real-time communication) - MySQL/MariaDB (for persistent storage)
- bcrypt (for password hashing)
- express-session & cookie-parser (for authentication)
- axios (for webhook notifications)
- uuid (for session management)
- dotenv (for environment configuration)
-
Security:
- Fail2Ban (active on
sshd
jail) - atd (for scheduling automatic unbans)
- bcrypt password hashing
- Session-based authentication
- Role-based access control
- Fail2Ban (active on
-
Frontend:
- Bootstrap 5 (UI framework)
- Chart.js (for dashboard metrics)
- Bootstrap Icons
- Vanilla JavaScript
-
System Requirements:
- Ubuntu/Debian-based system (for installation script)
- Systemd (for service management)
- Detection: Fail2Ban detects SSH brute force attempts
- Trigger:
fail2ban-trigger.sh
is called β IP is added to.ip_queue
- Distribution:
client.js
reads the queue β sends IP to WebSocket Server - Database: Server stores the IP in MySQL database
- Request Tracking: Server generates a unique requestId for each block/unblock request
- Broadcast:
server.js
distributes the IP to all other clients with the requestId - Block: All clients call
block_from_server.sh
β Fail2Ban blocks the IP - Response: Clients send BLOCK_RESULT/UNBLOCK_RESULT back to server with requestId
- Response Time: Server calculates and records response time for each client
- Automatic Unban:
unblock_from_server.sh
is scheduled byat
after the configured ban duration - Metrics: Clients send performance metrics to the server
- Dashboard: Admin can view clients, blocked IPs, response times, and metrics via web interface
-
Connection Management:
- Automatic reconnection with exponential backoff
- Heartbeat mechanism to detect stale connections
- Handling for temporary network failures
-
Error Handling:
- Comprehensive error handling in shell scripts
- Error reporting back to server when blocks fail
- Validation before executing commands with sudo
-
System Management:
- Admin interface/dashboard for managing clients
- Query system for current block status across network
- Mechanism to manually remove IPs from blocklist
- Centralized configuration management
-
Monitoring and Logging:
- Detailed logging with timestamps and status
- Alerting system to dashboard and Discord webhook
- Performance metrics tracking
- Response time tracking for all block/unblock operations
- Timeout detection for non-responsive clients
The admin dashboard provides the following features:
- Overview: Total clients, active clients, blocked IPs, total events
- Client Management: View client status, last seen time, version
- IP Management: View and manage blocked IPs (block/unblock)
- Block Events: Visualize block/unblock events with response times
- Charts: Visual analytics of response times, success rates, and block distribution
- Metrics: View performance metrics from all clients, including Blocks/Day (Avg), uptime, and memory usage
- Manual Controls: Manually block or unblock IPs across all clients
- User Management: Create, edit, and delete dashboard users with role-based access
- Authentication: Secure login with bcrypt-hashed passwords stored in MySQL
All communication between clients and server uses a standardized JSON format for consistency, easy management, and secure parsing.
- Registration:
{
"type": "REGISTER",
"client_id": "server1",
"token": "secret_token"
}
-
Sent once when client connects to server
-
Must include
client_id
andtoken
-
Heartbeat:
{
"type": "HEARTBEAT",
"client_id": "server1",
"token": "secret_token"
}
- Block IP:
{
"type": "BLOCK_IP",
"client_id": "server1",
"token": "secret_token",
"ip": "192.168.1.100",
"source": "fail2ban",
"requestId": "550e8400-e29b-41d4-a716-446655440000",
"timestamp": "2025-06-28T12:34:56.789Z"
}
-
Sent by the reporting client to the server
-
Server validates the request and distributes to all other clients
-
Server adds a unique requestId to track responses from all clients
-
Receiving clients execute
block_from_server.sh <IP>
-
Block Result:
{
"type": "BLOCK_RESULT",
"client_id": "server1",
"token": "secret_token",
"ip": "192.168.1.100",
"requestId": "550e8400-e29b-41d4-a716-446655440000",
"success": true,
"timestamp": "2025-06-28T12:34:58.123Z"
}
-
Sent by client back to server after executing block command
-
Includes success/failure status and requestId to track response time
-
Unblock Result:
{
"type": "UNBLOCK_RESULT",
"client_id": "server1",
"token": "secret_token",
"ip": "192.168.1.100",
"requestId": "550e8400-e29b-41d4-a716-446655440000",
"success": true,
"timestamp": "2025-06-28T12:34:58.123Z"
}
-
Sent by client back to server after executing unblock command
-
Includes success/failure status and requestId to track response time
-
Metrics:
{
"type": "METRICS",
"client_id": "server1",
"token": "secret_token",
"metrics": {
"lastMinuteBlockCount": 5,
"lastHourBlockCount": 23,
"uptime": 3600,
"memoryUsage": {
"heapUsed": 24000000
},
"timestamp": "2025-06-28T12:35:00.000Z"
}
}
- Heartbeat Acknowledgment:
{
"type": "HEARTBEAT_ACK",
"timestamp": "2025-06-28T12:34:56.000Z"
}
- Block IP:
{
"type": "BLOCK_IP",
"client_id": "server2",
"token": "secret_token",
"ip": "192.168.1.100",
"timestamp": "2025-06-28T12:34:56.789Z"
}
- Unblock IP:
{
"type": "UNBLOCK_IP",
"client_id": "admin",
"token": "secret_token",
"ip": "192.168.1.100",
"requestId": "550e8400-e29b-41d4-a716-446655440000",
"timestamp": "2025-06-28T12:40:00.000Z"
}
- Similar to BLOCK_IP but triggers unblocking of the IP
- Contains requestId for tracking response time
- Run the installation script as root:
sudo ./install/install.sh
- Follow the prompts to install either the client or server.
- Install dependencies:
# Install Node.js if not already installed
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt-get install -y nodejs
# Install MySQL/MariaDB if using database
sudo apt install mariadb-server
# Setup database
sudo mysql -e "CREATE DATABASE asda;"
sudo mysql -e "CREATE USER 'asda'@'localhost' IDENTIFIED BY 'password';"
sudo mysql -e "GRANT ALL PRIVILEGES ON asda.* TO 'asda'@'localhost';"
sudo mysql -e "FLUSH PRIVILEGES;"
# Install server dependencies
cd server
npm install
- Configure environment variables:
# Create .env file
cat > .env << EOF
PORT=3000
WEB_PORT=8080
SECRET_TOKEN=your_secret_token
DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/your_webhook_url
DB_HOST=localhost
DB_USER=asda
DB_PASSWORD=password
DB_NAME=asda
DEFAULT_ADMIN_PASSWORD=admin123
SESSION_SECRET=your_session_secret
EOF
- Start the server:
node server.js
- Install dependencies:
# Install required packages
sudo apt update
sudo apt install -y fail2ban at
# Install client dependencies
cd client
npm install
- Configure environment variables:
# Create .env file
cat > .env << EOF
SERVER_IP=your_server_ip
SERVER_PORT=3000
CLIENT_ID=unique_client_id
SECRET_TOKEN=your_secret_token
EOF
- Set up Fail2Ban integration:
# Copy action config to tell Fail2Ban to notify ASDA when IPs are banned
sudo cp install/asda-notify.conf /etc/fail2ban/action.d/
# Copy jail config to customize the SSH jail and add ASDA notification
sudo cp install/sshd-asda.conf /etc/fail2ban/jail.d/
# Check if the configuration is valid
sudo fail2ban-client -d
# Restart Fail2Ban to apply changes
sudo systemctl restart fail2ban
# Verify that the sshd jail is active and includes the ASDA action
sudo fail2ban-client status sshd
- Make scripts executable:
chmod +x *.sh
- Start the client:
node client.js
- Install systemd service files:
# For server
sudo cp install/asda-server.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now asda-server
# For client
sudo cp install/asda-client.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now asda-client
- Server Logs:
tail -f /opt/asda/server/logs/server_log.csv
- Client Logs:
tail -f /opt/asda/client/logs/actions.log
- Check Status:
sudo systemctl status asda-server
sudo systemctl status asda-client
- Restart Services:
sudo systemctl restart asda-server
sudo systemctl restart asda-client
- Backup Database:
mysqldump -u asda -p asda > asda_backup.sql
- Restore Database:
mysql -u asda -p asda < asda_backup.sql
-
Client can't connect to server:
- Verify network connectivity
- Check firewall settings
- Ensure the server is running
- Verify secret token matches
-
Fail2Ban not triggering ASDA:
- Check Fail2Ban configuration:
sudo fail2ban-client status sshd
- Verify script permissions:
sudo chmod +x /opt/asda/client/*.sh
- Check if action is properly registered:
grep -r "asda-notify" /etc/fail2ban/
- Verify the trigger script works:
sudo /opt/asda/client/fail2ban-trigger.sh 192.168.1.100
- Examine logs:
sudo tail -f /var/log/fail2ban.log
andtail -f /opt/asda/client/logs/actions.log
- Check if Fail2Ban service is running:
sudo systemctl status fail2ban
- Check Fail2Ban configuration:
-
Block/Unblock not working:
- Check sudo permissions
- Verify Fail2Ban is running
- Inspect client logs for errors
-
Authentication problems:
- Check that the database is properly configured
- Verify that user tables are created correctly
- Try resetting the admin password
- HTTPS/WSS support for secure communication
- JWT-based authentication
- Multi-service protection (not just SSH)
- Geolocation and threat intelligence integration
- Honeypot integration for proactive blocking
- Machine learning for attack pattern recognition
The ASDA system employs a comprehensive authentication system for both client-server communication and the admin dashboard.
- All WebSocket messages must include a secret token (
token
) configured in.env
- The server validates this token before processing any message
- Messages without a valid token are automatically ignored
Example .env
in Server:
PORT=3000
SECRET_TOKEN=ASDA_SECRET_2025
Example .env
in Client:
SERVER_IP=127.0.0.1
SERVER_PORT=3000
CLIENT_ID=client-01
SECRET_TOKEN=ASDA_SECRET_2025
Messages are only processed if:
- JSON format is valid
- Required fields (
type
,client_id
, andtoken
) are present - IP address is valid (for
BLOCK_IP
messages) - Token matches the server's token (
process.env.SECRET_TOKEN
)
The admin dashboard uses a secure authentication system:
-
Backend:
- MySQL database storage for user accounts
- bcrypt password hashing
- Session-based authentication
- Role-based access control (admin/user)
-
Frontend:
- Login page with secure form submission
- Session validation
- Automatic redirection to login when unauthenticated
- Role-based UI elements
Default admin credentials are created during the first run (configurable in .env
):
Username: admin
Password: admin123 (change this immediately after installation)
- Production-ready with full security features
- Regular maintenance and security updates
This project was created as part of a final thesis research project.
The integration between ASDA and Fail2Ban works through a custom action that notifies the ASDA client whenever Fail2Ban bans an IP address. Here's a detailed explanation of how to set it up and how it works:
Fail2Ban Components:
- Filter: Monitors log files and detects authentication failures (default
sshd
filter monitors SSH login attempts) - Jail: Defines what action to take when failures are detected (e.g., ban the IP with iptables)
- Action: Defines what commands to execute when banning/unbanning IPs
ASDA Components:
- fail2ban-trigger.sh: Called by Fail2Ban when an IP is banned, adds IP to the queue
- .ip_queue: Queue file that stores IPs to be sent to the ASDA server
- client.js: Reads the queue and sends IPs to the ASDA server
- asda-notify.conf: Custom Fail2Ban action that calls the trigger script
- sshd-asda.conf: Custom Fail2Ban jail configuration for SSH that includes the ASDA action
# Copy the ASDA action config to Fail2Ban's action directory
sudo cp install/asda-notify.conf /etc/fail2ban/action.d/
The asda-notify.conf
file defines an action that calls the ASDA trigger script when an IP is banned:
[Definition]
actionstart =
actionstop =
actioncheck =
actionban = /opt/asda/client/fail2ban-trigger.sh <ip>
actionunban =
[Init]
# Copy the ASDA jail config to Fail2Ban's jail directory
sudo cp install/sshd-asda.conf /etc/fail2ban/jail.d/
The sshd-asda.conf
file modifies the SSH jail to include the ASDA action:
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 5 # Number of failures before ban
findtime = 300 # Timeframe for failures (seconds)
bantime = 3600 # Ban duration (seconds)
banaction = iptables-multiport
action = %(action_)s # Default actions (ban with iptables)
asda-notify # Our custom ASDA notification action
You can adjust the Fail2Ban settings to match your security requirements:
# Create a custom jail configuration
sudo nano /etc/fail2ban/jail.local
Add or modify these settings:
[sshd]
# Increase sensitivity - ban after 3 failures within 5 minutes
maxretry = 3
findtime = 300
# Increase ban time to 24 hours
bantime = 86400
# Use both IPv4 and IPv6
banaction = iptables-multiport[name=ssh, port=ssh, protocol=tcp]
iptables-multiport[name=ssh-ipv6, port=ssh, protocol=tcp]
asda-notify
# Check if the configuration is valid
sudo fail2ban-client -d
# Check if the sshd jail is active
sudo fail2ban-client status sshd
sudo systemctl restart fail2ban
- Detection: Fail2Ban monitors
/var/log/auth.log
for failed SSH login attempts - Threshold: When an IP exceeds the threshold (default: 5 failed attempts within 5 minutes)
- Banning: Fail2Ban executes two actions:
- Uses iptables to block the IP address
- Calls the ASDA action (
asda-notify
)
- ASDA Notification: The
asda-notify
action calls/opt/asda/client/fail2ban-trigger.sh <ip>
- Queuing: The
fail2ban-trigger.sh
script:- Validates the IP address format
- Checks if the IP is already in the queue
- Adds the IP to the
.ip_queue
file
- Distribution: The ASDA client (
client.js
):- Periodically checks the
.ip_queue
file - Sends any new IPs to the ASDA server
- The server distributes the IP to all other clients
- Periodically checks the
- Network-wide Protection: All other ASDA clients:
- Receive the IP from the server
- Execute
block_from_server.sh <ip>
to block the IP
You can test if the integration is working correctly by:
# Manually trigger the ASDA notification for a test IP
sudo /opt/asda/client/fail2ban-trigger.sh 192.168.1.100
# Check if the IP was added to the queue
cat /opt/asda/client/.ip_queue
# Check the ASDA client logs
tail -f /opt/asda/client/logs/actions.log
# Check if Fail2Ban received and processed SSH failures
sudo tail -f /var/log/fail2ban.log
If the integration is not working:
- Check Permissions:
# Make sure scripts are executable
sudo chmod +x /opt/asda/client/*.sh
# Check if the ASDA user has permission to write to the queue file
sudo chown -R asda_user:asda_group /opt/asda/client/.ip_queue
sudo chmod 644 /opt/asda/client/.ip_queue
- Check Fail2Ban Configuration:
# Verify that the ASDA action is properly included
sudo grep -r "asda-notify" /etc/fail2ban/
# Check if the sshd jail is enabled
sudo fail2ban-client status | grep sshd
- Test the Trigger Script Manually:
# Run the script with debug output
sudo bash -x /opt/asda/client/fail2ban-trigger.sh 192.168.1.100
- Check Logs:
# Check ASDA logs
tail -f /opt/asda/client/logs/actions.log
# Check Fail2Ban logs
sudo tail -f /var/log/fail2ban.log
ASDA uses a MySQL/MariaDB database to store configuration, clients, blocked IPs, and events:
-
clients: Stores information about connected clients
id
: Unique client identifierlast_seen
: Timestamp of last heartbeatstatus
: Current status (online/offline)ip
: Client's IP addressfirst_connected
: When the client first connectedversion
: Client software version
-
blocked_ips: Records all blocked IP addresses
ip
: The blocked IP address (primary key)first_blocked
: When the IP was first blockedlast_blocked
: Most recent block timesource
: What triggered the block (fail2ban, manual, etc.)block_count
: Number of times this IP has been blockedstatus
: Current status (active/inactive)
-
block_events: Tracks individual block/unblock operations
id
: Unique event IDip
: The affected IP addressclient_id
: Which client performed the operationaction
: Type of action (block/unblock)timestamp
: When the event occurredsuccess
: Whether the operation succeedederror_message
: Error details if the operation failedresponse_time_ms
: How long the operation took to complete
-
metrics: Performance data from clients
client_id
: Which client reported the metrics (primary key)first_reported
: When the client first reported metricslast_reported
: Most recent metrics report timestampblocks_last_minute
: Number of blocks in the last minuteblocks_per_minute
: Average blocks per minute (rolling average)blocks_per_day
: Average blocks per day (rolling average)total_blocks
: Total number of blocks since client deploymentuptime_seconds
: Client uptime in secondsmemory_usage_mb
: Memory usage of the client process in MB
-
users: Dashboard user accounts
id
: Unique user IDusername
: Login usernamepassword
: Bcrypt-hashed passwordemail
: User's email addressrole
: User role (admin/user)created_at
: Account creation timelast_login
: Last successful login
-
sessions: Active user sessions
session_id
: Unique session identifieruser_id
: ID of the authenticated userip_address
: IP address of the useruser_agent
: Browser user agentcreated_at
: Session creation timeexpires_at
: Session expiration time
-
sessions_store: Express.js session storage
- Managed by express-mysql-session library
ASDA includes a robust response time tracking mechanism to monitor how quickly clients respond to block/unblock requests:
-
Request Initiation: When a block/unblock request is sent from a client or the admin dashboard, the server:
- Generates a unique requestId (UUID)
- Records the current timestamp
- Adds this information to the outgoing message
-
Request Tracking: The server maintains a map of pending requests:
pendingBlockRequests.set(requestId, { ip: "192.168.1.100", action: "block", pendingClients: Map<clientId, sentTimestamp>, initiatingClient: "client1", timestamp: Date.now() });
-
Client Response: When a client completes a block/unblock operation, it sends back:
{ "type": "BLOCK_RESULT", "client_id": "client1", "ip": "192.168.1.100", "requestId": "550e8400-e29b-41d4-a716-446655440000", "success": true }
-
Response Time Calculation: The server calculates the response time:
const responseTime = Date.now() - sentTimestamp;
-
Database Recording: The response time is stored in the
block_events
table:recordBlockEvent(ip, clientId, action, success, errorMessage, responseTime);
-
Timeout Handling: If a client doesn't respond within the timeout period (default: 30 seconds):
- The server marks the request as failed
- Records the timeout duration as the response time
- Logs a timeout error message
The dashboard displays response time data in several ways:
- Block Events Table: Lists recent events with their response times
- Response Time Chart: Shows trends in response times over time
- Success Rate Chart: Displays the percentage of successful operations
- Block/Unblock Distribution: Visualizes the ratio of block to unblock operations
This data helps administrators identify:
- Slow-responding clients that may need investigation
- Network latency issues between server and clients
- Patterns in block/unblock operations over time
- Overall system health and performance
For proper operation of the client blocking functionality, the ASDA system requires passwordless sudo access for certain iptables commands. This is set up during installation but may need manual verification if blocks are not working properly.
- The client blocking scripts (
block_from_server.sh
andunblock_from_server.sh
) usesudo iptables
commands to add and remove blocking rules. - The installation script creates a sudoers configuration file at
/etc/sudoers.d/asda-security
with the following content:This allows the asda user to run iptables with any arguments without requiring a password.asda ALL=(ALL) NOPASSWD: /usr/sbin/iptables *
If client-side blocking is not working properly, check the following:
-
Verify the sudoers file exists and has correct permissions:
ls -la /etc/sudoers.d/asda-security # Should show: -r--r----- 1 root root ...
-
Check the content of the sudoers file:
sudo cat /etc/sudoers.d/asda-security
Ensure it includes the asterisk (*) after the iptables path to allow arguments.
-
Verify that the asda user can run iptables commands without a password:
sudo -u asda sudo -n iptables -L
This should list the iptables rules without asking for a password.
-
Check the client logs for sudo access errors:
cat /opt/asda/client/logs/actions.log | grep sudo
-
If issues persist, you can manually update the sudoers configuration:
echo "asda ALL=(ALL) NOPASSWD: /usr/sbin/iptables *" | sudo tee /etc/sudoers.d/asda-security sudo chmod 440 /etc/sudoers.d/asda-security
The sudoers configuration grants specific permissions to run iptables commands with any arguments. This is necessary for the proper functioning of ASDA but should be considered in your overall security assessment. The configuration is limited to only the iptables binary and does not grant full sudo access to the asda user.