Deceptive Defense: Building a Honeypot for Attack Detection in Java

Honeypots are security mechanisms designed to detect, deflect, or study unauthorized use of information systems. This article provides a comprehensive guide to implementing various types of honeypots in Java, from simple port listeners to sophisticated interactive deception systems.

Understanding Honeypot Types

  • Low-Interaction: Emulates services and ports
  • Medium-Interaction: Provides more realistic service emulation
  • High-Interaction: Real systems with extensive monitoring
  • Database Honeypots: Trap SQL injection attempts
  • Web Honeypots: Detect web application attacks

Core Honeypot Implementation

Step 1: Basic Socket Honeypot

package com.security.honeypot.core;
import java.io.*;
import java.net.*;
import java.util.concurrent.*;
import java.time.LocalDateTime;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class BasicSocketHoneypot {
private ServerSocket serverSocket;
private final int port;
private volatile boolean running;
private final ExecutorService threadPool;
private final AttackLogger attackLogger;
private final Map<String, Integer> connectionAttempts;
// Common vulnerable ports to monitor
private static final int[] COMMON_PORTS = {22, 23, 135, 139, 445, 1433, 3306, 3389, 5432, 5900};
public BasicSocketHoneypot(int port) {
this.port = port;
this.threadPool = Executors.newFixedThreadPool(50);
this.attackLogger = new AttackLogger();
this.connectionAttempts = new ConcurrentHashMap<>();
}
public void start() {
try {
serverSocket = new ServerSocket(port);
running = true;
System.out.println("Honeypot started on port: " + port);
while (running) {
Socket clientSocket = serverSocket.accept();
threadPool.execute(new ConnectionHandler(clientSocket));
}
} catch (IOException e) {
System.err.println("Honeypot error: " + e.getMessage());
}
}
public void stop() {
running = false;
threadPool.shutdown();
try {
if (serverSocket != null) {
serverSocket.close();
}
} catch (IOException e) {
System.err.println("Error stopping honeypot: " + e.getMessage());
}
}
private class ConnectionHandler implements Runnable {
private final Socket clientSocket;
public ConnectionHandler(Socket clientSocket) {
this.clientSocket = clientSocket;
}
@Override
public void run() {
String clientIP = clientSocket.getInetAddress().getHostAddress();
// Track connection attempts
connectionAttempts.merge(clientIP, 1, Integer::sum);
try {
// Log the connection attempt
attackLogger.logConnection(clientIP, port);
// Simulate service based on port
simulateService(clientSocket);
// Keep connection open to gather more data
Thread.sleep(30000); // 30 seconds
} catch (Exception e) {
// Expected for honeypot operations
} finally {
try {
clientSocket.close();
} catch (IOException e) {
// Ignore close errors
}
}
}
}
private void simulateService(Socket socket) throws IOException {
int port = socket.getLocalPort();
switch (port) {
case 22:
simulateSSH(socket);
break;
case 23:
simulateTelnet(socket);
break;
case 3389:
simulateRDP(socket);
break;
case 3306:
simulateMySQL(socket);
break;
default:
simulateGenericService(socket);
}
}
private void simulateSSH(Socket socket) throws IOException {
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out.println("SSH-2.0-OpenSSH_7.4p1 Debian-10+deb9u7");
String input;
while ((input = in.readLine()) != null) {
attackLogger.logSSHAttempt(socket.getInetAddress().getHostAddress(), input);
out.println("Permission denied, please try again.");
}
}
private void simulateMySQL(Socket socket) throws IOException {
OutputStream out = socket.getOutputStream();
// Send MySQL handshake
out.write(new byte[]{74, 0, 0, 0, 10, 53, 46, 55, 46, 50, 56, 0, ...});
out.flush();
// Log connection attempts
attackLogger.logDatabaseProbe(socket.getInetAddress().getHostAddress(), "MySQL");
}
}

Step 2: Attack Logger and Monitoring

package com.security.honeypot.core;
import java.io.*;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
public class AttackLogger {
private static final String LOG_DIRECTORY = "honeypot_logs";
private final Map<String, List<AttackEvent>> attackEvents;
private final Set<String> suspiciousIPs;
public AttackLogger() {
this.attackEvents = new ConcurrentHashMap<>();
this.suspiciousIPs = ConcurrentHashMap.newKeySet();
initializeLogDirectory();
}
private void initializeLogDirectory() {
File logDir = new File(LOG_DIRECTORY);
if (!logDir.exists()) {
logDir.mkdirs();
}
}
public void logConnection(String ip, int port) {
AttackEvent event = new AttackEvent(ip, port, "CONNECTION_ATTEMPT", 
"Connection to port " + port);
logEvent(event);
checkForSuspiciousActivity(ip);
}
public void logSSHAttempt(String ip, String credentials) {
AttackEvent event = new AttackEvent(ip, 22, "SSH_BRUTE_FORCE", 
"Attempted credentials: " + credentials);
logEvent(event);
suspiciousIPs.add(ip);
}
public void logDatabaseProbe(String ip, String databaseType) {
AttackEvent event = new AttackEvent(ip, getDefaultPort(databaseType), 
"DATABASE_PROBE", "Probe: " + databaseType);
logEvent(event);
suspiciousIPs.add(ip);
}
public void logWebAttack(String ip, String url, String payload) {
AttackEvent event = new AttackEvent(ip, 80, "WEB_ATTACK", 
"URL: " + url + " Payload: " + payload);
logEvent(event);
suspiciousIPs.add(ip);
}
private void logEvent(AttackEvent event) {
String ip = event.getSourceIP();
attackEvents.computeIfAbsent(ip, k -> new ArrayList<>()).add(event);
// Write to file
writeToLogFile(event);
// Console alert for high-severity events
if (event.getSeverity() == AttackSeverity.HIGH) {
System.out.println("🚨 HIGH SEVERITY ATTACK: " + event);
}
}
private void writeToLogFile(AttackEvent event) {
String filename = LOG_DIRECTORY + "/attacks_" + 
LocalDateTime.now().format(java.time.format.DateTimeFormatter.ISO_DATE) + ".log";
try (PrintWriter writer = new PrintWriter(new FileWriter(filename, true))) {
writer.println(event.toLogFormat());
} catch (IOException e) {
System.err.println("Failed to write to log file: " + e.getMessage());
}
}
private void checkForSuspiciousActivity(String ip) {
List<AttackEvent> events = attackEvents.get(ip);
if (events != null) {
long recentEvents = events.stream()
.filter(e -> e.getTimestamp().isAfter(LocalDateTime.now().minusHours(1)))
.count();
if (recentEvents > 10) { // Threshold for suspicious activity
suspiciousIPs.add(ip);
System.out.println("⚠️ Suspicious activity detected from IP: " + ip);
}
}
}
public Set<String> getSuspiciousIPs() {
return Collections.unmodifiableSet(suspiciousIPs);
}
public List<AttackEvent> getEventsForIP(String ip) {
return attackEvents.getOrDefault(ip, Collections.emptyList());
}
private int getDefaultPort(String databaseType) {
switch (databaseType.toLowerCase()) {
case "mysql": return 3306;
case "postgresql": return 5432;
case "mongodb": return 27017;
case "redis": return 6379;
default: return 0;
}
}
}
class AttackEvent {
private final String sourceIP;
private final int targetPort;
private final String attackType;
private final String details;
private final LocalDateTime timestamp;
private final AttackSeverity severity;
public AttackEvent(String sourceIP, int targetPort, String attackType, String details) {
this.sourceIP = sourceIP;
this.targetPort = targetPort;
this.attackType = attackType;
this.details = details;
this.timestamp = LocalDateTime.now();
this.severity = calculateSeverity(attackType);
}
private AttackSeverity calculateSeverity(String attackType) {
switch (attackType) {
case "SSH_BRUTE_FORCE":
case "DATABASE_PROBE":
return AttackSeverity.MEDIUM;
case "WEB_ATTACK":
case "COMMAND_INJECTION":
return AttackSeverity.HIGH;
default:
return AttackSeverity.LOW;
}
}
public String toLogFormat() {
return String.format("[%s] %s -> %s:%d - %s - %s", 
timestamp, sourceIP, attackType, targetPort, severity, details);
}
// Getters
public String getSourceIP() { return sourceIP; }
public int getTargetPort() { return targetPort; }
public String getAttackType() { return attackType; }
public String getDetails() { return details; }
public LocalDateTime getTimestamp() { return timestamp; }
public AttackSeverity getSeverity() { return severity; }
}
enum AttackSeverity {
LOW, MEDIUM, HIGH, CRITICAL
}

Web Application Honeypot

Step 3: Spring Boot Web Honeypot

package com.security.honeypot.web;
import org.springframework.web.bind.annotation.*;
import org.springframework.stereotype.Controller;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
@Controller
public class WebHoneypotController {
private final AttackLogger attackLogger;
private final Set<String> honeypotEndpoints;
public WebHoneypotController(AttackLogger attackLogger) {
this.attackLogger = attackLogger;
this.honeypotEndpoints = initializeHoneypotEndpoints();
}
private Set<String> initializeHoneypotEndpoints() {
Set<String> endpoints = new HashSet<>();
// Common admin and sensitive endpoints that attackers probe
endpoints.add("/admin");
endpoints.add("/phpmyadmin");
endpoints.add("/wp-admin");
endpoints.add("/.env");
endpoints.add("/config.json");
endpoints.add("/backup");
endpoints.add("/shell");
endpoints.add("/cgi-bin");
return endpoints;
}
@GetMapping("/**")
public String catchAllRequests(HttpServletRequest request) {
String requestURI = request.getRequestURI();
String clientIP = getClientIP(request);
// Check if this is a honeypot endpoint
if (isHoneypotEndpoint(requestURI)) {
attackLogger.logWebAttack(clientIP, requestURI, "Directory traversal attempt");
return "honeypot/admin-login"; // Fake admin login page
}
// Check for suspicious parameters
checkSuspiciousParameters(request, clientIP);
// Check for SQL injection patterns
checkForSQLInjection(request, clientIP);
return "redirect:/"; // Redirect legitimate users
}
@PostMapping("/**")
public String catchAllPostRequests(HttpServletRequest request) {
String clientIP = getClientIP(request);
// Log POST attempts to honeypot endpoints
if (isHoneypotEndpoint(request.getRequestURI())) {
attackLogger.logWebAttack(clientIP, request.getRequestURI(), 
"POST attempt with parameters: " + getParameterString(request));
}
return "redirect:/";
}
// Fake login endpoint to capture credentials
@PostMapping("/honeypot/login")
public String fakeLogin(@RequestParam String username, 
@RequestParam String password,
HttpServletRequest request) {
String clientIP = getClientIP(request);
attackLogger.logWebAttack(clientIP, "/honeypot/login", 
"Credential attempt - Username: " + username + " Password: " + password);
// Always return "invalid credentials" to keep them trying
return "honeypot/login-failed";
}
// Fake database connection endpoint
@GetMapping("/db/connect")
public String fakeDatabaseConnect(HttpServletRequest request) {
String clientIP = getClientIP(request);
attackLogger.logWebAttack(clientIP, "/db/connect", 
"Database connection attempt with: " + request.getQueryString());
return "honeypot/database-error";
}
private boolean isHoneypotEndpoint(String uri) {
return honeypotEndpoints.stream().anyMatch(uri::contains);
}
private void checkSuspiciousParameters(HttpServletRequest request, String clientIP) {
Map<String, String[]> parameters = request.getParameterMap();
parameters.forEach((key, values) -> {
for (String value : values) {
if (containsSuspiciousPatterns(value)) {
attackLogger.logWebAttack(clientIP, request.getRequestURI(), 
"Suspicious parameter - " + key + ": " + value);
}
}
});
}
private void checkForSQLInjection(HttpServletRequest request, String clientIP) {
Map<String, String[]> parameters = request.getParameterMap();
parameters.forEach((key, values) -> {
for (String value : values) {
if (isSQLInjectionAttempt(value)) {
attackLogger.logWebAttack(clientIP, request.getRequestURI(), 
"SQL Injection attempt - " + key + ": " + value);
}
}
});
}
private boolean containsSuspiciousPatterns(String input) {
String[] patterns = {
"..", "/etc/passwd", "/bin/", "cmd.exe", "powershell",
"eval(", "system(", "exec(", "union select", "script>"
};
return Arrays.stream(patterns).anyMatch(input.toLowerCase()::contains);
}
private boolean isSQLInjectionAttempt(String input) {
String[] sqlPatterns = {
"' OR '1'='1", "union select", "drop table", "insert into", 
"update set", "delete from", "waitfor delay", "--", "/*", "*/"
};
return Arrays.stream(sqlPatterns).anyMatch(input.toLowerCase()::contains);
}
private String getClientIP(HttpServletRequest request) {
String xForwardedFor = request.getHeader("X-Forwarded-For");
if (xForwardedFor != null && !xForwardedFor.isEmpty()) {
return xForwardedFor.split(",")[0];
}
return request.getRemoteAddr();
}
private String getParameterString(HttpServletRequest request) {
StringBuilder params = new StringBuilder();
request.getParameterMap().forEach((key, values) -> {
params.append(key).append("=").append(String.join(",", values)).append(";");
});
return params.toString();
}
}

Database Honeypot

Step 4: SQL Injection Trap

package com.security.honeypot.database;
import java.sql.*;
import java.util.regex.Pattern;
public class DatabaseHoneypot {
private final AttackLogger attackLogger;
private final FakeDatabase fakeDatabase;
public DatabaseHoneypot(AttackLogger attackLogger) {
this.attackLogger = attackLogger;
this.fakeDatabase = new FakeDatabase();
}
public String processQuery(String query, String clientIP) {
// Log all queries for analysis
attackLogger.logWebAttack(clientIP, "DATABASE_QUERY", "Query: " + query);
if (isMaliciousQuery(query)) {
attackLogger.logWebAttack(clientIP, "SQL_INJECTION", 
"Malicious query detected: " + query);
return "ERROR: Query blocked by security policy";
}
if (isSuspiciousQuery(query)) {
attackLogger.logWebAttack(clientIP, "SUSPICIOUS_QUERY", 
"Suspicious query pattern: " + query);
// Return fake data to engage attacker
return fakeDatabase.executeFakeQuery(query);
}
// For normal-looking queries, return generic error
return "ERROR: Database connection failed";
}
private boolean isMaliciousQuery(String query) {
String[] maliciousPatterns = {
"(?i).*drop\\s+table.*",
"(?i).*delete\\s+from.*",
"(?i).*insert\\s+into.*",
"(?i).*update.*set.*",
"(?i).*union.*select.*",
"(?i).*or.*1=1.*",
"(?i).*waitfor\\s+delay.*",
"(?i).*shutdown.*"
};
for (String pattern : maliciousPatterns) {
if (Pattern.compile(pattern).matcher(query).matches()) {
return true;
}
}
return false;
}
private boolean isSuspiciousQuery(String query) {
String[] suspiciousPatterns = {
"(?i).*select.*from.*",
"(?i).*where.*=.*",
"(?i).*from.*information_schema.*",
"(?i).*from.*mysql\\.user.*",
"(?i).*version\\(\\)*"
};
for (String pattern : suspiciousPatterns) {
if (Pattern.compile(pattern).matcher(query).matches()) {
return true;
}
}
return false;
}
}
class FakeDatabase {
private final Random random = new Random();
public String executeFakeQuery(String query) {
// Return realistic-looking fake data based on query type
if (query.toLowerCase().contains("select")) {
return generateFakeResultSet();
} else if (query.toLowerCase().contains("version")) {
return "8.0.28 MySQL Community Server";
} else if (query.toLowerCase().contains("user")) {
return generateFakeUsers();
}
return "Query executed successfully. Rows affected: " + (random.nextInt(100) + 1);
}
private String generateFakeResultSet() {
return "id\tname\temail\ttimestamp\n" +
"1\tadmin\[email protected]\t2024-01-15 10:30:00\n" +
"2\tuser1\[email protected]\t2024-01-15 11:15:00\n" +
"3\tjohn\[email protected]\t2024-01-15 12:00:00";
}
private String generateFakeUsers() {
return "root\tlocalhost\n" +
"admin\t%\n" +
"backup\tlocalhost";
}
}

Honeypot Management System

Step 5: Centralized Honeypot Manager

package com.security.honeypot.management;
import com.security.honeypot.core.BasicSocketHoneypot;
import com.security.honeypot.core.AttackLogger;
import java.util.*;
import java.util.concurrent.*;
public class HoneypotManager {
private final Map<Integer, BasicSocketHoneypot> honeypots;
private final AttackLogger attackLogger;
private final ScheduledExecutorService scheduler;
private final AlertService alertService;
public HoneypotManager() {
this.honeypots = new ConcurrentHashMap<>();
this.attackLogger = new AttackLogger();
this.scheduler = Executors.newScheduledThreadPool(2);
this.alertService = new AlertService();
startMonitoring();
}
public void deployHoneypots(int[] ports) {
for (int port : ports) {
if (!honeypots.containsKey(port)) {
BasicSocketHoneypot honeypot = new BasicSocketHoneypot(port);
honeypots.put(port, honeypot);
new Thread(() -> {
try {
honeypot.start();
} catch (Exception e) {
System.err.println("Honeypot on port " + port + " failed: " + e.getMessage());
}
}).start();
System.out.println("✅ Honeypot deployed on port: " + port);
}
}
}
public void stopHoneypot(int port) {
BasicSocketHoneypot honeypot = honeypots.get(port);
if (honeypot != null) {
honeypot.stop();
honeypots.remove(port);
System.out.println("⏹️ Honeypot stopped on port: " + port);
}
}
public Map<String, Object> getHoneypotStatus() {
Map<String, Object> status = new HashMap<>();
status.put("activeHoneypots", honeypots.size());
status.put("suspiciousIPs", attackLogger.getSuspiciousIPs().size());
status.put("totalEvents", getTotalEvents());
Map<Integer, String> honeypotStatus = new HashMap<>();
honeypots.forEach((port, honeypot) -> {
honeypotStatus.put(port, "ACTIVE");
});
status.put("honeypots", honeypotStatus);
return status;
}
private void startMonitoring() {
// Periodic report generation
scheduler.scheduleAtFixedRate(this::generateReport, 1, 1, TimeUnit.HOURS);
// Alert checking
scheduler.scheduleAtFixedRate(this::checkForAlerts, 0, 5, TimeUnit.MINUTES);
}
private void generateReport() {
System.out.println("=== Honeypot Security Report ===");
System.out.println("Time: " + new Date());
System.out.println("Active honeypots: " + honeypots.size());
System.out.println("Suspicious IPs detected: " + attackLogger.getSuspiciousIPs().size());
System.out.println("Top attackers:");
attackLogger.getSuspiciousIPs().stream()
.limit(5)
.forEach(ip -> {
int eventCount = attackLogger.getEventsForIP(ip).size();
System.out.println("  " + ip + " - " + eventCount + " events");
});
}
private void checkForAlerts() {
Set<String> suspiciousIPs = attackLogger.getSuspiciousIPs();
if (!suspiciousIPs.isEmpty()) {
alertService.sendAlert("Honeypot detected " + suspiciousIPs.size() + " suspicious IPs");
}
}
private int getTotalEvents() {
return attackLogger.getSuspiciousIPs().stream()
.mapToInt(ip -> attackLogger.getEventsForIP(ip).size())
.sum();
}
}
class AlertService {
public void sendAlert(String message) {
// Integrate with email, Slack, SIEM, etc.
System.out.println("🚨 SECURITY ALERT: " + message);
// Example integration points:
// - Send email alert
// - Post to Slack channel
// - Create SIEM event
// - Trigger firewall block
}
}

Main Application Class

package com.security.honeypot;
import com.security.honeypot.management.HoneypotManager;
public class HoneypotApplication {
public static void main(String[] args) {
System.out.println("🚀 Starting Java Honeypot System...");
HoneypotManager manager = new HoneypotManager();
// Deploy honeypots on common attack vectors
int[] ports = {22, 23, 80, 443, 135, 139, 445, 1433, 3306, 3389, 5432, 5900, 8080};
manager.deployHoneypots(ports);
// Keep the application running
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
System.out.println("Shutting down honeypot system...");
}));
try {
Thread.currentThread().join();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}

Configuration File

package com.security.honeypot.config;
import java.util.Properties;
public class HoneypotConfig {
private final Properties properties;
public HoneypotConfig() {
properties = new Properties();
loadDefaultConfig();
}
private void loadDefaultConfig() {
properties.setProperty("honeypot.ports", "22,23,80,443,3389,3306,5432");
properties.setProperty("honeypot.log.directory", "./honeypot_logs");
properties.setProperty("honeypot.alert.threshold", "5");
properties.setProperty("honeypot.connection.timeout", "30000");
properties.setProperty("honeypot.max.connections", "50");
}
public int[] getHoneypotPorts() {
String ports = properties.getProperty("honeypot.ports");
return Arrays.stream(ports.split(","))
.map(String::trim)
.mapToInt(Integer::parseInt)
.toArray();
}
public String getLogDirectory() {
return properties.getProperty("honeypot.log.directory");
}
public int getAlertThreshold() {
return Integer.parseInt(properties.getProperty("honeypot.alert.threshold"));
}
}

Best Practices and Security Considerations

  1. Isolation: Run honeypots in isolated environments (Docker containers, VMs)
  2. Legal Compliance: Ensure honeypot deployment complies with local laws
  3. Monitoring: Implement comprehensive logging and alerting
  4. False Positives: Regularly review logs to minimize false positives
  5. Engagement: Keep attackers engaged to gather more intelligence
  6. Data Sanitization: Never use real data in honeypot responses
  7. Network Segmentation: Place honeypots in DMZ or separate network segments

Conclusion

This Java-based honeypot system provides a robust framework for detecting and analyzing attack attempts. By implementing multiple honeypot types (network, web, database), you can gather comprehensive threat intelligence about attack patterns, techniques, and sources. The modular design allows for easy extension and integration with existing security systems.

Remember that honeypots should be used as part of a layered security strategy, complementing other security controls like firewalls, intrusion detection systems, and regular security assessments.

Leave a Reply

Your email address will not be published. Required fields are marked *


Macro Nepal Helper