Introduction to Privilege Escalation Monitoring
Privilege escalation monitoring detects and prevents unauthorized elevation of privileges in Java applications. This includes monitoring file permissions, process privileges, user context changes, and suspicious system operations that could lead to security breaches.
Core Security Monitoring
Security Monitor Service
/**
* Privilege Escalation Monitoring Service
* Monitors system for privilege escalation attempts and suspicious activities
*/
@Service
@Slf4j
public class PrivilegeEscalationMonitor {
private final SecurityEventService securityEventService;
private final AlertService alertService;
private final SystemAccessMonitor systemAccessMonitor;
private final FileSystemMonitor fileSystemMonitor;
private final ProcessMonitor processMonitor;
private ScheduledExecutorService monitorScheduler;
private final Map<String, MonitoringRule> activeRules;
private final List<SecurityEvent> detectedEvents;
public PrivilegeEscalationMonitor(SecurityEventService securityEventService,
AlertService alertService,
SystemAccessMonitor systemAccessMonitor,
FileSystemMonitor fileSystemMonitor,
ProcessMonitor processMonitor) {
this.securityEventService = securityEventService;
this.alertService = alertService;
this.systemAccessMonitor = systemAccessMonitor;
this.fileSystemMonitor = fileSystemMonitor;
this.processMonitor = processMonitor;
this.activeRules = new ConcurrentHashMap<>();
this.detectedEvents = new CopyOnWriteArrayList<>();
initializeMonitor();
}
@PostConstruct
public void startMonitoring() {
log.info("Starting privilege escalation monitoring");
initializeRules();
startPeriodicScans();
startRealTimeMonitoring();
}
@PreDestroy
public void stopMonitoring() {
log.info("Stopping privilege escalation monitoring");
if (monitorScheduler != null) {
monitorScheduler.shutdown();
try {
if (!monitorScheduler.awaitTermination(30, TimeUnit.SECONDS)) {
monitorScheduler.shutdownNow();
}
} catch (InterruptedException e) {
monitorScheduler.shutdownNow();
Thread.currentThread().interrupt();
}
}
}
/**
* Monitors for privilege escalation patterns
*/
public void monitorPrivilegeEscalation() {
try {
// Monitor file system for suspicious permissions
monitorFilePermissions();
// Monitor process privileges
monitorProcessPrivileges();
// Monitor user context changes
monitorUserContext();
// Monitor system configuration changes
monitorSystemConfiguration();
// Check for suspicious system calls
monitorSystemCalls();
} catch (Exception e) {
log.error("Error during privilege escalation monitoring", e);
}
}
/**
* Monitors file permissions for suspicious changes
*/
private void monitorFilePermissions() {
try {
List<FilePermissionViolation> violations = fileSystemMonitor.checkFilePermissions();
for (FilePermissionViolation violation : violations) {
if (isSuspiciousPermissionChange(violation)) {
reportPrivilegeEscalationEvent(
"SUSPICIOUS_FILE_PERMISSION",
"File permission change may enable privilege escalation",
Map.of(
"file", violation.getFilePath(),
"permission", violation.getPermission(),
"owner", violation.getOwner(),
"previousPermission", violation.getPreviousPermission()
),
Severity.HIGH
);
}
}
} catch (Exception e) {
log.error("Error monitoring file permissions", e);
}
}
/**
* Monitors process privileges and elevation attempts
*/
private void monitorProcessPrivileges() {
try {
List<ProcessPrivilegeInfo> privilegedProcesses = processMonitor.getPrivilegedProcesses();
for (ProcessPrivilegeInfo process : privilegedProcesses) {
if (isSuspiciousPrivilegedProcess(process)) {
reportPrivilegeEscalationEvent(
"SUSPICIOUS_PRIVILEGED_PROCESS",
"Process running with elevated privileges",
Map.of(
"processId", process.getPid(),
"processName", process.getName(),
"user", process.getUser(),
"privileges", process.getPrivileges()
),
Severity.HIGH
);
}
}
// Monitor for privilege elevation attempts
List<ProcessExecution> elevationAttempts = processMonitor.getPrivilegeElevationAttempts();
for (ProcessExecution attempt : elevationAttempts) {
reportPrivilegeEscalationEvent(
"PRIVILEGE_ELEVATION_ATTEMPT",
"Attempt to elevate process privileges detected",
Map.of(
"process", attempt.getProcessName(),
"command", attempt.getCommandLine(),
"user", attempt.getUser(),
"targetUser", attempt.getTargetUser()
),
Severity.CRITICAL
);
}
} catch (Exception e) {
log.error("Error monitoring process privileges", e);
}
}
/**
* Monitors user context and role changes
*/
private void monitorUserContext() {
try {
List<UserSession> activeSessions = systemAccessMonitor.getActiveSessions();
for (UserSession session : activeSessions) {
if (isSuspiciousUserSession(session)) {
reportPrivilegeEscalationEvent(
"SUSPICIOUS_USER_SESSION",
"Suspicious user session detected",
Map.of(
"user", session.getUsername(),
"sessionId", session.getSessionId(),
"loginTime", session.getLoginTime(),
"source", session.getSourceIp(),
"privileges", session.getPrivileges()
),
Severity.MEDIUM
);
}
}
// Monitor for user privilege changes
List<UserPrivilegeChange> privilegeChanges = systemAccessMonitor.getRecentPrivilegeChanges();
for (UserPrivilegeChange change : privilegeChanges) {
if (isUnauthorizedPrivilegeChange(change)) {
reportPrivilegeEscalationEvent(
"UNAUTHORIZED_PRIVILEGE_CHANGE",
"Unauthorized user privilege change detected",
Map.of(
"user", change.getUsername(),
"changedBy", change.getChangedBy(),
"privilege", change.getPrivilege(),
"action", change.getAction(),
"timestamp", change.getTimestamp()
),
Severity.CRITICAL
);
}
}
} catch (Exception e) {
log.error("Error monitoring user context", e);
}
}
/**
* Monitors system configuration for security changes
*/
private void monitorSystemConfiguration() {
try {
// Monitor sudoers configuration
monitorSudoersConfiguration();
// Monitor service permissions
monitorServicePermissions();
// Monitor scheduled tasks
monitorScheduledTasks();
// Monitor environment variables
monitorEnvironmentVariables();
} catch (Exception e) {
log.error("Error monitoring system configuration", e);
}
}
/**
* Monitors system calls for suspicious activities
*/
private void monitorSystemCalls() {
try {
List<SystemCall> suspiciousCalls = systemAccessMonitor.getSuspiciousSystemCalls();
for (SystemCall systemCall : suspiciousCalls) {
if (isPrivilegeEscalationSystemCall(systemCall)) {
reportPrivilegeEscalationEvent(
"SUSPICIOUS_SYSTEM_CALL",
"Suspicious system call detected",
Map.of(
"call", systemCall.getCallName(),
"process", systemCall.getProcessName(),
"pid", systemCall.getPid(),
"user", systemCall.getUser(),
"arguments", systemCall.getArguments()
),
Severity.HIGH
);
}
}
} catch (Exception e) {
log.error("Error monitoring system calls", e);
}
}
private void monitorSudoersConfiguration() {
try {
List<SudoersEntry> suspiciousEntries = systemAccessMonitor.getSuspiciousSudoersEntries();
for (SudoersEntry entry : suspiciousEntries) {
reportPrivilegeEscalationEvent(
"SUSPICIOUS_SUDOERS_ENTRY",
"Suspicious sudoers configuration detected",
Map.of(
"user", entry.getUser(),
"host", entry.getHost(),
"command", entry.getCommand(),
"runAs", entry.getRunAsUser()
),
Severity.HIGH
);
}
} catch (Exception e) {
log.error("Error monitoring sudoers configuration", e);
}
}
private void monitorServicePermissions() {
try {
List<ServicePermission> suspiciousServices = systemAccessMonitor.getServicesWithElevatedPermissions();
for (ServicePermission service : suspiciousServices) {
reportPrivilegeEscalationEvent(
"SERVICE_WITH_ELEVATED_PERMISSIONS",
"Service running with elevated permissions",
Map.of(
"service", service.getServiceName(),
"user", service.getRunAsUser(),
"permissions", service.getPermissions()
),
Severity.MEDIUM
);
}
} catch (Exception e) {
log.error("Error monitoring service permissions", e);
}
}
private void monitorScheduledTasks() {
try {
List<ScheduledTask> suspiciousTasks = systemAccessMonitor.getSuspiciousScheduledTasks();
for (ScheduledTask task : suspiciousTasks) {
reportPrivilegeEscalationEvent(
"SUSPICIOUS_SCHEDULED_TASK",
"Suspicious scheduled task with elevated privileges",
Map.of(
"task", task.getTaskName(),
"command", task.getCommand(),
"user", task.getRunAsUser(),
"schedule", task.getSchedule()
),
Severity.HIGH
);
}
} catch (Exception e) {
log.error("Error monitoring scheduled tasks", e);
}
}
private void monitorEnvironmentVariables() {
try {
List<EnvironmentVariable> suspiciousVars = systemAccessMonitor.getSuspiciousEnvironmentVariables();
for (EnvironmentVariable envVar : suspiciousVars) {
reportPrivilegeEscalationEvent(
"SUSPICIOUS_ENVIRONMENT_VARIABLE",
"Suspicious environment variable with privilege implications",
Map.of(
"variable", envVar.getName(),
"value", envVar.getValue(),
"process", envVar.getProcessName()
),
Severity.MEDIUM
);
}
} catch (Exception e) {
log.error("Error monitoring environment variables", e);
}
}
/**
* Reports a privilege escalation event
*/
private void reportPrivilegeEscalationEvent(String eventType, String description,
Map<String, Object> details, Severity severity) {
SecurityEvent event = SecurityEvent.builder()
.eventType(eventType)
.severity(severity)
.description(description)
.timestamp(Instant.now())
.source("PrivilegeEscalationMonitor")
.details(details)
.build();
detectedEvents.add(event);
securityEventService.recordEvent(event);
// Trigger alert for critical events
if (severity == Severity.CRITICAL || severity == Severity.HIGH) {
alertService.sendImmediateAlert(event);
}
log.warn("Privilege escalation event detected: {} - {}", eventType, description);
}
private boolean isSuspiciousPermissionChange(FilePermissionViolation violation) {
// Check for world-writable sensitive files
if (violation.getPermission().contains("w") &&
violation.getPermission().contains("other") &&
isSensitiveFile(violation.getFilePath())) {
return true;
}
// Check for SUID/SGID binaries in unusual locations
if ((violation.getPermission().contains("s") || violation.getPermission().contains("S")) &&
isSuspiciousLocation(violation.getFilePath())) {
return true;
}
return false;
}
private boolean isSuspiciousPrivilegedProcess(ProcessPrivilegeInfo process) {
// Check for processes running as root from non-standard users
if ("root".equals(process.getUser()) &&
!isExpectedRootProcess(process.getName())) {
return true;
}
// Check for processes with excessive privileges
if (process.getPrivileges().size() > 5) {
return true;
}
// Check for processes accessing sensitive resources
if (isAccessingSensitiveResources(process)) {
return true;
}
return false;
}
private boolean isSuspiciousUserSession(UserSession session) {
// Check for root logins from non-console
if ("root".equals(session.getUsername()) &&
!session.getSourceIp().equals("localhost") &&
!session.getSourceIp().equals("127.0.0.1")) {
return true;
}
// Check for multiple simultaneous sessions from same user
if (hasMultipleSimultaneousSessions(session)) {
return true;
}
// Check for sessions with unusual privilege sets
if (hasUnusualPrivileges(session)) {
return true;
}
return false;
}
private boolean isUnauthorizedPrivilegeChange(UserPrivilegeChange change) {
// Check if privilege change was performed by unauthorized user
if (!isAuthorizedPrivilegeManager(change.getChangedBy())) {
return true;
}
// Check for sensitive privilege additions
if ("ADD".equals(change.getAction()) &&
isSensitivePrivilege(change.getPrivilege())) {
return true;
}
return false;
}
private boolean isPrivilegeEscalationSystemCall(SystemCall systemCall) {
Set<String> privilegeEscalationCalls = Set.of(
"setuid", "setgid", "setreuid", "setregid",
"setresuid", "setresgid", "capset", "prctl"
);
return privilegeEscalationCalls.contains(systemCall.getCallName());
}
// Helper methods for detection logic
private boolean isSensitiveFile(String filePath) {
Set<String> sensitiveFiles = Set.of(
"/etc/passwd", "/etc/shadow", "/etc/sudoers",
"/etc/crontab", "/root/.ssh/", "/etc/ssh/"
);
return sensitiveFiles.stream().anyMatch(filePath::contains);
}
private boolean isSuspiciousLocation(String filePath) {
Set<String> suspiciousLocations = Set.of(
"/tmp", "/var/tmp", "/dev/shm", "/home"
);
return suspiciousLocations.stream().anyMatch(filePath::contains);
}
private boolean isExpectedRootProcess(String processName) {
Set<String> expectedRootProcesses = Set.of(
"systemd", "init", "sshd", "crond", "syslogd"
);
return expectedRootProcesses.contains(processName);
}
private boolean isAccessingSensitiveResources(ProcessPrivilegeInfo process) {
// Implementation would check process file descriptors and resources
return false;
}
private boolean hasMultipleSimultaneousSessions(UserSession session) {
// Implementation would check session count for user
return false;
}
private boolean hasUnusualPrivileges(UserSession session) {
// Implementation would check against baseline privileges
return false;
}
private boolean isAuthorizedPrivilegeManager(String username) {
Set<String> authorizedUsers = Set.of("root", "admin", "security-admin");
return authorizedUsers.contains(username);
}
private boolean isSensitivePrivilege(String privilege) {
Set<String> sensitivePrivileges = Set.of(
"ALL", "SUDO", "DBA", "ROOT", "ADMIN"
);
return sensitivePrivileges.contains(privilege.toUpperCase());
}
private void initializeMonitor() {
this.monitorScheduler = Executors.newScheduledThreadPool(3, r -> {
Thread t = new Thread(r, "privilege-monitor");
t.setDaemon(true);
return t;
});
}
private void initializeRules() {
// Add monitoring rules
activeRules.put("FILE_PERMISSION_MONITOR",
new MonitoringRule("FILE_PERMISSION_MONITOR",
"Monitor sensitive file permissions",
MonitoringRule.Severity.HIGH));
activeRules.put("PROCESS_PRIVILEGE_MONITOR",
new MonitoringRule("PROCESS_PRIVILEGE_MONITOR",
"Monitor process privilege escalation",
MonitoringRule.Severity.CRITICAL));
activeRules.put("USER_PRIVILEGE_MONITOR",
new MonitoringRule("USER_PRIVILEGE_MONITOR",
"Monitor user privilege changes",
MonitoringRule.Severity.HIGH));
}
private void startPeriodicScans() {
// Schedule periodic monitoring
monitorScheduler.scheduleAtFixedRate(
this::monitorPrivilegeEscalation, 0, 60, TimeUnit.SECONDS);
// Schedule comprehensive scans
monitorScheduler.scheduleAtFixedRate(
this::performComprehensiveScan, 0, 300, TimeUnit.SECONDS);
}
private void startRealTimeMonitoring() {
// Start real-time monitoring based on platform capabilities
if (isLinuxSystem()) {
startLinuxRealTimeMonitoring();
} else if (isWindowsSystem()) {
startWindowsRealTimeMonitoring();
}
}
private void performComprehensiveScan() {
log.info("Starting comprehensive privilege escalation scan");
// Comprehensive scanning logic
}
private boolean isLinuxSystem() {
return System.getProperty("os.name").toLowerCase().contains("linux");
}
private boolean isWindowsSystem() {
return System.getProperty("os.name").toLowerCase().contains("windows");
}
private void startLinuxRealTimeMonitoring() {
// Linux-specific real-time monitoring
log.info("Starting Linux real-time privilege monitoring");
}
private void startWindowsRealTimeMonitoring() {
// Windows-specific real-time monitoring
log.info("Starting Windows real-time privilege monitoring");
}
/**
* Gets detected privilege escalation events
*/
public List<SecurityEvent> getDetectedEvents() {
return new ArrayList<>(detectedEvents);
}
/**
* Gets events by severity
*/
public List<SecurityEvent> getEventsBySeverity(Severity severity) {
return detectedEvents.stream()
.filter(event -> event.getSeverity() == severity)
.collect(Collectors.toList());
}
/**
* Clears old events
*/
public void clearEventsOlderThan(Duration duration) {
Instant cutoff = Instant.now().minus(duration);
detectedEvents.removeIf(event -> event.getTimestamp().isBefore(cutoff));
}
}
File System Monitoring
File System Security Monitor
/**
* File System Security Monitor
* Monitors file permissions, ownership, and sensitive file access
*/
@Service
@Slf4j
public class FileSystemMonitor {
private final Set<String> monitoredPaths;
private final Map<String, FileSnapshot> fileSnapshots;
private final WatchService watchService;
private final Set<Path> watchedDirectories;
public FileSystemMonitor() throws IOException {
this.monitoredPaths = ConcurrentHashMap.newKeySet();
this.fileSnapshots = new ConcurrentHashMap<>();
this.watchService = FileSystems.getDefault().newWatchService();
this.watchedDirectories = ConcurrentHashMap.newKeySet();
initializeDefaultPaths();
}
/**
* Checks file permissions for violations
*/
public List<FilePermissionViolation> checkFilePermissions() {
List<FilePermissionViolation> violations = new ArrayList<>();
for (String path : monitoredPaths) {
try {
violations.addAll(checkPathPermissions(Paths.get(path)));
} catch (Exception e) {
log.error("Error checking permissions for path: {}", path, e);
}
}
return violations;
}
/**
* Monitors file system changes in real-time
*/
public void startRealTimeMonitoring() {
Thread monitorThread = new Thread(this::monitorFileEvents, "file-monitor");
monitorThread.setDaemon(true);
monitorThread.start();
}
/**
* Adds a path to monitor
*/
public void addMonitoredPath(String path) {
monitoredPaths.add(path);
try {
Path dirPath = Paths.get(path);
if (Files.isDirectory(dirPath)) {
WatchKey key = dirPath.register(watchService,
StandardWatchEventKinds.ENTRY_CREATE,
StandardWatchEventKinds.ENTRY_MODIFY,
StandardWatchEventKinds.ENTRY_DELETE);
watchedDirectories.add(dirPath);
log.info("Started monitoring directory: {}", path);
}
} catch (IOException e) {
log.error("Failed to monitor directory: {}", path, e);
}
}
/**
* Takes snapshot of current file state
*/
public void takeSnapshot() {
fileSnapshots.clear();
for (String path : monitoredPaths) {
try {
takePathSnapshot(Paths.get(path));
} catch (Exception e) {
log.error("Error taking snapshot for path: {}", path, e);
}
}
log.info("File system snapshot completed. Monitored files: {}", fileSnapshots.size());
}
/**
* Detects changes since last snapshot
*/
public List<FileSystemChange> detectChanges() {
List<FileSystemChange> changes = new ArrayList<>();
for (String path : monitoredPaths) {
try {
changes.addAll(detectPathChanges(Paths.get(path)));
} catch (Exception e) {
log.error("Error detecting changes for path: {}", path, e);
}
}
return changes;
}
private List<FilePermissionViolation> checkPathPermissions(Path path) throws IOException {
List<FilePermissionViolation> violations = new ArrayList<>();
Files.walk(path)
.filter(Files::isRegularFile)
.forEach(file -> {
try {
FilePermissionViolation violation = checkFilePermission(file);
if (violation != null) {
violations.add(violation);
}
} catch (IOException e) {
log.error("Error checking file permissions: {}", file, e);
}
});
return violations;
}
private FilePermissionViolation checkFilePermission(Path file) throws IOException {
PosixFileAttributes attrs = Files.readAttributes(file, PosixFileAttributes.class);
PosixFilePermissions.toString(attrs.permissions());
String permissions = PosixFilePermissions.toString(attrs.permissions());
String filename = file.toString();
// Check for world-writable files
if (permissions.contains("w") && permissions.contains("other")) {
if (isSensitiveFile(filename)) {
return new FilePermissionViolation(
filename,
permissions,
attrs.owner().getName(),
"World-writable sensitive file",
FilePermissionViolation.Type.WORLD_WRITABLE_SENSITIVE
);
}
}
// Check for SUID/SGID files
if (permissions.contains("s") || permissions.contains("S")) {
if (isSuspiciousSuidFile(filename)) {
return new FilePermissionViolation(
filename,
permissions,
attrs.owner().getName(),
"Suspicious SUID/SGID file",
FilePermissionViolation.Type.SUSPICIOUS_SUID
);
}
}
// Check for files owned by root with non-root group
if ("root".equals(attrs.owner().getName()) &&
!"root".equals(attrs.group().getName())) {
return new FilePermissionViolation(
filename,
permissions,
attrs.owner().getName(),
"Root-owned file with non-root group",
FilePermissionViolation.Type.ROOT_NON_ROOT_GROUP
);
}
return null;
}
private void monitorFileEvents() {
while (!Thread.currentThread().isInterrupted()) {
try {
WatchKey key = watchService.take();
Path dir = (Path) key.watchable();
for (WatchEvent<?> event : key.pollEvents()) {
WatchEvent.Kind<?> kind = event.kind();
Path filename = (Path) event.context();
Path child = dir.resolve(filename);
handleFileEvent(kind, child);
}
boolean valid = key.reset();
if (!valid) {
watchedDirectories.remove(dir);
log.warn("Watch key no longer valid for: {}", dir);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
} catch (Exception e) {
log.error("Error in file monitoring", e);
}
}
}
private void handleFileEvent(WatchEvent.Kind<?> kind, Path file) {
try {
if (Files.exists(file)) {
PosixFileAttributes attrs = Files.readAttributes(file, PosixFileAttributes.class);
String permissions = PosixFilePermissions.toString(attrs.permissions());
// Check for permission changes
if (kind == StandardWatchEventKinds.ENTRY_MODIFY) {
FileSnapshot previous = fileSnapshots.get(file.toString());
if (previous != null && !previous.getPermissions().equals(permissions)) {
log.warn("File permission changed: {} -> {}",
previous.getPermissions(), permissions);
// Report permission change event
}
}
// Update snapshot
fileSnapshots.put(file.toString(),
new FileSnapshot(file.toString(), permissions,
attrs.owner().getName(), attrs.lastModifiedTime()));
}
} catch (IOException e) {
log.error("Error handling file event: {}", file, e);
}
}
private void takePathSnapshot(Path path) throws IOException {
Files.walk(path)
.filter(Files::isRegularFile)
.forEach(file -> {
try {
PosixFileAttributes attrs = Files.readAttributes(file, PosixFileAttributes.class);
String permissions = PosixFilePermissions.toString(attrs.permissions());
fileSnapshots.put(file.toString(),
new FileSnapshot(file.toString(), permissions,
attrs.owner().getName(), attrs.lastModifiedTime()));
} catch (IOException e) {
log.error("Error taking snapshot for file: {}", file, e);
}
});
}
private List<FileSystemChange> detectPathChanges(Path path) throws IOException {
List<FileSystemChange> changes = new ArrayList<>();
Files.walk(path)
.filter(Files::isRegularFile)
.forEach(file -> {
try {
FileSystemChange change = detectFileChange(file);
if (change != null) {
changes.add(change);
}
} catch (IOException e) {
log.error("Error detecting changes for file: {}", file, e);
}
});
return changes;
}
private FileSystemChange detectFileChange(Path file) throws IOException {
String filePath = file.toString();
FileSnapshot currentSnapshot = fileSnapshots.get(filePath);
if (currentSnapshot == null) {
return new FileSystemChange(filePath, FileSystemChange.Type.CREATED,
"New file detected", Instant.now());
}
PosixFileAttributes currentAttrs = Files.readAttributes(file, PosixFileAttributes.class);
String currentPermissions = PosixFilePermissions.toString(currentAttrs.permissions());
if (!currentPermissions.equals(currentSnapshot.getPermissions())) {
return new FileSystemChange(filePath, FileSystemChange.Type.PERMISSION_CHANGED,
String.format("Permissions changed from %s to %s",
currentSnapshot.getPermissions(), currentPermissions),
Instant.now());
}
if (!currentAttrs.owner().getName().equals(currentSnapshot.getOwner())) {
return new FileSystemChange(filePath, FileSystemChange.Type.OWNER_CHANGED,
String.format("Owner changed from %s to %s",
currentSnapshot.getOwner(), currentAttrs.owner().getName()),
Instant.now());
}
return null;
}
private void initializeDefaultPaths() {
// Add default sensitive paths to monitor
addMonitoredPath("/etc");
addMonitoredPath("/root");
addMonitoredPath("/usr/bin");
addMonitoredPath("/usr/sbin");
addMonitoredPath("/var/log");
}
private boolean isSensitiveFile(String filename) {
Set<String> sensitivePatterns = Set.of(
"passwd", "shadow", "sudoers", "crontab",
"ssh", ".pem", ".key", ".crt", ".p12"
);
return sensitivePatterns.stream().anyMatch(filename::contains);
}
private boolean isSuspiciousSuidFile(String filename) {
Set<String> expectedSuidFiles = Set.of(
"passwd", "su", "sudo", "mount", "umount", "ping"
);
String baseName = Paths.get(filename).getFileName().toString();
return !expectedSuidFiles.contains(baseName);
}
}
/**
* File system data models
*/
@Data
@AllArgsConstructor
public class FilePermissionViolation {
private String filePath;
private String permission;
private String owner;
private String description;
private Type type;
public enum Type {
WORLD_WRITABLE_SENSITIVE,
SUSPICIOUS_SUID,
ROOT_NON_ROOT_GROUP,
EXCESSIVE_PERMISSIONS
}
}
@Data
@AllArgsConstructor
public class FileSnapshot {
private String filePath;
private String permissions;
private String owner;
private FileTime lastModified;
}
@Data
@AllArgsConstructor
public class FileSystemChange {
private String filePath;
private Type type;
private String description;
private Instant detectedAt;
public enum Type {
CREATED, DELETED, MODIFIED, PERMISSION_CHANGED, OWNER_CHANGED
}
}
Process Monitoring
Process Security Monitor
/**
* Process Security Monitor
* Monitors process execution, privileges, and suspicious activities
*/
@Service
@Slf4j
public class ProcessMonitor {
private final Set<String> monitoredProcesses;
private final Map<Integer, ProcessInfo> activeProcesses;
private final ScheduledExecutorService processScanner;
public ProcessMonitor() {
this.monitoredProcesses = ConcurrentHashMap.newKeySet();
this.activeProcesses = new ConcurrentHashMap<>();
this.processScanner = Executors.newScheduledThreadPool(1, r -> {
Thread t = new Thread(r, "process-scanner");
t.setDaemon(true);
return t;
});
initializeProcessMonitoring();
}
/**
* Gets processes with elevated privileges
*/
public List<ProcessPrivilegeInfo> getPrivilegedProcesses() {
List<ProcessPrivilegeInfo> privilegedProcesses = new ArrayList<>();
try {
// Use platform-specific tools to get process information
if (isLinuxSystem()) {
privilegedProcesses.addAll(getLinuxPrivilegedProcesses());
} else if (isWindowsSystem()) {
privilegedProcesses.addAll(getWindowsPrivilegedProcesses());
}
} catch (Exception e) {
log.error("Error getting privileged processes", e);
}
return privilegedProcesses;
}
/**
* Gets privilege elevation attempts
*/
public List<ProcessExecution> getPrivilegeElevationAttempts() {
List<ProcessExecution> elevationAttempts = new ArrayList<>();
try {
// Monitor for sudo/su executions
elevationAttempts.addAll(getSudoExecutions());
// Monitor for runas executions (Windows)
if (isWindowsSystem()) {
elevationAttempts.addAll(getRunasExecutions());
}
} catch (Exception e) {
log.error("Error getting privilege elevation attempts", e);
}
return elevationAttempts;
}
/**
* Monitors process creation and termination
*/
public void startProcessMonitoring() {
processScanner.scheduleAtFixedRate(this::scanProcesses, 0, 5, TimeUnit.SECONDS);
}
/**
* Checks for suspicious process behavior
*/
public List<ProcessAnomaly> checkProcessAnomalies() {
List<ProcessAnomaly> anomalies = new ArrayList<>();
try {
// Check for process injection
anomalies.addAll(checkProcessInjection());
// Check for unusual parent-child relationships
anomalies.addAll(checkParentChildAnomalies());
// Check for process masquerading
anomalies.addAll(checkProcessMasquerading());
} catch (Exception e) {
log.error("Error checking process anomalies", e);
}
return anomalies;
}
private List<ProcessPrivilegeInfo> getLinuxPrivilegedProcesses() throws IOException {
List<ProcessPrivilegeInfo> processes = new ArrayList<>();
// Parse /proc for process information
File procDir = new File("/proc");
File[] processDirs = procDir.listFiles(File::isDirectory);
if (processDirs != null) {
for (File processDir : processDirs) {
try {
int pid = Integer.parseInt(processDir.getName());
ProcessPrivilegeInfo processInfo = getLinuxProcessInfo(pid);
if (processInfo != null && processInfo.isPrivileged()) {
processes.add(processInfo);
}
} catch (NumberFormatException e) {
// Skip non-process directories
}
}
}
return processes;
}
private ProcessPrivilegeInfo getLinuxProcessInfo(int pid) throws IOException {
Path statusPath = Paths.get("/proc", String.valueOf(pid), "status");
if (!Files.exists(statusPath)) {
return null;
}
Map<String, String> status = new HashMap<>();
Files.lines(statusPath).forEach(line -> {
String[] parts = line.split(":\t", 2);
if (parts.length == 2) {
status.put(parts[0].trim(), parts[1].trim());
}
});
String name = status.get("Name");
String user = status.get("Uid");
String group = status.get("Gid");
ProcessPrivilegeInfo info = new ProcessPrivilegeInfo();
info.setPid(pid);
info.setName(name);
info.setUser(user);
info.setGroup(group);
// Check privileges
if ("0".equals(user.split("\\s+")[0])) { // root user
info.setPrivileged(true);
info.getPrivileges().add("ROOT");
}
// Check capabilities
Set<String> capabilities = getProcessCapabilities(pid);
info.getPrivileges().addAll(capabilities);
return info;
}
private Set<String> getProcessCapabilities(int pid) throws IOException {
Set<String> capabilities = new HashSet<>();
Path statusPath = Paths.get("/proc", String.valueOf(pid), "status");
if (Files.exists(statusPath)) {
List<String> lines = Files.readAllLines(statusPath);
for (String line : lines) {
if (line.startsWith("Cap")) {
capabilities.add(line.trim());
}
}
}
return capabilities;
}
private List<ProcessPrivilegeInfo> getWindowsPrivilegedProcesses() {
List<ProcessPrivilegeInfo> processes = new ArrayList<>();
try {
// Use WMI or PowerShell to get process information
ProcessBuilder pb = new ProcessBuilder("tasklist", "/fo", "csv", "/v");
Process process = pb.start();
String output = new String(process.getInputStream().readAllBytes());
String[] lines = output.split("\n");
for (String line : lines) {
if (line.contains("NT AUTHORITY\\SYSTEM") || line.contains("Administrator")) {
ProcessPrivilegeInfo info = parseWindowsProcessLine(line);
if (info != null) {
processes.add(info);
}
}
}
} catch (Exception e) {
log.error("Error getting Windows privileged processes", e);
}
return processes;
}
private ProcessPrivilegeInfo parseWindowsProcessLine(String line) {
// Parse CSV line from tasklist output
String[] parts = line.split(",");
if (parts.length >= 8) {
ProcessPrivilegeInfo info = new ProcessPrivilegeInfo();
info.setName(parts[0].replace("\"", "").trim());
info.setPid(Integer.parseInt(parts[1].replace("\"", "").trim()));
info.setUser(parts[6].replace("\"", "").trim());
info.setPrivileged(true);
return info;
}
return null;
}
private List<ProcessExecution> getSudoExecutions() throws IOException {
List<ProcessExecution> executions = new ArrayList<>();
// Parse auth.log or secure log for sudo executions
Path authLog = Paths.get("/var/log/auth.log");
if (Files.exists(authLog)) {
List<String> lines = Files.readAllLines(authLog);
for (String line : lines) {
if (line.contains("sudo:") && line.contains("COMMAND=")) {
ProcessExecution execution = parseSudoLogLine(line);
if (execution != null) {
executions.add(execution);
}
}
}
}
return executions;
}
private ProcessExecution parseSudoLogLine(String line) {
// Parse sudo log line
// Example: "sudo: user : TTY=pts/0 ; PWD=/home/user ; USER=root ; COMMAND=/bin/bash"
ProcessExecution execution = new ProcessExecution();
String[] parts = line.split(";");
for (String part : parts) {
if (part.contains("USER=")) {
execution.setTargetUser(part.split("=")[1].trim());
} else if (part.contains("COMMAND=")) {
execution.setCommandLine(part.split("=")[1].trim());
}
}
execution.setProcessName("sudo");
execution.setUser(System.getProperty("user.name"));
return execution;
}
private List<ProcessExecution> getRunasExecutions() {
// Windows runas command monitoring
return new ArrayList<>(); // Implementation would use Windows event logs
}
private List<ProcessAnomaly> checkProcessInjection() {
List<ProcessAnomaly> anomalies = new ArrayList<>();
// Check for process injection techniques
// This would require platform-specific implementations
return anomalies;
}
private List<ProcessAnomaly> checkParentChildAnomalies() {
List<ProcessAnomaly> anomalies = new ArrayList<>();
// Check for unusual parent-child process relationships
// e.g., browser spawning cmd.exe, word spawning powershell
return anomalies;
}
private List<ProcessAnomaly> checkProcessMasquerading() {
List<ProcessAnomaly> anomalies = new ArrayList<>();
// Check for process masquerading (e.g., lsass.exe vs lsass.exe)
// Compare process names with expected locations and signatures
return anomalies;
}
private void scanProcesses() {
try {
Map<Integer, ProcessInfo> currentProcesses = getCurrentProcesses();
// Detect new processes
for (Integer pid : currentProcesses.keySet()) {
if (!activeProcesses.containsKey(pid)) {
ProcessInfo newProcess = currentProcesses.get(pid);
handleNewProcess(newProcess);
}
}
// Detect terminated processes
for (Integer pid : activeProcesses.keySet()) {
if (!currentProcesses.containsKey(pid)) {
ProcessInfo terminatedProcess = activeProcesses.get(pid);
handleTerminatedProcess(terminatedProcess);
}
}
activeProcesses.clear();
activeProcesses.putAll(currentProcesses);
} catch (Exception e) {
log.error("Error scanning processes", e);
}
}
private Map<Integer, ProcessInfo> getCurrentProcesses() {
Map<Integer, ProcessInfo> processes = new HashMap<>();
try {
ProcessHandle.allProcesses().forEach(handle -> {
ProcessInfo info = new ProcessInfo();
info.setPid((int) handle.pid());
info.setCommand(handle.info().command().orElse(""));
info.setUser(handle.info().user().orElse(""));
info.setStartTime(handle.info().startInstant().orElse(Instant.now()));
processes.put(info.getPid(), info);
});
} catch (Exception e) {
log.error("Error getting current processes", e);
}
return processes;
}
private void handleNewProcess(ProcessInfo process) {
// Check if process is suspicious
if (isSuspiciousProcess(process)) {
log.warn("Suspicious process started: {} (PID: {})",
process.getCommand(), process.getPid());
// Report security event
SecurityEvent event = SecurityEvent.builder()
.eventType("SUSPICIOUS_PROCESS_START")
.severity(Severity.MEDIUM)
.description("Suspicious process started: " + process.getCommand())
.timestamp(Instant.now())
.source("ProcessMonitor")
.details(Map.of(
"pid", process.getPid(),
"command", process.getCommand(),
"user", process.getUser()
))
.build();
// Send to security event service
}
}
private void handleTerminatedProcess(ProcessInfo process) {
// Log process termination if it was being monitored
if (monitoredProcesses.contains(process.getCommand())) {
log.info("Monitored process terminated: {} (PID: {})",
process.getCommand(), process.getPid());
}
}
private boolean isSuspiciousProcess(ProcessInfo process) {
Set<String> suspiciousPatterns = Set.of(
"meterpreter", "beacon", "cobaltstrike", "empire",
"powershell -enc", "cmd /c", "wscript.shell",
"regsvr32", "rundll32", "mshta"
);
String command = process.getCommand().toLowerCase();
return suspiciousPatterns.stream().anyMatch(command::contains);
}
private void initializeProcessMonitoring() {
// Add known suspicious processes to monitor
monitoredProcesses.addAll(Set.of(
"nc", "netcat", "socat", "ncat",
"wget", "curl", "powershell", "python",
"perl", "ruby", "php"
));
startProcessMonitoring();
}
private boolean isLinuxSystem() {
return System.getProperty("os.name").toLowerCase().contains("linux");
}
private boolean isWindowsSystem() {
return System.getProperty("os.name").toLowerCase().contains("windows");
}
}
/**
* Process monitoring data models
*/
@Data
public class ProcessPrivilegeInfo {
private int pid;
private String name;
private String user;
private String group;
private boolean privileged;
private Set<String> privileges = new HashSet<>();
public boolean isPrivileged() {
return privileged || !privileges.isEmpty();
}
}
@Data
public class ProcessExecution {
private String processName;
private String commandLine;
private String user;
private String targetUser;
private Instant executionTime;
}
@Data
public class ProcessAnomaly {
private int pid;
private String processName;
private String anomalyType;
private String description;
private Severity severity;
private Instant detectedAt;
}
@Data
public class ProcessInfo {
private int pid;
private String command;
private String user;
private Instant startTime;
private String parentPid;
}
Spring Boot Integration
Security Configuration
/**
* Security configuration for privilege escalation monitoring
*/
@Configuration
@EnableConfigurationProperties(SecurityMonitorProperties.class)
public class SecurityMonitorConfiguration {
@Bean
@ConditionalOnProperty(name = "security.monitoring.privilege-escalation.enabled", havingValue = "true")
public PrivilegeEscalationMonitor privilegeEscalationMonitor(
SecurityEventService securityEventService,
AlertService alertService,
SystemAccessMonitor systemAccessMonitor,
FileSystemMonitor fileSystemMonitor,
ProcessMonitor processMonitor) {
return new PrivilegeEscalationMonitor(
securityEventService, alertService, systemAccessMonitor,
fileSystemMonitor, processMonitor);
}
@Bean
public FileSystemMonitor fileSystemMonitor() throws IOException {
return new FileSystemMonitor();
}
@Bean
public ProcessMonitor processMonitor() {
return new ProcessMonitor();
}
@Bean
public SystemAccessMonitor systemAccessMonitor() {
return new SystemAccessMonitor();
}
@Bean
public SecurityEventService securityEventService() {
return new SecurityEventService();
}
@Bean
public AlertService alertService() {
return new AlertService();
}
}
/**
* Security monitor properties
*/
@ConfigurationProperties(prefix = "security.monitoring")
@Data
public class SecurityMonitorProperties {
private PrivilegeEscalation privilegeEscalation = new PrivilegeEscalation();
private FileSystem fileSystem = new FileSystem();
private Process process = new Process();
private Reporting reporting = new Reporting();
@Data
public static class PrivilegeEscalation {
private boolean enabled = true;
private int scanInterval = 60;
private boolean realTimeMonitoring = true;
private List<String> monitoredPaths = List.of("/etc", "/root", "/usr/bin");
}
@Data
public static class FileSystem {
private boolean enabled = true;
private int snapshotInterval = 300;
private List<String> sensitiveFiles = List.of(
"/etc/passwd", "/etc/shadow", "/etc/sudoers"
);
}
@Data
public static class Process {
private boolean enabled = true;
private int scanInterval = 5;
private List<String> suspiciousProcesses = List.of(
"nc", "netcat", "socat", "meterpreter"
);
}
@Data
public static class Reporting {
private boolean enabled = true;
private String logLevel = "WARN";
private Webhook webhook = new Webhook();
private Email email = new Email();
@Data
public static class Webhook {
private String url;
private String secret;
}
@Data
public static class Email {
private List<String> recipients;
private String subjectPrefix = "[SECURITY]";
}
}
}
/**
* Security monitor health indicator
*/
@Component
public class SecurityMonitorHealthIndicator implements HealthIndicator {
private final PrivilegeEscalationMonitor privilegeMonitor;
private final FileSystemMonitor fileSystemMonitor;
private final ProcessMonitor processMonitor;
public SecurityMonitorHealthIndicator(PrivilegeEscalationMonitor privilegeMonitor,
FileSystemMonitor fileSystemMonitor,
ProcessMonitor processMonitor) {
this.privilegeMonitor = privilegeMonitor;
this.fileSystemMonitor = fileSystemMonitor;
this.processMonitor = processMonitor;
}
@Override
public Health health() {
try {
Map<String, Object> details = new HashMap<>();
// Check monitoring components
details.put("privilege_monitoring", "ACTIVE");
details.put("file_system_monitoring", "ACTIVE");
details.put("process_monitoring", "ACTIVE");
// Get recent events count
List<SecurityEvent> recentEvents = privilegeMonitor.getEventsBySeverity(Severity.HIGH);
details.put("high_severity_events", recentEvents.size());
return Health.up()
.withDetails(details)
.build();
} catch (Exception e) {
return Health.down()
.withDetail("error", e.getMessage())
.build();
}
}
}
/**
* Security monitor REST controller
*/
@RestController
@RequestMapping("/api/security/monitoring")
@Slf4j
public class SecurityMonitorController {
private final PrivilegeEscalationMonitor privilegeMonitor;
public SecurityMonitorController(PrivilegeEscalationMonitor privilegeMonitor) {
this.privilegeMonitor = privilegeMonitor;
}
@GetMapping("/events")
public List<SecurityEvent> getSecurityEvents(
@RequestParam(defaultValue = "1") int hours,
@RequestParam(required = false) Severity severity) {
List<SecurityEvent> events = privilegeMonitor.getDetectedEvents();
Instant cutoff = Instant.now().minus(Duration.ofHours(hours));
return events.stream()
.filter(event -> event.getTimestamp().isAfter(cutoff))
.filter(event -> severity == null || event.getSeverity() == severity)
.collect(Collectors.toList());
}
@PostMapping("/scan")
public ResponseEntity<String> triggerSecurityScan() {
try {
privilegeMonitor.monitorPrivilegeEscalation();
return ResponseEntity.ok("Security scan completed successfully");
} catch (Exception e) {
log.error("Security scan failed", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body("Security scan failed: " + e.getMessage());
}
}
@GetMapping("/status")
public Map<String, Object> getMonitoringStatus() {
Map<String, Object> status = new HashMap<>();
List<SecurityEvent> events = privilegeMonitor.getDetectedEvents();
Instant lastHour = Instant.now().minus(Duration.ofHours(1));
long criticalEvents = events.stream()
.filter(event -> event.getTimestamp().isAfter(lastHour))
.filter(event -> event.getSeverity() == Severity.CRITICAL)
.count();
long highEvents = events.stream()
.filter(event -> event.getTimestamp().isAfter(lastHour))
.filter(event -> event.getSeverity() == Severity.HIGH)
.count();
status.put("critical_events_last_hour", criticalEvents);
status.put("high_events_last_hour", highEvents);
status.put("total_events", events.size());
status.put("monitoring_active", true);
status.put("last_scan", Instant.now());
return status;
}
}
Best Practices Summary
/**
* PRIVILEGE ESCALATION MONITORING BEST PRACTICES
*
* 1. Monitor file permissions for sensitive files and directories
* 2. Track process privileges and elevation attempts
* 3. Monitor user sessions and privilege changes
* 4. Implement real-time file system monitoring
* 5. Use behavioral analysis to detect anomalies
* 6. Establish baseline security configurations
* 7. Implement comprehensive logging and alerting
* 8. Regular security scanning and compliance checks
* 9. Use principle of least privilege for monitoring
* 10. Maintain audit trails for security events
*/
/**
* Utility class with security monitoring best practices
*/
public final class SecurityMonitoringBestPractices {
private SecurityMonitoringBestPractices() {
// Utility class
}
/**
* Validates security monitoring configuration
*/
public static List<String> validateConfiguration(SecurityMonitorProperties properties) {
List<String> issues = new ArrayList<>();
if (properties.getPrivilegeEscalation().isEnabled() &&
properties.getPrivilegeEscalation().getMonitoredPaths().isEmpty()) {
issues.add("No monitored paths configured for privilege escalation monitoring");
}
if (properties.getFileSystem().isEnabled() &&
properties.getFileSystem().getSensitiveFiles().isEmpty()) {
issues.add("No sensitive files configured for file system monitoring");
}
if (properties.getReporting().isEnabled() &&
properties.getReporting().getWebhook().getUrl() == null &&
properties.getReporting().getEmail().getRecipients().isEmpty()) {
issues.add("No reporting destinations configured");
}
return issues;
}
/**
* Generates security monitoring policy template
*/
public static String generateSecurityPolicy() {
return """
security_monitoring:
privilege_escalation:
enabled: true
scan_interval: 60
real_time_monitoring: true
monitored_paths:
- /etc
- /root
- /usr/bin
- /usr/sbin
file_system:
enabled: true
snapshot_interval: 300
sensitive_files:
- /etc/passwd
- /etc/shadow
- /etc/sudoers
- /root/.ssh/
process:
enabled: true
scan_interval: 5
suspicious_processes:
- nc
- netcat
- socat
- meterpreter
""";
}
/**
* Creates security monitoring checklist
*/
public static List<String> getMonitoringChecklist() {
return Arrays.asList(
"Enable file system permission monitoring",
"Configure process privilege monitoring",
"Set up user session monitoring",
"Implement real-time file system watchers",
"Configure security event logging",
"Set up alerting for critical events",
"Establish baseline security configurations",
"Implement regular security scans",
"Configure compliance checking",
"Set up audit trail maintenance"
);
}
/**
* Gets common privilege escalation indicators
*/
public static Set<String> getPrivilegeEscalationIndicators() {
return Set.of(
"World-writable sensitive files",
"Suspicious SUID/SGID binaries",
"Unauthorized privilege changes",
"Suspicious process executions",
"Unusual user session patterns",
"Sudo/su abuse attempts",
"Service permission changes",
"Scheduled task modifications",
"Environment variable tampering",
"Process injection attempts"
);
}
}
Conclusion
The Privilege Escalation Monitor provides comprehensive security monitoring for Java applications:
- File System Security - Monitors permissions, ownership, and sensitive file access
- Process Monitoring - Tracks process privileges, executions, and suspicious activities
- User Session Security - Monitors user sessions, logins, and privilege changes
- Real-time Detection - Immediate detection of security events and anomalies
- Behavioral Analysis - Identifies suspicious patterns and escalation attempts
- Comprehensive Reporting - Detailed security event logging and alerting
- Integration Ready - Spring Boot integration with REST API endpoints
- Platform Support - Cross-platform monitoring for Linux and Windows
By implementing this monitoring solution, organizations can significantly improve their security posture by detecting and preventing privilege escalation attacks in real-time while maintaining comprehensive audit trails for compliance and forensic analysis.
Advanced Java Supply Chain Security, Kubernetes Hardening & Runtime Threat Detection
Sigstore Rekor in Java – https://macronepal.com/blog/sigstore-rekor-in-java/
Explains integrating Sigstore Rekor into Java systems to create a transparent, tamper-proof log of software signatures and metadata for verifying supply chain integrity.
Securing Java Applications with Chainguard Wolfi – https://macronepal.com/blog/securing-java-applications-with-chainguard-wolfi-a-comprehensive-guide/
Explains using Chainguard Wolfi minimal container images to reduce vulnerabilities and secure Java applications with hardened, lightweight runtime environments.
Cosign Image Signing in Java Complete Guide – https://macronepal.com/blog/cosign-image-signing-in-java-complete-guide/
Explains how to digitally sign container images using Cosign in Java-based workflows to ensure authenticity and prevent unauthorized modifications.
Secure Supply Chain Enforcement Kyverno Image Verification for Java Containers – https://macronepal.com/blog/secure-supply-chain-enforcement-kyverno-image-verification-for-java-containers/
Explains enforcing Kubernetes policies with Kyverno to verify container image signatures and ensure only trusted Java container images are deployed.
Pod Security Admission in Java Securing Kubernetes Deployments for JVM Applications – https://macronepal.com/blog/pod-security-admission-in-java-securing-kubernetes-deployments-for-jvm-applications/
Explains Kubernetes Pod Security Admission policies that enforce security rules like restricted privileges and safe configurations for Java workloads.
Securing Java Applications at Runtime Kubernetes Security Context – https://macronepal.com/blog/securing-java-applications-at-runtime-a-guide-to-kubernetes-security-context/
Explains how Kubernetes security contexts control runtime permissions, user IDs, and access rights for Java containers to improve isolation.
Process Anomaly Detection in Java Behavioral Monitoring – https://macronepal.com/blog/process-anomaly-detection-in-java-comprehensive-behavioral-monitoring-2/
Explains detecting abnormal runtime behavior in Java applications to identify potential security threats using process monitoring techniques.
Achieving Security Excellence CIS Benchmark Compliance for Java Applications – https://macronepal.com/blog/achieving-security-excellence-implementing-cis-benchmark-compliance-for-java-applications/
Explains applying CIS security benchmarks to Java environments to standardize hardening and improve overall system security posture.
Process Anomaly Detection in Java Behavioral Monitoring – https://macronepal.com/blog/process-anomaly-detection-in-java-comprehensive-behavioral-monitoring/
Explains behavioral monitoring of Java processes to detect anomalies and improve runtime security through continuous observation and analysis.