HEX
Server: Apache
System: Linux eisbus 6.8.12-9-pve #1 SMP PREEMPT_DYNAMIC PMX 6.8.12-9 (2025-03-16T19:18Z) x86_64
User: www-data (33)
PHP: 8.2.29
Disabled: NONE
Upload Files
File: //includes/isppscan.go
package main

import (
	"bufio"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/smtp"
	"os"
	"os/exec"
	"regexp"
	"strings"
	"time"
)

const (
	EXITCODE_MALWARE   = 128
	EXITCODE_OUTDATED  = 2
	EXITCODE_PLUGINS   = 4
	EXITCODE_SQL       = 8
	EXITCODE_BLACKLIST = 16
)

func gethostname() string {
	hostname, err := os.Hostname()
	if err != nil {
		return ""
	}
	return hostname
}

type ISPProtectScanner struct {
	terminalCols     int
	wpPluginVersions map[string]string
	options          map[string]interface{}
	DeepCheckUrls    []string
}

func NewISPProtectScanner() *ISPProtectScanner {
	return &ISPProtectScanner{
		terminalCols:     0,
		wpPluginVersions: make(map[string]string),
		options:          make(map[string]interface{}),
		DeepCheckUrls:    []string{},
	}
}

func (s *ISPProtectScanner) readline(prompt string) string {
	fmt.Print(prompt)
	reader := bufio.NewReader(os.Stdin)
	input, _ := reader.ReadString('\n')
	return strings.TrimSpace(input)
}

func (s *ISPProtectScanner) sendMail(subject, text string) {
	opts := s.options

	var hostname string
	if val, ok := opts["email-hostname"].(string); ok && val != "" {
		hostname = strings.TrimSpace(val)
	} else {
		hostname = gethostname()
		if hostname == "" || hostname == "localhost" || hostname == "localhost.localdomain" {
			hostname = gethostname()
		}
	}

	subject = strings.ReplaceAll(subject, "{HOSTNAME}", hostname)
	text = strings.ReplaceAll(text, "{HOSTNAME}", hostname)

	fromEmail := "isppscan@" + hostname
	if val, ok := opts["email-results-sender"].(string); ok && isValidEmail(val) {
		fromEmail = val
	}

	emailList := strings.Split(strings.ReplaceAll(opts["email-results"].(string), " ", ""), ",")
	for _, email := range emailList {
		if !s.checkEmail(email) {
			fmt.Printf("Could not send email to invalid address %s\n", email)
		} else {
			s._sendMail(email, subject, text, fromEmail)
		}
	}
}

func (s *ISPProtectScanner) _sendMail(to, subject, text, from string) bool {
	options := make(map[string]string)

	mailconfFile := s.option("use-smtp", nil)
	if mailconfFile != nil {
		file, err := os.Open(mailconfFile.(string))
		if err != nil {
			fmt.Println("[WARN] invalid smtp configuration file. See --help for usage.")
		} else {
			defer file.Close()
			scanner := bufio.NewScanner(file)
			section := ""
			for scanner.Scan() {
				line := strings.TrimSpace(scanner.Text())
				if line == "" {
					continue
				}
				if strings.HasPrefix(line, "[") && strings.HasSuffix(line, "]") {
					section = line[1 : len(line)-1]
					continue
				}
				if section == "" {
					continue
				}
				parts := strings.SplitN(line, "=", 2)
				if len(parts) != 2 {
					continue
				}
				key := strings.TrimSpace(parts[0])
				value := strings.TrimSpace(parts[1])
				if strings.HasPrefix(key, ";") || strings.HasPrefix(key, "#") {
					continue
				}
				options[section+"."+key] = value
			}
		}
	}

	if useSMTP, ok := options["ispprotect-smtp.use_smtp"]; ok && (useSMTP == "yes" || useSMTP == "y" || useSMTP == "1" || useSMTP == "on") {
		auth := smtp.PlainAuth("", options["ispprotect-smtp.smtp_user"], options["ispprotect-smtp.smtp_pass"], options["ispprotect-smtp.smtp_host"])
		toList := []string{to}
		msg := []byte("To: " + to + "\r\n" +
			"Subject: " + subject + "\r\n" +
			"\r\n" +
			text + "\r\n")
		err := smtp.SendMail(options["ispprotect-smtp.smtp_host"]+":"+options["ispprotect-smtp.smtp_port"], auth, from, toList, msg)
		if err != nil {
			fmt.Println("[WARN] Could not send email via SMTP, check configuration!")
			return false
		}
		return true
	}
	return false
}

func (s *ISPProtectScanner) option(key string, value interface{}) interface{} {
	if val, ok := s.options[key]; ok {
		if value != nil && val != value {
			return nil
		}
		return val
	}
	return nil
}

func (s *ISPProtectScanner) statusPrint(msg string, newline bool) {
	if len(msg) > s.terminalCols-4 {
		msg = msg[:s.terminalCols-4] + " ..."
	}
	fmt.Printf("\r%s%s", msg, strings.Repeat(" ", s.terminalCols-len(msg)))
	if newline {
		fmt.Println()
	}
}

func (s *ISPProtectScanner) jsonOutput(msg string, err bool, data map[string]interface{}) {
	jsonData := make(map[string]interface{})
	if err {
		jsonData["error"] = err
		jsonData["error_msg"] = msg
	} else {
		jsonData["error"] = false
		jsonData["error_msg"] = ""
	}
	jsonData["version"] = "1.0.0" // Replace with actual version
	jsonData["result"] = data
	if newestVersion := os.Getenv("NEWEST_APP_VERSION"); newestVersion != "" {
		jsonData["newest_version"] = newestVersion
	} else {
		jsonData["newest_version"] = false
	}

	if file, ok := s.option("json-file", nil).(string); ok && file != "" {
		jsonBytes, _ := json.Marshal(jsonData)
		ioutil.WriteFile(file, jsonBytes, 0644)
	} else if s.option("json-out", nil) != nil {
		jsonBytes, _ := json.Marshal(jsonData)
		fmt.Print(string(jsonBytes))
	}

	if s.option("json-out", nil) == nil && msg != "" {
		fmt.Println(msg)
	}
}

func (s *ISPProtectScanner) log(text string, prio int, file string, line int) {
	if LOG_PRIO > prio {
		return
	}
	fmt.Printf("%s %s at %s line %d\n", time.Now().Format("02.01.2006 15:04:05"), text, file, line)
}

func (s *ISPProtectScanner) execute(command string) string {
	if command == "" {
		return ""
	}
	cmd := exec.Command("/usr/bin/env", "bash", "-c", command)
	output, err := cmd.CombinedOutput()
	if err != nil {
		return ""
	}
	return strings.TrimSpace(string(output))
}

func (s *ISPProtectScanner) sortVersions(a, b string) int {
	return s.versionCompare(a, b)
}

func (s *ISPProtectScanner) checkEmail(email string) bool {
	// Email validation logic
	var emailRegex = regexp.MustCompile(`^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$`)
	return emailRegex.MatchString(email)
}

func (s *ISPProtectScanner) splitToVersionParts(version string) []string {
	var parts []string
	if version == "" {
		return parts
	}

	var prevType, part string
	for _, c := range version {
		var currType string
		if c >= '0' && c <= '9' {
			currType = "num"
		} else {
			currType = "str"
		}
		if currType != prevType && part != "" {
			parts = append(parts, part)
			part = ""
		}
		part += string(c)
		prevType = currType
	}
	parts = append(parts, part)
	return parts
}

func (s *ISPProtectScanner) versionCompare(version1, version2 string) int {
	v1Parts := s.splitToVersionParts(version1)
	v2Parts := s.splitToVersionParts(version2)

	for i := 0; i < len(v1Parts); i++ {
		if i >= len(v2Parts) {
			return 1
		}
		if v1Parts[i] > v2Parts[i] {
			return 1
		}
		if v1Parts[i] < v2Parts[i] {
			return -1
		}
	}
	if len(v2Parts) > len(v1Parts) {
		return -1
	}
	return 0
}

func (s *ISPProtectScanner) exiting(signo os.Signal) {
	// Cleanup logic
	os.Exit(0)
}

func (s *ISPProtectScanner) getWPPluginVersion(pluginName string) string {
	if version, ok := s.wpPluginVersions[pluginName]; ok && version != "" {
		return version
	}

	resp, err := http.Get("http://api.wordpress.org/plugins/info/1.0/" + pluginName + "/")
	if err != nil {
		return ""
	}
	defer resp.Body.Close()

	data, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return ""
	}

	var pluginInfo map[string]interface{}
	if err := json.Unmarshal(data, &pluginInfo); err != nil {
		return ""
	}

	if version, ok := pluginInfo["version"].(string); ok {
		s.wpPluginVersions[pluginName] = version
		return version
	}

	return ""
}

func (s *ISPProtectScanner) run() {
	argv := os.Args
	opts := s.options

	// Initialize variables
	lowRisk := []string{
		"{ISPP}suspect.eb64.commented", "{ISPP}suspect.hide.ctime", "{ISPP}suspect.globals.func", "{ISPP}suspect.uploader", "{ISPP}suspect.exec.request", "{ISPP}suspect.passthru.request", "{ISPP}suspect.strrot.gzinflate", "{ISPP}suspect.crypted.eval", "{ISPP}suspect.crypted.globals", "{ISPP}suspect.crypted.base64", "{ISPP}suspect.crypted.code", "{ISPP}suspect.cookie.eval", "{ISPP}suspect.reversed.code", "{ISPP}suspect.hidden.explode", "{ISPP}suspect.crypted.pregeval", "{ISPP}suspect.js.malwarecrypt", "{ISPP}suspect.char.crypted"
	}

	exitCode := 0

	// Signal handling
	// ...

	// Check required extensions and functions
	// ...

	// Parse arguments
	// ...

	// Process options
	// ...

	// Update check
	// ...

	// Quarantine operations
	// ...

	// License verification
	// ...

	// Memory limit adjustment
	// ...

	// Key status and reporting
	// ...

	// Email results validation
	// ...

	// Status file handling
	// ...

	// Path processing
	// ...

	// Mount point checks
	// ...

	// Temporary file setup
	// ...

	// Signature download and verification
	// ...

	// File system scanning
	// ...

	// Malware scanning
	// ...

	// Version scanning
	// ...

	// Database scanning
	// ...

	// Blacklist checking
	// ...

	// Permissions checking
	// ...

	// Final output and cleanup
	// ...

	os.Exit(exitCode)
}

func main() {
	scanner := NewISPProtectScanner()
	scanner.run()
}

// Additional helper functions and constants
const LOG_PRIO = 0

func isValidEmail(email string) bool {
	// Simple regex for email validation
	var emailRegex = regexp.MustCompile(`^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$`)
	return emailRegex.MatchString(email)
}