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)
}