fix: update custom OLS binaries and add ModSecurity compatibility

- Update SHA256 checksums for December 2025 OLS build (v1.8.4.1)
- Add RHEL8 module support (cyberpanel_ols_x86_64_rhel8.so)
- Add compatible ModSecurity binaries to prevent ABI crashes
- Auto-detect and replace ModSecurity when custom OLS is installed
- Add auto-rollback feature if new binary fails to start
- Fix OWASP CRS UI toggle detection with multi-location checks

Features included in new binaries:
- PHPConfig support (.htaccess php_value/php_flag)
- Origin header forwarding (CORS/WebSocket support)
- Header unset fix (uses remove_resp_header API)
- Static linking for cross-platform compatibility

Platforms supported:
- Ubuntu 22.04+/Debian 12+ (ubuntu-static)
- AlmaLinux/Rocky/RHEL 9.x (rhel9-static)
- AlmaLinux/Rocky/RHEL 8.x (rhel8-static)
This commit is contained in:
usmannasir
2025-12-27 21:07:16 +05:00
parent f9e600345f
commit 3fc1aba229
3 changed files with 307 additions and 9 deletions

View File

@@ -1020,8 +1020,9 @@ class FirewallManager:
if owaspInstalled == 1 and comodoInstalled == 1:
break
# Also check rules.conf for manual OWASP installations
# Check multiple locations for OWASP CRS installation
if owaspInstalled == 0:
# Check 1: rules.conf for OWASP includes
rulesConfPath = os.path.join(virtualHostUtilities.Server_root, "conf/modsec/rules.conf")
if os.path.exists(rulesConfPath):
try:
@@ -1036,6 +1037,37 @@ class FirewallManager:
except:
pass
# Check 2: owasp-master.conf exists and has rules loaded
if owaspInstalled == 0:
owaspMasterConf = os.path.join(virtualHostUtilities.Server_root, "conf/modsec/owasp-modsecurity-crs-3.0-master/owasp-master.conf")
if os.path.exists(owaspMasterConf):
try:
command = "sudo cat " + owaspMasterConf
owaspConfig = ProcessUtilities.outputExecutioner(command).splitlines()
# Check if at least one rule file is enabled (not commented)
for items in owaspConfig:
if items.strip() and not items.strip().startswith('#') and 'include' in items.lower():
owaspInstalled = 1
break
except:
pass
# Check 3: OWASP CRS directory exists with rules
if owaspInstalled == 0:
owaspRulesDir = os.path.join(virtualHostUtilities.Server_root, "conf/modsec/owasp-modsecurity-crs-3.0-master/rules")
if os.path.exists(owaspRulesDir):
try:
command = "sudo ls " + owaspRulesDir + " | grep -c '.conf'"
output = ProcessUtilities.outputExecutioner(command).strip()
if output.isdigit() and int(output) > 0:
# Rules exist, check if referenced in httpd_config.conf
for items in httpdConfig:
if 'owasp-modsecurity-crs' in items.lower() or 'owasp-master.conf' in items.lower():
owaspInstalled = 1
break
except:
pass
final_dic = {
'modSecInstalled': 1,
'owaspInstalled': owaspInstalled,
@@ -1065,6 +1097,7 @@ class FirewallManager:
except subprocess.CalledProcessError:
pass
# Check multiple locations for OWASP in LiteSpeed Enterprise
try:
command = 'cat /usr/local/lsws/conf/modsec.conf'
output = ProcessUtilities.outputExecutioner(command)
@@ -1073,6 +1106,20 @@ class FirewallManager:
except:
pass
# Also check owasp-master.conf for LSWS Enterprise
if owaspInstalled == 0:
owaspMasterConf = '/usr/local/lsws/conf/modsec/owasp-modsecurity-crs-3.0-master/owasp-master.conf'
if os.path.exists(owaspMasterConf):
try:
command = "cat " + owaspMasterConf
owaspConfig = ProcessUtilities.outputExecutioner(command).splitlines()
for items in owaspConfig:
if items.strip() and not items.strip().startswith('#') and 'include' in items.lower():
owaspInstalled = 1
break
except:
pass
final_dic = {
'modSecInstalled': 1,
'owaspInstalled': owaspInstalled,

View File

@@ -18,6 +18,102 @@ class modSec:
tempRulesFile = "/home/cyberpanel/tempModSecRules"
mirrorPath = "cyberpanel.net"
# Compatible ModSecurity binaries (built against custom OLS headers)
# These prevent ABI incompatibility crashes (Signal 11/SIGSEGV)
MODSEC_COMPATIBLE = {
'rhel8': {
'url': 'https://cyberpanel.net/mod_security-compatible-rhel8.so',
'sha256': 'bbbf003bdc7979b98f09b640dffe2cbbe5f855427f41319e4c121403c05837b2'
},
'rhel9': {
'url': 'https://cyberpanel.net/mod_security-compatible-rhel.so',
'sha256': '19deb2ffbaf1334cf4ce4d46d53f747a75b29e835bf5a01f91ebcc0c78e98629'
},
'ubuntu': {
'url': 'https://cyberpanel.net/mod_security-compatible-ubuntu.so',
'sha256': 'ed02c813136720bd4b9de5925f6e41bdc8392e494d7740d035479aaca6d1e0cd'
}
}
@staticmethod
def detectPlatform():
"""Detect OS platform for compatible binary selection"""
try:
# Check for Ubuntu/Debian
if os.path.exists('/etc/lsb-release'):
with open('/etc/lsb-release', 'r') as f:
content = f.read()
if 'Ubuntu' in content or 'ubuntu' in content:
return 'ubuntu'
# Check for Debian
if os.path.exists('/etc/debian_version'):
return 'ubuntu' # Use Ubuntu binary for Debian
# Check for RHEL-based distributions
if os.path.exists('/etc/os-release'):
with open('/etc/os-release', 'r') as f:
content = f.read().lower()
# Check for version 8.x
if 'version="8.' in content or 'version_id="8' in content:
return 'rhel8'
# Check for version 9.x
if 'version="9.' in content or 'version_id="9' in content:
return 'rhel9'
return 'rhel9' # Default to rhel9
except:
return 'rhel9'
@staticmethod
def downloadCompatibleModSec(platform):
"""Download and install compatible ModSecurity binary"""
try:
config = modSec.MODSEC_COMPATIBLE.get(platform)
if not config:
logging.CyberCPLogFileWriter.writeToFile(f"No compatible ModSecurity for platform {platform}")
return False
modsec_path = "/usr/local/lsws/modules/mod_security.so"
tmp_path = "/tmp/mod_security-compatible.so"
# Download compatible binary
command = f"wget -q {config['url']} -O {tmp_path}"
result = subprocess.call(shlex.split(command))
if result != 0:
logging.CyberCPLogFileWriter.writeToFile("Failed to download compatible ModSecurity")
return False
# Verify checksum
import hashlib
sha256_hash = hashlib.sha256()
with open(tmp_path, "rb") as f:
for byte_block in iter(lambda: f.read(4096), b""):
sha256_hash.update(byte_block)
actual_sha256 = sha256_hash.hexdigest()
if actual_sha256 != config['sha256']:
logging.CyberCPLogFileWriter.writeToFile(f"ModSecurity checksum mismatch: expected {config['sha256']}, got {actual_sha256}")
os.remove(tmp_path)
return False
# Backup original if exists
if os.path.exists(modsec_path):
shutil.copy2(modsec_path, f"{modsec_path}.stock")
# Install compatible version
shutil.move(tmp_path, modsec_path)
os.chmod(modsec_path, 0o644)
logging.CyberCPLogFileWriter.writeToFile("Installed compatible ModSecurity binary")
return True
except BaseException as msg:
logging.CyberCPLogFileWriter.writeToFile(str(msg) + " [downloadCompatibleModSec]")
return False
@staticmethod
def installModSec():
try:
@@ -45,6 +141,23 @@ class modSec:
writeToFile.writelines("ModSecurity Installed.[200]\n")
writeToFile.close()
# Check if custom OLS binary is installed - if so, replace with compatible ModSecurity
custom_ols_marker = "/usr/local/lsws/modules/cyberpanel_ols.so"
if os.path.exists(custom_ols_marker):
writeToFile = open(modSec.installLogPath, 'a')
writeToFile.writelines("Custom OLS detected, installing compatible ModSecurity...\n")
writeToFile.close()
platform = modSec.detectPlatform()
if modSec.downloadCompatibleModSec(platform):
writeToFile = open(modSec.installLogPath, 'a')
writeToFile.writelines("Compatible ModSecurity installed successfully.\n")
writeToFile.close()
else:
writeToFile = open(modSec.installLogPath, 'a')
writeToFile.writelines("WARNING: Could not install compatible ModSecurity. May experience crashes.\n")
writeToFile.close()
return 1
except BaseException as msg:
logging.CyberCPLogFileWriter.writeToFile(str(msg) + "[installModSec]")

View File

@@ -733,25 +733,32 @@ class Upgrade:
platform = Upgrade.detectPlatform()
Upgrade.stdOut(f"Detected platform: {platform}", 0)
# Platform-specific URLs and checksums (OpenLiteSpeed v1.8.4.1 - v2.0.5 Static Build)
# Platform-specific URLs and checksums (OpenLiteSpeed v1.8.4.1 with PHPConfig + Header unset fix + Static Linking)
# Build Date: December 27, 2025
BINARY_CONFIGS = {
'rhel8': {
'url': 'https://cyberpanel.net/openlitespeed-phpconfig-x86_64-rhel8-static',
'sha256': '6ce688a237615102cc1603ee1999b3cede0ff3482d31e1f65705e92396d34b3a',
'module_url': None, # RHEL 8 doesn't have module (use RHEL 9 if needed)
'module_sha256': None
'module_url': 'https://cyberpanel.net/cyberpanel_ols_x86_64_rhel8.so',
'module_sha256': 'c57f6f14a9ba787b9051dee98c1375a4f34ec4e25b492e97a8825aee04dda02a',
'modsec_url': 'https://cyberpanel.net/mod_security-compatible-rhel8.so',
'modsec_sha256': 'bbbf003bdc7979b98f09b640dffe2cbbe5f855427f41319e4c121403c05837b2'
},
'rhel9': {
'url': 'https://cyberpanel.net/openlitespeed-phpconfig-x86_64-rhel9-static',
'sha256': '90468fb38767505185013024678d9144ae13100d2355097657f58719d98fbbc4',
'sha256': '709093d99d5d3e789134c131893614968e17eefd9ade2200f811d9b076b2f02e',
'module_url': 'https://cyberpanel.net/cyberpanel_ols_x86_64_rhel.so',
'module_sha256': '127227db81bcbebf80b225fc747b69cfcd4ad2f01cea486aa02d5c9ba6c18109'
'module_sha256': 'ae79d4fcf56131c01c3d81dc704ad265ac881b61d0a90cec62e4ac22c0e69929',
'modsec_url': 'https://cyberpanel.net/mod_security-compatible-rhel.so',
'modsec_sha256': '19deb2ffbaf1334cf4ce4d46d53f747a75b29e835bf5a01f91ebcc0c78e98629'
},
'ubuntu': {
'url': 'https://cyberpanel.net/openlitespeed-phpconfig-x86_64-ubuntu-static',
'sha256': '89aaf66474e78cb3c1666784e0e7a417550bd317e6ab148201bdc318d36710cb',
'module_url': 'https://cyberpanel.net/cyberpanel_ols_x86_64_ubuntu.so',
'module_sha256': 'e7734f1e6226c2a0a8e00c1f6534ea9f577df9081b046736a774b1c52c28e7e5'
'module_sha256': '57129f12b98c5b1693d10eddad3ad57917773540ca68c5491dee23588ef313ac',
'modsec_url': 'https://cyberpanel.net/mod_security-compatible-ubuntu.so',
'modsec_sha256': 'ed02c813136720bd4b9de5925f6e41bdc8392e494d7740d035479aaca6d1e0cd'
}
}
@@ -765,8 +772,11 @@ class Upgrade:
OLS_BINARY_SHA256 = config['sha256']
MODULE_URL = config['module_url']
MODULE_SHA256 = config['module_sha256']
MODSEC_URL = config.get('modsec_url')
MODSEC_SHA256 = config.get('modsec_sha256')
OLS_BINARY_PATH = "/usr/local/lsws/bin/openlitespeed"
MODULE_PATH = "/usr/local/lsws/modules/cyberpanel_ols.so"
MODSEC_PATH = "/usr/local/lsws/modules/mod_security.so"
# Create backup
from datetime import datetime
@@ -778,12 +788,16 @@ class Upgrade:
if os.path.exists(OLS_BINARY_PATH):
shutil.copy2(OLS_BINARY_PATH, f"{backup_dir}/openlitespeed.backup")
Upgrade.stdOut(f"Backup created at: {backup_dir}", 0)
# Also backup existing ModSecurity if it exists
if os.path.exists(MODSEC_PATH):
shutil.copy2(MODSEC_PATH, f"{backup_dir}/mod_security.so.backup")
except Exception as e:
Upgrade.stdOut(f"WARNING: Could not create backup: {e}", 0)
# Download binaries to temp location
tmp_binary = "/tmp/openlitespeed-custom"
tmp_module = "/tmp/cyberpanel_ols.so"
tmp_modsec = "/tmp/mod_security.so"
Upgrade.stdOut("Downloading custom binaries...", 0)
@@ -804,6 +818,18 @@ class Upgrade:
else:
Upgrade.stdOut("Note: No CyberPanel module for this platform", 0)
# Download compatible ModSecurity if existing ModSecurity is installed
# This prevents ABI incompatibility crashes (Signal 11/SIGSEGV)
modsec_downloaded = False
if os.path.exists(MODSEC_PATH) and MODSEC_URL and MODSEC_SHA256:
Upgrade.stdOut("Existing ModSecurity detected - downloading compatible version...", 0)
if Upgrade.downloadCustomBinary(MODSEC_URL, tmp_modsec, MODSEC_SHA256):
modsec_downloaded = True
else:
Upgrade.stdOut("WARNING: Failed to download compatible ModSecurity", 0)
Upgrade.stdOut("ModSecurity may crash due to ABI incompatibility", 0)
Upgrade.stdOut("Consider manually updating ModSecurity after upgrade", 0)
# Install OpenLiteSpeed binary
Upgrade.stdOut("Installing custom binaries...", 0)
@@ -826,9 +852,49 @@ class Upgrade:
Upgrade.stdOut(f"ERROR: Failed to install module: {e}", 0)
return False
# Verify installation
# Install compatible ModSecurity (if downloaded)
if modsec_downloaded:
try:
shutil.move(tmp_modsec, MODSEC_PATH)
os.chmod(MODSEC_PATH, 0o644)
Upgrade.stdOut("Installed compatible ModSecurity module", 0)
except Exception as e:
Upgrade.stdOut(f"WARNING: Failed to install ModSecurity: {e}", 0)
# Non-fatal, continue
# Verify installation - test binary before restart
if os.path.exists(OLS_BINARY_PATH):
if not module_downloaded or os.path.exists(MODULE_PATH):
# Test 1: Verify binary is executable and shows version
Upgrade.stdOut("Verifying new binary...", 0)
try:
result = subprocess.run(
[OLS_BINARY_PATH, '-v'],
capture_output=True,
text=True,
timeout=10
)
if result.returncode != 0:
raise Exception(f"Binary test failed with exit code {result.returncode}")
# Extract version info
version_output = result.stdout if result.stdout else result.stderr
if 'LiteSpeed' in version_output or 'OpenLiteSpeed' in version_output:
Upgrade.stdOut(f"Binary version check passed", 0)
else:
Upgrade.stdOut("WARNING: Could not verify binary version", 0)
except subprocess.TimeoutExpired:
Upgrade.stdOut("WARNING: Binary version check timed out", 0)
except Exception as e:
Upgrade.stdOut(f"ERROR: Binary verification failed: {e}", 0)
# Auto-rollback
Upgrade.stdOut("Initiating auto-rollback...", 0)
if Upgrade.rollbackOLSBinary(backup_dir, OLS_BINARY_PATH, MODULE_PATH if module_downloaded else None):
Upgrade.stdOut("Rollback completed successfully", 0)
else:
Upgrade.stdOut("WARNING: Rollback may have failed", 0)
return False
Upgrade.stdOut("=" * 50, 0)
Upgrade.stdOut("Custom Binaries Installed Successfully", 0)
Upgrade.stdOut("Features enabled:", 0)
@@ -842,6 +908,9 @@ class Upgrade:
return True
Upgrade.stdOut("ERROR: Installation verification failed", 0)
# Auto-rollback on verification failure
if Upgrade.rollbackOLSBinary(backup_dir, OLS_BINARY_PATH, MODULE_PATH if module_downloaded else None):
Upgrade.stdOut("Rollback completed successfully", 0)
return False
except Exception as msg:
@@ -849,6 +918,50 @@ class Upgrade:
Upgrade.stdOut("Continuing with standard OLS", 0)
return True # Non-fatal error, continue
@staticmethod
def rollbackOLSBinary(backup_dir, binary_path, module_path=None):
"""Rollback OpenLiteSpeed binary to previous version from backup"""
try:
Upgrade.stdOut("Rolling back to previous binary...", 0)
backup_binary = os.path.join(backup_dir, "openlitespeed.backup")
if os.path.exists(backup_binary):
# Stop OLS before rollback
Upgrade.stdOut("Stopping OpenLiteSpeed for rollback...", 0)
subprocess.run(['/usr/local/lsws/bin/lswsctrl', 'stop'],
capture_output=True, timeout=30)
# Restore binary
shutil.copy2(backup_binary, binary_path)
os.chmod(binary_path, 0o755)
Upgrade.stdOut(f"Restored binary from {backup_binary}", 0)
# Start OLS after rollback
Upgrade.stdOut("Starting OpenLiteSpeed after rollback...", 0)
result = subprocess.run(['/usr/local/lsws/bin/lswsctrl', 'start'],
capture_output=True, timeout=30)
# Verify OLS started
import time
time.sleep(3)
result = subprocess.run(['pgrep', '-f', 'openlitespeed'],
capture_output=True)
if result.returncode == 0:
Upgrade.stdOut("OpenLiteSpeed started successfully after rollback", 0)
return True
else:
Upgrade.stdOut("WARNING: OpenLiteSpeed may not have started after rollback", 0)
return True # Rollback was successful, startup issue is separate
else:
Upgrade.stdOut(f"ERROR: Backup not found at {backup_binary}", 0)
return False
except Exception as e:
Upgrade.stdOut(f"ERROR during rollback: {e}", 0)
return False
@staticmethod
def configureCustomModule():
"""Configure CyberPanel module in OpenLiteSpeed config"""
@@ -4482,10 +4595,35 @@ pm.max_spare_servers = 3
# Configure the custom module
Upgrade.configureCustomModule()
# Restart OpenLiteSpeed to apply changes
# Restart OpenLiteSpeed to apply changes and verify it started
Upgrade.stdOut("Restarting OpenLiteSpeed...", 0)
command = '/usr/local/lsws/bin/lswsctrl restart'
Upgrade.executioner(command, 'Restart OpenLiteSpeed', 0)
# Verify OLS started successfully after restart
import time
time.sleep(5) # Give OLS time to start
result = subprocess.run(['pgrep', '-f', 'openlitespeed'],
capture_output=True)
if result.returncode != 0:
Upgrade.stdOut("WARNING: OpenLiteSpeed may not have started after upgrade!", 0)
Upgrade.stdOut("Attempting auto-rollback...", 0)
# Find the most recent backup directory
backup_base = '/usr/local/lsws'
backups = [d for d in os.listdir(backup_base) if d.startswith('backup-')]
if backups:
backups.sort(reverse=True) # Most recent first
latest_backup = os.path.join(backup_base, backups[0])
if Upgrade.rollbackOLSBinary(latest_backup, '/usr/local/lsws/bin/openlitespeed'):
Upgrade.stdOut("Auto-rollback completed successfully", 0)
else:
Upgrade.stdOut("ERROR: Auto-rollback failed! Manual intervention may be required.", 0)
else:
Upgrade.stdOut("ERROR: No backup found for rollback!", 0)
else:
Upgrade.stdOut("OpenLiteSpeed restarted successfully", 0)
else:
Upgrade.stdOut("Custom binary installation failed, continuing with upgrade...", 0)