From 270bb18b982a7fe83a9e0a428bedd36ac6f0dfc1 Mon Sep 17 00:00:00 2001 From: zitn Date: Mon, 6 Nov 2023 16:31:16 +0800 Subject: [PATCH] feat(d-eyes): init --- .../info/ExchangeServerOWASSRF_windows.go | 132 + basicinfo/info/autorun_linux.go | 59 + basicinfo/info/autorun_windows.go | 59 + basicinfo/info/base.go | 27 + basicinfo/info/contab_windows.go | 111 + basicinfo/info/crontab_linux.go | 81 + basicinfo/info/network_linux.go | 109 + basicinfo/info/network_windows.go | 103 + basicinfo/info/summary_linux.go | 70 + basicinfo/info/summary_windows.go | 74 + basicinfo/info/top.go | 77 + basicinfo/info/users_linux.go | 42 + basicinfo/info/users_windows.go | 38 + basicinfo/utils/autoruns.go | 18 + basicinfo/utils/autoruns_linux.go | 111 + basicinfo/utils/autoruns_windows.go | 276 + basicinfo/utils/stringutil.go | 16 + configcheck/check/CheckTrigger.go | 110 + configcheck/check/check_alias_conf.go | 89 + configcheck/check/crontab_check.go | 79 + configcheck/check/empytpasswd.go | 34 + configcheck/check/env.go | 330 ++ configcheck/check/history.go | 126 + configcheck/check/log.go | 33 + configcheck/check/rootkit.go | 1093 ++++ configcheck/check/setuid.go | 48 + configcheck/check/ssh.go | 51 + configcheck/check/sshlog.go | 223 + configcheck/check/sshserver.go | 27 + configcheck/check/sudo.go | 33 + configcheck/common/common.go | 117 + deyes_linux.go | 291 + deyes_windows.go | 337 ++ filedetection/file.go | 56 + filedetection/filescan.go | 54 + filedetection/filesystemScanner_linux.go | 68 + filedetection/filesystemScanner_windows.go | 61 + filedetection/filesystem_linux.go | 236 + filedetection/filesystem_windows.go | 203 + filedetection/hashes.go | 87 + filedetection/iterator.go | 172 + go.mod | 43 + logo/logo_linux.go | 41 + logo/logo_windows.go | 60 + output/result.go | 6 + process/controller/init_linux.go | 50 + process/controller/init_windows.go | 51 + process/models/models_linux.go | 216 + process/models/models_windows.go | 214 + process/scanner/scanner_linux.go | 298 + process/scanner/scanner_windows.go | 309 + process/utils/iputil.go | 27 + process/utils/readfile.go | 29 + yaraRules/Botnet.BlackMoon.yar | 53 + yaraRules/Botnet.Festi.yar | 11 + yaraRules/Botnet.Gafgyt.yar | 272 + yaraRules/Botnet.Kelihos.yar | 24 + yaraRules/Botnet.Mykings.yar | 27 + yaraRules/CoinMiner.CryptoELF.yar | 14 + yaraRules/CoinMiner.Monero.yar | 88 + yaraRules/CoinMiner.Trojan.yar | 138 + yaraRules/CoinMiner.Wannamine.yar | 36 + yaraRules/CoinMiner.givemexyz.yar | 215 + yaraRules/Malicious.tools.yar | 2198 +++++++ yaraRules/Malicious.webshells.yar | 5276 +++++++++++++++++ yaraRules/Malware.FiveSys.yar | 29 + yaraRules/Malware.Mikey.yar | 31 + yaraRules/Malware.Rekoobe.yar | 48 + yaraRules/Ransom.BCrypt.yar | 18 + yaraRules/Ransom.Babuk.yar | 31 + yaraRules/Ransom.BadEncript.yar | 112 + yaraRules/Ransom.BadRabbit.yar | 39 + yaraRules/Ransom.BlackMatter.yar | 9 + yaraRules/Ransom.Cerber.yar | 133 + yaraRules/Ransom.Chaos.yar | 14 + yaraRules/Ransom.ChupaCabra.yar | 30 + yaraRules/Ransom.Common.yar | 101 + yaraRules/Ransom.Conti.yar | 200 + yaraRules/Ransom.Cryakl.yar | 15 + yaraRules/Ransom.CryptoLocker.yar | 41 + yaraRules/Ransom.DarkSide.yar | 265 + yaraRules/Ransom.Fonix.yar | 29 + yaraRules/Ransom.GandCrab.yar | 101 + yaraRules/Ransom.Globeimposter.yar | 162 + yaraRules/Ransom.Henry217.yar | 30 + yaraRules/Ransom.HiddenTear.yar | 32 + yaraRules/Ransom.House.yar | 78 + yaraRules/Ransom.LockBit.yar | 29 + yaraRules/Ransom.Locky.yar | 185 + yaraRules/Ransom.MBRLocker.yar | 28 + yaraRules/Ransom.Magniber.yar | 16 + yaraRules/Ransom.Makop.yar | 174 + yaraRules/Ransom.MedusaLocker.yar | 18 + yaraRules/Ransom.Nemty.yar | 189 + yaraRules/Ransom.NoCry.yar | 20 + yaraRules/Ransom.Petya.yar | 273 + yaraRules/Ransom.Phobos.yar | 113 + yaraRules/Ransom.Povlsomware.yar | 12 + yaraRules/Ransom.QNAPCrypt.yar | 16 + yaraRules/Ransom.Sarbloh.yar | 12 + yaraRules/Ransom.Satana.yar | 26 + yaraRules/Ransom.ScreenLocker.yar | 13 + yaraRules/Ransom.Sodinokibi.yar | 435 ++ yaraRules/Ransom.Stop.yar | 152 + yaraRules/Ransom.Termite.yar | 22 + yaraRules/Ransom.TeslaCrypt.yar | 136 + yaraRules/Ransom.Thanos.yar | 138 + yaraRules/Ransom.Tohnichi.yar | 71 + yaraRules/Ransom.TrumpLocker.yar | 20 + yaraRules/Ransom.Venus.yar | 22 + yaraRules/Ransom.VoidCrypt.yar | 20 + yaraRules/Ransom.WannaDie.yar | 13 + yaraRules/Ransom.WannaRen.yar | 22 + yaraRules/Ransom.Wannacrypt.yar | 313 + yaraRules/Ransom.Zeppelin.yar | 12 + yaraRules/Ransom.cryt0y.yar | 12 + yaraobj/yaraobj.go | 105 + 117 files changed, 19222 insertions(+) create mode 100644 basicinfo/info/ExchangeServerOWASSRF_windows.go create mode 100644 basicinfo/info/autorun_linux.go create mode 100644 basicinfo/info/autorun_windows.go create mode 100644 basicinfo/info/base.go create mode 100644 basicinfo/info/contab_windows.go create mode 100644 basicinfo/info/crontab_linux.go create mode 100644 basicinfo/info/network_linux.go create mode 100644 basicinfo/info/network_windows.go create mode 100644 basicinfo/info/summary_linux.go create mode 100644 basicinfo/info/summary_windows.go create mode 100644 basicinfo/info/top.go create mode 100644 basicinfo/info/users_linux.go create mode 100644 basicinfo/info/users_windows.go create mode 100644 basicinfo/utils/autoruns.go create mode 100644 basicinfo/utils/autoruns_linux.go create mode 100644 basicinfo/utils/autoruns_windows.go create mode 100644 basicinfo/utils/stringutil.go create mode 100644 configcheck/check/CheckTrigger.go create mode 100644 configcheck/check/check_alias_conf.go create mode 100644 configcheck/check/crontab_check.go create mode 100644 configcheck/check/empytpasswd.go create mode 100644 configcheck/check/env.go create mode 100644 configcheck/check/history.go create mode 100644 configcheck/check/log.go create mode 100644 configcheck/check/rootkit.go create mode 100644 configcheck/check/setuid.go create mode 100644 configcheck/check/ssh.go create mode 100644 configcheck/check/sshlog.go create mode 100644 configcheck/check/sshserver.go create mode 100644 configcheck/check/sudo.go create mode 100644 configcheck/common/common.go create mode 100644 deyes_linux.go create mode 100644 deyes_windows.go create mode 100644 filedetection/file.go create mode 100644 filedetection/filescan.go create mode 100644 filedetection/filesystemScanner_linux.go create mode 100644 filedetection/filesystemScanner_windows.go create mode 100644 filedetection/filesystem_linux.go create mode 100644 filedetection/filesystem_windows.go create mode 100644 filedetection/hashes.go create mode 100644 filedetection/iterator.go create mode 100644 go.mod create mode 100644 logo/logo_linux.go create mode 100644 logo/logo_windows.go create mode 100644 output/result.go create mode 100644 process/controller/init_linux.go create mode 100644 process/controller/init_windows.go create mode 100644 process/models/models_linux.go create mode 100644 process/models/models_windows.go create mode 100644 process/scanner/scanner_linux.go create mode 100644 process/scanner/scanner_windows.go create mode 100644 process/utils/iputil.go create mode 100644 process/utils/readfile.go create mode 100644 yaraRules/Botnet.BlackMoon.yar create mode 100644 yaraRules/Botnet.Festi.yar create mode 100644 yaraRules/Botnet.Gafgyt.yar create mode 100644 yaraRules/Botnet.Kelihos.yar create mode 100644 yaraRules/Botnet.Mykings.yar create mode 100644 yaraRules/CoinMiner.CryptoELF.yar create mode 100644 yaraRules/CoinMiner.Monero.yar create mode 100644 yaraRules/CoinMiner.Trojan.yar create mode 100644 yaraRules/CoinMiner.Wannamine.yar create mode 100644 yaraRules/CoinMiner.givemexyz.yar create mode 100644 yaraRules/Malicious.tools.yar create mode 100644 yaraRules/Malicious.webshells.yar create mode 100644 yaraRules/Malware.FiveSys.yar create mode 100644 yaraRules/Malware.Mikey.yar create mode 100644 yaraRules/Malware.Rekoobe.yar create mode 100644 yaraRules/Ransom.BCrypt.yar create mode 100644 yaraRules/Ransom.Babuk.yar create mode 100644 yaraRules/Ransom.BadEncript.yar create mode 100644 yaraRules/Ransom.BadRabbit.yar create mode 100644 yaraRules/Ransom.BlackMatter.yar create mode 100644 yaraRules/Ransom.Cerber.yar create mode 100644 yaraRules/Ransom.Chaos.yar create mode 100644 yaraRules/Ransom.ChupaCabra.yar create mode 100644 yaraRules/Ransom.Common.yar create mode 100644 yaraRules/Ransom.Conti.yar create mode 100644 yaraRules/Ransom.Cryakl.yar create mode 100644 yaraRules/Ransom.CryptoLocker.yar create mode 100644 yaraRules/Ransom.DarkSide.yar create mode 100644 yaraRules/Ransom.Fonix.yar create mode 100644 yaraRules/Ransom.GandCrab.yar create mode 100644 yaraRules/Ransom.Globeimposter.yar create mode 100644 yaraRules/Ransom.Henry217.yar create mode 100644 yaraRules/Ransom.HiddenTear.yar create mode 100644 yaraRules/Ransom.House.yar create mode 100644 yaraRules/Ransom.LockBit.yar create mode 100644 yaraRules/Ransom.Locky.yar create mode 100644 yaraRules/Ransom.MBRLocker.yar create mode 100644 yaraRules/Ransom.Magniber.yar create mode 100644 yaraRules/Ransom.Makop.yar create mode 100644 yaraRules/Ransom.MedusaLocker.yar create mode 100644 yaraRules/Ransom.Nemty.yar create mode 100644 yaraRules/Ransom.NoCry.yar create mode 100644 yaraRules/Ransom.Petya.yar create mode 100644 yaraRules/Ransom.Phobos.yar create mode 100644 yaraRules/Ransom.Povlsomware.yar create mode 100644 yaraRules/Ransom.QNAPCrypt.yar create mode 100644 yaraRules/Ransom.Sarbloh.yar create mode 100644 yaraRules/Ransom.Satana.yar create mode 100644 yaraRules/Ransom.ScreenLocker.yar create mode 100644 yaraRules/Ransom.Sodinokibi.yar create mode 100644 yaraRules/Ransom.Stop.yar create mode 100644 yaraRules/Ransom.Termite.yar create mode 100644 yaraRules/Ransom.TeslaCrypt.yar create mode 100644 yaraRules/Ransom.Thanos.yar create mode 100644 yaraRules/Ransom.Tohnichi.yar create mode 100644 yaraRules/Ransom.TrumpLocker.yar create mode 100644 yaraRules/Ransom.Venus.yar create mode 100644 yaraRules/Ransom.VoidCrypt.yar create mode 100644 yaraRules/Ransom.WannaDie.yar create mode 100644 yaraRules/Ransom.WannaRen.yar create mode 100644 yaraRules/Ransom.Wannacrypt.yar create mode 100644 yaraRules/Ransom.Zeppelin.yar create mode 100644 yaraRules/Ransom.cryt0y.yar create mode 100644 yaraobj/yaraobj.go diff --git a/basicinfo/info/ExchangeServerOWASSRF_windows.go b/basicinfo/info/ExchangeServerOWASSRF_windows.go new file mode 100644 index 0000000..38a5ea6 --- /dev/null +++ b/basicinfo/info/ExchangeServerOWASSRF_windows.go @@ -0,0 +1,132 @@ +package info + +import ( + "bufio" + "encoding/csv" + "fmt" + "os" + "path/filepath" + "strings" + + "github.com/gookit/color" +) + +func CheckExchangeServerOWASSRF(path string) { + if path == "" { + path = "C:\\Program Files\\Microsoft\\Exchange Server\\V15\\Logging\\CmdletInfra\\Powershell-Proxy\\Http" + } + _, err := os.Stat(path) + if os.IsNotExist(err) { + fmt.Println("Didn't find the directory '", path, "' on this host!") + return + } + var logs []string + var paths []string + var users []string + var successDocs []string + var failDocs []string + + color.Info.Println("Checking the Rps_Http logs in '", path, "'...") + + files, err := filepath.Glob(path + "/*Rps_Http_20*") + if err != nil { + fmt.Println(err) + return + } + if len(files) == 0 { + fmt.Println("Not found Rps_Http logs in the directory '", path, "'") + return + } + for _, file := range files { + csvFile, err := os.Open(file) + if err != nil { + fmt.Println(err) + return + } + defer csvFile.Close() + + reader := csv.NewReader(bufio.NewReader(csvFile)) + reader.Comma = ',' + reader.FieldsPerRecord = -1 + + csvData, err := reader.ReadAll() + if err != nil { + fmt.Println(err) + return + } + + for _, record := range csvData { + if len(record) < 30 { + continue + } + ua := record[29] + if ua != "ClientInfo" && ua != "Microsoft WinRM Client" && ua != "Exchange BackEnd Probes" && strings.ContainsAny(ua, "a-zA-Z0-9") { + time := record[0] + src := strings.Replace(record[15], " ", " -> ", -1) + server := record[16] + frontend := record[17] + status := record[18] + user := record[12] + + if status != "200" { + failDocs = append(failDocs, time+" [FAILURE: "+status+" ] Path: "+src+" -> "+frontend+" -> "+server+" as User: [ "+user+" ]") + } else { + successDocs = append(successDocs, time+" [SUCCESS: "+status+" ] Path: "+src+" -> "+frontend+" -> "+server+" as User: [ "+user+" ]") + } + paths = append(paths, src+" -> "+frontend+" -> "+server) + if strings.ContainsAny(user, "a-zA-Z0-9") { + users = append(users, user) + } + logs = append(logs, file) + } + } + } + paths = removeDuplicates(paths) + users = removeDuplicates(users) + logs = removeDuplicates(logs) + if len(successDocs) > 0 || len(failDocs) > 0 { + fmt.Println() + color.Error.Println("Something Suspicious Found !!!") + fmt.Println() + if len(successDocs) > 0 { + color.Warn.Println(len(successDocs), "instances of possible successful proxied exploitation found using UA indicator:") + for _, s := range successDocs { + fmt.Println(" ", s) + } + } + if len(failDocs) > 0 { + color.Warn.Println(len(failDocs), "instances of failed proxied exploitation attempts found using UA indicator") + for _, f := range failDocs { + fmt.Println(" ", f) + } + } + color.Warn.Println("Network paths used for exploitation attempts:") + for _, p := range paths { + fmt.Println(" ", p) + } + color.Warn.Println("Compromised users:") + for _, u := range users { + fmt.Println(" ", u) + } + color.Warn.Println("The above information is obtained from the following files:") + for _, l := range logs { + fmt.Println(" ", l) + } + } else { + fmt.Println() + color.Info.Println("Nothing Suspicious Found !") + } +} + +func removeDuplicates(elements []string) []string { + encountered := map[string]bool{} + result := []string{} + for v := range elements { + if encountered[elements[v]] == true { + } else { + encountered[elements[v]] = true + result = append(result, elements[v]) + } + } + return result +} diff --git a/basicinfo/info/autorun_linux.go b/basicinfo/info/autorun_linux.go new file mode 100644 index 0000000..1f71348 --- /dev/null +++ b/basicinfo/info/autorun_linux.go @@ -0,0 +1,59 @@ +package info + +import ( + "os" + + "github.com/olekukonko/tablewriter" + + autoruns "d-eyes/basicinfo/utils" +) + +type AutoRuns struct { + AutoRuns []*autoruns.Autorun +} + +func GetAutoruns() *AutoRuns { + ret := autoruns.Autoruns() + return &AutoRuns{AutoRuns: ret} +} + +func DisplayAutoruns(autoRuns *AutoRuns) { + data := make([][]string, 0) + for _, autorun := range autoRuns.AutoRuns { + autorunData := make([]string, 0) + + path := StringNewLine(autorun.ImagePath, 25) + autorunData = append(autorunData, autorun.Type, autorun.ImageName, autorun.Arguments, path) + data = append(data, autorunData) + } + + table := tablewriter.NewWriter(os.Stdout) + table.SetHeader([]string{"Type", "ImageName", "Arguments", "Path"}) + table.SetHeaderAlignment(tablewriter.ALIGN_CENTER) + table.SetBorder(true) + table.SetRowLine(true) + table.SetAutoMergeCells(true) + table.AppendBulk(data) + table.SetCaption(true, "Autoruns list") + table.Render() +} + +func StringNewLine(str string, ln uint8) string { + var sub_str string + res_str := "" + for { + if len(str) < int(ln) { + res_str += str + break + } + sub_str = str[0:ln] + str = str[ln:] + res_str += sub_str + "\n" + } + return res_str +} + +func CallDisplayAutoruns() { + autoruns := GetAutoruns() + DisplayAutoruns(autoruns) +} diff --git a/basicinfo/info/autorun_windows.go b/basicinfo/info/autorun_windows.go new file mode 100644 index 0000000..89ad468 --- /dev/null +++ b/basicinfo/info/autorun_windows.go @@ -0,0 +1,59 @@ +package info + +import ( + "os" + + "github.com/olekukonko/tablewriter" + + autoruns "d-eyes/basicinfo/utils" +) + +type AutoRuns struct { + AutoRuns []*autoruns.Autorun +} + +func GetAutoruns() *AutoRuns { + ret := autoruns.Autoruns() + return &AutoRuns{AutoRuns: ret} +} + +func DisplayAutoruns(autoRuns *AutoRuns) { + data := make([][]string, 0) + for _, autorun := range autoRuns.AutoRuns { + autorunData := make([]string, 0) + + path := StringNewLine(autorun.LaunchString, 25) + autorunData = append(autorunData, autorun.Type, autorun.ImageName, path) + data = append(data, autorunData) + } + + table := tablewriter.NewWriter(os.Stdout) + table.SetHeader([]string{"Type", "ImageName", "LaunchCommand"}) + table.SetHeaderAlignment(tablewriter.ALIGN_CENTER) + table.SetBorder(true) + table.SetRowLine(true) + table.SetAutoMergeCells(true) + table.AppendBulk(data) + table.SetCaption(true, "Autoruns list") + table.Render() +} + +func StringNewLine(str string, ln uint8) string { + var subStr string + res_str := "" + for { + if len(str) < int(ln) { + res_str += str + break + } + subStr = str[0:ln] + str = str[ln:] + res_str += subStr + "\n" + } + return res_str +} + +func CallDisplayAutoruns() { + ar := GetAutoruns() + DisplayAutoruns(ar) +} diff --git a/basicinfo/info/base.go b/basicinfo/info/base.go new file mode 100644 index 0000000..de00d8c --- /dev/null +++ b/basicinfo/info/base.go @@ -0,0 +1,27 @@ +package info + +import ( + "fmt" + "os/user" + + "github.com/gookit/color" + "github.com/shirou/gopsutil/v3/host" +) + +func DisplayBaseInfo() { + infoStat, _ := host.Info() + platform := infoStat.Platform + " " + infoStat.PlatformVersion + OsKernel := infoStat.KernelArch + " " + infoStat.KernelVersion + + CurrentUser, _ := user.Current() + + color.Greenp("* ") + fmt.Println("OS VERSION: ", platform) + + color.Greenp("* ") + fmt.Println("KERNEL VERSION: ", OsKernel) + + color.Greenp("* ") + fmt.Println("CURRENT USER: ", CurrentUser.Username) + +} diff --git a/basicinfo/info/contab_windows.go b/basicinfo/info/contab_windows.go new file mode 100644 index 0000000..496b959 --- /dev/null +++ b/basicinfo/info/contab_windows.go @@ -0,0 +1,111 @@ +//go:build windows + +package info + +import ( + "encoding/xml" + "fmt" + "io/ioutil" + "log" + "runtime" + "strings" + + "github.com/gookit/color" + + "github.com/axgle/mahonia" +) + +type task struct { + RegistrationInfo struct { + Description string + } + Actions struct { + Exec struct { + Command string + Arguments string + } + } + Triggers struct { + CalendarTrigger struct { + StartBoundary string + } + } + Principals struct { + Principal struct { + UserId string + } + } +} + +type CronTab struct { + Name string `json:"name,omitempty"` + Command string `json:"command,omitempty"` + Arg string `json:"arg,omitempty"` + User string `json:"user,omitempty"` + Rule string `json:"rule,omitempty"` + Description string `json:"description,omitempty"` +} + +func DisplayPlanTask() { + crontab := GetCronTab() + DisplayCronTab(crontab) +} + +// GetCronTab 获取计划任务 +func GetCronTab() (resultData []CronTab) { + var taskPath string + if runtime.GOARCH == "386" { + taskPath = `C:\Windows\SysNative\Tasks\` + } else { + taskPath = `C:\Windows\System32\Tasks\` + } + dir, err := ioutil.ReadDir(taskPath) + if err != nil { + return resultData + } + for _, f := range dir { + if f.IsDir() { + continue + } + dat, err := ioutil.ReadFile(taskPath + f.Name()) + if err != nil { + continue + } + v := task{} + dec := mahonia.NewDecoder("utf-16") + data := dec.ConvertString(string(dat)) + err = xml.Unmarshal([]byte(strings.Replace(data, "UTF-16", "UTF-8", 1)), &v) + if err != nil { + log.Println("Windows crontab info xml Unmarshal error: ", err.Error()) + continue + } + m := CronTab{} + m.Name = f.Name() + m.Command = v.Actions.Exec.Command + m.Arg = v.Actions.Exec.Arguments + m.User = v.Principals.Principal.UserId + m.Rule = v.Triggers.CalendarTrigger.StartBoundary + m.Description = v.RegistrationInfo.Description + resultData = append(resultData, m) + } + return resultData +} + +func DisplayCronTab(cronTab []CronTab) { + color.Greenp("==============================================================================================\n") + for _, item := range cronTab { + color.Greenp("* ") + fmt.Println("NAME: ", item.Name) + color.Greenp("* ") + fmt.Println("COMMAND: ", item.Command) + color.Greenp("* ") + fmt.Println("ARG: ", item.Arg) + color.Greenp("* ") + fmt.Println("USER: ", item.User) + color.Greenp("* ") + fmt.Println("RULE: ", item.Rule) + color.Greenp("* ") + fmt.Println("DESCRIPTION: ", item.Description) + color.Greenp("==============================================================================================\n") + } +} diff --git a/basicinfo/info/crontab_linux.go b/basicinfo/info/crontab_linux.go new file mode 100644 index 0000000..46cb42a --- /dev/null +++ b/basicinfo/info/crontab_linux.go @@ -0,0 +1,81 @@ +package info + +import ( + "fmt" + "io/ioutil" + "strings" + + "github.com/gookit/color" +) + +var resultData []string + +func DisplayPlanTask() { + Crontab_file() + Crontab_dir() + DisplayCronTab(resultData) +} + +// single crontab file +func Crontab_file() { + dat, err := ioutil.ReadFile("/etc/crontab") + if err != nil { + return + } + cronList := strings.Split(string(dat), "\n") + for _, info := range cronList { + if strings.HasPrefix(info, "#") || strings.Count(info, " ") < 6 { + continue + } + resultData = append(resultData, info) + } +} + +// dir crontab files +func Crontab_dir() { + dir_list := []string{"/var/spool/cron/", "/var/spool/cron/crontabs/"} + for _, dirTmp := range dir_list { + dir, err := ioutil.ReadDir(dirTmp) + if err != nil { + continue + } + for _, f := range dir { + if f.IsDir() { + continue + } + dat, err := ioutil.ReadFile(dirTmp + f.Name()) + if err != nil { + continue + } + cronList := strings.Split(string(dat), "\n") + for _, info := range cronList { + if strings.HasPrefix(info, "#") || strings.Count(info, " ") < 5 { + continue + } + info = info + " (user '" + f.Name() + "' created this task.)" + resultData = append(resultData, info) + } + } + } +} + +func DisplayCronTab(cronTab []string) { + color.Greenp("==============================================================================================\n") + if len(cronTab) == 0 { + fmt.Println("There is no crontab task in this host.") + return + } + taskSum := 0 + for _, item := range cronTab { + taskSum++ + color.Greenp("* task", taskSum) + fmt.Println() + fmt.Println(item) + color.Greenp("==============================================================================================\n") + } +} +func GetCronTab() []string { + Crontab_file() + Crontab_dir() + return resultData +} diff --git a/basicinfo/info/network_linux.go b/basicinfo/info/network_linux.go new file mode 100644 index 0000000..dd65c29 --- /dev/null +++ b/basicinfo/info/network_linux.go @@ -0,0 +1,109 @@ +package info + +import ( + "encoding/csv" + "fmt" + "os" + "strings" + + "github.com/olekukonko/tablewriter" + "github.com/shirou/gopsutil/v3/process" + + "d-eyes/basicinfo/utils" +) + +// remote connection ip +func DisplayNetStat() { + networkData := make([][]string, 0) + var remoteIp []string + ps, err := process.Processes() + if err != nil { + fmt.Println("Error:", err) + return + } + + for _, p := range ps { + + pid := os.Getpid() + if pid == int(p.Pid) || p.Pid == 0 { + continue + } + + connList := make([]string, 0) + connection := make([]string, 0) + _pc, _ := p.Connections() + for _, conn := range _pc { + if conn.Family == 1 { + continue + } + c := fmt.Sprintf( + "%v:%v<->%v:%v(%v)\n", + conn.Laddr.IP, conn.Laddr.Port, conn.Raddr.IP, conn.Raddr.Port, conn.Status, + ) + remoteIp = append(remoteIp, conn.Raddr.IP) + connection = append(connection, c) + } + _pUname, _ := p.Username() + if len(connection) > 0 && _pUname != "" { + network := strings.Join(connection, "") + _exe, _ := p.Exe() + path := utils.StringNewLine(_exe, 25) + connList = append(connList, fmt.Sprintf("%v", p.Pid), fmt.Sprintf("%v", p.Username), network, path) + networkData = append(networkData, connList) + } + } + + //output the information of current netstat + tableConn := tablewriter.NewWriter(os.Stdout) + tableConn.SetHeader([]string{"pid", "user", "local/remote(TCP Status)", "program name"}) + tableConn.SetBorder(true) + tableConn.SetRowLine(true) + tableConn.AppendBulk(networkData) + tableConn.Render() + remoteIpNew := RemoveRepeatedElement(remoteIp) + + if len(remoteIpNew) > 0 { + + f, err := os.Create("RemoteConnectionIP.csv") + if err != nil { + panic(err) + } + _, err = f.WriteString("\xEF\xBB\xBF") + if err != nil { + panic(err) + } + writer := csv.NewWriter(f) + length := len(remoteIpNew) + for i := 0; i < length; i++ { + err := writer.Write([]string{remoteIpNew[i]}) + if err != nil { + panic(err) + } + } + writer.Flush() + f.Close() + fmt.Println("The IP of the local remote connection has been exported to 'RemoteConnectionIP.csv'.") + } else { + fmt.Println("\nThere is no remote connection IP on this host.") + } +} + +func RemoveRepeatedElement(arr []string) (newArr []string) { + newArr = make([]string, 0) + for i := 0; i < len(arr); i++ { + if arr[i] == "127.0.0.1" || arr[i] == "0.0.0.0" || arr[i] == "::" || arr[i] == "::1" || arr[i] == "" { + continue + } + repeat := false + for j := i + 1; j < len(arr); j++ { + if arr[i] == arr[j] { + repeat = true + break + } + } + if !repeat { + newArr = append(newArr, arr[i]) + } + } + return +} diff --git a/basicinfo/info/network_windows.go b/basicinfo/info/network_windows.go new file mode 100644 index 0000000..0a12e8b --- /dev/null +++ b/basicinfo/info/network_windows.go @@ -0,0 +1,103 @@ +package info + +import ( + "encoding/csv" + "fmt" + "os" + "strings" + + "github.com/olekukonko/tablewriter" + "github.com/shirou/gopsutil/v3/process" + + "d-eyes/basicinfo/utils" +) + +// remote connection ip +func DisplayNetStat(srcPath string) { + networkData := make([][]string, 0) + var remoteIp []string + ps, err := process.Processes() + if err != nil { + fmt.Println("Error:", err) + return + } + for _, p := range ps { + + pid := os.Getpid() + if pid == int(p.Pid) || p.Pid == 0 { + continue + } + + connList := make([]string, 0) + connection := make([]string, 0) + _pc, _ := p.Connections() + for _, conn := range _pc { + if conn.Family == 1 { + continue + } + c := fmt.Sprintf( + "%v:%v<->%v:%v(%v)\n", + conn.Laddr.IP, conn.Laddr.Port, conn.Raddr.IP, conn.Raddr.Port, conn.Status, + ) + remoteIp = append(remoteIp, conn.Raddr.IP) + + connection = append(connection, c) + } + _pUname, _ := p.Username() + if len(connection) > 0 && _pUname != "" { + network := strings.Join(connection, "") + _exe, _ := p.Exe() + path := utils.StringNewLine(_exe, 25) + username, _ := p.Username() + connList = append(connList, fmt.Sprintf("%v", p.Pid), fmt.Sprintf("%v", username), network, path) + networkData = append(networkData, connList) + } + } + + tableConn := tablewriter.NewWriter(os.Stdout) + tableConn.SetHeader([]string{"pid", "user", "local/remote(TCP Status)", "program name"}) + tableConn.SetBorder(true) + tableConn.SetRowLine(true) + tableConn.AppendBulk(networkData) + tableConn.Render() + remoteIpNew := RemoveRepeatedElement(remoteIp) + + if len(remoteIpNew) > 0 { + + f, err := os.Create(srcPath + "RemoteConnectionIP.csv") + if err != nil { + panic(err) + } + f.WriteString("\xEF\xBB\xBF") + writer := csv.NewWriter(f) + length := len(remoteIpNew) + for i := 0; i < length; i++ { + writer.Write([]string{remoteIpNew[i]}) + } + writer.Flush() + f.Close() + fmt.Println("The IP of the local remote connection has been exported to 'RemoteConnectionIP.csv'.") + } else { + fmt.Println("\nThere is no remote connection IP on this host.") + } +} + +func RemoveRepeatedElement(arr []string) (newArr []string) { + newArr = make([]string, 0) + for i := 0; i < len(arr); i++ { + if arr[i] == "127.0.0.1" || arr[i] == "0.0.0.0" || arr[i] == "::" || arr[i] == "::1" || arr[i] == "" { + continue + } + repeat := false + for j := i + 1; j < len(arr); j++ { + if arr[i] == arr[j] { + repeat = true + break + } + } + if !repeat { + newArr = append(newArr, arr[i]) + } + } + return +} diff --git a/basicinfo/info/summary_linux.go b/basicinfo/info/summary_linux.go new file mode 100644 index 0000000..3d02694 --- /dev/null +++ b/basicinfo/info/summary_linux.go @@ -0,0 +1,70 @@ +package info + +import ( + "fmt" + "os" + "os/exec" + "os/user" + "strconv" + + "github.com/shirou/gopsutil/v3/host" +) + +func SaveSummaryBaseInfo() { + f, err := os.Create("SummaryBaseInfo") + + if err != nil { + fmt.Errorf(err.Error()) + } + + baseInfo := GetBaseInfo() + _, err = f.WriteString("HostInfo: \n" + baseInfo) + + users := GetLinuxUser() + _, err = f.WriteString("AllUsers: \n") + for _, user := range users { + _, err = f.WriteString(" * " + user + "\n") + } + + crontab := GetCronTab() + crontabString := "" + crontabString += "Os Crontab: \n==============================================================================================\n" + taskSum := 0 + for _, item := range crontab { + taskSum++ + crontabString += "* task " + strconv.Itoa(taskSum) + "\n" + + "" + item + "\n" + + "==============================================================================================\n" + } + _, err = f.WriteString(crontabString) + _, err = f.WriteString("InterfaceInfo: \n") + if err == nil { + path, _ := os.Getwd() + fmt.Println("Summary file to ", path+"/SummaryBaseInfo") + fmt.Println("Summary Base Info file created!") + } else { + fmt.Errorf(err.Error()) + } + f.Close() + c := exec.Command("/bin/bash", "-c", "ifconfig -a>>SummaryBaseInfo") + + if err := c.Run(); err != nil { + fmt.Println("Error: ", err) + } + +} + +func GetBaseInfo() string { + infoStat, _ := host.Info() + platform := infoStat.Platform + " " + infoStat.PlatformVersion + OsKernel := infoStat.KernelArch + " " + infoStat.KernelVersion + + user, _ := user.Current() + + baseInfo := "" + baseInfo += " * OS VERSION: " + platform + "\n" + + " * KERNEL VERSION: " + OsKernel + "\n" + + " * CURRENT USER: " + user.Username + "\n" + + return baseInfo +} diff --git a/basicinfo/info/summary_windows.go b/basicinfo/info/summary_windows.go new file mode 100644 index 0000000..4e1f8d1 --- /dev/null +++ b/basicinfo/info/summary_windows.go @@ -0,0 +1,74 @@ +package info + +import ( + "fmt" + "os" + "os/exec" + "os/user" + + "github.com/shirou/gopsutil/v3/host" +) + +func SaveSummaryBaseInfo() { + f, err := os.Create("SummaryBaseInfo.txt") + if err != nil { + fmt.Println(err) + return + } + + baseInfo := GetBaseInfo() + _, err = f.WriteString("HostInfo: \n" + baseInfo) + + users := GetWindowsUser() + _, err = f.WriteString("AllUsers: \n") + for _, userInfo := range users { + _, err = f.WriteString(" * " + userInfo + "\n") + } + + crontab := GetCronTab() + crontabString := "" + crontabString += "Os Crontab: \n==============================================================================================\n" + for _, item := range crontab { + + crontabString += "*NAME: " + item.Name + "\n" + + "*COMMAND: " + item.Command + "\n" + + "*ARG: " + item.Arg + "\n" + + "*USER: " + item.User + "\n" + + "*RULE: " + item.Rule + "\n" + + "*DESCRIPTION: " + item.Description + "\n" + + "==============================================================================================\n" + } + _, err = f.WriteString(crontabString) + _, err = f.WriteString("InterfaceInfo: ") + + if err == nil { + path, _ := os.Getwd() + fmt.Println("Summary file to ", path+"\\SummaryBaseInfo.txt") + fmt.Println("Summary Base Info file created!") + } else { + fmt.Println(err) + return + } + f.Close() + c := exec.Command("cmd", "/C", "ipconfig /all>>SummaryBaseInfo.txt") + + if err := c.Run(); err != nil { + fmt.Println("Error: ", err) + } + +} + +func GetBaseInfo() string { + infoStat, _ := host.Info() + platform := infoStat.Platform + " " + infoStat.PlatformVersion + OsKernel := infoStat.KernelArch + " " + infoStat.KernelVersion + + userInfo, _ := user.Current() + + baseInfo := "" + baseInfo += " * OS VERSION: " + platform + "\n" + + " * KERNEL VERSION: " + OsKernel + "\n" + + " * CURRENT USER: " + userInfo.Username + "\n" + + return baseInfo +} diff --git a/basicinfo/info/top.go b/basicinfo/info/top.go new file mode 100644 index 0000000..051b457 --- /dev/null +++ b/basicinfo/info/top.go @@ -0,0 +1,77 @@ +package info + +import ( + "fmt" + "os" + "sort" + "time" + + "github.com/gookit/color" + "github.com/shirou/gopsutil/v3/process" +) + +type ( + Process struct { + Process []*process.Process + } +) + +func Top() { + ps, err := process.Processes() + if err != nil { + fmt.Println(err) + return + } + + sort.Slice( + ps, func(i, j int) bool { + pic, _ := ps[i].CPUPercent() + pjc, _ := ps[j].CPUPercent() + return pic > pjc + }, + ) + pss := Process{Process: ps} + CPUSum := 0 + color.Greenp("==============================================================================================\n") + for _, ps := range pss.Process { + pid := os.Getpid() + if pid == int(ps.Pid) { + continue + } + CPUSum++ + color.Greenp("* CPU Top ", CPUSum) + fmt.Println() + _pct, _ := ps.CreateTime() + _pPath, _ := ps.Exe() + _pCpuP, _ := ps.CPUPercent() + startDate := time.Unix(_pct, 0).Format("2006-01-02 15:04:05") + username, _ := ps.Username() + MemPer, _ := ps.MemoryPercent() + fmt.Printf( + "[User]:%s | [Pid]:%d | [Path]:%s | [CPU]:%.5f | [Memory]:%.5f | [Createdtime]:%v \n", + username, ps.Pid, _pPath, _pCpuP, MemPer, startDate, + ) + //network + _ps, _ := ps.Connections() + if len(_ps) == 0 { + fmt.Println("[netstat]: null") + } else { + netSum := 0 + + for _, conn := range _ps { + if conn.Family == 1 { + continue + } + netSum++ + fmt.Printf( + "[netstat %d]: %v:%v<->%v:%v(%v)\n", + netSum, conn.Laddr.IP, conn.Laddr.Port, conn.Raddr.IP, conn.Raddr.Port, conn.Status, + ) + } + } + color.Greenp("==============================================================================================\n") + if CPUSum == 15 { + break + } + } +} diff --git a/basicinfo/info/users_linux.go b/basicinfo/info/users_linux.go new file mode 100644 index 0000000..f372b1f --- /dev/null +++ b/basicinfo/info/users_linux.go @@ -0,0 +1,42 @@ +package info + +import ( + "fmt" + "github.com/gookit/color" + "io/ioutil" + "strings" +) + +func DisplayAllUsers() { + + users := GetLinuxUser() + for _, user := range users { + color.Greenp("* ") + fmt.Println(user) + } + +} + +// GetUser +func GetLinuxUser() (resultData []string) { + dat, err := ioutil.ReadFile("/etc/passwd") + if err != nil { + return resultData + } + userList := strings.Split(string(dat), "\n") + if len(userList) < 2 { + return + } + for _, info := range userList[0 : len(userList)-1] { + + if strings.Contains(info, "/nologin") { + continue + } + if strings.Contains(info, "/bin/false") { + continue + } + s := strings.SplitN(info, ":", 2) + resultData = append(resultData, s[0]) + } + return resultData +} diff --git a/basicinfo/info/users_windows.go b/basicinfo/info/users_windows.go new file mode 100644 index 0000000..c374c3a --- /dev/null +++ b/basicinfo/info/users_windows.go @@ -0,0 +1,38 @@ +package info + +import ( + "fmt" + + "github.com/gookit/color" + "github.com/yusufpapurcu/wmi" +) + +func DisplayAllUsers() { + + users := GetWindowsUser() + + for _, user := range users { + color.Greenp("* ") + fmt.Println(user) + } +} + +type userAccount struct { + Name string // 用户名 + Description string // 用户描述 + Status string // 用户状态 +} + +// GetUser 获取系统用户列表 +func GetWindowsUser() (resultData []string) { + + var dst []userAccount + err := wmi.Query("SELECT * FROM Win32_UserAccount where LocalAccount=TRUE", &dst) + if err != nil { + return resultData + } + for _, v := range dst { + resultData = append(resultData, v.Name) + } + return resultData +} diff --git a/basicinfo/utils/autoruns.go b/basicinfo/utils/autoruns.go new file mode 100644 index 0000000..d47d2b2 --- /dev/null +++ b/basicinfo/utils/autoruns.go @@ -0,0 +1,18 @@ +package utils + +type Autorun struct { + Type string `json:"type"` + Location string `json:"location"` + ImagePath string `json:"image_path"` + ImageName string `json:"image_name"` + Arguments string `json:"arguments"` + MD5 string `json:"md5"` + SHA1 string `json:"sha1"` + SHA256 string `json:"sha256"` + Entry string `json:"entry"` + LaunchString string `json:"launch_string"` +} + +func Autoruns() []*Autorun { + return getAutoruns() +} diff --git a/basicinfo/utils/autoruns_linux.go b/basicinfo/utils/autoruns_linux.go new file mode 100644 index 0000000..74d9cfb --- /dev/null +++ b/basicinfo/utils/autoruns_linux.go @@ -0,0 +1,111 @@ +package utils + +import ( + "bufio" + "io/ioutil" + "os" + "path" + "path/filepath" + "regexp" + "strings" + + files "github.com/botherder/go-files" +) + +// This function just invokes all the platform-dependant functions. +func getAutoruns() (records []*Autorun) { + records = append(records, linuxGetSystemd()...) + return +} + +var regexSection = regexp.MustCompile("\\[.*\\]") + +func parseShellInvocation(shellLine string, autorun *Autorun) { + autorun.LaunchString = strings.SplitAfter(shellLine, "=")[1] + // We need to make sure to drop !! from paths + autorun.ImagePath = strings.Replace(strings.Split(autorun.LaunchString, " ")[0], "!!", "", -1) + autorun.ImageName = path.Base(autorun.ImagePath) + + args := strings.Split(autorun.LaunchString, " ") + if len(args) > 1 { + autorun.Arguments = strings.Join(args[1:], " ") + } +} + +func stringToAutorun(fileName string) (*Autorun, error) { + reader, err := os.Open(fileName) + if err != nil { + return nil, err + } + defer reader.Close() + + autorun := Autorun{ + Location: fileName, + //Type: "systemd", + Type: "Autorun services", + } + + inSection := "" + scanner := bufio.NewScanner(reader) + for scanner.Scan() { + line := scanner.Text() + if regexSection.MatchString(line) { + inSection = line + } + + switch inSection { + case "[Service]": + if strings.HasPrefix(line, "ExecStart=") { + parseShellInvocation(line, &autorun) + } + case "[D-BUS Service]": + if strings.HasPrefix(line, "Exec=") { + parseShellInvocation(line, &autorun) + } + } + } + + autorun.MD5, _ = files.HashFile(autorun.ImagePath, "md5") + autorun.SHA1, _ = files.HashFile(autorun.ImagePath, "sha1") + autorun.SHA256, _ = files.HashFile(autorun.ImagePath, "sha256") + + return &autorun, nil +} + +func linuxGetSystemd() (records []*Autorun) { + folders := []string{ + "/etc/systemd/system/", + "/usr/share/dbus-1/system-services/", + } + + for _, folder := range folders { + // Check if the folders exists. + if _, err := os.Stat(folder); os.IsNotExist(err) { + continue + } + + // Get list of files in folder. + filesList, err := ioutil.ReadDir(folder) + if err != nil { + continue + } + + // Loop through all files in folder. + for _, fileEntry := range filesList { + // Skip all files that don't end with .service. + if !(strings.HasSuffix(fileEntry.Name(), ".service")) { + continue + } + + filePath := filepath.Join(folder, fileEntry.Name()) + record, err := stringToAutorun(filePath) + if err != nil { + continue + } + + records = append(records, record) + } + } + + return +} diff --git a/basicinfo/utils/autoruns_windows.go b/basicinfo/utils/autoruns_windows.go new file mode 100644 index 0000000..8833920 --- /dev/null +++ b/basicinfo/utils/autoruns_windows.go @@ -0,0 +1,276 @@ +package utils + +import ( + "errors" + "fmt" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "strings" + + files "github.com/botherder/go-files" + "github.com/mattn/go-shellwords" + "golang.org/x/sys/windows/registry" +) + +// Just return a string value for a given registry root Key. +func registryToString(reg registry.Key) string { + if reg == registry.LOCAL_MACHINE { + return "LOCAL_MACHINE" + } else if reg == registry.CURRENT_USER { + return "CURRENT_USER" + } else { + return "" + } +} + +func parsePath(entryValue string) ([]string, error) { + if entryValue == "" { + return nil, errors.New("empty path") + } + if strings.HasPrefix(entryValue, `\??\`) { + entryValue = entryValue[4:] + } + // do some typical replacements + if len(entryValue) >= 11 && strings.ToLower(entryValue[:11]) == "\\systemroot" { + entryValue = strings.Replace(entryValue, entryValue[:11], os.Getenv("SystemRoot"), -1) + } + if len(entryValue) >= 8 && strings.ToLower(entryValue[:8]) == "system32" { + entryValue = strings.Replace(entryValue, entryValue[:8], fmt.Sprintf("%s\\System32", os.Getenv("SystemRoot")), -1) + } + // replace environment variables + entryValue, err := registry.ExpandString(entryValue) + if err != nil { + return []string{}, err + } + // We clean the path for proper backslashes. + entryValue = strings.Replace(entryValue, "\\", "\\\\", -1) + // Check if the whole entry is an executable and clean the file path. + if v, err := cleanPath(entryValue); err == nil { + return []string{v}, nil + } + // Otherwise we can split the entry for executable and arguments + parser := shellwords.NewParser() + args, err := parser.Parse(entryValue) + if err != nil { + return []string{}, err + } + // If the split worked, find the correct path to the executable and clean + // the file path. + if len(args) > 0 { + if v, err := cleanPath(args[0]); err == nil { + args[0] = v + } + } + return args, nil +} + +func stringToAutorun(entryType string, entryLocation string, entryValue string, toParse bool, entry string) *Autorun { + var imagePath = entryValue + var launchString = entryValue + var argsString = "" + + // TODO: This optional parsing is quite spaghetti. To change. + if toParse == true { + args, err := parsePath(entryValue) + + if err == nil { + if len(args) > 0 { + imagePath = args[0] + if len(args) > 1 { + argsString = strings.Join(args[1:], " ") + } + } + } + } + + md5, _ := files.HashFile(imagePath, "md5") + sha1, _ := files.HashFile(imagePath, "sha1") + sha256, _ := files.HashFile(imagePath, "sha256") + + newAutorun := Autorun{ + Type: entryType, + Location: entryLocation, + ImagePath: imagePath, + ImageName: filepath.Base(imagePath), + Arguments: argsString, + MD5: md5, + SHA1: sha1, + SHA256: sha256, + Entry: entry, + LaunchString: launchString, + } + + return &newAutorun +} + +// This function invokes all the platform-dependant functions. +func getAutoruns() (records []*Autorun) { + records = append(records, windowsGetCurrentVersionRun()...) + //records = append(records, windowsGetServices()...) + records = append(records, windowsGetStartupFiles()...) + // records = append(records, windowsGetTasks()...) + + return +} + +// This function enumerates items registered through CurrentVersion\Run. +func windowsGetCurrentVersionRun() (records []*Autorun) { + regs := []registry.Key{ + registry.LOCAL_MACHINE, + registry.CURRENT_USER, + } + + keyNames := []string{ + "Software\\Microsoft\\Windows\\CurrentVersion\\Run", + "Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce", + "Software\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Run", + "Software\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\RunOnce", + } + + // We loop through HKLM and HKCU. + for _, reg := range regs { + // We loop through the keys we're interested in. + for _, keyName := range keyNames { + // Open registry key. + key, err := registry.OpenKey(reg, keyName, registry.READ) + if err != nil { + continue + } + + // Enumerate value names. + names, err := key.ReadValueNames(0) + if err != nil { + key.Close() + continue + } + + for _, name := range names { + // For each entry we get the string value. + value, _, err := key.GetStringValue(name) + if err != nil || value == "" { + continue + } + + imageLocation := fmt.Sprintf("%s\\%s", registryToString(reg), keyName) + + /*reTime,err:=key.Stat() + if err != nil { + fmt.Println(err) + continue + } + reTime.ModTime()*/ + newAutorun := stringToAutorun("Autoruns", imageLocation, value, true, name) + + // Add the new autorun to the records. + records = append(records, newAutorun) + } + key.Close() + } + } + + return +} + +// This function enumerates Windows Services. +func windowsGetServices() (records []*Autorun) { + var reg registry.Key = registry.LOCAL_MACHINE + var servicesKey string = "System\\CurrentControlSet\\Services" + + // Open the registry key. + key, err := registry.OpenKey(reg, servicesKey, registry.READ) + if err != nil { + return + } + + // Enumerate subkeys. + names, err := key.ReadSubKeyNames(0) + key.Close() + if err != nil { + return + } + + for _, name := range names { + // We open each subkey. + subkeyPath := fmt.Sprintf("%s\\%s", servicesKey, name) + subkey, err := registry.OpenKey(reg, subkeyPath, registry.READ) + if err != nil { + continue + } + + // Check if there is an ImagePath value. + imagePath, _, err := subkey.GetStringValue("ImagePath") + subkey.Close() + // If not, we skip to the next one. + if err != nil { + continue + } + + imageLocation := fmt.Sprintf("%s\\%s", registryToString(reg), subkeyPath) + + // We pass the value string to a function to return an Autorun. + newAutorun := stringToAutorun("service", imageLocation, imagePath, true, "") + + // Add the new autorun to the records. + records = append(records, newAutorun) + } + + return +} + +// %ProgramData%\Microsoft\Windows\Start Menu\Programs\StartUp +// %AppData%\Microsoft\Windows\Start Menu\Programs\Startup +func windowsGetStartupFiles() (records []*Autorun) { + // We look for both global and user Startup folders. + folders := []string{ + os.Getenv("ProgramData"), + os.Getenv("AppData"), + } + + // The base path is the same for both. + var startupBasepath string = "Microsoft\\Windows\\Start Menu\\Programs\\StartUp" + + for _, folder := range folders { + // Get the full path. + startupPath := filepath.Join(folder, startupBasepath) + + // Get list of files in folder. + filesList, err := ioutil.ReadDir(startupPath) + if err != nil { + continue + } + + // Loop through all files in folder. + for _, fileEntry := range filesList { + // We skip desktop.ini files. + if fileEntry.Name() == "desktop.ini" { + continue + } + + filePath := filepath.Join(startupPath, fileEntry.Name()) + + // Instantiate new autorun record. + newAutorun := stringToAutorun("startup", startupPath, filePath, false, "") + + // Add new record to list. + records = append(records, newAutorun) + } + } + + return +} + +// cleanPath uses lookPath to search for the correct path to +// the executable and cleans the file path. +func cleanPath(file string) (string, error) { + file, err := exec.LookPath(file) + if err != nil { + return "", err + } + return filepath.Clean(file), nil +} + +// func windowsGetTasks() { + +// } diff --git a/basicinfo/utils/stringutil.go b/basicinfo/utils/stringutil.go new file mode 100644 index 0000000..d8d8ebb --- /dev/null +++ b/basicinfo/utils/stringutil.go @@ -0,0 +1,16 @@ +package utils + +func StringNewLine(str string, ln uint8) string { + var sub_str string + res_str := "" + for { + if len(str) < int(ln) { + res_str += str + break + } + sub_str = str[0:ln] + str = str[ln:] + res_str += sub_str + "\n" + } + return res_str +} diff --git a/configcheck/check/CheckTrigger.go b/configcheck/check/CheckTrigger.go new file mode 100644 index 0000000..e442035 --- /dev/null +++ b/configcheck/check/CheckTrigger.go @@ -0,0 +1,110 @@ +package check + +import ( + "github.com/gookit/color" +) + +func Trigger() { + color.Greenp("==============================================================================================\n") + color.Greenp("空密码账户检测中··· \n") + if !Empty() { + color.Infoln("空密码账户检测: [safe]") + } + color.Greenp("==============================================================================================\n") + color.Greenp("主机 Sudoer 检测中··· \n") + if !Sudo() { + color.Infoln("主机 Sudoer 检测: [safe]") + } + color.Greenp("==============================================================================================\n") + color.Greenp("SSH Server wrapper 检测中··· \n") + if !SshWrapper() { + color.Infoln("SSH Server wrapper 检测: [safe]") + } + color.Greenp("==============================================================================================\n") + color.Greenp("SSH用户免密证书登录检测中··· \n") + if !AuthorizedKeys() { + color.Infoln("SSH用户免密证书登录检测: [safe]") + } + color.Greenp("==============================================================================================\n") + color.Greenp("SSH登录爆破检测中··· \n") + SSHLog() + + color.Greenp("==============================================================================================\n") + color.Greenp("LD_PRELOAD 检测中··· \n") + if !LdPreloadCheck() { + color.Infoln("LD_PRELOAD 检测: [safe]") + } + color.Greenp("==============================================================================================\n") + color.Greenp("LD_AOUT_PRELOAD 检测中··· \n") + if !LdAoutPreloadCheck() { + color.Infoln("LD_AOUT_PRELOAD 检测: [safe]") + } + color.Greenp("==============================================================================================\n") + color.Greenp("LD_ELF_PRELOAD 检测中··· \n") + if !LdElfPreloadCheck() { + color.Infoln("LD_ELF_PRELOAD 检测: [safe]") + } + color.Greenp("==============================================================================================\n") + color.Greenp("LD_LIBRARY_PATH 检测中··· \n") + if !LdLibraryPathCheck() { + color.Infoln("LD_LIBRARY_PATH 检测: [safe]") + } + color.Greenp("==============================================================================================\n") + color.Greenp("ld.so.preload 检测中··· \n") + if !LdSoPreload() { + color.Infoln("ld.so.preload 检测: [safe]") + } + color.Greenp("==============================================================================================\n") + color.Greenp("PROMPT_COMMAND 检测中··· \n") + if !PromptCommandCheck() { + color.Infoln("PROMPT_COMMAND 检测: [safe]") + } + color.Greenp("==============================================================================================\n") + color.Greenp("自定义环境变量检测中··· \n") + if !ExportCheck() { + color.Infoln("自定义环境变量检测: [safe]") + } + color.Greenp("==============================================================================================\n") + color.Greenp("inetd.conf 检测中··· \n") + if !IntedCheck() { + color.Infoln("inted.conf 检测: [safe]") + } + color.Greenp("==============================================================================================\n") + color.Greenp("xinetd.conf 检测中··· \n") + if !XinetdCheck() { + color.Infoln("xinetd.conf 检测: [safe]") + } + color.Greenp("==============================================================================================\n") + color.Greenp("系统启动服务检测中··· \n") + if !StartupCheck() { + color.Infoln("系统启动服务检测: [safe]") + } + color.Greenp("==============================================================================================\n") + color.Greenp("主机计划任务检测中··· \n") + CrontabCheck() + color.Greenp("==============================================================================================\n") + color.Greenp("TCP Wrappers 检测中··· \n") + if !TcpWrappersCheck() { + color.Infoln("TCP Wrappers 检测: [safe]") + } + color.Greenp("==============================================================================================\n") + color.Greenp("alias 检测中··· \n") + if !AliasConf() { + color.Infoln("alias 检测: [safe]") + } + color.Greenp("==============================================================================================\n") + color.Greenp("主机历史命令检测中··· \n") + HistoryCheck() + color.Greenp("==============================================================================================\n") + color.Greenp("主机最近成功登录信息: \n") + SuccessLoginDetail() + color.Greenp("==============================================================================================\n") + color.Greenp("主机Rootkit检测中··· \n") + RootkitCheck() + color.Greenp("==============================================================================================\n") + color.Greenp("Setuid检测中··· \n") + if !SetUid() { + color.Infoln("Setuid检测: [safe]") + } + color.Greenp("==============================================================================================\n") +} diff --git a/configcheck/check/check_alias_conf.go b/configcheck/check/check_alias_conf.go new file mode 100644 index 0000000..a0ef19b --- /dev/null +++ b/configcheck/check/check_alias_conf.go @@ -0,0 +1,89 @@ +package check + +import ( + "fmt" + "io/ioutil" + "os" + "regexp" + "strings" +) + +func AliasConf() bool { + suspicious := false + + var files = []string{"/root/.bashrc", "/root/.bash_profile", "/etc/bashrc", "/etc/profile", "/etc/bash.bashrc"} + + dirs, _ := ioutil.ReadDir("/home") + for _, dir := range dirs { + + if !dir.IsDir() { + continue + } + + suspicious2 := alias_file_analysis("/home/" + dir.Name() + "/.bashrc") + if suspicious2 { + suspicious = true + } + + suspicious2 = alias_file_analysis("/home/" + dir.Name() + "/.bash_profile") + if suspicious2 { + suspicious = true + } + + } + + for _, file := range files { + suspicious2 := alias_file_analysis(file) + if suspicious2 { + suspicious = true + } + } + + return suspicious +} + +func alias_file_analysis(filepath string) bool { + suspicious := false + + if !FileExist(filepath) { + return suspicious + } + + syscmds := []string{ + "ps", "strings", "netstat", "find", "echo", "iptables", "lastlog", "who", "ifconfig", "ssh", "top", "crontab", "adduser", "kill", "killall", "mv", "rm", + "userdel", "cp", "locate", "ls", "show", "ll", + } + + dat, _ := ioutil.ReadFile(filepath) + flist := strings.Split(string(dat), "\n") + for _, line := range flist { + if len(line) > 5 && line[:5] == "alias" { + for _, syscmd := range syscmds { + + reg := regexp.MustCompile("alias\\s+" + syscmd) + dataSlice := reg.FindAll([]byte(line), -1) + if dataSlice != nil { + fmt.Printf("配置文件: %s | 存在可疑的alias设置: %s \n", filepath, line) + suspicious = true + } + + } + } else if len(line) > 6 && line[:6] == "source" { + fmt.Printf("配置文件: %s | 存在可疑的alias设置: %s \n", filepath, line) + suspicious = true + } + } + + return suspicious +} + +func FileExist(path string) bool { + _, err := os.Stat(path) + if err == nil { + return true + } + if os.IsNotExist(err) { + return false + } + return false +} diff --git a/configcheck/check/crontab_check.go b/configcheck/check/crontab_check.go new file mode 100644 index 0000000..d4604a6 --- /dev/null +++ b/configcheck/check/crontab_check.go @@ -0,0 +1,79 @@ +package check + +import ( + "fmt" + "io/ioutil" + "strings" + + "github.com/gookit/color" + + "d-eyes/configcheck/common" +) + +var suspiciousContents [][2]string + +func CrontabCheck() { + CrontabFile() + CrontabDir() + if len(suspiciousContents) == 0 { + color.Infoln("主机计划任务检测: [safe]") + } else { + fmt.Println("主机计划任务存在可疑内容, 请确认:") + for _, detail := range suspiciousContents { + fmt.Printf("[*]File: %s Detail: %s\n", detail[0], detail[1]) + } + } + +} + +// check single file +func CrontabFile() { + dat, err := ioutil.ReadFile("/etc/crontab") + if err != nil { + return + } + cronList := strings.Split(string(dat), "\n") + for _, info := range cronList { + if strings.HasPrefix(info, "#") { + continue + } + contents := common.CheckShell(info) + if contents == true { + suspiciousContents = append(suspiciousContents, [2]string{"/etc/crontab", info}) + } + } + +} + +// check dir files +func CrontabDir() { + dirList := []string{ + "/var/spool/cron/", "/var/spool/cron/crontabs/", "/etc/cron.d/", "/etc/cron.hourly/", "/etc/cron.daily/", "/etc/cron.weekly/", "/etc/cron.monthly/", + } + for _, dirTmp := range dirList { + dir, err := ioutil.ReadDir(dirTmp) + if err != nil { + continue + } + for _, f := range dir { + if f.IsDir() { + continue + } + dat, err := ioutil.ReadFile(dirTmp + f.Name()) + if err != nil { + continue + } + cronList := strings.Split(string(dat), "\n") + + for _, info := range cronList { + if strings.HasPrefix(info, "#") { + continue + } + contents := common.CheckShell(info) + if contents == true { + suspiciousContents = append(suspiciousContents, [2]string{dirTmp + f.Name(), info}) + } + } + } + } +} diff --git a/configcheck/check/empytpasswd.go b/configcheck/check/empytpasswd.go new file mode 100644 index 0000000..fe38efb --- /dev/null +++ b/configcheck/check/empytpasswd.go @@ -0,0 +1,34 @@ +package check + +import ( + "fmt" + "os/exec" + "strings" +) + +func Empty() bool { + suspicious := false + + if FileExist("/etc/shadow") { + c := exec.Command("bash", "-c", "awk -F: 'length($2)==0 {print $1}' /etc/shadow 2>/dev/null") + output, err := c.CombinedOutput() + if err != nil { + fmt.Println(err.Error()) + } + shellProcess := strings.Split(string(output), "\n") + sum := 0 + for _, user := range shellProcess { + if user == "" { + continue + } + sum++ + if sum == 1 { + fmt.Println("") + } + fmt.Printf("存在空口令用户 %s\n", user) + suspicious = true + } + } + + return suspicious +} diff --git a/configcheck/check/env.go b/configcheck/check/env.go new file mode 100644 index 0000000..3692d38 --- /dev/null +++ b/configcheck/check/env.go @@ -0,0 +1,330 @@ +package check + +import ( + "bufio" + "fmt" + "io" + "io/fs" + "io/ioutil" + "os" + "path/filepath" + "strings" + + "d-eyes/configcheck/common" +) + +func checkBackdoor(tag string) bool { + suspicious := false + files := []string{ + "/root/.bashrc", "/root/.tcshrc", "/root/.bash_profile", "/root/.cshrc", "/root/.tcshrc", + "/etc/bashrc", "/etc/profile", "/etc/profile.d/", "/etc/csh.login", "/etc/csh.cshrc", + } + + homeFiles := []string{"/.bashrc", "/.bash_profile", "/.tcshrc", "/.cshrc", "/.tcshrc"} + + dirs, _ := ioutil.ReadDir("/home/") + for _, subDir := range dirs { + for _, homeFile := range homeFiles { + subFile := "/home/" + subDir.Name() + homeFile + info := checkTag(subFile, tag) + if info { + suspicious = true + } + } + } + for _, subFile := range files { + + s, err := os.Stat(subFile) + if err != nil { + continue + } + if s.IsDir() { + filepath.Walk( + subFile, func(path string, info fs.FileInfo, err error) error { + + if info.IsDir() { + return nil + } else { + inf := checkTag(path, tag) + if inf { + suspicious = true + } + } + return err + }, + ) + } else { + inf := checkTag(subFile, tag) + if inf { + suspicious = true + } + + } + } + return suspicious +} + +func checkTag(filename string, tag string) bool { + result := false + if !common.PathExists(filename) { + return false + } + _, err := ioutil.ReadDir(filename) + if err == nil { + return false + } + + fr, _ := os.Open(filename) + defer fr.Close() + br := bufio.NewReader(fr) + for { + line, _, c := br.ReadLine() + if c == io.EOF { + break + } + + if len(line) == 0 || line[0] == '#' { + continue + } + if strings.Contains(string(line), "export "+tag+"=") { + fmt.Println("[*]File:", filename, " Found:", string(line)) + result = true + } + } + return result +} + +func checkEnv() bool { + suspicious := false + files := []string{ + "/root/.bashrc", "/root/.tcshrc", "/root/.bash_profile", "/root/.cshrc", "/root/.tcshrc", + "/etc/bashrc", "/etc/profile", "/etc/csh.login", "/etc/csh.cshrc", + } + + homeFiles := []string{"/.bashrc", "/.bash_profile", "/.tcshrc", "/.cshrc", "/.tcshrc"} + + dirs, _ := ioutil.ReadDir("/home/") + for _, subDir := range dirs { + for _, homeFile := range homeFiles { + subFile := "/home/" + subDir.Name() + homeFile + info1 := common.Check_file(subFile) + if info1 { + suspicious = true + } + + } + } + for _, subFile := range files { + + s, err := os.Stat(subFile) + if err != nil { + continue + } + if s.IsDir() { + filepath.Walk( + subFile, func(path string, info fs.FileInfo, err error) error { + + if info.IsDir() { + return nil + } else { + info1 := common.Check_file(path) + if info1 { + suspicious = true + } + } + return err + }, + ) + } else { + info1 := common.Check_file(subFile) + if info1 { + suspicious = true + } + + } + } + return suspicious +} + +func LdPreloadCheck() bool { + result := checkBackdoor("LD_PRELOAD") + return result +} +func LdAoutPreloadCheck() bool { + result := checkBackdoor("LD_AOUT_PRELOAD") + return result +} +func LdElfPreloadCheck() bool { + result := checkBackdoor("LD_ELF_PRELOAD") + return result +} +func LdLibraryPathCheck() bool { + result := checkBackdoor("LD_LIBRARY_PATH") + return result +} +func PromptCommandCheck() bool { + result := checkBackdoor("PROMPT_COMMAND") + return result +} + +func ExportCheck() bool { + result := false + tmp := checkBackdoor("PATH") + tmp1 := checkEnv() + if tmp { + result = tmp + } else { + result = tmp1 + } + return result +} + +func TcpWrappersCheck() bool { + result := common.Check_file("/etc/hosts.allow") + return result +} + +func LdSoPreload() bool { + result := false + if common.PathExists("/etc/ld.so.preload") { + fr, _ := os.Open("/etc/ld.so.preload") + defer fr.Close() + buf := bufio.NewReader(fr) + for { + data, _, c := buf.ReadLine() + if c == io.EOF { + break + } + line := strings.Replace(string(data), "\n", "", -1) + if line[0] == '#' { + continue + } + if line[len(line)-3:] == ".so" { + fmt.Println("[*]File: /etc/ld.so.preload, Found:", line) + result = true + } else { + info := common.CheckShell(line) + if info { + fmt.Println("[*]File: /etc/ld.so.preload, Found:", line) + result = true + } + } + } + } + return result +} + +func IntedCheck() bool { + result := false + if !common.PathExists("/etc/inetd.conf") { + return false + } + + fr, _ := os.Open("/etc/inetd.conf") + defer fr.Close() + buf := bufio.NewReader(fr) + for { + data, _, c := buf.ReadLine() + if c == io.EOF { + break + } + line := string(data) + content := common.CheckShell(line) + if content { + fmt.Println("[*]File: /etc/inetd.conf, Found:", line) + result = true + } + } + + return result +} + +func XinetdCheck() bool { + result := false + if !common.PathExists("/etc/xinetd.conf") { + return false + } + + dirs, err := ioutil.ReadDir("/etc/xinetd.conf") + if err != nil { + return true + } + for _, dir := range dirs { + subFile := "/etc/xinetd.conf" + dir.Name() + fr, _ := os.Open(subFile) + defer fr.Close() + buf := bufio.NewReader(fr) + for { + data, _, c := buf.ReadLine() + if c == io.EOF { + break + } + line := string(data) + content := common.CheckShell(line) + if content { + fmt.Println("[*]File: /etc/xinetd.conf, Found:", line) + result = true + } + } + } + + return result +} + +func StartupCheck() bool { + result := false + var suspicious []bool + init_path := []string{ + "/etc/init.d/", "/etc/rc.d/", "/etc/rc.local", "/usr/local/etc/rc.d", + "/usr/local/etc/rc.local", "/etc/conf.d/local.start", "/etc/inittab", "/etc/systemd/system", + } + for _, path := range init_path { + + if !common.PathExists(path) { + continue + } + filepath.Walk( + path, func(p string, info fs.FileInfo, err error) error { + if info.IsDir() { + return nil + } + b := common.Check_file(p) + if b { + suspicious = append(suspicious, b) + } + return err + }, + ) + + } + end := len(suspicious) + if end != 0 { + result = true + } + return result +} + +func pam_check() bool { + result := false + + if common.PathExists("/etc/ssh/sshd_config") { + fr, _ := os.Open("/etc/ssh/sshd_config") + defer fr.Close() + + bur := bufio.NewReader(fr) + for { + line, _, c := bur.ReadLine() + if c == io.EOF { + break + } + if len(line) == 0 || line[0] == '#' { + continue + } + if strings.Contains(string(line), "UsePAM") && strings.Contains(string(line), "yes") { + fmt.Println("[*]File: /etc/ssh/sshd_config, PAM enabled !!!") + result = true + } + } + } + return result +} diff --git a/configcheck/check/history.go b/configcheck/check/history.go new file mode 100644 index 0000000..72e25cd --- /dev/null +++ b/configcheck/check/history.go @@ -0,0 +1,126 @@ +package check + +import ( + "bufio" + "fmt" + "io" + "os" + "strings" + + "github.com/gookit/color" + + "d-eyes/configcheck/common" +) + +var suspiciousHistory [][2]string + +func HistoryCheck() { + + if HistoryFiles() { + color.Infoln("主机历史命令检测: [safe]") + } else { + fmt.Println("历史存在可疑命令, 请确认:") + for _, detail := range suspiciousHistory { + fmt.Printf("[*]File: %s Detail: %s\n", detail[0], detail[1]) + } + } + +} + +func HistoryFiles() bool { + + filePath := []string{"/home/", "/root/.bash_history", "/Users/"} + for _, path := range filePath { + + if !common.PathExists(path) { + continue + } + + dirs, err := os.ReadDir(path) + + if err != nil { + fi, _ := os.Open(path) + defer fi.Close() + + br := bufio.NewReader(fi) + for { + data, _, c := br.ReadLine() + if c == io.EOF { + break + } + line := strings.Replace(string(data), "\n", "", -1) + contents := Shell(line) + if contents == true { + suspiciousHistory = append(suspiciousHistory, [2]string{path, line}) + } + } + continue + } + for _, dir := range dirs { + subFile := path + dir.Name() + "/.bash_history" + if !common.PathExists(subFile) { + continue + } + + fi, _ := os.Open(subFile) + defer fi.Close() + + br := bufio.NewReader(fi) + for { + data, _, c := br.ReadLine() + if c == io.EOF { + break + } + line := strings.Replace(string(data), "\n", "", -1) + contents := Shell(line) + if contents { + suspiciousHistory = append(suspiciousHistory, [2]string{subFile, line}) + } + } + } + } + if len(suspiciousHistory) == 0 { + return true + } + return false +} + +func Shell(content string) bool { + + if strings.Contains(content, "docker") { + return false + } + + if (strings.Contains(content, "sh") && (strings.Contains(content, "/dev/tcp/") || + strings.Contains(content, "telnet ") || strings.Contains(content, "nc ") || + (strings.Contains(content, "exec ") && strings.Contains(content, "socket")) || + strings.Contains(content, "curl ") || strings.Contains(content, "wget ") || + strings.Contains(content, "lynx "))) || strings.Contains(content, ".decode('base64')") || strings.Contains(content, "exec(base64.b64decode") || + (strings.Contains(content, "base64 ") && strings.Contains(content, "--decode") && strings.Contains(content, "python")) || + (strings.Contains(content, "base64 ") && strings.Contains(content, "-d") && strings.Contains(content, "bash")) || + (strings.Contains(content, "nc ") && strings.Contains(content, "-vv")) || + (strings.Contains(content, "ln ") && strings.Contains(content, "-sf") && strings.Contains(content, "/usr/sbin/sshd")) { + + return true + } else if strings.Contains(content, "/dev/tcp/") && (strings.Contains(content, "exec ") || + strings.Contains(content, "ksh -c")) { + return true + } else if strings.Contains(content, "sh -i") { + return true + } else if strings.Contains(content, "exec ") && (strings.Contains(content, "socket.") || + strings.Contains(content, ".decode('base64')")) { + return true + } else if strings.Contains(content, "socket.socket") { + return true + } else if (strings.Contains(content, "wget ") || strings.Contains(content, "curl ")) && + (strings.Contains(content, " -O ") || strings.Contains(content, " -s ")) && + strings.Contains(content, " http") && (strings.Contains(content, "php ") || + strings.Contains(content, "perl ") || strings.Contains(content, "ruby ") || + strings.Contains(content, "python ") || strings.Contains(content, "sh ") || + strings.Contains(content, "bash ")) { // Ruby added + return true + } else { + return false + } + +} diff --git a/configcheck/check/log.go b/configcheck/check/log.go new file mode 100644 index 0000000..6f3d316 --- /dev/null +++ b/configcheck/check/log.go @@ -0,0 +1,33 @@ +package check + +import ( + "fmt" + "os/exec" + "strings" +) + +func SuccessLoginDetail() { + c := exec.Command("bash", "-c", "who /var/log/wtmp | awk '{print $1,$3\"-\"$4\"\",$5}'") + out, err := c.CombinedOutput() + if err != nil { + fmt.Println("读取记录失败!") + return + } + infos := strings.Split(string(out), "\n") + infos = infos[:len(infos)-1] + + if len(infos) == 1 && infos[0] == "" { + fmt.Println("未找到成功的登录信息.") + return + } + sum := 0 + for i := len(infos) - 1; i >= 0; i-- { + sum++ + success := strings.Split(infos[i], " ") + fmt.Printf("User : %s time : %s IP : %s\n", success[0], success[1], success[2]) + if sum == 5 { + return + } + } + +} diff --git a/configcheck/check/rootkit.go b/configcheck/check/rootkit.go new file mode 100644 index 0000000..dd19161 --- /dev/null +++ b/configcheck/check/rootkit.go @@ -0,0 +1,1093 @@ +package check + +import ( + "fmt" + "os" + "os/exec" + "path/filepath" + "strings" + + "github.com/gookit/color" +) + +type Rootkit struct { + Name string + File []string + Dir []string + Ksyms []string +} + +type RootKitRulesResult struct { + Type string + Name string + Res string +} + +var W55808A = Rootkit{Name: "55808 Variant A", File: []string{"/tmp/.../r", "/tmp/.../a"}, Dir: nil, Ksyms: nil} + +var AdoreRootkit = Rootkit{ + Name: "Adore Rootkit", + File: []string{ + "/usr/secure", "/usr/doc/sys/qrt", "/usr/doc/sys/run", "/usr/doc/sys/crond", + "/usr/sbin/kfd", "/usr/doc/kern/var", "/usr/doc/kern/string.o", "/usr/doc/kern/ava", "/usr/doc/kern/adore.o", + "/var/log/ssh/old", + }, + Dir: []string{ + "/lib/security/.config/ssh", "/usr/doc/kern", "/usr/doc/backup", "/usr/doc/backup/txt", + "/lib/backup", "/lib/backup/txt", "/usr/doc/work", "/usr/doc/sys", "/var/log/ssh", + "/usr/doc/.spool", "/usr/lib/kterm", + }, Ksyms: nil, +} + +var AjakitRootkit = Rootkit{ + Name: "AjaKit Rootkit", File: []string{ + "/dev/tux/.addr", "/dev/tux/.proc", + "/dev/tux/.file", "/lib/.libgh-gh/cleaner", "/lib/.libgh-gh/Patch/patch", "/lib/.libgh-gh/sb0k", + }, + Dir: []string{"/dev/tux", "/lib/.libgh-gh"}, Ksyms: nil, +} + +var apaKitRootkit = Rootkit{Name: "aPa Kit Rootkit", File: []string{"/usr/share/.aPa"}, Dir: nil, Ksyms: nil} + +var ApacheWorm = Rootkit{Name: "Apache Worm", File: []string{"/bin/.log"}, Dir: nil, Ksyms: nil} + +var AmbientRootkit = Rootkit{ + Name: "Ambient Rootkit", + File: []string{"/usr/lib/.ark?", "/dev/ptyxx/.log", "/dev/ptyxx/.file", "/dev/ptyxx/.proc", "/dev/ptyxx/.addr"}, + Dir: []string{"/dev/ptyxx"}, Ksyms: nil, +} + +var BalaurRootkit = Rootkit{ + Name: "Balaur Rootkit", File: []string{"/usr/lib/liblog.o"}, + Dir: []string{"/usr/lib/.kinetic", "/usr/lib/.egcs", "/usr/lib/.wormie"}, Ksyms: nil, +} + +var BeastkitRootkit = Rootkit{ + Name: "Beastkit Rootkit", + File: []string{ + "/usr/sbin/arobia", "/usr/sbin/idrun", "/usr/lib/elm/arobia/elm", + "/usr/lib/elm/arobia/elm/hk", "/usr/lib/elm/arobia/elm/hk.pub", + "/usr/lib/elm/arobia/elm/sc", "/usr/lib/elm/arobia/elm/sd.pp", + "/usr/lib/elm/arobia/elm/sdco", "/usr/lib/elm/arobia/elm/srsd", + }, + Dir: []string{"/lib/ldd.so/bktools"}, Ksyms: nil, +} + +var bex2Rootkit = Rootkit{ + Name: "beX2 Rootkit", File: []string{"/usr/info/termcap.info-5.gz", "/usr/bin/sshd2"}, + Dir: []string{"/usr/include/bex"}, Ksyms: nil, +} + +var BobkitRootkit = Rootkit{ + Name: "BOBkit Rootkit", + File: []string{ + "/usr/sbin/ntpsx", "/usr/sbin/.../bkit-ava", "/usr/sbin/.../bkit-d", "/usr/sbin/.../bkit-shd", + "/usr/sbin/.../bkit-f", "/usr/include/.../proc.h", "/usr/include/.../.bash_history", + "/usr/include/.../bkit-get", "/usr/include/.../bkit-dl", "/usr/include/.../bkit-screen", + "/usr/include/.../bkit-sleep", "/usr/lib/.../bkit-adore.o", "/usr/lib/.../ls", + "/usr/lib/.../netstat", "/usr/lib/.../lsof", "/usr/lib/.../bkit-ssh/bkit-shdcfg", + "/usr/lib/.../bkit-ssh/bkit-shhk", "/usr/lib/.../bkit-ssh/bkit-pw", + "/usr/lib/.../bkit-ssh/bkit-shrs", "/usr/lib/.../bkit-ssh/bkit-mots", + "/usr/lib/.../uconf.inv", "/usr/lib/.../psr", "/usr/lib/.../find", + "/usr/lib/.../pstree", "/usr/lib/.../slocate", "/usr/lib/.../du", "/usr/lib/.../top", + }, + Dir: []string{ + "/usr/sbin/...", "/usr/include/...", "/usr/include/.../.tmp", "/usr/lib/...", + "/usr/lib/.../.ssh", "/usr/lib/.../bkit-ssh", "/usr/lib/.bkit-", "/tmp/.bkp", + }, + Ksyms: nil, +} + +var OsxBoonanaATrojan = Rootkit{ + Name: "OSX Boonana-A Trojan", + File: []string{ + "/Library/StartupItems/OSXDriverUpdates/OSXDriverUpdates", + "/Library/StartupItems/OSXDriverUpdates/StartupParameters.plist", + }, + Dir: []string{"/var/root/.jnana"}, Ksyms: nil, +} + +var cbRootkit = Rootkit{ + Name: "cb Rootkit", + File: []string{ + "/dev/srd0", "/lib/libproc.so.2.0.6", "/dev/mounnt", "/etc/rc.d/init.d/init", + "/usr/bin/.zeen/..%/cl", "/usr/bin/.zeen/..%/.x.tgz", "/usr/bin/.zeen/..%/statdx", + "/usr/bin/.zeen/..%/wted", "/usr/bin/.zeen/..%/write", "/usr/bin/.zeen/..%/scan", + "/usr/bin/.zeen/..%/sc", "/usr/bin/.zeen/..%/sl2", "/usr/bin/.zeen/..%/wroot", + "/usr/bin/.zeen/..%/wscan", "/usr/bin/.zeen/..%/wu", "/usr/bin/.zeen/..%/v", + "/usr/bin/.zeen/..%/read", "/usr/lib/sshrc", "/usr/lib/ssh_host_key", + "/usr/lib/ssh_host_key.pub", "/usr/lib/ssh_random_seed", "/usr/lib/sshd_config", + "/usr/lib/shosts.equiv", "/usr/lib/ssh_known_hosts", "/u/zappa/.ssh/pid", + "/usr/bin/.system/..%/tcp.log", "/usr/bin/.zeen/..%/curatare/attrib", + "/usr/bin/.zeen/..%/curatare/chattr", "/usr/bin/.zeen/..%/curatare/ps", + "/usr/bin/.zeen/..%/curatare/pstree", "/usr/bin/.system/..%/.x/xC.o", + }, + Dir: []string{ + "/usr/bin/.zeen", "/usr/bin/.zeen/..%/curatare", "/usr/bin/.zeen/..%/scan", + "/usr/bin/.system/..%", + }, Ksyms: nil, +} + +var CinikWorm = Rootkit{Name: "CiNIK Worm", File: []string{"/tmp/.cinik"}, Dir: []string{"/tmp/.font-unix/.cinik"}, Ksyms: nil} + +var CxRootkit = Rootkit{ + Name: "CX Rootkit", + File: []string{ + "/usr/lib/ldlibso", "/usr/lib/configlibso", "/usr/lib/shklibso", "/usr/lib/randomlibso", + "/usr/lib/ldlibstrings.so", "/usr/lib/ldlibdu.so", "/usr/lib/ldlibns.so", "/usr/include/db", + }, + Dir: []string{"/usr/include/cxk"}, Ksyms: nil, +} + +var AbuseKit = Rootkit{Name: "Abuse Kit", File: []string{"/dev/mdev", "/usr/lib/libX.a"}, Dir: nil, Ksyms: nil} + +var DevilRootkit = Rootkit{ + Name: "Devil Rootkit", + File: []string{ + "/var/lib/games/.src", "/dev/dsx", "/dev/caca", "/dev/pro", "/bin/bye", + "/bin/homedir", "/usr/bin/xfss", "/usr/sbin/tzava", + "/usr/doc/tar/.../.dracusor/stuff/holber", + "/usr/doc/tar/.../.dracusor/stuff/sense", + "/usr/doc/tar/.../.dracusor/stuff/clear", + "/usr/doc/tar/.../.dracusor/stuff/tzava", + "/usr/doc/tar/.../.dracusor/stuff/citeste", + "/usr/doc/tar/.../.dracusor/stuff/killrk", + "/usr/doc/tar/.../.dracusor/stuff/searchlog", + "/usr/doc/tar/.../.dracusor/stuff/gaoaza", + "/usr/doc/tar/.../.dracusor/stuff/cleaner", + "/usr/doc/tar/.../.dracusor/stuff/shk", + "/usr/doc/tar/.../.dracusor/stuff/srs", + "/usr/doc/tar/.../.dracusor/utile.tgz", + "/usr/doc/tar/.../.dracusor/webpage", "/usr/doc/tar/.../.dracusor/getpsy", + "/usr/doc/tar/.../.dracusor/getbnc", + "/usr/doc/tar/.../.dracusor/getemech", + "/usr/doc/tar/.../.dracusor/localroot.sh", + "/usr/doc/tar/.../.dracusor/stuff/old/sense", + }, + Dir: []string{"/usr/doc/tar/.../.dracusor"}, Ksyms: nil, +} + +var DiamorphineLkm = Rootkit{ + Name: "Diamorphine LKM", File: nil, Dir: nil, + Ksyms: []string{"diamorphine", "module_hide", "module_hidden", "is_invisible", "hacked_getdents", "hacked_kill"}, +} + +var DicaKitRootkit = Rootkit{ + Name: "Dica-Kit Rootkit", + File: []string{ + "/lib/.sso", "/lib/.so", "/var/run/...dica/clean", "/var/run/...dica/dxr", + "/var/run/...dica/read", "/var/run/...dica/write", "/var/run/...dica/lf", + "/var/run/...dica/xl", "/var/run/...dica/xdr", "/var/run/...dica/psg", + "/var/run/...dica/secure", "/var/run/...dica/rdx", "/var/run/...dica/va", + "/var/run/...dica/cl.sh", "/var/run/...dica/last.log", "/usr/bin/.etc", + "/etc/sshd_config", "/etc/ssh_host_key", "/etc/ssh_random_seed", + }, + Dir: []string{"/var/run/...dica", "/var/run/...dica/mh", "/var/run/...dica/scan"}, Ksyms: nil, +} + +var Dreams_Rootkit = Rootkit{ + Name: "Dreams Rootkit", + File: []string{ + "/dev/ttyoa", "/dev/ttyof", "/dev/ttyop", "/usr/bin/sense", "/usr/bin/sl2", + "/usr/bin/logclear", "/usr/bin/(swapd)", "/usr/bin/initrd", "/usr/bin/crontabs", + "/usr/bin/snfs", "/usr/lib/libsss", "/usr/lib/libsnf.log", "/usr/lib/libshtift/top", + "/usr/lib/libshtift/ps", "/usr/lib/libshtift/netstat", "/usr/lib/libshtift/ls", + "/usr/lib/libshtift/ifconfig", "/usr/include/linseed.h", "/usr/include/linpid.h", + "/usr/include/linkey.h", "/usr/include/linconf.h", "/usr/include/iceseed.h", + "/usr/include/icepid.h", "/usr/include/icekey.h", "/usr/include/iceconf.h", + }, + Dir: []string{"/dev/ida/.hpd", "/usr/lib/libshtift"}, Ksyms: nil, +} + +var Duarawkz_Rootkit = Rootkit{ + Name: "Duarawkz Rootkit", File: []string{"/usr/bin/duarawkz/loginpass"}, + Dir: []string{"/usr/bin/duarawkz"}, Ksyms: nil, +} + +var Ebury_sshd_backdoor = Rootkit{ + Name: "Ebury sshd backdoor", + File: []string{ + "/lib/libns2.so", "/lib64/libns2.so", "/lib/libns5.so", "/lib64/libns5.so", + "/lib/libpw3.so", "/lib64/libpw3.so", "/lib/libpw5.so", "/lib64/libpw5.so", + "/lib/libsbr.so", "/lib64/libsbr.so", "/lib/libslr.so", "/lib64/libslr.so", + "/lib/tls/libkeyutils.so.1", "/lib64/tls/libkeyutils.so.1", + }, + Dir: nil, Ksyms: nil, +} + +var ENYE_LKM = Rootkit{ + Name: "ENYE LKM", File: []string{"/etc/.enyelkmHIDE^IT.ko", "/etc/.enyelkmOCULTAR.ko"}, + Dir: nil, Ksyms: nil, +} + +var Flea_Rootkit = Rootkit{ + Name: "Flea Rootkit", File: []string{ + "/etc/ld.so.hash", + "/lib/security/.config/ssh/sshd_config", + "/lib/security/.config/ssh/ssh_host_key", + "/lib/security/.config/ssh/ssh_host_key.pub", + "/lib/security/.config/ssh/ssh_random_seed", "/usr/bin/ssh2d", + "/usr/lib/ldlibns.so", "/usr/lib/ldlibps.so", + "/usr/lib/ldlibpst.so", + "/usr/lib/ldlibdu.so", "/usr/lib/ldlibct.so", + }, + Dir: []string{"/lib/security/.config/ssh", "/dev/..0", "/dev/..0/backup"}, Ksyms: nil, +} + +var FreeBSD_Rootkit = Rootkit{ + Name: "FreeBSD Rootkit", + File: []string{ + "/dev/ptyp", "/dev/ptyq", "/dev/ptyr", "/dev/ptys", "/dev/ptyt", + "/dev/fd/.88/freshb-bsd", "/dev/fd/.88/fresht", "/dev/fd/.88/zxsniff", + "/dev/fd/.88/zxsniff.log", "/dev/fd/.99/.ttyf00", "/dev/fd/.99/.ttyp00", + "/dev/fd/.99/.ttyq00", "/dev/fd/.99/.ttys00", "/dev/fd/.99/.pwsx00", "/etc/.acid", + "/usr/lib/.fx/sched_host.2", "/usr/lib/.fx/random_d.2", "/usr/lib/.fx/set_pid.2", + "/usr/lib/.fx/setrgrp.2", "/usr/lib/.fx/TOHIDE", "/usr/lib/.fx/cons.saver", + "/usr/lib/.fx/adore/ava/ava", "/usr/lib/.fx/adore/adore/adore.ko", "/bin/sysback", + "/usr/local/bin/sysback", + }, + Dir: []string{"/dev/fd/.88", "/dev/fd/.99", "/usr/lib/.fx", "/usr/lib/.fx/adore"}, Ksyms: nil, +} + +var Fu_Rootkit = Rootkit{ + Name: "Fu Rootkit", File: []string{"/sbin/xc", "/usr/include/ivtype.h", "/bin/.lib"}, + Dir: nil, Ksyms: nil, +} + +var Fuckit_Rootkit = Rootkit{ + Name: "Fuckit Rootkit", + File: []string{ + "/lib/libproc.so.2.0.7", "/dev/proc/.bash_profile", "/dev/proc/.bashrc", + "/dev/proc/.cshrc", "/dev/proc/fuckit/hax0r", "/dev/proc/fuckit/hax0rshell", + "/dev/proc/fuckit/config/lports", "/dev/proc/fuckit/config/rports", + "/dev/proc/fuckit/config/rkconf", "/dev/proc/fuckit/config/password", + "/dev/proc/fuckit/config/progs", "/dev/proc/fuckit/system-bins/init", + "/usr/lib/libcps.a", "/usr/lib/libtty.a", + }, + Dir: []string{"/dev/proc", "/dev/proc/fuckit", "/dev/proc/fuckit/system-bins", "/dev/proc/toolz"}, Ksyms: nil, +} + +var GasKit_Rootkit = Rootkit{ + Name: "GasKit Rootkit", File: []string{"/dev/dev/gaskit/sshd/sshdd"}, + Dir: []string{"/dev/dev", "/dev/dev/gaskit", "/dev/dev/gaskit/sshd"}, Ksyms: nil, +} + +var Heroin_LKM = Rootkit{Name: "Heroin LKM", File: nil, Dir: nil, Ksyms: []string{"heroin"}} + +var HjC_Kit_Rootkit = Rootkit{Name: "HjC Kit Rootkit", File: nil, Dir: []string{"/dev/.hijackerz"}, Ksyms: nil} + +var ignoKit_Rootkit = Rootkit{ + Name: "ignoKit Rootkit", + File: []string{ + "/lib/defs/p", "/lib/defs/q", "/lib/defs/r", "/lib/defs/s", "/lib/defs/t", + "/usr/lib/defs/p", "/usr/lib/defs/q", "/usr/lib/defs/r", "/usr/lib/defs/s", + "/usr/lib/defs/t", "/usr/lib/.libigno/pkunsec", + "/usr/lib/.libigno/.igno/psybnc/psybnc", + }, + Dir: []string{"/usr/lib/.libigno", "/usr/lib/.libigno/.igno"}, Ksyms: nil, +} + +var iLLogiC_Rootkit = Rootkit{ + Name: "iLLogiC Rootkit", + File: []string{ + "/dev/kmod", "/dev/dos", "/usr/lib/crth.o", "/usr/lib/crtz.o", "/etc/ld.so.hash", + "/usr/bin/sia", "/usr/bin/ssh2d", "/lib/security/.config/sn", + "/lib/security/.config/iver", "/lib/security/.config/uconf.inv", + "/lib/security/.config/ssh/ssh_host_key", + "/lib/security/.config/ssh/ssh_host_key.pub", "/lib/security/.config/ssh/sshport", + "/lib/security/.config/ssh/ssh_random_seed", "/lib/security/.config/ava", + "/lib/security/.config/cleaner", "/lib/security/.config/lpsched", + "/lib/security/.config/sz", "/lib/security/.config/rcp", + "/lib/security/.config/patcher", "/lib/security/.config/pg", + "/lib/security/.config/crypt", "/lib/security/.config/utime", + "/lib/security/.config/wget", "/lib/security/.config/instmod", + "/lib/security/.config/bin/find", "/lib/security/.config/bin/du", + "/lib/security/.config/bin/ls", "/lib/security/.config/bin/psr", + "/lib/security/.config/bin/netstat", "/lib/security/.config/bin/su", + "/lib/security/.config/bin/ping", "/lib/security/.config/bin/passwd", + }, + Dir: []string{ + "/lib/security/.config", "/lib/security/.config/ssh", "/lib/security/.config/bin", + "/lib/security/.config/backup", "/root/%%%/.dir", "/root/%%%/.dir/mass-scan", + "/root/%%%/.dir/flood", + }, Ksyms: nil, +} + +var OSX_Inqtana = Rootkit{ + Name: "OSX Inqtana Variant A", + File: []string{ + "/Users/w0rm-support.tgz", "/Users/InqTest.class", "/Users/com.openbundle.plist", + "/Users/com.pwned.plist", "/Users/libavetanaBT.jnilib", + }, + Dir: []string{"/Users/de", "/Users/javax"}, Ksyms: nil, +} + +var OSX_Inqtana2 = Rootkit{ + Name: "OSX Inqtana Variant B", + File: []string{ + "/Users/w0rms.love.apples.tgz", "/Users/InqTest.class", "/Users/InqTest.java", + "/Users/libavetanaBT.jnilib", "/Users/InqTanaHandler", "/Users/InqTanaHandler.bundle", + }, + Dir: []string{"/Users/de", "/Users/javax"}, Ksyms: nil, +} + +var OSX_Inqtana3 = Rootkit{ + Name: "OSX Inqtana Variant C", + File: []string{ + "/Users/applec0re.tgz", "/Users/InqTest.class", "/Users/InqTest.java", + "/Users/libavetanaBT.jnilib", "/Users/environment.plist", "/Users/pwned.c", + "/Users/pwned.dylib", + }, + Dir: []string{"/Users/de", "/Users/javax"}, Ksyms: nil, +} + +var IntoXonia_NG_Rootkit = Rootkit{ + Name: "IntoXonia-NG Rootkit", File: nil, Dir: nil, + Ksyms: []string{ + "funces", "ixinit", "tricks", "kernel_unlink", "rootme", "hide_module", + "find_sys_call_tbl", + }, +} + +var Irix_Rootkit = Rootkit{ + Name: "Irix Rootkit", File: nil, + Dir: []string{"/dev/pts/01", "/dev/pts/01/backup", "/dev/pts/01/etc", "/dev/pts/01/tmp"}, Ksyms: nil, +} + +var Jynx_Rootkit = Rootkit{ + Name: "Jynx Rootkit", + File: []string{ + "/xochikit/bc", "/xochikit/ld_poison.so", "/omgxochi/bc", "/omgxochi/ld_poison.so", + "/var/local/^^/bc", "/var/local/^^/ld_poison.so", + }, + Dir: []string{"/xochikit", "/omgxochi", "/var/local/^^"}, Ksyms: nil, +} + +var Jynx2_Rootkit = Rootkit{ + Name: "Jynx2 Rootkit", File: []string{"/XxJynx/reality.so"}, Dir: []string{"/XxJynx"}, + Ksyms: nil, +} + +var KBeast_Rootkit = Rootkit{ + Name: "KBeast Rootkit", + File: []string{"/usr/_h4x_/ipsecs-kbeast-v1.ko", "/usr/_h4x_/_h4x_bd", "/usr/_h4x_/acctlog"}, + Dir: []string{"/usr/_h4x_"}, + Ksyms: []string{ + "h4x_delete_module", "h4x_getdents64", "h4x_kill", "h4x_open", "h4x_read", + "h4x_rename", "h4x_rmdir", "h4x_tcp4_seq_show", "h4x_write", + }, +} + +var OSX_Keydnap_backdoor = Rootkit{ + Name: "OSX Keydnap backdoor", + File: []string{ + "/Applications/Transmission.app/Contents/Resources/License.rtf", + "/Volumes/Transmission/Transmission.app/Contents/Resources/License.rtf", + "/Library/LaunchAgents/com.apple.iCloud.sync.daemon.plist", + "/Library/LaunchAgents/com.geticloud.icloud.photo.plist", + }, + Dir: []string{"/Library/Application%Support/com.apple.iCloud.sync.daemon/"}, Ksyms: nil, +} + +var Kitko_Rootkit = Rootkit{Name: "Kitko Rootkit", File: nil, Dir: []string{"/usr/src/redhat/SRPMS/..."}, Ksyms: nil} + +var KNARK_FILES = Rootkit{ + Name: "Knark Rootkit", File: []string{"/proc/knark/pids"}, Dir: []string{"/proc/knark"}, + Ksyms: nil, +} + +var KOMPLEX_FILES = Rootkit{ + Name: "OSX Komplex Trojan", + File: []string{ + "/Users/Shared/.local/kextd", "/Users/Shared/com.apple.updates.plist", + "/Users/Shared/start.sh", + }, Dir: nil, Ksyms: nil, +} + +var LINUXV_FILES = Rootkit{ + Name: "ld-linuxv rootkit", File: []string{"/lib/ld-linuxv.so.1"}, + Dir: []string{"/var/opt/_so_cache", "/var/opt/_so_cache/ld", "/var/opt/_so_cache/lc"}, Ksyms: nil, +} + +var LION_FILES = Rootkit{ + Name: "Lion Worm", File: []string{ + "/bin/in.telnetd", "/bin/mjy", + "/usr/man/man1/man1/lib/.lib/mjy", + "/usr/man/man1/man1/lib/.lib/in.telnetd", + "/usr/man/man1/man1/lib/.lib/.x", "/dev/.lib/lib/scan/1i0n.sh", + "/dev/.lib/lib/scan/hack.sh", "/dev/.lib/lib/scan/bind", + "/dev/.lib/lib/scan/randb", "/dev/.lib/lib/scan/scan.sh", + "/dev/.lib/lib/scan/pscan", "/dev/.lib/lib/scan/star.sh", + "/dev/.lib/lib/scan/bindx.sh", "/dev/.lib/lib/scan/bindname.log", + "/dev/.lib/lib/1i0n.sh", "/dev/.lib/lib/lib/netstat", + "/dev/.lib/lib/lib/dev/.1addr", "/dev/.lib/lib/lib/dev/.1logz", + "/dev/.lib/lib/lib/dev/.1proc", "/dev/.lib/lib/lib/dev/.1file", + }, + Dir: nil, Ksyms: nil, +} + +var LOCKIT_FILES = Rootkit{ + Name: "Lockit Rootkit", + File: []string{ + "/usr/lib/libmen.oo/.LJK2/ssh_config", "/usr/lib/libmen.oo/.LJK2/ssh_host_key", + "/usr/lib/libmen.oo/.LJK2/ssh_host_key.pub", + "/usr/lib/libmen.oo/.LJK2/ssh_random_seed*", "/usr/lib/libmen.oo/.LJK2/sshd_config", + "/usr/lib/libmen.oo/.LJK2/backdoor/RK1bd", "/usr/lib/libmen.oo/.LJK2/backup/du", + "/usr/lib/libmen.oo/.LJK2/backup/ifconfig", + "/usr/lib/libmen.oo/.LJK2/backup/inetd.conf", "/usr/lib/libmen.oo/.LJK2/backup/locate", + "/usr/lib/libmen.oo/.LJK2/backup/login", "/usr/lib/libmen.oo/.LJK2/backup/ls", + "/usr/lib/libmen.oo/.LJK2/backup/netstat", "/usr/lib/libmen.oo/.LJK2/backup/ps", + "/usr/lib/libmen.oo/.LJK2/backup/pstree", "/usr/lib/libmen.oo/.LJK2/backup/rc.sysinit", + "/usr/lib/libmen.oo/.LJK2/backup/syslogd", "/usr/lib/libmen.oo/.LJK2/backup/tcpd", + "/usr/lib/libmen.oo/.LJK2/backup/top", "/usr/lib/libmen.oo/.LJK2/clean/RK1sauber", + "/usr/lib/libmen.oo/.LJK2/clean/RK1wted", "/usr/lib/libmen.oo/.LJK2/hack/RK1parse", + "/usr/lib/libmen.oo/.LJK2/hack/RK1sniff", "/usr/lib/libmen.oo/.LJK2/hide/.RK1addr", + "/usr/lib/libmen.oo/.LJK2/hide/.RK1dir", "/usr/lib/libmen.oo/.LJK2/hide/.RK1log", + "/usr/lib/libmen.oo/.LJK2/hide/.RK1proc", + "/usr/lib/libmen.oo/.LJK2/hide/RK1phidemod.c", + "/usr/lib/libmen.oo/.LJK2/modules/README.modules", + "/usr/lib/libmen.oo/.LJK2/modules/RK1hidem.c", + "/usr/lib/libmen.oo/.LJK2/modules/RK1phide", + "/usr/lib/libmen.oo/.LJK2/sshconfig/RK1ssh", + }, + Dir: []string{"/usr/lib/libmen.oo/.LJK2"}, Ksyms: nil, +} + +var MOKES_FILES = Rootkit{ + Name: "Mokes backdoor", File: []string{ + "/tmp/ss0-{0-9}{0-9}{0-9}{0-9}{0-9}{0-9}-{0-9}{0-9}{0-9}{0-9}{0-9}{0-9}-{0-9}{0-9}{0-9}.sst", + "/tmp/aa0-{0-9}{0-9}{0-9}{0-9}{0-9}{0-9}-{0-9}{0-9}{0-9}{0-9}{0-9}{0-9}-{0-9}{0-9}{0-9}.aat", + "/tmp/kk0-{0-9}{0-9}{0-9}{0-9}{0-9}{0-9}-{0-9}{0-9}{0-9}{0-9}{0-9}{0-9}-{0-9}{0-9}{0-9}.kkt", + "/tmp/dd0-{0-9}{0-9}{0-9}{0-9}{0-9}{0-9}-{0-9}{0-9}{0-9}{0-9}{0-9}{0-9}-{0-9}{0-9}{0-9}.ddt", + }, + Dir: nil, Ksyms: nil, +} + +var MRK_FILES = Rootkit{ + Name: "MRK RootKit", + File: []string{ + "/dev/ida/.inet/pid", "/dev/ida/.inet/ssh_host_key", "/dev/ida/.inet/ssh_random_seed", + "/dev/ida/.inet/tcp.log", + }, Dir: []string{"/dev/ida/.inet", "/var/spool/cron/.sh"}, Ksyms: nil, +} + +var MOODNT_FILES = Rootkit{ + Name: "Mood-NT Rootkit", + File: []string{ + "/sbin/init__mood-nt-_-_cthulhu", "/_cthulhu/mood-nt.init", "/_cthulhu/mood-nt.conf", + "/_cthulhu/mood-nt.sniff", + }, Dir: []string{"/_cthulhu"}, Ksyms: nil, +} + +var NIO_FILES = Rootkit{ + Name: "Ni0 Rootkit", + File: []string{ + "/var/lock/subsys/...datafile.../...net...", "/var/lock/subsys/...datafile.../...port...", + "/var/lock/subsys/...datafile.../...ps...", "/var/lock/subsys/...datafile.../...file...", + }, + Dir: []string{"/tmp/waza", "/var/lock/subsys/...datafile...", "/usr/sbin/es"}, Ksyms: nil, +} + +var OHHARA_FILES = Rootkit{ + Name: "Ohhara Rootkit", + File: []string{"/var/lock/subsys/...datafile.../...datafile.../in.smbd.log"}, + Dir: []string{ + "/var/lock/subsys/...datafile...", "/var/lock/subsys/...datafile.../...datafile...", + "/var/lock/subsys/...datafile.../...datafile.../bin", + "/var/lock/subsys/...datafile.../...datafile.../usr/bin", + "/var/lock/subsys/...datafile.../...datafile.../usr/sbin", + "/var/lock/subsys/...datafile.../...datafile.../lib/security", + }, Ksyms: nil, +} + +var OPTICKIT_FILES = Rootkit{ + Name: "Optic Kit Rootkit", File: nil, + Dir: []string{"/dev/tux", "/usr/bin/xchk", "/usr/bin/xsf", "/usr/bin/ssh2d"}, Ksyms: nil, +} + +var OSXRK_FILES = Rootkit{ + Name: "OSXRK", + File: []string{ + "/dev/.rk/nc", "/dev/.rk/diepu", "/dev/.rk/backd", "/Library/StartupItems/opener", + "/Library/StartupItems/opener.sh", "/System/Library/StartupItems/opener", + "/System/Library/StartupItems/opener.sh", + }, + Dir: []string{"/dev/.rk", "/Users/LDAP-daemon", "/tmp/.work"}, Ksyms: nil, +} + +var OZ_FILES = Rootkit{ + Name: "Oz Rootkit", File: []string{"/dev/.oz/.nap/rkit/terror"}, Dir: []string{"/dev/.oz"}, + Ksyms: nil, +} + +var PHALANX_FILES = Rootkit{ + Name: "Phalanx Rootkit", + File: []string{ + "/uNFuNF", "/etc/host.ph1", "/bin/host.ph1", "/usr/share/.home.ph1/phalanx", + "/usr/share/.home.ph1/cb", "/usr/share/.home.ph1/kebab", + }, + Dir: []string{"/usr/share/.home.ph1", "/usr/share/.home.ph1/tty"}, Ksyms: nil, +} + +var PHALANX2_FILES = Rootkit{ + Name: "Phalanx2 Rootkit", + File: []string{ + "/etc/khubd.p2/.p2rc", "/etc/khubd.p2/.phalanx2", "/etc/khubd.p2/.sniff", + "/etc/khubd.p2/sshgrab.py", "/etc/lolzz.p2/.p2rc", "/etc/lolzz.p2/.phalanx2", + "/etc/lolzz.p2/.sniff", "/etc/lolzz.p2/sshgrab.py", "/etc/cron.d/zupzzplaceholder", + "/usr/lib/zupzz.p2/.p-2.3d", "/usr/lib/zupzz.p2/.p2rc", + }, + Dir: []string{"/etc/khubd.p2", "/etc/lolzz.p2", "/usr/lib/zupzz.p2"}, Ksyms: nil, +} + +var PORTACELO_FILES = Rootkit{ + Name: "Portacelo Rootkit", + File: []string{ + "/var/lib/.../.ak", "/var/lib/.../.hk", "/var/lib/.../.rs", "/var/lib/.../.p", + "/var/lib/.../getty", "/var/lib/.../lkt.o", "/var/lib/.../show", + "/var/lib/.../nlkt.o", "/var/lib/.../ssshrc", "/var/lib/.../sssh_equiv", + "/var/lib/.../sssh_known_hosts", "/var/lib/.../sssh_pid ~/.sssh/known_hosts", + }, + Dir: nil, Ksyms: nil, +} + +var PROTON_FILES = Rootkit{ + Name: "OSX Proton backdoor", File: []string{ + "Library/LaunchAgents/com.apple.xpcd.plist", + "/Library/LaunchAgents/com.Eltima.UpdaterAgent.plist", + "/Library/.rand/updateragent.app", "/tmp/Updater.app", + }, + Dir: []string{"/Library/.rand", "/Library/.cachedir", "/Library/.random"}, Ksyms: nil, +} + +var REDSTORM_FILES = Rootkit{ + Name: "R3dstorm Toolkit", + File: []string{ + "/var/log/tk02/see_all", "/var/log/tk02/.scris", "/bin/.../sshd/sbin/sshd1", + "/bin/.../hate/sk", "/bin/.../see_all", + }, + Dir: []string{"/var/log/tk02", "/var/log/tk02/old", "/bin/..."}, Ksyms: nil, +} + +var RHSHARPES_FILES = Rootkit{ + Name: "RH-Sharpe Rootkit", + File: []string{ + "/bin/lps", "/usr/bin/lpstree", "/usr/bin/ltop", "/usr/bin/lkillall", + "/usr/bin/ldu", "/usr/bin/lnetstat", "/usr/bin/wp", "/usr/bin/shad", + "/usr/bin/vadim", "/usr/bin/slice", "/usr/bin/cleaner", "/usr/include/rpcsvc/du", + }, + Dir: nil, Ksyms: nil, +} + +var RSHA_FILES = Rootkit{ + Name: "RSHA Rootkit", + File: []string{ + "/bin/kr4p", "/usr/bin/n3tstat", "/usr/bin/chsh2", "/usr/bin/slice2", + "/usr/src/linux/arch/alpha/lib/.lib/.1proc", "/etc/rc.d/arch/alpha/lib/.lib/.1addr", + }, + Dir: []string{"/etc/rc.d/rsha", "/etc/rc.d/arch/alpha/lib/.lib"}, Ksyms: nil, +} + +var SHUTDOWN_FILES = Rootkit{ + Name: "Shutdown Rootkit", + File: []string{ + "/usr/man/man5/..%/.dir/scannah/asus", "/usr/man/man5/..%/.dir/see", + "/usr/man/man5/..%/.dir/nscd", "/usr/man/man5/..%/.dir/alpd", "/etc/rc.d/rc.local%", + }, + Dir: []string{ + "/usr/man/man5/..%/.dir", "/usr/man/man5/..%/.dir/scannah", + "/etc/rc.d/rc0.d/..%/.dir", + }, Ksyms: nil, +} + +var SCALPER_FILES = Rootkit{Name: "Scalper Worm", File: []string{"/tmp/.a", "/tmp/.uua"}, Dir: nil, Ksyms: nil} + +var SHV4_FILES = Rootkit{ + Name: "SHV4 Rootkit", + File: []string{ + "/etc/ld.so.hash", "/lib/libext-2.so.7", "/lib/lidps1.so", "/lib/libproc.a", + "/lib/libproc.so.2.0.6", "/lib/ldd.so/tks", "/lib/ldd.so/tkp", "/lib/ldd.so/tksb", + "/lib/security/.config/sshd", "/lib/security/.config/ssh/ssh_host_key", + "/lib/security/.config/ssh/ssh_host_key.pub", + "/lib/security/.config/ssh/ssh_random_seed", "/usr/include/file.h", + "/usr/include/hosts.h", "/usr/include/lidps1.so", "/usr/include/log.h", + "/usr/include/proc.h", "/usr/sbin/xntps", "/dev/srd0", + }, + Dir: []string{"/lib/ldd.so", "/lib/security/.config", "/lib/security/.config/ssh"}, Ksyms: nil, +} + +var SHV5_FILES = Rootkit{ + Name: "SHV5 Rootkit", + File: []string{ + "/etc/sh.conf", "/lib/libproc.a", "/lib/libproc.so.2.0.6", "/lib/lidps1.so", + "/lib/libsh.so/bash", "/usr/include/file.h", "/usr/include/hosts.h", + "/usr/include/log.h", "/usr/include/proc.h", "/lib/libsh.so/shdcf2", + "/lib/libsh.so/shhk", "/lib/libsh.so/shhk.pub", "/lib/libsh.so/shrs", + "/usr/lib/libsh/.bashrc", "/usr/lib/libsh/shsb", "/usr/lib/libsh/hide", + "/usr/lib/libsh/.sniff/shsniff", "/usr/lib/libsh/.sniff/shp", "/dev/srd0", + }, + Dir: []string{"/lib/libsh.so", "/usr/lib/libsh", "/usr/lib/libsh/utilz", "/usr/lib/libsh/.backup"}, + Ksyms: nil, +} + +var SINROOTKIT_FILES = Rootkit{ + Name: "Sin Rootkit", + File: []string{ + "/dev/.haos/haos1/.f/Denyed", "/dev/ttyoa", "/dev/ttyof", "/dev/ttyop", + "/dev/ttyos", "/usr/lib/.lib", "/usr/lib/sn/.X", "/usr/lib/sn/.sys", + "/usr/lib/ld/.X", "/usr/man/man1/...", "/usr/man/man1/.../.m", + "/usr/man/man1/.../.w", + }, + Dir: []string{"/usr/lib/sn", "/usr/lib/man1/...", "/dev/.haos"}, Ksyms: nil, +} + +var SLAPPER_FILES = Rootkit{ + Name: "Slapper Worm", + File: []string{ + "/tmp/.bugtraq", "/tmp/.uubugtraq", "/tmp/.bugtraq.c", "/tmp/httpd", "/tmp/.unlock", + "/tmp/update", "/tmp/.cinik", "/tmp/.b", + }, Dir: nil, Ksyms: nil, +} + +var SNEAKIN_FILES = Rootkit{Name: "Sneakin Rootkit", File: nil, Dir: []string{"/tmp/.X11-unix/.../rk"}, Ksyms: nil} + +var WANUKDOOR_FILES = Rootkit{ + Name: "Solaris Wanuk backdoor", + File: []string{ + "/var/adm/sa/.adm/.lp-door.i86pc", "/var/adm/sa/.adm/.lp-door.sun4", + "/var/spool/lp/admins/.lp-door.i86pc", "/var/spool/lp/admins/.lp-door.sun4", + "/var/spool/lp/admins/lpshut", "/var/spool/lp/admins/lpsystem", + "/var/spool/lp/admins/lpadmin", "/var/spool/lp/admins/lpmove", + "/var/spool/lp/admins/lpusers", "/var/spool/lp/admins/lpfilter", + "/var/spool/lp/admins/lpstat", "/var/spool/lp/admins/lpd", + "/var/spool/lp/admins/lpsched", "/var/spool/lp/admins/lpc", + }, + Dir: []string{"/var/adm/sa/.adm"}, Ksyms: nil, +} + +var WANUKWORM_FILES = Rootkit{ + Name: "Solaris Wanuk Worm", + File: []string{ + "/var/adm/.adm", "/var/adm/.i86pc", "/var/adm/.sun4", "/var/adm/sa/.adm", + "/var/adm/sa/.adm/.i86pc", "/var/adm/sa/.adm/.sun4", "/var/adm/sa/.adm/.crontab", + "/var/adm/sa/.adm/devfsadmd", "/var/adm/sa/.adm/svcadm", "/var/adm/sa/.adm/cfgadm", + "/var/adm/sa/.adm/kadmind", "/var/adm/sa/.adm/zoneadmd", "/var/adm/sa/.adm/sadm", + "/var/adm/sa/.adm/sysadm", "/var/adm/sa/.adm/dladm", "/var/adm/sa/.adm/bootadm", + "/var/adm/sa/.adm/routeadm", "/var/adm/sa/.adm/uadmin", "/var/adm/sa/.adm/acctadm", + "/var/adm/sa/.adm/cryptoadm", "/var/adm/sa/.adm/inetadm", "/var/adm/sa/.adm/logadm", + "/var/adm/sa/.adm/nlsadmin", "/var/adm/sa/.adm/sacadm", + "/var/adm/sa/.adm/syseventadmd", "/var/adm/sa/.adm/ttyadmd", + "/var/adm/sa/.adm/consadmd", "/var/adm/sa/.adm/metadevadm", "/var/adm/sa/.i86pc", + "/var/adm/sa/.sun4", "/var/adm/sa/acctadm", "/var/adm/sa/bootadm", + "/var/adm/sa/cfgadm", "/var/adm/sa/consadmd", "/var/adm/sa/cryptoadm", + "/var/adm/sa/devfsadmd", "/var/adm/sa/dladm", "/var/adm/sa/inetadm", + "/var/adm/sa/kadmind", "/var/adm/sa/logadm", "/var/adm/sa/metadevadm", + "/var/adm/sa/nlsadmin", "/var/adm/sa/routeadm", "/var/adm/sa/sacadm", + "/var/adm/sa/sadm", "/var/adm/sa/svcadm", "/var/adm/sa/sysadm", + "/var/adm/sa/syseventadmd", "/var/adm/sa/ttyadmd", "/var/adm/sa/uadmin", + "/var/adm/sa/zoneadmd", "/var/spool/lp/admins/.lp/.crontab", + "/var/spool/lp/admins/.lp/lpshut", "/var/spool/lp/admins/.lp/lpsystem", + "/var/spool/lp/admins/.lp/lpadmin", "/var/spool/lp/admins/.lp/lpmove", + "/var/spool/lp/admins/.lp/lpusers", "/var/spool/lp/admins/.lp/lpfilter", + "/var/spool/lp/admins/.lp/lpstat", "/var/spool/lp/admins/.lp/lpd", + "/var/spool/lp/admins/.lp/lpsched", "/var/spool/lp/admins/.lp/lpc", + }, + Dir: []string{"/var/adm/sa/.adm", "/var/spool/lp/admins/.lp"}, Ksyms: nil, +} + +var SPANISH_FILES = Rootkit{ + Name: "Spanish Rootkit", + File: []string{ + "/dev/ptyq", "/bin/ad", "/bin/ava", "/bin/server", "/usr/sbin/rescue", + "/usr/share/.../chrps", "/usr/share/.../chrifconfig", "/usr/share/.../netstat", + "/usr/share/.../linsniffer", "/usr/share/.../charbd", "/usr/share/.../charbd2", + "/usr/share/.../charbd3", "/usr/share/.../charbd4", "/usr/man/tmp/update.tgz", + "/var/lib/rpm/db.rpm", "/var/cache/man/.cat", "/var/spool/lpd/remote/.lpq", + }, + Dir: []string{"/usr/share/..."}, Ksyms: nil, +} + +var SUCKIT_FILES = Rootkit{ + Name: "Suckit Rootkit", + File: []string{ + "/sbin/initsk12", "/sbin/initxrk", "/usr/bin/null", "/usr/share/locale/sk/.sk12/sk", + "/etc/rc.d/rc0.d/S23kmdac", "/etc/rc.d/rc1.d/S23kmdac", "/etc/rc.d/rc2.d/S23kmdac", + "/etc/rc.d/rc3.d/S23kmdac", "/etc/rc.d/rc4.d/S23kmdac", "/etc/rc.d/rc5.d/S23kmdac", + "/etc/rc.d/rc6.d/S23kmdac", + }, + Dir: []string{ + "/dev/sdhu0/tehdrakg", "/etc/.MG", "/usr/share/locale/sk/.sk12", + "/usr/lib/perl5/site_perl/i386-linux/auto/TimeDate/.packlist", + }, Ksyms: nil, +} + +var NSDAP_FILES = Rootkit{ + Name: "NSDAP Rootkit", + File: []string{ + "/dev/pts/01/55su", "/dev/pts/01/55ps", "/dev/pts/01/55ping", "/dev/pts/01/55login", + "/dev/pts/01/PATCHER_COMPLETED", "/dev/prom/sn.l", "/dev/prom/dos", + "/usr/lib/vold/nsdap/.kit", "/usr/lib/vold/nsdap/defines", + "/usr/lib/vold/nsdap/patcher", "/usr/lib/vold/nsdap/pg", "/usr/lib/vold/nsdap/cleaner", + "/usr/lib/vold/nsdap/utime", "/usr/lib/vold/nsdap/crypt", "/usr/lib/vold/nsdap/findkit", + "/usr/lib/vold/nsdap/sn2", "/usr/lib/vold/nsdap/sniffload", + "/usr/lib/vold/nsdap/runsniff", "/usr/lib/lpset", "/usr/lib/lpstart", + "/usr/bin/mc68000", "/usr/bin/mc68010", "/usr/bin/mc68020", "/usr/ucb/bin/ps", + "/usr/bin/m68k", "/usr/bin/sun2", "/usr/bin/mc68030", "/usr/bin/mc68040", + "/usr/bin/sun3", "/usr/bin/sun3x", "/usr/bin/lso", "/usr/bin/u370", + }, + Dir: []string{"/dev/pts/01", "/dev/prom", "/usr/lib/vold/nsdap", "/.pat"}, Ksyms: nil, +} + +var SUNOSROOTKIT_FILES = Rootkit{ + Name: "SunOS Rootkit", + File: []string{ + "/etc/ld.so.hash", "/lib/libext-2.so.7", "/usr/bin/ssh2d", "/bin/xlogin", + "/usr/lib/crth.o", "/usr/lib/crtz.o", "/sbin/login", "/lib/security/.config/sn", + "/lib/security/.config/lpsched", "/dev/kmod", "/dev/dos", + }, + Dir: nil, Ksyms: nil, +} + +var SUPERKIT_FILES = Rootkit{ + Name: "Superkit Rootkit", + File: []string{ + "/usr/man/.sman/sk/backsh", "/usr/man/.sman/sk/izbtrag", "/usr/man/.sman/sk/sksniff", + "/var/www/cgi-bin/cgiback.cgi", + }, Dir: []string{"/usr/man/.sman/sk"}, Ksyms: nil, +} + +var TBD_FILES = Rootkit{Name: "TBD(Telnet Backdoor)", File: []string{"/usr/lib/.tbd"}, Dir: nil, Ksyms: nil} + +var TELEKIT_FILES = Rootkit{ + Name: "TeLeKiT Rootkit", + File: []string{ + "/usr/man/man3/.../TeLeKiT/bin/sniff", "/usr/man/man3/.../TeLeKiT/bin/telnetd", + "/usr/man/man3/.../TeLeKiT/bin/teleulo", "/usr/man/man3/.../cl", "/dev/ptyr", + "/dev/ptyp", "/dev/ptyq", "/dev/hda06", "/usr/info/libc1.so", + }, + Dir: []string{"/usr/man/man3/...", "/usr/man/man3/.../lsniff", "/usr/man/man3/.../TeLeKiT"}, + Ksyms: nil, +} + +var TOGROOT_FILES = Rootkit{ + Name: "OSX Togroot Rootkit", + File: []string{ + "/System/Library/Extensions/Togroot.kext/Contents/Info.plist", + "/System/Library/Extensions/Togroot.kext/Contents/pbdevelopment.plist", + "/System/Library/Extensions/Togroot.kext/Contents/MacOS/togrootkext", + }, + Dir: []string{ + "/System/Library/Extensions/Togroot.kext", + "/System/Library/Extensions/Togroot.kext/Contents", + "/System/Library/Extensions/Togroot.kext/Contents/MacOS", + }, Ksyms: nil, +} + +var TORN_FILES = Rootkit{ + Name: "T0rn Rootkit", + File: []string{ + "/dev/.lib/lib/lib/t0rns", "/dev/.lib/lib/lib/du", "/dev/.lib/lib/lib/ls", + "/dev/.lib/lib/lib/t0rnsb", "/dev/.lib/lib/lib/ps", "/dev/.lib/lib/lib/t0rnp", + "/dev/.lib/lib/lib/find", "/dev/.lib/lib/lib/ifconfig", "/dev/.lib/lib/lib/pg", + "/dev/.lib/lib/lib/ssh.tgz", "/dev/.lib/lib/lib/top", "/dev/.lib/lib/lib/sz", + "/dev/.lib/lib/lib/login", "/dev/.lib/lib/lib/in.fingerd", "/dev/.lib/lib/lib/1i0n.sh", + "/dev/.lib/lib/lib/pstree", "/dev/.lib/lib/lib/in.telnetd", "/dev/.lib/lib/lib/mjy", + "/dev/.lib/lib/lib/sush", "/dev/.lib/lib/lib/tfn", "/dev/.lib/lib/lib/name", + "/dev/.lib/lib/lib/getip.sh", "/usr/info/.torn/sh*", "/usr/src/.puta/.1addr", + "/usr/src/.puta/.1file", "/usr/src/.puta/.1proc", "/usr/src/.puta/.1logz", + "/usr/info/.t0rn", + }, + Dir: []string{ + "/dev/.lib", "/dev/.lib/lib", "/dev/.lib/lib/lib", "/dev/.lib/lib/lib/dev", + "/dev/.lib/lib/scan", "/usr/src/.puta", "/usr/man/man1/man1", "/usr/man/man1/man1/lib", + "/usr/man/man1/man1/lib/.lib", "/usr/man/man1/man1/lib/.lib/.backup", + }, + Ksyms: nil, +} + +var TRNKIT_FILES = Rootkit{ + Name: "trNkit Rootkit", + File: []string{ + "/usr/lib/libbins.la", "/usr/lib/libtcs.so", "/dev/.ttpy/ulogin.sh", + "/dev/.ttpy/tcpshell.sh", "/dev/.ttpy/bupdu", "/dev/.ttpy/buloc", "/dev/.ttpy/buloc1", + "/dev/.ttpy/buloc2", "/dev/.ttpy/stat", "/dev/.ttpy/backps", "/dev/.ttpy/tree", + "/dev/.ttpy/topk", "/dev/.ttpy/wold", "/dev/.ttpy/whoold", "/dev/.ttpy/backdoors", + }, + Dir: nil, Ksyms: nil, +} + +var TROJANIT_FILES = Rootkit{ + Name: "Trojanit Kit Rootkit", + File: []string{"bin/.ls", "/bin/.ps", "/bin/.netstat", "/usr/bin/.nop", "/usr/bin/.who"}, Dir: nil, + Ksyms: nil, +} + +var TURTLE_FILES = Rootkit{Name: "Turtle Rootkit", File: []string{"/dev/turtle2dev"}, Dir: nil, Ksyms: nil} + +var TUXTENDO_FILES = Rootkit{ + Name: "Tuxtendo Rootkit", + File: []string{ + "/lib/libproc.so.2.0.7", "/usr/bin/xchk", "/usr/bin/xsf", "/dev/tux/suidsh", + "/dev/tux/.addr", "/dev/tux/.cron", "/dev/tux/.file", "/dev/tux/.log", + "/dev/tux/.proc", "/dev/tux/.iface", "/dev/tux/.pw", "/dev/tux/.df", "/dev/tux/.ssh", + "/dev/tux/.tux", "/dev/tux/ssh2/sshd2_config", "/dev/tux/ssh2/hostkey", + "/dev/tux/ssh2/hostkey.pub", "/dev/tux/ssh2/logo", "/dev/tux/ssh2/random_seed", + "/dev/tux/backup/crontab", "/dev/tux/backup/df", "/dev/tux/backup/dir", + "/dev/tux/backup/find", "/dev/tux/backup/ifconfig", "/dev/tux/backup/locate", + "/dev/tux/backup/netstat", "/dev/tux/backup/ps", "/dev/tux/backup/pstree", + "/dev/tux/backup/syslogd", "/dev/tux/backup/tcpd", "/dev/tux/backup/top", + "/dev/tux/backup/updatedb", "/dev/tux/backup/vdir", + }, + Dir: []string{"/dev/tux", "/dev/tux/ssh2", "/dev/tux/backup"}, Ksyms: nil, +} + +var URK_FILES = Rootkit{ + Name: "Universal Rootkit", + File: []string{ + "/dev/prom/sn.l", "/usr/lib/ldlibps.so", "/usr/lib/ldlibnet.so", "/dev/pts/01/uconf.inv", + "/dev/pts/01/cleaner", "/dev/pts/01/bin/psniff", "/dev/pts/01/bin/du", + "/dev/pts/01/bin/ls", "/dev/pts/01/bin/passwd", "/dev/pts/01/bin/ps", + "/dev/pts/01/bin/psr", "/dev/pts/01/bin/su", "/dev/pts/01/bin/find", + "/dev/pts/01/bin/netstat", "/dev/pts/01/bin/ping", "/dev/pts/01/bin/strings", + "/dev/pts/01/bin/bash", "/usr/man/man1/xxxxxxbin/du", "/usr/man/man1/xxxxxxbin/ls", + "/usr/man/man1/xxxxxxbin/passwd", "/usr/man/man1/xxxxxxbin/ps", + "/usr/man/man1/xxxxxxbin/psr", "/usr/man/man1/xxxxxxbin/su", + "/usr/man/man1/xxxxxxbin/find", "/usr/man/man1/xxxxxxbin/netstat", + "/usr/man/man1/xxxxxxbin/ping", "/usr/man/man1/xxxxxxbin/strings", + "/usr/man/man1/xxxxxxbin/bash", "/tmp/conf.inv", + }, + Dir: []string{"/dev/prom", "/dev/pts/01", "/dev/pts/01/bin", "/usr/man/man1/xxxxxxbin"}, Ksyms: nil, +} + +var VCKIT_FILES = Rootkit{ + Name: "VcKit Rootkit", File: nil, + Dir: []string{"/usr/include/linux/modules/lib.so", "/usr/include/linux/modules/lib.so/bin"}, + Ksyms: nil, +} + +var VAMPIRE_FILES = Rootkit{ + Name: "Vampire Rootkit", File: nil, Dir: nil, + Ksyms: []string{"new_getdents", "old_getdents", "should_hide_file_name", "should_hide_task_name"}, +} + +var VOLC_FILES = Rootkit{ + Name: "Volc Rootkit", + File: []string{ + "/usr/bin/volc", "/usr/lib/volc/backdoor/divine", "/usr/lib/volc/linsniff", + "/etc/rc.d/rc1.d/S25sysconf", "/etc/rc.d/rc2.d/S25sysconf", "/etc/rc.d/rc3.d/S25sysconf", + "/etc/rc.d/rc4.d/S25sysconf", "/etc/rc.d/rc5.d/S25sysconf", + }, + Dir: []string{ + "/var/spool/.recent", "/var/spool/.recent/.files", "/usr/lib/volc", + "/usr/lib/volc/backup", + }, Ksyms: nil, +} + +var WEAPONX_FILES = Rootkit{ + Name: "weaponX", File: []string{"/System/Library/Extensions/WeaponX.kext"}, + Dir: []string{"/tmp/..."}, Ksyms: nil, +} + +var XZIBIT_FILES = Rootkit{ + Name: "Xzibit Rootkit", + File: []string{ + "/dev/dsx", "/dev/caca", "/dev/ida/.inet/linsniffer", "/dev/ida/.inet/logclear", + "/dev/ida/.inet/sense", "/dev/ida/.inet/sl2", "/dev/ida/.inet/sshdu", + "/dev/ida/.inet/s", "/dev/ida/.inet/ssh_host_key", "/dev/ida/.inet/ssh_random_seed", + "/dev/ida/.inet/sl2new.c", "/dev/ida/.inet/tcp.log", "/home/httpd/cgi-bin/becys.cgi", + "/usr/local/httpd/cgi-bin/becys.cgi", "/usr/local/apache/cgi-bin/becys.cgi", + "/www/httpd/cgi-bin/becys.cgi", "/www/cgi-bin/becys.cgi", + }, + Dir: []string{"/dev/ida/.inet"}, Ksyms: nil, +} + +var XORGSUNOS_FILES = Rootkit{ + Name: "X-Org SunOS Rootkit", + File: []string{ + "/usr/lib/libX.a/bin/tmpfl", "/usr/lib/libX.a/bin/rps", "/usr/bin/srload", + "/usr/lib/libX.a/bin/sparcv7/rps", "/usr/sbin/modcheck", + }, + Dir: []string{ + "/usr/lib/libX.a", "/usr/lib/libX.a/bin", "/usr/lib/libX.a/bin/sparcv7", + "/usr/share/man...", + }, Ksyms: nil, +} + +var ZARWT_FILES = Rootkit{ + Name: "zaRwT.KiT Rootkit", + File: []string{"/dev/rd/s/sendmeil", "/dev/ttyf", "/dev/ttyp", "/dev/ttyn", "/rk/tulz"}, + Dir: []string{"/rk", "/dev/rd/s"}, Ksyms: nil, +} + +var ZK_FILES = Rootkit{ + Name: "ZK Rootkit", + File: []string{ + "/usr/share/.zk/zk", "/usr/X11R6/.zk/xfs", "/usr/X11R6/.zk/echo", "/etc/1ssue.net", + "/etc/sysconfig/console/load.zk", + }, + Dir: []string{"/usr/share/.zk", "/usr/X11R6/.zk"}, Ksyms: nil, +} + +var LOGIN_BACKDOOR_FILES = Rootkit{ + Name: "Miscellaneous login backdoors", File: []string{"/bin/.login", "/sbin/.login"}, + Dir: nil, Ksyms: nil, +} + +var Sniffer_FILES = Rootkit{ + Name: "Sniffer log", + File: []string{"/usr/lib/libice.log", "/dev/prom/sn.l", "/dev/fd/.88/zxsniff.log"}, + Dir: nil, Ksyms: nil, +} + +var SUSPICIOUS_DIRS = Rootkit{ + Name: "Suspicious dir", File: nil, Dir: []string{"/usr/X11R6/bin/.,/copy", "/dev/rd/cdb"}, + Ksyms: nil, +} + +var Apache_Door = Rootkit{ + Name: "Apache backdoor", + File: []string{ + "/etc/apache2/mods-enabled/mod_rootme.so", "/etc/apache2/mods-enabled/mod_rootme2.so", + "/etc/httpd/modules/mod_rootme.so", "/etc/httpd/modules/mod_rootme2.so", + "/usr/apache/libexec/mod_rootme.so", "/usr/apache/libexec/mod_rootme2.so", + "/usr/lib/modules/mod_rootme.so", "/usr/lib/modules/mod_rootme2.so", + "/usr/local/apache/modules/mod_rootme.so", "/usr/local/apache/modules/mod_rootme2.so", + "/usr/local/apache/conf/mod_rootme.so", "/usr/local/apache/conf/mod_rootme2.so", + "/usr/local/etc/apache/mod_rootme.so", "/usr/local/etc/apache/mod_rootme2.so", + "/etc/apache/mod_rootme.so", "/etc/apache/mod_rootme2.so", + "/etc/httpd/conf/mod_rootme.so", "/etc/httpd/conf/mod_rootme2.so", + }, Dir: nil, + Ksyms: nil, +} + +var rootkit_rules = []Rootkit{ + W55808A, AdoreRootkit, AjakitRootkit, apaKitRootkit, ApacheWorm, AmbientRootkit, + BalaurRootkit, BeastkitRootkit, bex2Rootkit, BobkitRootkit, OsxBoonanaATrojan, CinikWorm, CxRootkit, + AbuseKit, DevilRootkit, DiamorphineLkm, DicaKitRootkit, Dreams_Rootkit, Duarawkz_Rootkit, Ebury_sshd_backdoor, + ENYE_LKM, Flea_Rootkit, FreeBSD_Rootkit, Fu_Rootkit, Fuckit_Rootkit, GasKit_Rootkit, Heroin_LKM, HjC_Kit_Rootkit, + ignoKit_Rootkit, iLLogiC_Rootkit, OSX_Inqtana, OSX_Inqtana2, OSX_Inqtana3, IntoXonia_NG_Rootkit, Irix_Rootkit, + Jynx_Rootkit, Jynx2_Rootkit, KBeast_Rootkit, OSX_Keydnap_backdoor, Kitko_Rootkit, KNARK_FILES, KOMPLEX_FILES, + LINUXV_FILES, LION_FILES, LOCKIT_FILES, MOKES_FILES, MRK_FILES, MOODNT_FILES, NIO_FILES, OHHARA_FILES, + OPTICKIT_FILES, OSXRK_FILES, OZ_FILES, PHALANX_FILES, PHALANX2_FILES, PORTACELO_FILES, PROTON_FILES, REDSTORM_FILES, + RHSHARPES_FILES, RSHA_FILES, SHUTDOWN_FILES, SCALPER_FILES, SHV4_FILES, SHV5_FILES, SINROOTKIT_FILES, SLAPPER_FILES, + SNEAKIN_FILES, WANUKDOOR_FILES, WANUKWORM_FILES, SPANISH_FILES, SUCKIT_FILES, NSDAP_FILES, SUNOSROOTKIT_FILES, + SUPERKIT_FILES, TBD_FILES, TELEKIT_FILES, TOGROOT_FILES, TORN_FILES, TRNKIT_FILES, TROJANIT_FILES, TURTLE_FILES, + TUXTENDO_FILES, URK_FILES, VCKIT_FILES, VAMPIRE_FILES, VOLC_FILES, WEAPONX_FILES, XZIBIT_FILES, XORGSUNOS_FILES, + ZARWT_FILES, ZK_FILES, LOGIN_BACKDOOR_FILES, Sniffer_FILES, SUSPICIOUS_DIRS, Apache_Door, +} + +var LKM_BADNAMES = []string{ + "adore.o", "bkit-adore.o", "cleaner.o", "flkm.o", "knark.o", "modhide.o", "mod_klgr.o", + "phide_mod.o", "vlogger.o", "p2.ko", "rpldev.o", "xC.o", "strings.o", "wkmr26.o", +} + +var kallsyms []string + +var rootkit_results []RootKitRulesResult + +var bad_lkm_results map[string]string + +func RootkitCheck() { + + for _, rootkit := range rootkit_rules { + check_rootkit_rules(rootkit) + } + + check_bad_LKM() + + for _, result := range rootkit_results { + if result.Type == "file" { + fmt.Printf("检测到%s的恶意rootkit文件: %s\n", result.Name, result.Res) + } + if result.Type == "dir" { + fmt.Printf("检测到%s的恶意rootkit目录: %s\n", result.Name, result.Res) + } + if result.Type == "kms" { + fmt.Printf("检测到%s内核符号表特征: %s\n", result.Name, result.Res) + } + } + for file := range bad_lkm_results { + fmt.Printf("检测到内核模块可疑文件 %s \n", file) + } + if len(rootkit_results) == 0 && len(bad_lkm_results) == 0 { + color.Infoln("主机Rootkit检测: [safe]") + } +} + +func check_rootkit_rules(rootkit Rootkit) { + for _, file := range rootkit.File { + if PathExists(file) { + rootkit_results = append(rootkit_results, RootKitRulesResult{Name: rootkit.Name, Type: "file", Res: file}) + } + } + for _, dir := range rootkit.Dir { + if PathExists(dir) { + rootkit_results = append(rootkit_results, RootKitRulesResult{Name: rootkit.Name, Type: "dir", Res: dir}) + } + } + get_kmsinfo() + for _, kms := range kallsyms { + for _, ksyms := range rootkit.Ksyms { + if strings.Contains(kms, ksyms) { + rootkit_results = append(rootkit_results, RootKitRulesResult{Name: rootkit.Name, Type: "kms", Res: kms}) + } + } + } +} + +func check_bad_LKM() { + bad_lkm_results = make(map[string]string) + if !PathExists("/lib/modules/") { + return + } + + cmd := exec.Command( + "bash", "-c", + "find /lib/modules/ -name '*.so' -o -name '*.ko' -o -name '*.ko.xz' 2>/dev/null", + ) + + out, err := cmd.CombinedOutput() + if err != nil { + fmt.Println(err.Error()) + } + infos := strings.Split(string(out), "\n") + for _, file := range infos { + for _, lkm := range LKM_BADNAMES { + filename := filepath.Base(file) + if lkm == filename { + bad_lkm_results[file] = lkm + } + } + } +} + +func get_kmsinfo() { + + var cmd *exec.Cmd + + if PathExists("/proc/kallsyms") { + cmd = exec.Command("bash", "-c", "cat /proc/kallsyms 2>/dev/null|awk '{print $3}'") + } else if PathExists("/proc/ksyms") { + cmd = exec.Command("bash", "-c", "cat /proc/ksyms") + } else { + return + } + + out, err := cmd.Output() + if err != nil { + fmt.Println(err.Error()) + } + kallsyms = strings.Split(string(out), "\n") + +} + +func PathExists(path string) bool { + _, err := os.Stat(path) + if err == nil { + return true + } + if os.IsNotExist(err) { + return false + } + return false +} diff --git a/configcheck/check/setuid.go b/configcheck/check/setuid.go new file mode 100644 index 0000000..664fb32 --- /dev/null +++ b/configcheck/check/setuid.go @@ -0,0 +1,48 @@ +package check + +import ( + "fmt" + "os/exec" + "strings" + + "github.com/toolkits/slice" +) + +func SetUid() bool { + suspicious := false + whitelist := []string{ + "pam_timestamp_check", "unix_chkpwd", "ping", "mount", "umount", "sudo", "su", "pt_chown", "ssh-keysign", "at", "passwd", "chsh", "crontab", "chfn", + "usernetctl", "staprun", "newgrp", "chage", "dhcp", "helper", "pkexec", "top", "Xorg", "nvidia-modprobe", "quota", "login", "security_authtrampoline", + "authopen", "traceroute6", "traceroute", "ps", "auth_pam_tool", "Xorg.wrap", "gpasswd", "mount.cifs", "mount.nfs", "ping6", "pppd", "fusermount3", + "ntfs-3g", + } + c := exec.Command( + "bash", "-c", + "find / ! -path '/proc/*' -type f -perm -4000 2>/dev/null", + ) + + output, err := c.CombinedOutput() + + if err != nil { + fmt.Println(err.Error()) + return suspicious + } + + fileInfos := strings.Split(string(output), "\n") + if len(fileInfos) != 0 { + suspicious = true + fmt.Println("主机含有非常见suid程序,请确认") + } + for _, info := range fileInfos { + if info == "" { + continue + } + tmp := strings.Split(info, "/") + if !slice.ContainsString(whitelist, tmp[len(tmp)-1]) { + fmt.Println(info) + } + } + + return suspicious + +} diff --git a/configcheck/check/ssh.go b/configcheck/check/ssh.go new file mode 100644 index 0000000..054ab82 --- /dev/null +++ b/configcheck/check/ssh.go @@ -0,0 +1,51 @@ +package check + +import ( + "fmt" + "io/ioutil" + "os/exec" + "strings" +) + +func AuthorizedKeys() bool { + suspicious := false + + dirs, _ := ioutil.ReadDir("/home") + for _, dir := range dirs { + + if !dir.IsDir() { + continue + } + + suspicious2 := fileAnalysis("/home/"+dir.Name()+"/.ssh/authorized_keys", dir.Name()) + if suspicious2 { + suspicious = true + } + } + + suspicious2 := fileAnalysis("/root/.ssh/authorized_keys", "root") + if suspicious2 { + suspicious = true + } + + return suspicious +} + +func fileAnalysis(file string, user string) bool { + suspicious := false + + if FileExist(file) { + c := exec.Command( + "bash", "-c", + "cat "+file+" 2>/dev/null |awk '{print $3}'", + ) + output, _ := c.CombinedOutput() + shell_process3 := strings.Split(string(output), "\n") + if len(shell_process3) > 0 { + fmt.Printf("用户 %s 存在免密登录的证书,证书位置: %s \n", user, file) + } + suspicious = true + } + return suspicious + +} diff --git a/configcheck/check/sshlog.go b/configcheck/check/sshlog.go new file mode 100644 index 0000000..4908abf --- /dev/null +++ b/configcheck/check/sshlog.go @@ -0,0 +1,223 @@ +package check + +import ( + "fmt" + "io/ioutil" + "os" + "path/filepath" + "strings" + + "github.com/gookit/color" + "github.com/toolkits/slice" +) + +type BaopoInfo struct { + User string + Ip string + Time string +} + +// 爆破成功 +var correct_baopo_info []BaopoInfo + +// 所有爆破的信息(超过阈值) +var baopo_info []BaopoInfo + +//所有C段爆破信息(超过阈值) +//var c_baopo_info []BaopoInfo + +// ip_failed_count: 单IP错误的次数,超过此错误代表发生了爆破行为 +// ips_failed_count: IP C段错误的次数,超过此错误代表发生了爆破行为 +// correct_baopo_info: 记录爆破成功的信息 + +func SSH_Analysis(log string, log_dir string, ip_failed_count uint, ips_failed_count uint) { + + if log == "" { + dir_file_detect(log_dir, ip_failed_count, ips_failed_count) + } else { + attack_detect(log, ip_failed_count, ips_failed_count) + } + +} + +func dir_file_detect(log_dir string, ip_failed_count uint, ips_failed_count uint) { + + var files []string + dirs, _ := ioutil.ReadDir(log_dir) + for _, dir := range dirs { + if dir.IsDir() { + continue + } + if strings.Contains(dir.Name(), "secure") { + files = append(files, log_dir+dir.Name()) + } + + } + for _, file := range files { + attack_detect(file, ip_failed_count, ips_failed_count) + } + +} + +func reRepeat(old []BaopoInfo) []string { + var ip_sum []string + // 遍历数组 + for _, item := range old { + if !slice.ContainsString(ip_sum, item.Ip) { + ip_sum = append(ip_sum, item.Ip) + } + } + return ip_sum +} + +func filter(old map[string]uint, count uint) map[string]uint { + + var new_dict map[string]uint + new_dict = make(map[string]uint) + for key := range old { + if old[key] > count { + new_dict[key] = old[key] + } + } + return new_dict +} + +func counter(old []string) map[string]uint { + + var count_dict map[string]uint + count_dict = make(map[string]uint) + for _, item := range old { + _, ok := count_dict[item] + if ok { + count_dict[item] += 1 + } else { + count_dict[item] = 1 + } + } + return count_dict +} + +func attack_detect(log string, ip_failed_count uint, ips_failed_count uint) { + // 账户错误特征 + username_error := "Invalid user" + // 账户正确密码错误特征 + username_correct := "Failed password for" + // 成功登陆 + username_password_correct := "Accepted password for" + // 所有错误登陆日志ip + var failed_ips []string + // 登陆成功日志 + var correct_infos []BaopoInfo + // 登录日志 + var login_infos []BaopoInfo + // C段ip登陆错误日志 + //var failed_c_ips []string + + _, filename := filepath.Split(log) + year := "" + if strings.Contains(filename, "secure-") && len(filename) == 15 { + year = filename[7:11] + } + + dat, err := ioutil.ReadFile(log) + if err != nil { + fmt.Println(err.Error()) + } + lines := strings.Split(string(dat), "\n") + + for _, line := range lines { + + if strings.Contains(line, username_error) && strings.Contains(line, "from") && strings.Contains(line, "sshd") { + + ip := strings.Split(strings.Split(line, ": ")[1], " ")[4] + failed_ips = append(failed_ips, ip) + time := strings.Join(strings.Split(strings.Replace(line, " ", " ", -1), " ")[:3], " ") + " " + year + login_infos = append(login_infos, BaopoInfo{User: "", Ip: ip, Time: time}) + + } else if strings.Contains(line, username_correct) && strings.Contains(line, "from") && strings.Contains(line, "sshd") { + + strs := strings.Split(strings.TrimSpace(strings.Split(line, ": ")[1]), " ") + ip := strs[len(strs)-4] + failed_ips = append(failed_ips, ip) + time := strings.Join(strings.Split(strings.Replace(line, " ", " ", -1), " ")[:3], " ") + " " + year + login_infos = append(login_infos, BaopoInfo{User: "", Ip: ip, Time: time}) + + } else if strings.Contains(line, username_password_correct) && strings.Contains(line, "sshd") { + + ip := strings.Split(strings.Split(line, ": ")[1], " ")[5] + user := strings.Split(strings.Split(line, ": ")[1], " ")[3] + time := strings.Join(strings.Split(strings.Replace(line, " ", " ", -1), " ")[:3], " ") + " " + year + correct_infos = append(correct_infos, BaopoInfo{User: user, Ip: ip, Time: time}) + + } + + } + + // 记录登陆失败攻击源IP地址和尝试次数 + failed_ip_dict := filter(counter(failed_ips), ip_failed_count) + + // 获取所有未爆破成功的ip信息 + for _, login_info := range login_infos { + for failed := range failed_ip_dict { + if login_info.Ip == failed { + baopo_info = append(baopo_info, login_info) + } + } + + } + + // 判断爆破行为是否成功: + for _, correct_info := range correct_infos { + for failed := range failed_ip_dict { + if correct_info.Ip == failed { + correct_baopo_info = append(correct_baopo_info, correct_info) + } + } + } + +} + +func SSHLog() { + _, err := os.Lstat("/var/log/auth.log") + if os.IsNotExist(err) { + _, err := os.Lstat("/var/log/secure") + if os.IsNotExist(err) { + fmt.Println("Could't find SSH log !!!") + } else { + if !sshLogNotSafe("/var/log/secure", "") { + color.Infoln("主机SSH登录爆破检测: [safe]") + } + } + } else { + if !sshLogNotSafe("/var/log/auth.log", "") { + color.Infoln("主机SSH登录爆破检测: [safe]") + } + } +} + +func sshLogNotSafe(log string, log_dir string) bool { + malice := false + + SSH_Analysis(log, log_dir, 10, 10) + + for _, info := range correct_baopo_info { + user := info.User + time := info.Time + ip := info.Ip + fmt.Printf("主机SSH被外部爆破且成功登录,时间: %s, ip: %s, 用户: %s\n", time, ip, user) + malice = true + } + ip_sum := reRepeat(baopo_info) + if len(ip_sum) != 0 { + malice = true + fmt.Println("以下", len(ip_sum), "个IP尝试SSH登录爆破,建议封禁:") + for _, ip := range ip_sum { + fmt.Print(ip + "、") + } + if len(ip_sum) != 0 { + fmt.Println("") + } + } + + return malice +} diff --git a/configcheck/check/sshserver.go b/configcheck/check/sshserver.go new file mode 100644 index 0000000..835aa14 --- /dev/null +++ b/configcheck/check/sshserver.go @@ -0,0 +1,27 @@ +package check + +import ( + "fmt" + "os/exec" + "strings" +) + +func SshWrapper() bool { + suspicious := false + + c := exec.Command("bash", "-c", "file /usr/sbin/sshd 2>/dev/null") + output, err := c.CombinedOutput() + if err != nil { + fmt.Println(err.Error()) + } + infos := strings.Split(string(output), "\n") + if len(infos) == 0 { + return suspicious + } + if !strings.Contains(infos[0], "ELF") && !strings.Contains(infos[0], "executable") { + fmt.Println("/usr/sbin/sshd被篡改,文件非可执行文件") + suspicious = true + } + + return suspicious +} diff --git a/configcheck/check/sudo.go b/configcheck/check/sudo.go new file mode 100644 index 0000000..51f6954 --- /dev/null +++ b/configcheck/check/sudo.go @@ -0,0 +1,33 @@ +package check + +import ( + "fmt" + "os/exec" + "strings" +) + +func Sudo() bool { + suspicious := false + if FileExist("/etc/sudoers") { + c := exec.Command( + "bash", "-c", + "cat /etc/sudoers 2>/dev/null |grep -v '#'|grep -v '%'|grep '(ALL\\|(root'|awk '{print $1}'", + ) + output, err := c.CombinedOutput() + if err != nil { + fmt.Println(err.Error()) + return suspicious + } + shell_process3 := strings.Split(string(output), "\n") + for _, user := range shell_process3 { + if len(user) < 1 { + continue + } + if user != "root" && user[0] != '%' { + fmt.Printf("用户 %s 可通过sudo命令获取特权\n", user) + suspicious = true + } + } + } + return suspicious +} diff --git a/configcheck/common/common.go b/configcheck/common/common.go new file mode 100644 index 0000000..91eed77 --- /dev/null +++ b/configcheck/common/common.go @@ -0,0 +1,117 @@ +package common + +import ( + "bufio" + "fmt" + "io" + "os" + "strings" +) + +func Printf(f func() bool) string { + b := f() + if b { + return "\033[1;32m[ OK ]\033[0m" + } + return "\033[1;31m[Warn]\033[0m" +} + +func PathExists(path string) bool { + _, err := os.Stat(path) + if err == nil { + return true + } + if os.IsNotExist(err) { + return false + } + return false +} + +func Align(str string, width int) string { + if len(str) < width { + end := " " + i := 1 + for { + if i >= (width - len(str)) { + break + } + end += " " + i++ + } + + return str + end + } + return str +} + +func CheckShell(content string) bool { + + if strings.Contains(content, "docker") { + return false + } + + if (strings.Contains(content, "sh") && (strings.Contains(content, "/dev/tcp/") || + strings.Contains(content, "telnet ") || strings.Contains(content, "nc ") || + (strings.Contains(content, "exec ") && strings.Contains(content, "socket")) || + strings.Contains(content, "curl ") || strings.Contains(content, "wget ") || + strings.Contains(content, "lynx "))) || strings.Contains(content, ".decode('base64')") || strings.Contains(content, "exec(base64.b64decode") || + (strings.Contains(content, "base64 ") && strings.Contains(content, "--decode") && strings.Contains(content, "python")) || + (strings.Contains(content, "base64 ") && strings.Contains(content, "-d") && strings.Contains(content, "bash")) || + (strings.Contains(content, "nc ") && strings.Contains(content, "-vv")) || + (strings.Contains(content, "ln ") && strings.Contains(content, "-sf") && strings.Contains(content, "/usr/sbin/sshd")) { + + return true + } else if strings.Contains(content, "/dev/tcp/") && (strings.Contains(content, "exec ") || + strings.Contains(content, "ksh -c")) { + return true + } else if strings.Contains(content, "sh -i") { + return true + } else if strings.Contains(content, "exec ") && (strings.Contains(content, "socket.") || + strings.Contains(content, ".decode('base64')")) { + return true + } else if strings.Contains(content, "socket.socket") { + return true + } else if (strings.Contains(content, "wget ") || strings.Contains(content, "curl ")) && + (strings.Contains(content, " -O ") || strings.Contains(content, " -s ")) && + strings.Contains(content, " http") && (strings.Contains(content, "php ") || + strings.Contains(content, "perl ") || strings.Contains(content, "ruby ") || + strings.Contains(content, "python ") || strings.Contains(content, "sh ") || + strings.Contains(content, "bash ")) { // Ruby added + return true + } else { + return false + } + +} + +func Check_file(path string) bool { + + result := false + _, err := os.Stat(path) + if err != nil { + return false + } + fr, _ := os.Open(path) + buf := bufio.NewReader(fr) + + for { + line, _, e := buf.ReadLine() + + if e == io.EOF { + break + } + if len(string(line)) < 3 { + continue + } + if string(line)[0] == '#' { + continue + } + + c := CheckShell(string(line)) + if c { + fmt.Println("[*]File:", path, "Found:", string(line)) + result = true + } + } + return result +} diff --git a/deyes_linux.go b/deyes_linux.go new file mode 100644 index 0000000..af8e768 --- /dev/null +++ b/deyes_linux.go @@ -0,0 +1,291 @@ +package main + +import ( + "fmt" + "log" + "os" + "strconv" + "strings" + "time" + + "github.com/gookit/color" + "github.com/urfave/cli/v2" + "github.com/xuri/excelize/v2" + + "d-eyes/basicinfo/info" + "d-eyes/configcheck/check" + "d-eyes/filedetection" + "d-eyes/logo" + "d-eyes/output" + "d-eyes/process/controller" + "d-eyes/yaraobj" +) + +var path string +var rule string +var thread int +var pid int + +func main() { + logo.ShowLogo() + app := &cli.App{ + Name: "D-Eyes", + Usage: "The Eyes of Darkness from Nsfocus spy on everything.", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "path", + Aliases: []string{"P"}, + Value: "/", + Usage: "--path / or -P / (Only For Filescan)", + Destination: &path, + }, + &cli.IntFlag{ + Name: "pid", + Aliases: []string{"p"}, + Value: -1, + Usage: "--pid 666 or -p 666 (Only For processcan.'-1' means all processes.)", + Destination: &pid, + }, + &cli.StringFlag{ + Name: "rule", + Aliases: []string{"r"}, + //Value: 5, + Usage: "--rule Ransom.Wannacrypt or -r Ransom.Wannacrypt", + Destination: &rule, + }, + &cli.IntFlag{ + Name: "thread", + Aliases: []string{"t"}, + Value: 5, + Usage: "--thread 1 or -t 1 (Only For Filescan)", + Destination: &thread, + }, + }, + Commands: []*cli.Command{ + { + Name: "filescan", + Aliases: []string{"fs"}, + Usage: "Command for scanning filesystem", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "path", + Aliases: []string{"P"}, + Value: "/", + Usage: "--path / or -P / (Only For Filescan)", + Destination: &path, + }, + &cli.StringFlag{ + Name: "rule", + Aliases: []string{"r"}, + //Value: 5, + Usage: "--rule Ransom.Wannacrypt or -r Ransom.Wannacrypt", + Destination: &rule, + }, + &cli.IntFlag{ + Name: "thread", + Aliases: []string{"t"}, + Value: 5, + Usage: "--thread 1 or -t 1", + Destination: &thread, + }, + }, + Action: func(c *cli.Context) error { + // fmt.Println("added task: ", c.Args().First()) + // + // + var paths []string + r := []output.Result{} + paths = strings.Split(path, ",") + var start = time.Now() + var sum = 0 + + if rule == "" { + yaraRule := "./yaraRules" + rules, err := yaraobj.LoadAllYaraRules(yaraRule) + if err != nil { + color.Redln("LoadCompiledRules goes error !!!") + color.Redln("GetRules err: ", err) + os.Exit(1) + } + for _, path := range paths { + files := filedetection.StartFileScan(path, rules, thread, &r) + sum += files + } + } else { + yaraRule := "./yaraRules/" + rule + ".yar" + _, err := os.Lstat(yaraRule) + if err != nil { + color.Redln("There is no such rule yet !!!") + os.Exit(1) + } + rules, err := yaraobj.LoadSingleYaraRule(yaraRule) + if err != nil { + color.Redln("GetRules err: ", err) + os.Exit(1) + } + for _, path := range paths { + files := filedetection.StartFileScan(path, rules, thread, &r) + sum += files + } + } + + if len(r) > 0 { + length := len(r) + categories := map[string]string{ + "A1": "Risk Description", "B1": "Risk File Path", + } + var values = make(map[string]string) + vulsumTmp := 0 + for i := 0; i < length; i++ { + vulsumTmp++ + color.Error.Println("[ Risk ", vulsumTmp, " ]") + fmt.Print("Risk Description: ") + color.Warn.Println(r[i].Risk) + fmt.Println("Risk File Path: ") + color.Warn.Println(r[i].RiskPath) + //set excel values + excelValuetmpA := "A" + strconv.Itoa(vulsumTmp+1) + excelValuetmpB := "B" + strconv.Itoa(vulsumTmp+1) + values[excelValuetmpA] = r[i].Risk + values[excelValuetmpB] = r[i].RiskPath + } + //output to a excel + f := excelize.NewFile() + f.SetColWidth("Sheet1", "A", "B", 50) + for k, v := range categories { + f.SetCellValue("Sheet1", k, v) + } + for k, v := range values { + f.SetCellValue("Sheet1", k, v) + } + style, err := f.NewStyle( + &excelize.Style{ + Font: &excelize.Font{ + Bold: true, + Size: 11, + Color: "e83723", + }, + }, + ) + if err != nil { + fmt.Println(err) + } + f.SetCellStyle("Sheet1", "A1", "A1", style) + f.SetCellStyle("Sheet1", "B1", "B1", style) + // save the result to Deyes.xlsx + if err := f.SaveAs("D-Eyes.xlsx"); err != nil { + fmt.Println(err) + } + } else { + fmt.Println("\nNo suspicious files found. Your computer is safe with the rules you choose.") + } + var end = time.Now().Sub(start) + fmt.Println("Consuming Time: ", end, " Number of scanned files: ", sum) + + return nil + }, + }, + { + Name: "processcan", + Aliases: []string{"ps"}, + Usage: "Command for scanning processes", + Flags: []cli.Flag{ + &cli.IntFlag{ + Name: "pid", + Aliases: []string{"p"}, + Value: -1, + Usage: "--pid 666 or -p 666 ('-1' means all processes.)", + Destination: &pid, + }, + &cli.StringFlag{ + Name: "rule", + Aliases: []string{"r"}, + Usage: "--rule Ransom.Wannacrypt or -r Ransom.Wannacrypt", + Destination: &rule, + }, + }, + Action: func(c *cli.Context) error { + var start = time.Now() + controller.ScanProcess(pid, rule) + var end = time.Now().Sub(start) + fmt.Println("Consuming Time: ", end) + return nil + }, + }, + { + Name: "selfcheck", + Aliases: []string{"sc"}, + Usage: "Command for checking some files which may have backdoors", + Action: func(c *cli.Context) error { + check.Trigger() + return nil + }, + }, + { + Name: "host", + Usage: "Command for displaying basic host information", + Action: func(c *cli.Context) error { + color.Infoln("Host Info:") + info.DisplayBaseInfo() + return nil + }, + }, + { + Name: "users", + Usage: "Command for displaying all the users on the host", + Action: func(c *cli.Context) error { + color.Infoln("AllUsers:") + info.DisplayAllUsers() + return nil + }, + }, + { + Name: "top", + Usage: "Command for displaying the top 15 processes in CPU usage", + Action: func(c *cli.Context) error { + info.Top() + return nil + }, + }, + { + Name: "netstat", + Usage: "Command for displaying host network information", + Action: func(c *cli.Context) error { + color.Infoln("Network Info:") + info.DisplayNetStat() + return nil + }, + }, + { + Name: "task", + Usage: "Command for displaying all the tasks on the host", + Action: func(c *cli.Context) error { + color.Infoln("Task:") + info.DisplayPlanTask() + return nil + }, + }, + { + Name: "autoruns", + Usage: "Command for displaying all the autoruns on the host", + Action: func(c *cli.Context) error { + color.Infoln("Autoruns:") + info.CallDisplayAutoruns() + return nil + }, + }, + { + Name: "export", + Usage: "Command for exporting basic host information", + Action: func(c *cli.Context) error { + info.SaveSummaryBaseInfo() + return nil + }, + }, + }, + } + err := app.Run(os.Args) + if err != nil { + log.Fatal(err) + } +} diff --git a/deyes_windows.go b/deyes_windows.go new file mode 100644 index 0000000..1a5f54f --- /dev/null +++ b/deyes_windows.go @@ -0,0 +1,337 @@ +package main + +import ( + "fmt" + "log" + "os" + "strconv" + "strings" + "time" + + "github.com/gookit/color" + "github.com/urfave/cli/v2" + "github.com/xuri/excelize/v2" + + "d-eyes/basicinfo/info" + "d-eyes/filedetection" + "d-eyes/logo" + "d-eyes/output" + "d-eyes/yaraobj" +) + +var path string +var rule string +var thread int +var pid int +var vulnerability int + +func main() { + srcPath := SrcPath() + logo.ShowLogo() + app := &cli.App{ + Name: "D-Eyes", + Usage: "The Eyes of Darkness from Nsfocus spy on everything.", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "path", + Aliases: []string{"P"}, + Value: "C://", + Usage: "-P C:// (Only For Filescan)", + Destination: &path, + }, + &cli.IntFlag{ + Name: "pid", + Aliases: []string{"p"}, + Value: -1, + Usage: "-p 666 (Only For processcan.'-1' means all processes.)", + Destination: &pid, + }, + &cli.StringFlag{ + Name: "rule", + Aliases: []string{"r"}, + Usage: "-r Ransom.Wannacrypt", + Destination: &rule, + }, + &cli.IntFlag{ + Name: "thread", + Aliases: []string{"t"}, + Value: 5, + Usage: "-t 1 (Only For Filescan)", + Destination: &thread, + }, + &cli.IntFlag{ + Name: "vul", + Aliases: []string{"v"}, + Usage: "-v 1 (1 is to check Exchange Server OWASSRF exploitation)", + Destination: &vulnerability, + }, + }, + Commands: []*cli.Command{ + { + Name: "filescan", + Aliases: []string{"fs"}, + Usage: "Command for scanning filesystem", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "path", + Aliases: []string{"P"}, + Value: "C://", + Usage: "--path C:// or -P C:// (Only For Filescan)", + Destination: &path, + }, + &cli.StringFlag{ + Name: "rule", + Aliases: []string{"r"}, + Usage: "--rule Ransom.Wannacrypt or -r Ransom.Wannacrypt", + Destination: &rule, + }, + &cli.IntFlag{ + Name: "thread", + Aliases: []string{"t"}, + Value: 5, + Usage: "--thread 1 or -t 1", + Destination: &thread, + }, + }, + Action: func(c *cli.Context) error { + var paths []string + var r []output.Result + paths = strings.Split(path, ",") + var start = time.Now() + var sum = 0 + + if rule == "" { + yaraRule := srcPath + "yaraRules" + rules, err := yaraobj.LoadAllYaraRules(yaraRule) + if err != nil { + color.Redln("LoadCompiledRules goes error !!!") + color.Redln("GetRules err: ", err) + os.Exit(1) + } + for _, path := range paths { + files := filedetection.StartFileScan(path, rules, thread, &r) + sum += files + } + } else { + yaraRule := srcPath + "yaraRules\\" + rule + ".yar" + _, err := os.Lstat(yaraRule) + if err != nil { + color.Redln("There is no such rule yet !!!") + os.Exit(1) + } + rules, err := yaraobj.LoadSingleYaraRule(yaraRule) + if err != nil { + color.Redln("GetRules err: ", err) + os.Exit(1) + } + for _, path := range paths { + files := filedetection.StartFileScan(path, rules, thread, &r) + sum += files + } + } + + if len(r) > 0 { + length := len(r) + categories := map[string]string{ + "A1": "Risk Description", "B1": "Risk File Path", + } + var values = make(map[string]string) + vulsumTmp := 0 + for i := 0; i < length; i++ { + vulsumTmp++ + color.Error.Println("[ Risk ", vulsumTmp, " ]") + fmt.Print("Risk Description: ") + color.Warn.Println(r[i].Risk) + fmt.Println("Risk File Path: ") + color.Warn.Println(r[i].RiskPath) + //set excel values + excelValuetmpA := "A" + strconv.Itoa(vulsumTmp+1) + excelValuetmpB := "B" + strconv.Itoa(vulsumTmp+1) + values[excelValuetmpA] = r[i].Risk + values[excelValuetmpB] = r[i].RiskPath + } + //output to a excel + f := excelize.NewFile() + f.SetColWidth("Sheet1", "A", "B", 50) + for k, v := range categories { + f.SetCellValue("Sheet1", k, v) + } + for k, v := range values { + f.SetCellValue("Sheet1", k, v) + } + style, err := f.NewStyle( + &excelize.Style{ + Font: &excelize.Font{ + Bold: true, + Size: 11, + Color: "e83723", + }, + }, + ) + if err != nil { + fmt.Println(err) + } + f.SetCellStyle("Sheet1", "A1", "A1", style) + f.SetCellStyle("Sheet1", "B1", "B1", style) + + // save the result to Deyes.xlsx + if err := f.SaveAs(srcPath + "D-Eyes_FileResult.xlsx"); err != nil { + fmt.Println(err) + } + } else { + fmt.Println("\nNo suspicious files found. Your computer is safe with the rules you choose.") + } + + var end = time.Now().Sub(start) + fmt.Println("Consuming Time: ", end, " Number of scanned files: ", sum) + + return nil + }, + }, + { + Name: "processcan", + Aliases: []string{"ps"}, + Usage: "Command for scanning processes", + Flags: []cli.Flag{ + &cli.IntFlag{ + Name: "pid", + Aliases: []string{"p"}, + Value: -1, + Usage: "--pid 666 or -p 666 ('-1' means all processes.)", + Destination: &pid, + }, + &cli.StringFlag{ + Name: "rule", + Aliases: []string{"r"}, + Usage: "--rule Ransom.Wannacrypt or -r Ransom.Wannacrypt", + Destination: &rule, + }, + }, + Action: func(c *cli.Context) error { + + var start = time.Now() + // todo + //controller.ScanProcess(pid, rule, src_path) + var end = time.Now().Sub(start) + fmt.Println("Consuming Time: ", end) + return nil + }, + }, + { + Name: "host", + Usage: "Command for displaying basic host information", + Action: func(c *cli.Context) error { + color.Infoln("Host Info:") + info.DisplayBaseInfo() + return nil + }, + }, + { + Name: "users", + Usage: "Command for displaying all the users on the host", + Action: func(c *cli.Context) error { + color.Infoln("AllUsers:") + info.DisplayAllUsers() + return nil + }, + }, + { + Name: "top", + Usage: "Command for displaying the top 15 processes in CPU usage", + Action: func(c *cli.Context) error { + info.Top() + return nil + }, + }, + { + Name: "netstat", + Usage: "Command for displaying host network information", + Action: func(c *cli.Context) error { + color.Infoln("Network Info:") + info.DisplayNetStat(srcPath) + return nil + }, + }, + { + Name: "task", + Usage: "Command for displaying all the tasks on the host", + Action: func(c *cli.Context) error { + color.Infoln("Task:") + info.DisplayPlanTask() + return nil + }, + }, + { + Name: "autoruns", + Usage: "Command for displaying all the autoruns on the host", + Action: func(c *cli.Context) error { + color.Infoln("Autoruns:") + info.CallDisplayAutoruns() + return nil + }, + }, + { + Name: "export", + Usage: "Command for exporting basic host information", + Action: func(c *cli.Context) error { + info.SaveSummaryBaseInfo() + return nil + }, + }, + + { + Name: "check", + Usage: "Command for checking vulnerability exploitation", + Flags: []cli.Flag{ + &cli.IntFlag{ + Name: "vulnerability", + Aliases: []string{"v"}, + Usage: "-v 1 (1 is to check Exchange Server OWASSRF exploitation)", + Destination: &vulnerability, + }, + }, + Action: func(c *cli.Context) error { + switch vulnerability { + case 1: + var path string + if len(os.Args) > 4 { + path = os.Args[4] + } + info.CheckExchangeServerOWASSRF(path) + default: + fmt.Println("Please enter the number of vulnerability exploitation you want to check.") + fmt.Println() + color.Warn.Println("Currently supported vulnerability exploitation list:") + fmt.Println(" 1: Exchange Server OWASSRF") + fmt.Println() + fmt.Print("Like this, if you want to check 'Exchange Server OWASSRF' exploitation, just input ") + color.Warn.Println("'D-Eyes check -v 1'") + } + return nil + }, + }, + }, + } + err := app.Run(os.Args) + if err != nil { + log.Fatal(err) + } +} + +func SrcPath() string { + + args := os.Args + lastIndex := strings.LastIndex(args[0], "\\") + cmdPath := args[0][0 : lastIndex+1] + currentDir, _ := os.Getwd() + + dir, _ := os.ReadDir(currentDir) + for _, f := range dir { + if f.IsDir() { + if f.Name() == "yaraRules" { + return currentDir + "\\" + } + } + } + return cmdPath +} diff --git a/filedetection/file.go b/filedetection/file.go new file mode 100644 index 0000000..c5a904c --- /dev/null +++ b/filedetection/file.go @@ -0,0 +1,56 @@ +package filedetection + +import ( + "os" +) + +type File interface { + Path() string + Stat() (os.FileInfo, error) + Hashes() (md5sum, sha256sum string, err error) + EnableHashMarshalling() error +} + +type OSFile struct { + FilePath string `json:"path"` + MD5Sum string `json:"MD5,omitempty"` + SHA256Sum string `json:"SHA256,omitempty"` +} + +func NewFile(path string) File { + return &OSFile{FilePath: path} +} + +// +//func CloneFile(f File) File { +// if f == nil { +// return nil +// } +// +// osFile, ok := f.(*OSFile) +// if ok { +// return &OSFile{ +// FilePath: osFile.FilePath, +// MD5Sum: osFile.MD5Sum, +// SHA256Sum: osFile.SHA256Sum, +// } +// } +// return NewFile(f.Path()) +//} + +func (f *OSFile) Path() string { + return f.FilePath +} + +func (f *OSFile) Stat() (os.FileInfo, error) { + return os.Stat(f.FilePath) +} + +func (f *OSFile) Hashes() (md5sum, sha256sum string, err error) { + return ComputeHashes(f.FilePath) +} + +func (f *OSFile) EnableHashMarshalling() (err error) { + f.MD5Sum, f.SHA256Sum, err = f.Hashes() + return +} diff --git a/filedetection/filescan.go b/filedetection/filescan.go new file mode 100644 index 0000000..5667987 --- /dev/null +++ b/filedetection/filescan.go @@ -0,0 +1,54 @@ +package filedetection + +import ( + "context" + "fmt" + "sync" + + "github.com/hillu/go-yara/v4" + + "d-eyes/output" + "d-eyes/yaraobj" +) + +func StringSlice(name string) []string { + return nil +} + +var sum = 0 + +func StartFileScan(path string, rules *yara.Rules, thread int, r *[]output.Result) int { + + iteratorCtx := context.Background() + var pathIterator Iterator + + fileExtensions := StringSlice("") + + pIt, err := IteratePath(iteratorCtx, path, fileExtensions) + + if err != nil { + fmt.Printf("- %s ERROR: could not intialize scanner for path, reason: %v", path, err) + } + pathIterator = Concurrent(pathIterator, pIt) + fmt.Printf("- %s\n", path) + + if pathIterator != nil { + defer pathIterator.Close() + yaraScanner, err := yaraobj.NewYaraScanner(rules) + if err != nil { + fmt.Println("NewYaraScanner goes error !!!") + } + + fsScanner := NewFSScanner(yaraScanner) + + wg := &sync.WaitGroup{} + wg.Add(thread) + + for i := 0; i < thread; i++ { + go fsScanner.Scan(pathIterator, wg, &sum, r) + } + wg.Wait() + } + return sum + +} diff --git a/filedetection/filesystemScanner_linux.go b/filedetection/filesystemScanner_linux.go new file mode 100644 index 0000000..e5a68df --- /dev/null +++ b/filedetection/filesystemScanner_linux.go @@ -0,0 +1,68 @@ +package filedetection + +import ( + "encoding/json" + "io" + "path/filepath" + "strings" + "sync" + + "github.com/hillu/go-yara/v4" + + "d-eyes/output" + "d-eyes/yaraobj" +) + +type FSScanner struct { + scanner *yaraobj.YaraScanner +} + +func NewFSScanner(scanner *yaraobj.YaraScanner) *FSScanner { + return &FSScanner{ + scanner: scanner, + } +} + +type FSScanProgress struct { + File File + Matches yara.MatchRules + Error error +} + +func (s *FSScanner) Scan(it Iterator, wg *sync.WaitGroup, sum *int, r *[]output.Result) { + defer wg.Done() + for { + file, err := it.Next() + if err == io.EOF { + break + } else if err != nil { + continue + } + *sum++ + switch ext := strings.ToLower(filepath.Ext(file.Path())); ext { + case ".yar": + continue + case ".zip", ".tar.gz", ".rar", ".7z", ".gzp", ".bzp2", ".tar", ".gz", ".iso", ".vmem", ".vhd", ".qcow2", ".vmdk": + continue + default: + matches, err := s.scanner.ScanFile(file.Path()) + if err != nil { + //fmt.Println("The matches of ScanFile function goes wrong!!! ") + //fmt.Println("err is ",err," file is ",file.Path()) + //fmt.Println("-----------------------------------------------") + //return nil + } + + if len(matches) != 0 { + + data := matches[0].Metas[0] + dataType, _ := json.Marshal(data) + dataString := string(dataType) + meta := strings.Split(dataString, ":")[2] + metaTmp := strings.Trim(meta, "\"}") + resTmp := output.Result{metaTmp, file.Path()} + *r = append(*r, resTmp) + } + } + } +} diff --git a/filedetection/filesystemScanner_windows.go b/filedetection/filesystemScanner_windows.go new file mode 100644 index 0000000..ec0e8ac --- /dev/null +++ b/filedetection/filesystemScanner_windows.go @@ -0,0 +1,61 @@ +package filedetection + +import ( + "encoding/json" + "fmt" + "io" + "path/filepath" + "strings" + "sync" + + "github.com/gookit/color" + + "d-eyes/output" + "d-eyes/yaraobj" +) + +type FSScanner struct { + scanner *yaraobj.YaraScanner +} + +func NewFSScanner(scanner *yaraobj.YaraScanner) *FSScanner { + return &FSScanner{ + scanner: scanner, + } +} + +func (s *FSScanner) Scan(it Iterator, wg *sync.WaitGroup, sum *int, r *[]output.Result) { + defer wg.Done() + for { + file, err := it.Next() + if err == io.EOF { + break + } else if err != nil { + continue + } + *sum++ + color.Info.Print("[INFO] D-Eyes FileScan scanning: ") + fmt.Println(file.Path()) + + switch ext := strings.ToLower(filepath.Ext(file.Path())); ext { + case ".yar": + continue + case ".zip", ".tar.gz", ".rar", ".7z", ".gzp", ".bzp2", ".tar", ".gz", ".iso", ".vmem", ".vhd", ".qcow2", ".vmdk": + continue + default: + matches, err := s.scanner.ScanFile(file.Path()) + if err != nil { + continue + } + if len(matches) != 0 { + data := matches[0].Metas[0] + dataType, _ := json.Marshal(data) + dataString := string(dataType) + meta := strings.Split(dataString, ":")[2] + metaTmp := strings.Trim(meta, "\"}") + resTmp := output.Result{Risk: metaTmp, RiskPath: file.Path()} + *r = append(*r, resTmp) + } + } + } +} diff --git a/filedetection/filesystem_linux.go b/filedetection/filesystem_linux.go new file mode 100644 index 0000000..3656534 --- /dev/null +++ b/filedetection/filesystem_linux.go @@ -0,0 +1,236 @@ +package filedetection + +import ( + "context" + "fmt" + "io" + "os" + "path/filepath" + "strings" +) + +var ( + FilesBuffer = 8 +) + +// doScandir linux +var skippedRoots = []string{ + "/dev", + "/proc", + "/sys", + "/run", +} + +var skippedDirs = []string{ + "lost+found", +} + +func doScanDir(path string) bool { + var err error + path, err = filepath.Abs(path) + if err != nil { + return false + } + + for _, root := range skippedRoots { + if len(path) < len(root) { + continue + } + if path[:len(root)] == root { + if len(path) == len(root) || path[len(root)] == '/' { + return false + } + } + } + for _, dir := range skippedDirs { + if strings.Contains(path, "/"+dir) { + if len(path) == len(dir)+1 || path[len(dir)+1] == '/' { + return false + } + } + } + return true +} + +var ErrSkipped = fmt.Errorf("skipped") + +type nextEntry struct { + File File + Err error +} + +type fsIterator struct { + root string + validExtensions []string + + ctx context.Context + cancel context.CancelFunc + closed bool + + dirs []string + next chan *nextEntry +} + +func IteratePath(ctx context.Context, path string, validExtensions []string) (Iterator, error) { + stat, err := os.Stat(path) + if err != nil { + return nil, err + } + if !stat.IsDir() { + return nil, fmt.Errorf("path must be a directory") + } + + for i := range validExtensions { + validExtensions[i] = strings.ToLower(validExtensions[i]) + } + + it := &fsIterator{ + root: path, + validExtensions: validExtensions, + closed: false, + dirs: make([]string, 1, 16), + next: make(chan *nextEntry, FilesBuffer), + } + it.dirs[0] = path + it.ctx, it.cancel = context.WithCancel(ctx) + + go it.dirScanner() + + return it, nil +} + +func (it *fsIterator) Root() string { + return it.root +} + +func (it *fsIterator) doesExtensionMatch(path string) bool { + if it.validExtensions == nil || len(it.validExtensions) == 0 { + return true + } + _, file := filepath.Split(path) + parts := strings.Split(file, ".") + var ext string + if len(parts) > 1 { + ext = parts[len(parts)-1] + } + ext = strings.ToLower(ext) + + for _, vExt := range it.validExtensions { + if ext == vExt { + return true + } + } + return false +} + +func (it *fsIterator) dirScanner() { + defer close(it.next) + + for { + select { + case <-it.ctx.Done(): + break + default: + } + + if len(it.dirs) == 0 { + break + } + + dir := it.dirs[0] + it.dirs = it.dirs[1:] + + func() { + f, err := os.Open(dir) + if err != nil { + it.next <- &nextEntry{ + File: NewFile(dir), + Err: err, + } + return + } + defer f.Close() + + for { + contents, err := f.Readdir(1) + if err == io.EOF { + break + } else if err != nil { + it.next <- &nextEntry{ + File: NewFile(dir), + Err: err, + } + return + } + + path := filepath.Join(dir, contents[0].Name()) + if contents[0].IsDir() { + if doScanDir(path) { + it.dirs = append(it.dirs, path) + } + } else { + if it.doesExtensionMatch(path) { + it.next <- &nextEntry{ + File: NewFile(path), + } + } else { + it.next <- &nextEntry{ + File: NewFile(path), + Err: ErrSkipped, + } + } + } + } + }() + } +} + +func (it *fsIterator) Next() (File, error) { + if it.closed { + return nil, io.EOF + } + + next := <-it.next + if next == nil { + return nil, io.EOF + } + + return next.File, next.Err +} + +func (it *fsIterator) Close() error { + if it.closed { + return nil + } + + it.closed = true + defer it.cancel() + + return it.ctx.Err() +} + +type fileListIterator struct { + files []string + i int +} + +func IterateFileList(files []string) Iterator { + return &fileListIterator{ + files: files, + i: 0, + } +} + +func (it *fileListIterator) Next() (File, error) { + if it.i >= len(it.files) { + return nil, io.EOF + } + + file := NewFile(it.files[it.i]) + it.i++ + return file, nil +} + +func (it *fileListIterator) Close() error { + return nil +} diff --git a/filedetection/filesystem_windows.go b/filedetection/filesystem_windows.go new file mode 100644 index 0000000..8d0c967 --- /dev/null +++ b/filedetection/filesystem_windows.go @@ -0,0 +1,203 @@ +package filedetection + +import ( + "context" + "fmt" + "io" + "os" + "path/filepath" + "strings" +) + +var ( + FilesBuffer = 8 +) + +//doScandir windows + +func doScanDir(path string) bool { + return true +} + +var ErrSkipped = fmt.Errorf("skipped") + +type nextEntry struct { + File File + Err error +} + +type fsIterator struct { + root string + validExtensions []string + + ctx context.Context + cancel context.CancelFunc + closed bool + + dirs []string + next chan *nextEntry +} + +func IteratePath(ctx context.Context, path string, validExtensions []string) (Iterator, error) { + stat, err := os.Stat(path) + if err != nil { + return nil, err + } + if !stat.IsDir() { + return nil, fmt.Errorf("path must be a directory") + } + + for i := range validExtensions { + validExtensions[i] = strings.ToLower(validExtensions[i]) + } + + it := &fsIterator{ + root: path, + validExtensions: validExtensions, + closed: false, + dirs: make([]string, 1, 16), + next: make(chan *nextEntry, FilesBuffer), + } + it.dirs[0] = path + it.ctx, it.cancel = context.WithCancel(ctx) + + go it.dirScanner() + + return it, nil +} + +func (it *fsIterator) Root() string { + return it.root +} + +func (it *fsIterator) doesExtensionMatch(path string) bool { + if it.validExtensions == nil || len(it.validExtensions) == 0 { + return true + } + _, file := filepath.Split(path) + parts := strings.Split(file, ".") + var ext string + if len(parts) > 1 { + ext = parts[len(parts)-1] + } + ext = strings.ToLower(ext) + + for _, vExt := range it.validExtensions { + if ext == vExt { + return true + } + } + return false +} + +func (it *fsIterator) dirScanner() { + defer close(it.next) + + for { + select { + case <-it.ctx.Done(): + break + default: + } + + if len(it.dirs) == 0 { + break + } + + dir := it.dirs[0] + it.dirs = it.dirs[1:] + + func() { + f, err := os.Open(dir) + if err != nil { + it.next <- &nextEntry{ + File: NewFile(dir), + Err: err, + } + return + } + defer f.Close() + + for { + contents, err := f.Readdir(1) + if err == io.EOF { + break + } else if err != nil { + it.next <- &nextEntry{ + File: NewFile(dir), + Err: err, + } + return + } + + path := filepath.Join(dir, contents[0].Name()) + if contents[0].IsDir() { + if doScanDir(path) { + it.dirs = append(it.dirs, path) + } + } else { + if it.doesExtensionMatch(path) { + it.next <- &nextEntry{ + File: NewFile(path), + } + } else { + it.next <- &nextEntry{ + File: NewFile(path), + Err: ErrSkipped, + } + } + } + } + }() + } +} + +func (it *fsIterator) Next() (File, error) { + if it.closed { + return nil, io.EOF + } + + next := <-it.next + if next == nil { + return nil, io.EOF + } + + return next.File, next.Err +} + +func (it *fsIterator) Close() error { + if it.closed { + return nil + } + + it.closed = true + defer it.cancel() + + return it.ctx.Err() +} + +type fileListIterator struct { + files []string + i int +} + +func IterateFileList(files []string) Iterator { + return &fileListIterator{ + files: files, + i: 0, + } +} + +func (it *fileListIterator) Next() (File, error) { + if it.i >= len(it.files) { + return nil, io.EOF + } + + file := NewFile(it.files[it.i]) + it.i++ + return file, nil +} + +func (it *fileListIterator) Close() error { + return nil +} diff --git a/filedetection/hashes.go b/filedetection/hashes.go new file mode 100644 index 0000000..e365d6b --- /dev/null +++ b/filedetection/hashes.go @@ -0,0 +1,87 @@ +package filedetection + +import ( + "crypto/md5" + "crypto/sha256" + "encoding/hex" + "io" + "os" + "sync" +) + +var globalHasher *CachingHasher + +func init() { + globalHasher = NewCachingHasher() +} + +// ComputeHashes computes the md5 and sha256 hashes of a given file. +func ComputeHashes(file string) (md5sum, sha256sum string, err error) { + return globalHasher.ComputeHashes(file) +} + +type multiHash struct { + md5sum string + sha256sum string +} + +type CachingHasher struct { + hashes map[string]*multiHash + mux *sync.RWMutex +} + +func NewCachingHasher() *CachingHasher { + return &CachingHasher{ + hashes: map[string]*multiHash{}, + mux: &sync.RWMutex{}, + } +} + +func (h *CachingHasher) readCache(file string) (*multiHash, bool) { + h.mux.RLock() + defer h.mux.RUnlock() + + hashes, ok := h.hashes[file] + return hashes, ok +} + +func (h *CachingHasher) writeCache(file string, hashes *multiHash) { + h.mux.Lock() + defer h.mux.Unlock() + + h.hashes[file] = hashes +} + +// ComputeHashes computes the md5 and sha256 hashes of a given file. +func (h *CachingHasher) ComputeHashes(file string) (md5sum, sha256sum string, err error) { + hashes, ok := h.readCache(file) + if ok { + return hashes.md5sum, hashes.sha256sum, nil + } + + var f *os.File + f, err = os.OpenFile(file, os.O_RDONLY, 0666) + if err != nil { + return + } + defer f.Close() + + h5 := md5.New() + h256 := sha256.New() + + teeH5 := io.TeeReader(f, h5) + _, err = io.Copy(h256, teeH5) + if err != nil { + return + } + + md5sum = hex.EncodeToString(h5.Sum(nil)) + sha256sum = hex.EncodeToString(h256.Sum(nil)) + + h.writeCache(file, &multiHash{ + md5sum: md5sum, + sha256sum: sha256sum, + }) + + return +} diff --git a/filedetection/iterator.go b/filedetection/iterator.go new file mode 100644 index 0000000..f5614e1 --- /dev/null +++ b/filedetection/iterator.go @@ -0,0 +1,172 @@ +package filedetection + +import ( + "io" + "sync" + + "github.com/targodan/go-errors" +) + +type Iterator interface { + Next() (File, error) + Close() error +} + +type concatIterator struct { + i int + iterators []Iterator +} + +func concat(it1 Iterator, it2 Iterator) Iterator { + if it1 == nil { + return it2 + } + if it2 == nil { + return it1 + } + cit1, ok1 := it1.(*concatIterator) + cit2, ok2 := it2.(*concatIterator) + if ok1 && ok2 { + cit1.iterators = append(cit1.iterators, cit2.iterators...) + return cit1 + } + if ok1 { + cit1.iterators = append(cit1.iterators, it2) + return cit1 + } + if ok2 { + cit2.iterators = append(cit2.iterators, it1) + return cit2 + } + return &concatIterator{ + i: 0, + iterators: []Iterator{it1, it2}, + } +} + +func Concat(iterators ...Iterator) Iterator { + var ret Iterator + for _, it := range iterators { + ret = concat(ret, it) + } + return ret +} + +func (it *concatIterator) Next() (File, error) { + if it.i >= len(it.iterators) { + return nil, io.EOF + } + + f, err := it.iterators[it.i].Next() + if err == io.EOF { + it.i++ + return it.Next() + } + return f, err +} + +func (it *concatIterator) Close() error { + var err error + for _, iterator := range it.iterators { + err = errors.NewMultiError(err, iterator.Close()) + } + return err +} + +type concurrentIterator struct { + iterators []Iterator + c chan *nextEntry + wg *sync.WaitGroup + closed bool +} + +func concurrent(it1 Iterator, it2 Iterator) Iterator { + if it1 == nil { + return it2 + } + if it2 == nil { + return it1 + } + cit1, ok1 := it1.(*concurrentIterator) + cit2, ok2 := it2.(*concurrentIterator) + if ok1 && ok2 { + panic("cannot combine two concurrent iterators") + } + if ok1 { + cit1.iterators = append(cit1.iterators, it2) + cit1.wg.Add(1) + go cit1.consume(len(cit1.iterators) - 1) + return cit1 + } + if ok2 { + cit2.iterators = append(cit2.iterators, it1) + cit2.wg.Add(1) + go cit2.consume(len(cit2.iterators) - 1) + return cit2 + } + + cit := &concurrentIterator{ + iterators: []Iterator{it1, it2}, + c: make(chan *nextEntry), + wg: new(sync.WaitGroup), + } + cit.wg.Add(2) + go cit.consume(0) + go cit.consume(1) + + go func() { + cit.wg.Wait() + close(cit.c) + }() + return cit +} + +func Concurrent(iterators ...Iterator) Iterator { + var cit Iterator + for _, it := range iterators { + cit = concurrent(cit, it) + } + return cit +} + +func (it *concurrentIterator) consume(i int) { + defer it.wg.Done() + + for { + f, err := it.iterators[i].Next() + if err == io.EOF { + break + } + + it.c <- &nextEntry{ + File: f, + Err: err, + } + } +} + +func (it *concurrentIterator) Next() (File, error) { + if it.closed { + return nil, io.EOF + } + + next := <-it.c + if next == nil { + return nil, io.EOF + } + + return next.File, next.Err +} + +func (it *concurrentIterator) Close() error { + if it.closed { + return nil + } + it.closed = true + + var err error + for _, iterator := range it.iterators { + err = errors.NewMultiError(err, iterator.Close()) + } + return err +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..c684488 --- /dev/null +++ b/go.mod @@ -0,0 +1,43 @@ +module d-eyes + +go 1.21.1 + +require ( + github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394 + github.com/botherder/go-files v0.0.0-20180205213231-2246e61e05ec + github.com/daviddengcn/go-colortext v1.0.0 + github.com/gookit/color v1.5.4 + github.com/hillu/go-yara/v4 v4.3.2 + github.com/mattn/go-shellwords v1.0.12 + github.com/olekukonko/tablewriter v0.0.5 + github.com/shirou/gopsutil/v3 v3.23.10 + github.com/targodan/go-errors v1.0.0 + github.com/toolkits/slice v0.0.0-20141116085117-e44a80af2484 + github.com/urfave/cli/v2 v2.25.7 + github.com/xuri/excelize/v2 v2.8.0 + github.com/yusufpapurcu/wmi v1.2.3 + golang.org/x/sys v0.13.0 +) + +require ( + github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect + github.com/go-ole/go-ole v1.3.0 // indirect + github.com/lufia/plan9stats v0.0.0-20231016141302-07b5767bb0ed // indirect + github.com/mattn/go-runewidth v0.0.15 // indirect + github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect + github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b // indirect + github.com/richardlehane/mscfb v1.0.4 // indirect + github.com/richardlehane/msoleps v1.0.3 // indirect + github.com/rivo/uniseg v0.4.4 // indirect + github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/shoenig/go-m1cpu v0.1.6 // indirect + github.com/tklauser/go-sysconf v0.3.12 // indirect + github.com/tklauser/numcpus v0.6.1 // indirect + github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect + github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect + github.com/xuri/efp v0.0.0-20231025114914-d1ff6096ae53 // indirect + github.com/xuri/nfp v0.0.0-20230919160717-d98342af3f05 // indirect + golang.org/x/crypto v0.14.0 // indirect + golang.org/x/net v0.17.0 // indirect + golang.org/x/text v0.13.0 // indirect +) diff --git a/logo/logo_linux.go b/logo/logo_linux.go new file mode 100644 index 0000000..50d14c2 --- /dev/null +++ b/logo/logo_linux.go @@ -0,0 +1,41 @@ +package logo + +import ( + "fmt" + "github.com/daviddengcn/go-colortext" +) + +var logo = [...]string{ + ` ____ ______ `, + ` / __ \ / ____/_ _____ _____`, + ` / / / /_____/ __/ / / / / _ \/ ___/`, + ` / /_/ /_____/ /___/ /_/ / __(__ ) `, + `/_____/ /_____/\__, /\___/____/ `, + ` /____/ `, +} + +func ShowLogo() { + ct.Foreground(ct.Blue, true) + fmt.Println(logo[0]) + fmt.Println(logo[1]) + + ct.ResetColor() + ct.Foreground(ct.Blue, true) + fmt.Println(logo[2]) + ct.Foreground(ct.Magenta, true) + fmt.Println(logo[3]) + ct.ResetColor() + + ct.Foreground(ct.Magenta, true) + fmt.Println(logo[4]) + ct.ResetColor() + + ct.Foreground(ct.Magenta, true) + fmt.Println(logo[5]) + ct.ResetColor() + + ct.Foreground(ct.Blue, true) + fmt.Println(" ———The Eyes of Darkness from Nsfocus spy on everything") + ct.ResetColor() + fmt.Println() +} diff --git a/logo/logo_windows.go b/logo/logo_windows.go new file mode 100644 index 0000000..3e3e847 --- /dev/null +++ b/logo/logo_windows.go @@ -0,0 +1,60 @@ +package logo + +import ( + "fmt" + + "github.com/daviddengcn/go-colortext" +) + +var logo = [...]string{ + ` ____ ______ `, + ` / __ \ / ____/_ _____ _____`, + ` / / / /_____/ __/ / / / / _ \/ ___/`, + ` / /_/ /_____/ /___/ /_/ / __(__ ) `, + `/_____/ /_____/\__, /\___/____/ `, + ` /____/ `, +} + +func ShowLogo() { + ct.Foreground(ct.Blue, true) + fmt.Println(logo[0]) + fmt.Println(logo[1]) + + ct.ResetColor() + + ct.Foreground(ct.Blue, true) + fmt.Println(logo[2]) + + ct.Foreground(ct.Magenta, true) + fmt.Println(logo[3]) + ct.ResetColor() + + ct.Foreground(ct.Magenta, true) + fmt.Println(logo[4]) + ct.ResetColor() + + ct.Foreground(ct.Magenta, true) + fmt.Println(logo[5]) + ct.ResetColor() + + ct.Foreground(ct.Blue, true) + fmt.Println(" ———The Eyes of Darkness from Nsfocus spy on everything") + ct.ResetColor() + fmt.Println() +} + +func Usage() { + + usage := `Usage: D-Eyes.exe filescan/processcan/info [other arguments...] + -info string + Basic information options: host, users, netstat, task, autoruns, summary.(For 'basicInfo' function) + -path string + The filepath where you want to scan. Such as C:// (windows) or / (linux).(For 'filescan' function) + -pid int + The pid of process you want to scan. (optional) (Only For processcan.'-1' means all processes.) (default -1) + -rule string + The rule you want to scan with. (optional) + -thread int + The default thread is 5. (optional) (Only For filescan) (default 5)` + fmt.Print(usage) +} diff --git a/output/result.go b/output/result.go new file mode 100644 index 0000000..d2e09e8 --- /dev/null +++ b/output/result.go @@ -0,0 +1,6 @@ +package output + +type Result struct { + Risk string + RiskPath string +} diff --git a/process/controller/init_linux.go b/process/controller/init_linux.go new file mode 100644 index 0000000..2d535da --- /dev/null +++ b/process/controller/init_linux.go @@ -0,0 +1,50 @@ +package controller + +import ( + "github.com/gookit/color" + "github.com/shirou/gopsutil/v3/process" + + "d-eyes/process/models" + "d-eyes/process/scanner" + "d-eyes/process/utils" +) + +func GetProcess() models.Process { + ps, err := process.Processes() + if err != nil { + return models.Process{} + } + return models.Process{Process: ps} +} + +func ScanProcess(pid int, rule string) { + var scannerEngine *scanner.Scanner + var err error + + if rule == "" { + scannerEngine, err = scanner.NewScannerAllRules() + } else { + rulePath := "yaraRules\\" + rule + ".yar" + scannerEngine, err = scanner.NewScanner(rulePath) + if err != nil { + color.Redln(err.Error()) + return + } + } + + ipList, err := utils.ReadLindIp("ip.config") + Npattern := []string{"ms-msdt:/id\\s+PCWDiagnostic\\s+/skip force\\s+/param"} + + if err == nil { + scanResults, err := scannerEngine.ScanProcesses(pid, ipList, Npattern) + if err == nil { + models.SaveProcessResult(scanResults) + } else { + color.Redln(err.Error()) + } + } else { + color.Redln(err.Error()) + return + } + //scannerEngine.Rules.Destroy() +} diff --git a/process/controller/init_windows.go b/process/controller/init_windows.go new file mode 100644 index 0000000..a1f4059 --- /dev/null +++ b/process/controller/init_windows.go @@ -0,0 +1,51 @@ +package controller + +import ( + "github.com/gookit/color" + "github.com/shirou/gopsutil/v3/process" + + "d-eyes/process/models" + "d-eyes/process/scanner" + "d-eyes/process/utils" +) + +func GetProcess() models.Process { + ps, err := process.Processes() + if err != nil { + return models.Process{} + } + return models.Process{Process: ps} +} + +func ScanProcess(pid int, rule string, src_path string) { + var scannerEngine *scanner.Scanner + var err error + + if rule == "" { + scannerEngine, err = scanner.NewScannerAllRules(src_path) + } else { + rulePath := src_path + "yaraRules\\" + rule + ".yar" + scannerEngine, err = scanner.NewScanner(rulePath) + if err != nil { + color.Redln(err.Error()) + return + } + } + + ipList, err := utils.ReadLindIp(src_path + "ip.config") + Npattern := []string{"ms-msdt:/id\\s+PCWDiagnostic\\s+/skip force\\s+/param"} + + if err == nil { + err, scanResults := scannerEngine.ScanProcesses(pid, ipList, Npattern) + if err == nil { + models.SaveProcessResult(scanResults) + } else { + color.Redln(err.Error()) + } + } else { + color.Redln(err.Error()) + return + } + // todo + //scannerEngine.Rules.Destroy() +} diff --git a/process/models/models_linux.go b/process/models/models_linux.go new file mode 100644 index 0000000..1e3ef4a --- /dev/null +++ b/process/models/models_linux.go @@ -0,0 +1,216 @@ +package models + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "strings" + + "github.com/gookit/color" + "github.com/hillu/go-yara/v4" + "github.com/shirou/gopsutil/v3/net" + "github.com/shirou/gopsutil/v3/process" +) + +type ( + Process struct { + Process []*process.Process + } + + ProcessScanResult struct { + //Pid int + CheckIP bool + Connection []string + Ps *process.Process + PidMatches []yara.MatchRule + PathMatches []yara.MatchRule + CheckArgs bool + Args string + } + + ProcessResult struct { + Pid int + Path string + Namespace string + Rule string + Description string + } +) + +func SaveProcessResult(results []*ProcessScanResult) { + + red := color.FgRed.Render + green := color.FgGreen.Render + riskSum := 0 + color.Warn.Println("\nD-Eyes Detection Result : \n") + for _, psr := range results { + + lenPidMatches := len(psr.PidMatches) + lenPathMatches := len(psr.PathMatches) + + psrPath, _ := psr.Ps.Exe() + if lenPidMatches != 0 && lenPathMatches != 0 { + riskSum++ + data1 := psr.PidMatches[0].Metas[0] + dataType1, _ := json.Marshal(data1) + dataString1 := string(dataType1) + meta1 := strings.Split(dataString1, ":")[2] + metaTmp1 := strings.Trim(meta1, "\"}") + + data2 := psr.PathMatches[0].Metas[0] + dataType2, _ := json.Marshal(data2) + dataString2 := string(dataType2) + met2a := strings.Split(dataString2, ":")[2] + metaTmp2 := strings.Trim(met2a, "\"}") + color.Error.Println("[ Risk ", riskSum, " ]") + fmt.Printf( + "[pid]:%d [%s]:%s | [path]:%s [%s]:%s | ", + psr.Ps.Pid, red("status"), red(metaTmp1), psrPath, red("status"), + red(metaTmp2), + ) + + if psr.CheckArgs { + fmt.Printf("[args]:%s | ", red(psr.Args)) + } else { + fmt.Printf("[args]:%s | ", green(psr.Args)) + } + + if len(psr.Connection) == 0 { + fmt.Println("[network]:", green("null")) + } else { + fmt.Println("[network]:", psr.Connection) + } + continue + } + + if lenPidMatches != 0 && lenPathMatches == 0 { + + riskSum++ + data := psr.PidMatches[0].Metas[0] + dataType, _ := json.Marshal(data) + dataString := string(dataType) + meta := strings.Split(dataString, ":")[2] + metaTmp := strings.Trim(meta, "\"}") + + color.Error.Println("[ Risk ", riskSum, " ]") + fmt.Printf( + "[pid]:%d [%s]:%s | [path]:%s [%s]:%s | ", + psr.Ps.Pid, red("status"), red(metaTmp), psrPath, green("status"), green("safe"), + ) + + if psr.CheckArgs { + fmt.Printf("[args]:%s | ", red(psr.Args)) + } else { + fmt.Printf("[args]:%s | ", green(psr.Args)) + } + + if len(psr.Connection) == 0 { + fmt.Println("[network]:", green("null")) + } else { + fmt.Println("[network]:", psr.Connection) + } + continue + } + + if lenPidMatches == 0 && lenPathMatches != 0 { + + riskSum++ + data := psr.PathMatches[0].Metas[0] + dataType, _ := json.Marshal(data) + dataString := string(dataType) + meta := strings.Split(dataString, ":")[2] + metaTmp := strings.Trim(meta, "\"}") + + color.Error.Println("[ Risk ", riskSum, " ]") + fmt.Printf( + "[pid]:%d [%s]:%s | [path]:%s [%s]:%s | ", + psr.Ps.Pid, green("status"), green("safe"), psrPath, red("status"), red(metaTmp), + ) + + if psr.CheckArgs { + fmt.Printf("[args]:%s | ", red(psr.Args)) + } else { + fmt.Printf("[args]:%s | ", green(psr.Args)) + } + + if len(psr.Connection) == 0 { + fmt.Println("[network]:", green("null")) + } else { + fmt.Println("[network]:", psr.Connection) + } + continue + } + + if psr.CheckIP { + riskSum++ + color.Error.Println("[ Risk ", riskSum, " ]") + fmt.Printf( + "[pid]:%d [%s]:%s | [path]:%s [%s]:%s | ", + psr.Ps.Pid, green("status"), green("safe"), psrPath, green("status"), green("safe"), + ) + + if psr.CheckArgs { + fmt.Printf("[args]:%s | ", red(psr.Args)) + } else { + fmt.Printf("[args]:%s | ", green(psr.Args)) + } + fmt.Println("[network]:", psr.Connection) + + continue + } + + if psr.CheckArgs { + riskSum++ + color.Error.Println("[ Risk ", riskSum, " ]") + fmt.Printf( + "[pid]:%d [%s]:%s | [path]:%s [%s]:%s | ", + psr.Ps.Pid, green("status"), green("safe"), psrPath, green("status"), green("safe"), + ) + + fmt.Printf("[args]:%s | ", red(psr.Args)) + + if len(psr.Connection) == 0 { + fmt.Println("[network]:", green("null")) + } else { + fmt.Println("[network]:", psr.Connection) + } + } + } + if riskSum == 0 { + fmt.Println("\nNo suspicious process found. Your computer is safe with the rules you choose.") + } + +} + +func DisplayNetworkInfo(connects []net.ConnectionStat) { + + green := color.FgGreen.Render + blue := color.FgBlue.Render + red := color.FgRed.Render + + if len(connects) == 0 { + fmt.Println("[network]:", green("null")) + return + } + + ipf, _ := ioutil.TempFile("", "hostip") + //defer os.Remove(ipf.Name()) + + connection := make([]string, 0) + for _, conn := range connects { + if conn.Family == 1 { + continue + } + raddrip := red(conn.Raddr.IP) + c := fmt.Sprintf( + "%v:%v<->%v:%v(%v)", + blue(conn.Laddr.IP), blue(conn.Laddr.Port), raddrip, blue(conn.Raddr.Port), blue(conn.Status), + ) + connection = append(connection, c) + ipf.Write([]byte(raddrip)) + + } + ipf.Close() + fmt.Println("[network]:", connection) + +} diff --git a/process/models/models_windows.go b/process/models/models_windows.go new file mode 100644 index 0000000..cc6e263 --- /dev/null +++ b/process/models/models_windows.go @@ -0,0 +1,214 @@ +package models + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "strings" + + "github.com/gookit/color" + "github.com/hillu/go-yara/v4" + "github.com/shirou/gopsutil/v3/net" + "github.com/shirou/gopsutil/v3/process" +) + +type ( + Process struct { + Process []*process.Process + } + + ProcessScanResult struct { + CheckIP bool + Connection []string + Ps *process.Process + PidMatches yara.MatchRules + PathMatches yara.MatchRules + CheckArgs bool + Args string + } + + ProcessResult struct { + Pid int + Path string + Namespace string + Rule string + Description string + } +) + +func SaveProcessResult(results []*ProcessScanResult) { + + red := color.FgRed.Render + green := color.FgGreen.Render + riskSum := 0 + color.Warn.Println("\nD-Eyes Detection Result : \n") + for _, psr := range results { + + lenPidMatches := len(psr.PidMatches) + lenPathMatches := len(psr.PathMatches) + + psrPath, _ := psr.Ps.Exe() + if lenPidMatches != 0 && lenPathMatches != 0 { + riskSum++ + data1 := psr.PidMatches[0].Metas[0] + dataType1, _ := json.Marshal(data1) + dataString1 := string(dataType1) + meta1 := strings.Split(dataString1, ":")[2] + metaTmp1 := strings.Trim(meta1, "\"}") + + data2 := psr.PathMatches[0].Metas[0] + dataType2, _ := json.Marshal(data2) + dataString2 := string(dataType2) + met2a := strings.Split(dataString2, ":")[2] + metaTmp2 := strings.Trim(met2a, "\"}") + color.Error.Println("[ Risk ", riskSum, " ]") + fmt.Printf( + "[pid]:%d [%s]:%s | [path]:%s [%s]:%s | ", + psr.Ps.Pid, red("status"), red(metaTmp1), psrPath, red("status"), + red(metaTmp2), + ) + + if psr.CheckArgs { + fmt.Printf("[args]:%s | ", red(psr.Args)) + } else { + fmt.Printf("[args]:%s | ", green(psr.Args)) + } + + if len(psr.Connection) == 0 { + fmt.Println("[network]:", green("null")) + } else { + fmt.Println("[network]:", psr.Connection) + } + continue + } + + if lenPidMatches != 0 && lenPathMatches == 0 { + + riskSum++ + data := psr.PidMatches[0].Metas[0] + dataType, _ := json.Marshal(data) + dataString := string(dataType) + meta := strings.Split(dataString, ":")[2] + metaTmp := strings.Trim(meta, "\"}") + + color.Error.Println("[ Risk ", riskSum, " ]") + fmt.Printf( + "[pid]:%d [%s]:%s | [path]:%s [%s]:%s | ", + psr.Ps.Pid, red("status"), red(metaTmp), psrPath, green("status"), green("safe"), + ) + + if psr.CheckArgs { + fmt.Printf("[args]:%s | ", red(psr.Args)) + } else { + fmt.Printf("[args]:%s | ", green(psr.Args)) + } + + if len(psr.Connection) == 0 { + fmt.Println("[network]:", green("null")) + } else { + fmt.Println("[network]:", psr.Connection) + } + continue + } + + if lenPidMatches == 0 && lenPathMatches != 0 { + + riskSum++ + data := psr.PathMatches[0].Metas[0] + dataType, _ := json.Marshal(data) + dataString := string(dataType) + meta := strings.Split(dataString, ":")[2] + metaTmp := strings.Trim(meta, "\"}") + + color.Error.Println("[ Risk ", riskSum, " ]") + fmt.Printf( + "[pid]:%d [%s]:%s | [path]:%s [%s]:%s | ", + psr.Ps.Pid, green("status"), green("safe"), psrPath, red("status"), red(metaTmp), + ) + + if psr.CheckArgs { + fmt.Printf("[args]:%s | ", red(psr.Args)) + } else { + fmt.Printf("[args]:%s | ", green(psr.Args)) + } + + if len(psr.Connection) == 0 { + fmt.Println("[network]:", green("null")) + } else { + fmt.Println("[network]:", psr.Connection) + } + continue + } + + if psr.CheckIP { + riskSum++ + color.Error.Println("[ Risk ", riskSum, " ]") + fmt.Printf( + "[pid]:%d [%s]:%s | [path]:%s [%s]:%s | ", + psr.Ps.Pid, green("status"), green("safe"), psrPath, green("status"), green("safe"), + ) + + if psr.CheckArgs { + fmt.Printf("[args]:%s | ", red(psr.Args)) + } else { + fmt.Printf("[args]:%s | ", green(psr.Args)) + } + fmt.Println("[network]:", psr.Connection) + + continue + } + + if psr.CheckArgs { + riskSum++ + color.Error.Println("[ Risk ", riskSum, " ]") + fmt.Printf( + "[pid]:%d [%s]:%s | [path]:%s [%s]:%s | ", + psr.Ps.Pid, green("status"), green("safe"), psrPath, green("status"), green("safe"), + ) + + fmt.Printf("[args]:%s | ", red(psr.Args)) + + if len(psr.Connection) == 0 { + fmt.Println("[network]:", green("null")) + } else { + fmt.Println("[network]:", psr.Connection) + } + } + } + if riskSum == 0 { + fmt.Println("\nNo suspicious process found. Your computer is safe with the rules you choose.") + } + +} + +func DisplayNetworkInfo(connects []net.ConnectionStat) { + + green := color.FgGreen.Render + blue := color.FgBlue.Render + red := color.FgRed.Render + + if len(connects) == 0 { + fmt.Println("[network]:", green("null")) + return + } + + ipf, _ := ioutil.TempFile("", "hostip") + + connection := make([]string, 0) + for _, conn := range connects { + if conn.Family == 1 { + continue + } + raddrip := red(conn.Raddr.IP) + c := fmt.Sprintf( + "%v:%v<->%v:%v(%v)", + blue(conn.Laddr.IP), blue(conn.Laddr.Port), raddrip, blue(conn.Raddr.Port), blue(conn.Status), + ) + connection = append(connection, c) + ipf.Write([]byte(raddrip)) + + } + ipf.Close() + fmt.Println("[network]:", connection) + +} diff --git a/process/scanner/scanner_linux.go b/process/scanner/scanner_linux.go new file mode 100644 index 0000000..dc4d70c --- /dev/null +++ b/process/scanner/scanner_linux.go @@ -0,0 +1,298 @@ +package scanner + +import ( + "encoding/json" + "fmt" + "os" + "strings" + "sync" + + "github.com/gookit/color" + "github.com/hillu/go-yara/v4" + "github.com/shirou/gopsutil/v3/process" + "github.com/toolkits/slice" + + "d-eyes/process/models" + "d-eyes/process/utils" + "d-eyes/yaraobj" +) + +var resultListTMP []*models.ProcessScanResult + +type Scanner struct { + Rules *yara.Rules +} + +type ( + Process struct { + Process []*process.Process + } +) + +func (i Process) Iterator() *Iterator { + return &Iterator{ + data: i, + index: 0, + } +} + +type Iterator struct { + data Process + index int +} + +func (i *Iterator) HasNext() bool { + return i.index < len(i.data.Process) +} + +func (i *Iterator) Next() *process.Process { + pro := i.data.Process[i.index] + i.index++ + return pro +} + +// Open the rule file and add it to the Yara compiler. +func NewScanner(rulepath string) (*Scanner, error) { + f, err := os.ReadFile(rulepath) + if err != nil { + color.Redln("GetErr: Can't open the rule file: ", rulepath) + os.Exit(1) + return nil, err + } + compiler, err := yara.NewCompiler() + if err != nil { + return nil, err + } + err = compiler.AddString(string(f), "") + if err != nil { + return nil, err + } + rules, err := compiler.GetRules() + if err != nil { + return nil, err + } + return &Scanner{Rules: rules}, err +} + +func NewScannerAllRules() (*Scanner, error) { + rulesPath := "yaraRules" + _, err := os.Stat(rulesPath) + if os.IsNotExist(err) { + color.Redln("GetErr: The './yaraRules' directory does not exist.") + os.Exit(1) + } + rules, err := yaraobj.LoadAllYaraRules(rulesPath) + if err != nil { + color.Redln("LoadCompiledRules goes error !!!") + color.Redln("GetRules err: ", err) + os.Exit(1) + } + return &Scanner{Rules: rules}, err +} + +func (s *Scanner) ScanProcesses(pid int, ipList []string, Npattern []string) ([]*models.ProcessScanResult, error) { + + whiteList := []string{"ruby", "sagent", "crond", "mysqld", "rsyslogd"} + var resultList []*models.ProcessScanResult + + if pid != -1 { + + var pidMatches yara.MatchRules + var pathMatches yara.MatchRules + err := s.Rules.ScanProc(pid, 0, 10, &pidMatches) + if err != nil { + return nil, fmt.Errorf("pid: %d is not exist! (%s)", pid, err) + } + ps, _ := process.NewProcess(int32(pid)) + path, _ := ps.Exe() + err = s.Rules.ScanFile(path, 0, 10, &pathMatches) + if err != nil { + return nil, fmt.Errorf("ScanFile err: %s", err) + } + + var checkarg bool + var args string + // todo + //for _, i := range Npattern { + // reg := regexp.MustCompile(i) + // if reg.FindString(ps.Arguments) != "" { + // checkarg = true + // args = ps.Arguments + // } else { + // checkarg = false + // args = "safe" + // } + //} + + connection, ok := DisplayScanResult(ps, pidMatches, pathMatches, ipList) + resultList = append( + resultList, &models.ProcessScanResult{ + CheckIP: ok, Connection: connection, + Ps: ps, PidMatches: pidMatches, PathMatches: pathMatches, CheckArgs: checkarg, Args: args, + }, + ) + + return resultList, nil + } + + ps, err := process.Processes() + if err != nil { + return nil, err + } + + pss := Process{Process: ps} + it := pss.Iterator() + wg := &sync.WaitGroup{} + wg.Add(5) + for i := 0; i < 5; i++ { + go s.ProScan(it, wg, whiteList, ipList, Npattern) + } + wg.Wait() + + resultList = resultListTMP + return resultList, nil +} + +func (s *Scanner) ProScan(it *Iterator, wg *sync.WaitGroup, whiteList []string, ipList []string, Npattern []string) { + defer wg.Done() + for { + var err error + if it.HasNext() { + ps := it.Next() + var pidMatches yara.MatchRules + var pathMatches yara.MatchRules + + pid := os.Getpid() + if pid == int(ps.Pid) { + continue + } + + _psPath, _ := ps.Exe() + t := strings.Split(_psPath, "/") + filename := t[len(t)-1] + if !slice.ContainsString(whiteList, filename) { + + err = s.Rules.ScanProc(int(ps.Pid), 0, 10, &pidMatches) + if err != nil { + err = nil + continue + } + err = s.Rules.ScanFile(_psPath, 0, 10, &pathMatches) + + if err != nil { + err = nil + continue + } + + var checkarg bool + var args string + // todo + //for _, i := range Npattern { + // reg := regexp.MustCompile(i) + // if reg.FindString(ps.Arguments) != "" { + // checkarg = true + // args = ps.Arguments + // } else { + // checkarg = false + // args = "safe" + // } + //} + + connection, ok := DisplayScanResult(ps, pidMatches, pathMatches, ipList) + + resultListTMP = append( + resultListTMP, &models.ProcessScanResult{ + CheckIP: ok, Connection: connection, + Ps: ps, PidMatches: pidMatches, PathMatches: pathMatches, CheckArgs: checkarg, Args: args, + }, + ) + + } + } else { + break + } + } +} + +func DisplayScanResult(ps *process.Process, pidMatches yara.MatchRules, pathMatches yara.MatchRules, ipList []string) ([]string, bool) { + + var pid_matches string + var path_matches string + var pid_rules string + var path_rules string + var ipexist bool + + red := color.FgRed.Render + green := color.FgGreen.Render + blue := color.FgBlue.Render + + color.Info.Printf("D-Eyes progress scanning: ") + + if len(pidMatches) == 0 { + pid_matches = green("status") + pid_rules = green("safe") + } else { + pid_matches = red("status") + data := pidMatches[0].Metas[0] + dataType, _ := json.Marshal(data) + dataString := string(dataType) + meta := strings.Split(dataString, ":")[2] + metaTmp := strings.Trim(meta, "\"}") + pid_rules = red(metaTmp) + } + + if len(pathMatches) == 0 { + path_matches = green("status") + path_rules = green("safe") + } else { + path_matches = red("status") + + data := pathMatches[0].Metas[0] + dataType, _ := json.Marshal(data) + dataString := string(dataType) + meta := strings.Split(dataString, ":")[2] + metaTmp := strings.Trim(meta, "\"}") + + path_rules = red(metaTmp) + } + _pUname, _ := ps.Username() + _exe, _ := ps.Exe() + fmt.Printf( + "[username]:%s | [pid]:%d [%s]:%s | [path]:%s [%s]:%s | ", + _pUname, ps.Pid, pid_matches, pid_rules, _exe, path_matches, path_rules, + ) + + // 显示网络连接信息 + connection := make([]string, 0) + _psConn, _ := ps.Connections() + for _, conn := range _psConn { + if conn.Family == 1 { + continue + } + ok := utils.CheckIpInipconfig(ipList, conn.Raddr.IP) + if !ok { + c := fmt.Sprintf( + "%v:%v<->%v:%v(%v)", + conn.Laddr.IP, conn.Laddr.Port, conn.Raddr.IP, conn.Raddr.Port, conn.Status, + ) + connection = append(connection, blue(c)) + } else { + c := fmt.Sprintf( + "%v:%v<->%v:%v(%v)", + blue(conn.Laddr.IP), blue(conn.Laddr.Port), red(conn.Raddr.IP), blue(conn.Raddr.Port), blue(conn.Status), + ) + connection = append(connection, c) + ipexist = true + } + + } + + if len(connection) == 0 { + fmt.Println("[network]:", green("null")) + } else { + fmt.Println("[network]:", connection) + } + + return connection, ipexist + +} diff --git a/process/scanner/scanner_windows.go b/process/scanner/scanner_windows.go new file mode 100644 index 0000000..324fd30 --- /dev/null +++ b/process/scanner/scanner_windows.go @@ -0,0 +1,309 @@ +package scanner + +import ( + "encoding/json" + "fmt" + "os" + "strings" + "sync" + + "github.com/gookit/color" + "github.com/hillu/go-yara/v4" + "github.com/shirou/gopsutil/v3/process" + "github.com/toolkits/slice" + + "d-eyes/process/models" + "d-eyes/process/utils" + "d-eyes/yaraobj" +) + +var resultListTMP []*models.ProcessScanResult + +type Scanner struct { + Rules *yara.Rules +} + +type ( + Process struct { + Process []*process.Process + } +) + +func (i Process) Iterator() *Iterator { + return &Iterator{ + data: i, + index: 0, + } +} + +type Iterator struct { + data Process + index int +} + +func (i *Iterator) HasNext() bool { + return i.index < len(i.data.Process) +} + +func (i *Iterator) Next() *process.Process { + pro := i.data.Process[i.index] + i.index++ + return pro +} + +// Open the rule file and add it to the Yara compiler. +func NewScanner(rulepath string) (*Scanner, error) { + f, err := os.ReadFile(rulepath) + if err != nil { + color.Redln("GetErr: Can't open the rule file: ", rulepath) + os.Exit(1) + return nil, err + } + compiler, err := yara.NewCompiler() + if err != nil { + return nil, err + } + err = compiler.AddString(string(f), "") + if err != nil { + return nil, err + } + rules, err := compiler.GetRules() + if err != nil { + return nil, err + } + return &Scanner{Rules: rules}, err +} + +func NewScannerAllRules(src_path string) (*Scanner, error) { + rulesPath := src_path + "yaraRules" + _, err := os.Stat(rulesPath) + if os.IsNotExist(err) { + color.Redln("GetErr: The './yaraRules' directory does not exist.") + os.Exit(1) + } + rules, err := yaraobj.LoadAllYaraRules(rulesPath) + if err != nil { + color.Redln("LoadCompiledRules goes error !!!") + color.Redln("GetRules err: ", err) + os.Exit(1) + } + return &Scanner{Rules: rules}, err +} + +func (s *Scanner) ScanProcesses(pid int, ipList []string, Npattern []string) ([]*models.ProcessScanResult, error) { + + whiteList := []string{"ruby", "sagent", "crond", "mysqld", "rsyslogd"} + var resultList []*models.ProcessScanResult + + if pid != -1 { + + var pidMatches yara.MatchRules + var pathMatches yara.MatchRules + err := s.Rules.ScanProc(pid, 0, 10, &pidMatches) + if err != nil { + return nil, fmt.Errorf("pid: %d is not exist! (%s)", pid, err) + } + ps, _ := process.NewProcess(int32(pid)) + _psPath, _ := ps.Exe() + f, err := os.Open(_psPath) + if err != nil { + return fmt.Errorf("ScanFile err: %s", err), nil + } + defer f.Close() + err = s.Rules.ScanFileDescriptor(f.Fd(), 0, 10, &pathMatches) + + if err != nil { + return fmt.Errorf("ScanFile err: %s", err), nil + } + + var checkarg bool + var args string + // todo + //for _, i := range Npattern { + // reg := regexp.MustCompile(i) + // if reg.FindString(ps.Arguments) != "" { + // checkarg = true + // args = ps.Arguments + // } else { + // checkarg = false + // args = "safe" + // } + //} + + connection, ok := DisplayScanResult(ps, pidMatches, pathMatches, ipList) + resultList = append( + resultList, &models.ProcessScanResult{ + CheckIP: ok, Connection: connection, + Ps: ps, PidMatches: pidMatches, PathMatches: pathMatches, CheckArgs: checkarg, Args: args, + }, + ) + + return resultList, nil + } + + ps, err := process.Processes() + if err != nil { + return nil, err + } + + pss := Process{Process: ps} + it := pss.Iterator() + wg := &sync.WaitGroup{} + wg.Add(5) + for i := 0; i < 5; i++ { + go s.ProScan(it, wg, whiteList, ipList, Npattern) + } + wg.Wait() + + resultList = resultListTMP + return resultList, nil +} + +func (s *Scanner) ProScan(it *Iterator, wg *sync.WaitGroup, whiteList []string, ipList []string, Npattern []string) { + defer wg.Done() + for { + var err error + if it.HasNext() { + ps := it.Next() + var pidMatches yara.MatchRules + var pathMatches yara.MatchRules + + pid := os.Getpid() + if pid == int(ps.Pid) { + continue + } + + _psPath, _ := ps.Exe() + t := strings.Split(_psPath, "/") + filename := t[len(t)-1] + if !slice.ContainsString(whiteList, filename) { + + err = s.Rules.ScanProc(int(ps.Pid), 0, 10, &pidMatches) + if err != nil { + err = nil + continue + } + + f, err := os.Open(_psPath) + if err != nil { + continue + } + defer f.Close() + err = s.Rules.ScanFileDescriptor(f.Fd(), 0, 10, &pathMatches) + if err != nil { + err = nil + continue + } + + var checkarg bool + var args string + // todo + //for _, i := range Npattern { + // reg := regexp.MustCompile(i) + // if reg.FindString(ps.Arguments) != "" { + // checkarg = true + // args = ps.Arguments + // } else { + // checkarg = false + // args = "safe" + // } + //} + + connection, ok := DisplayScanResult(ps, pidMatches, pathMatches, ipList) + + resultListTMP = append( + resultListTMP, &models.ProcessScanResult{ + CheckIP: ok, Connection: connection, + Ps: ps, PidMatches: pidMatches, PathMatches: pathMatches, CheckArgs: checkarg, Args: args, + }, + ) + + } + } else { + break + } + } +} + +func DisplayScanResult(ps *process.Process, pidMatches yara.MatchRules, pathMatches yara.MatchRules, ipList []string) ([]string, bool) { + + var pid_matches string + var path_matches string + var pid_rules string + var path_rules string + var ipexist bool + + red := color.FgRed.Render + green := color.FgGreen.Render + blue := color.FgBlue.Render + + color.Info.Printf("D-Eyes progress scanning: ") + + if len(pidMatches) == 0 { + pid_matches = green("status") + pid_rules = green("safe") + } else { + pid_matches = red("status") + data := pidMatches[0].Metas[0] + dataType, _ := json.Marshal(data) + dataString := string(dataType) + meta := strings.Split(dataString, ":")[2] + metaTmp := strings.Trim(meta, "\"}") + pid_rules = red(metaTmp) + } + + if len(pathMatches) == 0 { + path_matches = green("status") + path_rules = green("safe") + } else { + path_matches = red("status") + + data := pathMatches[0].Metas[0] + dataType, _ := json.Marshal(data) + dataString := string(dataType) + meta := strings.Split(dataString, ":")[2] + metaTmp := strings.Trim(meta, "\"}") + + path_rules = red(metaTmp) + } + _pUname, _ := ps.Username() + _exe, _ := ps.Exe() + fmt.Printf( + "[username]:%s | [pid]:%d [%s]:%s | [path]:%s [%s]:%s | ", + _pUname, ps.Pid, pid_matches, pid_rules, _exe, path_matches, path_rules, + ) + + // 显示网络连接信息 + connection := make([]string, 0) + _psConn, _ := ps.Connections() + for _, conn := range _psConn { + if conn.Family == 1 { + continue + } + ok := utils.CheckIpInipconfig(ipList, conn.Raddr.IP) + if !ok { + c := fmt.Sprintf( + "%v:%v<->%v:%v(%v)", + conn.Laddr.IP, conn.Laddr.Port, conn.Raddr.IP, conn.Raddr.Port, conn.Status, + ) + connection = append(connection, blue(c)) + } else { + c := fmt.Sprintf( + "%v:%v<->%v:%v(%v)", + blue(conn.Laddr.IP), blue(conn.Laddr.Port), red(conn.Raddr.IP), blue(conn.Raddr.Port), blue(conn.Status), + ) + connection = append(connection, c) + ipexist = true + } + + } + + if len(connection) == 0 { + fmt.Println("[network]:", green("null")) + } else { + fmt.Println("[network]:", connection) + } + + return connection, ipexist + +} diff --git a/process/utils/iputil.go b/process/utils/iputil.go new file mode 100644 index 0000000..2a6306e --- /dev/null +++ b/process/utils/iputil.go @@ -0,0 +1,27 @@ +package utils + +import ( + "math/big" + "net" +) + +type IntIP struct { + IP string + Intip int64 +} + +func (i *IntIP) toIntIp() int64 { + ret := big.NewInt(0) + ret.SetBytes(net.ParseIP(i.IP).To4()) + return ret.Int64() +} + +func CheckIpInipconfig(ipList []string, ip string) bool { + + for _, hip := range ipList { + if hip == ip { + return true + } + } + return false +} diff --git a/process/utils/readfile.go b/process/utils/readfile.go new file mode 100644 index 0000000..e1e5ad6 --- /dev/null +++ b/process/utils/readfile.go @@ -0,0 +1,29 @@ +package utils + +import ( + "bufio" + "os" + "strings" +) + +func ReadLindIp(fileName string) ([]string, error) { + f, err := os.Open(fileName) + if err != nil { + return nil, err + } + buf := bufio.NewScanner(f) + var result []string + + for { + if !buf.Scan() { + break + } + + line := buf.Text() + line = strings.TrimSpace(line) + + result = append(result, line) + } + + return result, nil +} diff --git a/yaraRules/Botnet.BlackMoon.yar b/yaraRules/Botnet.BlackMoon.yar new file mode 100644 index 0000000..6351ca0 --- /dev/null +++ b/yaraRules/Botnet.BlackMoon.yar @@ -0,0 +1,53 @@ +import "hash" +rule blackmoon_hash +{ + meta: + description ="Detect the risk of Malware blackmoon Rule 1" + condition: + hash.md5(0,filesize) =="22E46CBCF02D78390D257AEE0FE26EDE" or + hash.md5(0,filesize) =="65982DEB6AC30B9F1F4DAB1AA26A0D0E" or + hash.md5(0,filesize) =="C4A73F3BBDD1E64EF146A232967B1BC5" or + hash.md5(0,filesize) =="93EB67FDB2D0C767887C6F6284844386" or + hash.md5(0,filesize) =="F73436646F905504027809A461D0A8D9" or + hash.md5(0,filesize) =="63EC62319605B43D68EB25B9F84153C8" or + hash.sha256(0,filesize) =="25f87c65a793186c7a9e1d8680ad7f32acb9bae4cb7284b98781b3a15f810ba2" or + hash.sha256(0,filesize) =="a57980012b38dc89baab954e7da3fa7112dd52b2252a72f87ec2510a70d2ade7" + +} + +rule BLACKMOON_BANKER { + meta: + description ="Detect the risk of Malware blackmoon Rule 2" + detail = "blackmoon update" + strings: + $s1 = "BlackMoon RunTime Error:" nocase wide ascii + $s2 = "\\system32\\rundll32.exe" wide ascii + $s3 = "cmd.exe /c ipconfig /flushdns" wide ascii + $s4 = "\\system32\\drivers\\etc\\hosts.ics" wide ascii + condition: + all of them + +} + +rule BlackMoon_2022 +{ + meta: + description ="Detect the risk of Malware blackmoon Rule 3" + strings: + $s1 = "kongxin1123" + $s2 = "m27p.com" + $s3 = "jincpay.com" + $s4 = "xiaoniu321.com" + condition: + hash.md5(0,filesize) == "22e46cbcf02d78390d257aee0fe26ede" or + hash.md5(0,filesize) == "65982deb6ac30b9f1f4dab1aa26a0d0e" or + hash.md5(0,filesize) == "93eb67fdb2d0c767887c6f6284844386" or + hash.md5(0,filesize) == "c4a73f3bbdd1e64ef146a232967b1bc5" or + hash.md5(0,filesize) == "f73436646f905504027809a461d0a8d9" or + hash.md5(0,filesize) == "63ec62319605b43d68eb25b9f84153c8" or + hash.md5(0,filesize) == "37C030456818878AF1DC8CE7928A504F" or + $s1 or + $s2 or + $s3 or + $s4 +} \ No newline at end of file diff --git a/yaraRules/Botnet.Festi.yar b/yaraRules/Botnet.Festi.yar new file mode 100644 index 0000000..b7e7320 --- /dev/null +++ b/yaraRules/Botnet.Festi.yar @@ -0,0 +1,11 @@ +rule festi_botnet_pdb { + meta: + description = "Detect the risk of Botnet Malware Festi Rule 1" + hash = "e55913523f5ae67593681ecb28d0fa1accee6739fdc3d52860615e1bc70dcb99" + strings: + $pdb = "\\eclipse\\botnet\\drivers\\Bin\\i386\\kernel.pdb" + condition: + uint16(0) == 0x5a4d and + filesize < 80KB and + any of them +} diff --git a/yaraRules/Botnet.Gafgyt.yar b/yaraRules/Botnet.Gafgyt.yar new file mode 100644 index 0000000..515703d --- /dev/null +++ b/yaraRules/Botnet.Gafgyt.yar @@ -0,0 +1,272 @@ +rule Gafgyt_Generic_Botnet { + meta: + description = "Detect the risk of Botnet Malware Gafgyt Rule 1" + hash0 = "2a18f2d59f172622e76d9d9b5c73393b" + hash1 = "06de2d19862494be7dbcbcf20b3dbe3a" + hash2 = "0fc30a802a07386f5cd4b18b47547979" + hash3 = "be6865ccb948f2937fd25fe465e434da" + hash4 = "c8d58acfe524a09d4df7ffbe4a43c429" + hash5 = "0f979b4ae1209020dd2b672f9dad7398" + hash6 = "45826c129bf3d3bd067e33cf7bef3883" + hash7 = "79b9d4cea7972951efad765406459f5e" + hash8 = "baad702930571c414b0e8896f8bb4a5f" + hash9 = "11754a20e705dccf96f1a1def7220efc" + hash10 = "67db9ed04d3b56f966a739fd40a47748" + strings: + $s0 = "busybox" fullword + $s1 = "PONG!" fullword + $s2 = "GETLOCALIP" fullword + $s3 = "HTTPFLOOD" fullword + $s4 = "LUCKYLILDUDE" fullword + $s5 = "/dev/null" + $s6 = "/etc/resolv.conf" + $s7 = "/etc/config/resolv.conf" + condition: + all of them +} + +rule Gafgyt_July_1 { + meta: + description = "Detect the risk of Botnet Malware Gafgyt Rule 2" + hash1 = "041db2cf6eac2a47ae4651751158838104e502ff33dcc7f5dd48472789870e6c" + hash2 = "0839b33e2da179eac610673769e9568d1942877739cf4d990f3787672a4e9af1" + hash3 = "2a1c1a22ed6989e9ba86f9a192834e0a35afec8026e8ecc0bb5c958d2892d46c" + hash4 = "30b682ee7114bf68f881e641e9ab14c7d62c84f725e9cf5bfccb403aaa1fe8f7" + hash5 = "3b9a35f7a0698b24d214818efd22235c995f1460fc55dd3ebd923ff0dca5370c" + hash6 = "4110dd04db3932f1f03bdce6fa74f5298ffb429b816c7a8fce40f1cbb043e968" + hash7 = "471b4d64420bdf2c8749c390a142ed449aff23b0d67609b268be044657501fa7" + hash8 = "5a9f02031f0b3b1a2edaeae2d77b8c1f67de2b611449432c42c88f840d7a1d5c" + hash9 = "78d9488d688f3b12181b54df0e9da3770e90a4a42a13db001fd211d16645a1bb" + hash10 = "7f2aa6e5e1f1229fb18a15d1599a7a6014796cc7c08b26b9c4336a2048dc8928" + hash11 = "805917658c7761debdaf18e83b54ec4e9ba645950c773ddd21d6cd8ba29b32d6" + hash12 = "ae880c7dd79ebb1d626aea57152fdaa779d07d5b326d7f7fad1d42b637e5da84" + hash13 = "b0d36c18bf900988d01828202ce1ab77949b9a8a29b264ea1639f170a6c9825b" + hash14 = "c17bf892498ed1dce5db1b0f3d588774b8e82f2636f397b2456d15e7442781e6" + hash15 = "c27e328d2fe6fd75066938f58c3359c5dbb9deea166c6a4d3b0397d295a3e8d5" + hash16 = "df292a289d93136fbdd6ac0850b2c8845f967d9a9a3bd29a9386b39843b82eda" + hash17 = "e07a008aaf0a0a2666a705a9756da5bc54be18e2a53a50eb7539f1143548a57f" + hash18 = "0be1e96f318d98398861217a9754bc003e6861d84de8553cdbd87531db66e19b" + hash19 = "2d049876c256e55ae48a1060c32f8d75b691525cd877556172f163fe39466001" + hash20 = "3d8194b7853a1edbaa5d14b4b7a0323c5584b8a5c959efe830073e43d0b4418a" + hash21 = "576bce5c1d1143b0e532333a28d37c98d65b271d651dbce86360d3e80460733f" + hash22 = "b7c5895189c7f4e30984e2f0db703c2120909dccaa339e59795d3e732bca9340" + hash23 = "db23bf90a7f0c69c3501876243ca2fe29e9208864dfa6f2b5d0dac51061a3d86" + hash24 = "e1093d59bef8f260b0ca1ebe82c0635cc225e060b8d7296efe330ca7837e6d44" + hash25 = "e29d1c2cbd64d0f1433602f2b63cf40e33b4376ac613e911a2160b268496164d" + hash26 = "e6523f691d0b4a16cc1892ec4eb3ee113d62443317e337412b70e0cea3e106f7" + hash27 = "ec9387b582e5a935094c6d165741d2c989e72afc3c6063a29e96153e97a74af3" + hash28 = "ed2eaf4c44f83c7920b2d73cbe242b82cc92e3188d04b1bb8742783c49487da7" + strings: + $s1 = "/20x/x58/x4b/x49/x57/x44/x49/x4a/x22/x20/x22/x64/x39/x63/x39/x29/x4d/x20/x29/x57/x5f/x22/x21/x5f/x2b/x20/x51/x53/x4d/x45/x4d/x44" ascii + $s2 = "/73x/6ax/x4a/x4b/x4d/x44/x20/x44/x57/x29/x5f/x20/x44/x57/x49/x4f/x57/x20/x57/x4f/x4b/x3c/x20/x57/x44/x4b/x20/x44/x29/x5f/x41/" fullword ascii + $s3 = "/20x/x58/x4b/x49/x57/x44/x49/x4a/x22/x20/x22/x64/x39/x63/x39/x29/x4d/x20/x29/x57/x5f/x22/x21/x5f/x2b/x20/x51/x53/x4d/x45/x4d/x44" ascii + $s4 = "/x4d/x20/x29/x28/x28/x22/x29/x45/x4f/x4b/x58/x50/x7b/x20/x5f/x57/x44/x44/x57/x44/" fullword ascii + $s5 = "/x71/x3b/x38/x38/x20/x43/x57/x29/x57/x22/x29/x64/x32/x20/x4b/x58/x4b/x4b/x4c/x22/x44/x20/x2d/x44/x5f/" fullword ascii + $s6 = "UDPBYPASS" fullword ascii + $s7 = "Is a named type file" fullword ascii + $s8 = "Structure needs cleaning" fullword ascii + $s9 = "No XENIX semaphores available" fullword ascii + condition: + uint16(0) == 0x457f and filesize < 600KB and 5 of them +} + +rule Gafgyt_July_6 { + meta: + description = "Detect the risk of Botnet Malware Gafgyt Rule 3" + author = "LightDefender" + date = "2021-07-06" + hash1 = "821d34f7978fc65fe3b570e86cce45edc921a6cbf02b127fb1263a8448a1f62a" + strings: + $s1 = "infected.log" fullword ascii + $s2 = "Samael-DDoS-Attack" fullword ascii + $s3 = "B0TK1LL" fullword ascii + $s4 = "This Device Has Been Infected by Samael Botnet Made By ur0a :)" ascii + condition: + uint16(0) == 0x457f and filesize < 600KB and 2 of them +} + +rule elf_bashlite_auto { + + meta: + description = "Detect the risk of Botnet Malware Gafgyt Rule 4" + strings: + $sequence_0 = { 21d0 3345fc c9 c3 55 } + // n = 5, score = 300 + // 21d0 | mov dword ptr [ebp - 4], 0 + // 3345fc | mov edi, 0x512c00 + // c9 | inc esp + // c3 | mov edi, esp + // 55 | mov edi, 0x512c00 + + $sequence_1 = { e8???????? 89c2 89d0 c1e81f } + // n = 4, score = 300 + // e8???????? | + // 89c2 | mov byte ptr [ebx], 0 + // 89d0 | sub eax, edx + // c1e81f | cmp eax, dword ptr [esp + 0x7c] + + $sequence_2 = { e8???????? 8945ec 837dec00 750b 8b45ec } + // n = 5, score = 300 + // e8???????? | + // 8945ec | je 0xffffff7c + // 837dec00 | mov al, byte ptr [ebp - 0xf] + // 750b | cmp al, 0xc0 + // 8b45ec | mov al, byte ptr [ebp - 0xd] + + $sequence_3 = { f7d0 21d0 3345fc c9 } + // n = 4, score = 300 + // f7d0 | mov ecx, eax + // 21d0 | dec eax + // 3345fc | mov edx, dword ptr [ebp - 0x40] + // c9 | mov edi, 0x800 + + $sequence_4 = { 750c e8???????? 8b00 83f804 } + // n = 4, score = 300 + // 750c | cmp al, 0xfc + // e8???????? | + // 8b00 | jne 0x18a + // 83f804 | dec eax + + $sequence_5 = { eb0a c785ecefffff00000000 8b85ecefffff c9 c3 } + // n = 5, score = 300 + // eb0a | mov eax, dword ptr [eax] + // c785ecefffff00000000 | mov dword ptr [ebp - 0x108], eax + // 8b85ecefffff | mov dword ptr [ebp - 0x10c], 0x8056e9e + // c9 | mov dword ptr [ebp - 0x110], 5 + // c3 | mov eax, dword ptr [ebp + 0xc] + + $sequence_6 = { 8b85ecefffff c9 c3 55 } + // n = 4, score = 300 + // 8b85ecefffff | add eax, 0x41 + // c9 | mov byte ptr [ebx], al + // c3 | mov dword ptr [ebp - 0x1c], edx + // 55 | mov eax, dword ptr [ebp - 0x20] + + $sequence_7 = { c1f802 89c2 89d0 01c0 01d0 } + // n = 5, score = 300 + // c1f802 | mov dword ptr [ebp - 0x88], eax + // 89c2 | jmp 0x159 + // 89d0 | mov dword ptr [esp], eax + // 01c0 | mov ecx, eax + // 01d0 | or ecx, 0x800 + + $sequence_8 = { 85c0 750c c785ecefffff01000000 eb0a c785ecefffff00000000 8b85ecefffff } + // n = 6, score = 300 + // 85c0 | mov dword ptr [ebp - 0x4c], edx + // 750c | dec eax + // c785ecefffff01000000 | mov edi, dword ptr [ebp - 0x18] + // eb0a | mov ecx, dword ptr [ebp - 0x38] + // c785ecefffff00000000 | mov edx, dword ptr [ebp - 0x3c] + // 8b85ecefffff | add dword ptr [ebp - 0x34], eax + + $sequence_9 = { 21d0 3345fc c9 c3 } + // n = 4, score = 300 + // 21d0 | mov eax, dword ptr [ebp - 0x1c] + // 3345fc | mov word ptr [eax + 0xa], dx + // c9 | mov dword ptr [esp], 0 + // c3 | movzx edx, ax + + condition: + 7 of them and filesize < 274018 +} + + +rule Gafgyt_Botnet_generic : MALW +{ +meta: + description = "Detect the risk of Botnet Malware Gafgyt Rule 5" + MD5 = "e3fac853203c3f1692af0101eaad87f1" + SHA1 = "710781e62d49419a3a73624f4a914b2ad1684c6a" + +strings: + $etcTZ = "/bin/busybox;echo -e 'gayfgt'" + $s2 = "/proc/net/route" + $s3 = "admin" + $s4 = "root" + +condition: + $etcTZ and $s2 and $s3 and $s4 +} + +rule Gafgyt_Botnet_oh : MALW +{ +meta: + description = "Detect the risk of Botnet Malware Gafgyt Rule 6" + MD5 = "97f5edac312de349495cb4afd119d2a5" + SHA1 = "916a51f2139f11e8be6247418dca6c41591f4557" + + strings: + $s1 = "busyboxterrorist" + $s2 = "BOGOMIPS" + $s3 = "124.105.97.%d" + $s4 = "fucknet" + condition: + $s1 and $s2 and $s3 and $s4 +} + +rule Gafgyt_Botnet_bash : MALW +{ +meta: + description = "Detect the risk of Botnet Malware Gafgyt Rule 7" + MD5 = "c8d58acfe524a09d4df7ffbe4a43c429" + SHA1 = "b41fefa8470f3b3657594af18d2ea4f6ac4d567f" + + strings: + $s1 = "PONG!" + $s2 = "GETLOCALIP" + $s3 = "HTTPFLOOD" + $s4 = "LUCKYLILDUDE" + condition: + $s1 and $s2 and $s3 and $s4 +} + +rule Gafgyt_Botnet_hoho : MALW +{ +meta: + description = "Detect the risk of Botnet Malware Gafgyt Rule 8" + MD5 = "369c7c66224b343f624803d595aa1e09" + SHA1 = "54519d2c124cb536ed0ddad5683440293d90934f" + + strings: + $s1 = "PING" + $s2 = "PRIVMSG" + $s3 = "Remote IRC Bot" + $s4 = "23.95.43.182" + condition: + $s1 and $s2 and $s3 and $s4 +} + +rule Gafgyt_Botnet_jackmy : MALW +{ +meta: + description = "Detect the risk of Botnet Malware Gafgyt Rule 9" + MD5 = "419b8a10a3ac200e7e8a0c141b8abfba" + SHA1 = "5433a5768c5d22dabc4d133c8a1d192d525939d5" + + strings: + $s1 = "PING" + $s2 = "PONG" + $s3 = "jackmy" + $s4 = "203.134.%d.%d" + condition: + $s1 and $s2 and $s3 and $s4 +} + +rule Gafgyt_Botnet_HIHI: MALW +{ +meta: + description = "Detect the risk of Botnet Malware Gafgyt Rule 10" + MD5 = "cc99e8dd2067fd5702a4716164865c8a" + SHA1 = "b9b316c1cc9f7a1bf8c70400861de08d95716e49" + + strings: + $s1 = "PING" + $s2 = "PONG" + $s3 = "TELNET LOGIN CRACKED - %s:%s:%s" + $s4 = "ADVANCEDBOT" + $s5 = "46.166.185.92" + $s6 = "LOLNOGTFO" + + condition: + $s1 and $s2 and $s3 and $s4 and $s5 and $s6 +} diff --git a/yaraRules/Botnet.Kelihos.yar b/yaraRules/Botnet.Kelihos.yar new file mode 100644 index 0000000..cb50c92 --- /dev/null +++ b/yaraRules/Botnet.Kelihos.yar @@ -0,0 +1,24 @@ +import "pe" + +rule KelihosHlux +{ +meta: + description = "Detect the risk of Botnet Malware Kelihos Rule 1" + strings: + $KelihosHlux_HexString = { 73 20 7D 8B FE 95 E4 12 4F 3F 99 3F 6E C8 28 26 C2 41 D9 8F C1 6A 72 A6 CE 36 0F 73 DD 2A 72 B0 CC D1 07 8B 2B 98 73 0E 7E 8C 07 DC 6C 71 63 F4 23 27 DD 17 56 AE AB 1E 30 52 E7 54 51 F7 20 ED C7 2D 4B 72 E0 77 8E B4 D2 A8 0D 8D 6A 64 F9 B7 7B 08 70 8D EF F3 9A 77 F6 0D 88 3A 8F BB C8 89 F5 F8 39 36 BA 0E CB 38 40 BF 39 73 F4 01 DC C1 17 BF C1 76 F6 84 8F BD 87 76 BC 7F 85 41 81 BD C6 3F BC 39 BD C0 89 47 3E 92 BD 80 60 9D 89 15 6A C6 B9 89 37 C4 FF 00 3D 45 38 09 CD 29 00 90 BB B6 38 FD 28 9C 01 39 0E F9 30 A9 66 6B 19 C9 F8 4C 3E B1 C7 CB 1B C9 3A 87 3E 8E 74 E7 71 D1 } + condition: + $KelihosHlux_HexString +} + +rule kelihos_botnet_pdb { +meta: + description = "Detect the risk of Botnet Malware Kelihos Rule 2" + hash = "f0a6d09b5f6dbe93a4cf02e120a846073da2afb09604b7c9c12b2e162dfe7090" +strings: + $pdb = "\\Only\\Must\\Not\\And.pdb" + $pdb1 = "\\To\\Access\\Do.pdb" +condition: + uint16(0) == 0x5a4d and + filesize < 1440KB and + any of them +} \ No newline at end of file diff --git a/yaraRules/Botnet.Mykings.yar b/yaraRules/Botnet.Mykings.yar new file mode 100644 index 0000000..c359c8f --- /dev/null +++ b/yaraRules/Botnet.Mykings.yar @@ -0,0 +1,27 @@ +rule vbs_mykings_botnet { + meta: + description = "Detect the risk of Botnet Malware Mykings Rule 1" + strings: + $s1 = "fso.DeleteFile(WScript.ScriptFullName)" fullword ascii + $s2 = "Set ws = CreateObject(\"Wscript.Shell\")" fullword ascii + $s3 = "Set fso = CreateObject(\"Scripting.Filesystemobject\")" fullword ascii + $r = /Windows\\ime|web|inf|\\c[0-9].bat/ + condition: + uint16(0) == 0x6553 and + filesize < 1KB + and any of ($s*) and + $r +} + +rule shellcode_mykins_botnet +{ + meta: + description = "Detect the risk of Botnet Malware Mykings Rule 1" + strings: + $a = { 4883EC28E847000000488D0DF0FFFFFF488D1539000000482BCA4803C14883C428C3CCCC488D05D5FFFFFF482BC8488BC1C3CCCC4883EC28E83F0D000033C04883C428C3CCCCCCCCCCCCCCCCCCCCCCCCE8000000005848B95510004001000000482BC148B950100040010000004803C1C3CCCCCC48897C24084C8BC94D85C0740C488BF9480FBEC2498BC8F3AA488B7C2408498BC1C3CCCC40534883EC20488BD9E85AFFFFFF488D0D53FFFFFF482BD94803C34883C4205BC3CCCCCC33D28BC2EB06FFC04883C10266391175F5F3C3CC668339004C8BC1740B4983C002664183380075F54C2BC20FB70266418904104883C2026685C075EF488BC1C34C8BC14C2BC20FB70266418904104883C2026685C075EF488BC1C3CC4C8BC14C2BC28A024188041048FFC284C075F3488BC1C3CC8039004C8BC1740949FFC04180380075F74C2BC28A024188041048FFC284C075F3488BC1C3CCCCCC48895C24084533D2458BCA4585C07E320FB702663901741A0FB719440FB7D88BC3412BC383F8207409442BDB4183FB20751041FFC14883C1024883C202453BC87CCE488B5C2408453BC8410F95C2418BC2C3CCCC4533C948895108458BC16644390A740D41FFC04963C06644390C4275F3664503C066448901664183C0026644894102C34883EC3833C04C8BD233D248895424228954242A668954242E66894424204885C9741A4D85D27415488BD1488D4C2420E89BFFFFFF488D4C242041FFD24883C438C3CCCC4883EC284863C14C8BCA4C8D44243833D233C94869C0F0D8FFFF488944243841FFD14883C428C3CC48895C241048897C241855488BEC4883EC604883651000488365C800488365D800488365E000488365F000488365F800498BD9498BF848894DC0488BC24C8D4DC04C8D45D0488D4D10BAFFFF1F00C745D030000000C745E840020000FFD0488B4D104885C9740DBA01000000FFD7488B4D10FFD34C8D5C2460498B5B18498B7B20498BE35DC3CCCC488BC44889580848896810565741544883EC308360D80083601800498BF18BEA4C8BE1498BD833FF4C8D4818488D50D88D4F054533C0FFD3894424208B44246085C0750733C0E9C20000008D14004533C033C9FFD6448B4424604C8D4C2460488BD0B9050000004503C0488BF0FFD38944242085C0740B33D2488BCEFF542470EBC28B4C246048B81986611886611886488BDE48F7E1482BCA48D1E94803CA48C1E908894C2460488B4B404885C9742E0FB743383BC57C262BC5992BC2D1F84C63C8781A8BC54A8D0C49992BC2498BD4D1F8448BC0E8AEFDFFFF85C0740B393B740B8B034803D8EBBE488B7B50488B4424784885C0740A4885FF7405488918EB0933D2488BCEFF542470488BC7488B5C2450488B6C24584883C430415C5F5EC3C20000CC4585C07410482BCA8A0288041148FFC241FFC875F3F3C3CC40534883EC20488BD9E8E6FBFFFF488D0DDFFBFFFF482BD94803C34883C4205BC3CCCCCC48895C2408488974241048897C24185541544155488BEC4883EC404863413C4C8BC1B90B020000488BF2C745E04D6D4765C745E474537973C745E874656D52C745EC6F757469C745F06E654164C745F46472657366C745F873006642394C00180F8584000000428B8400880000004533D24903C08B50208B58248B781C448B68184903D04903D84903F84585ED745B8B024533C94903C044380874234C8D5DE0488BC84C2BD8458A240B4584E47410443821750B48FFC149FFC180390075E741803C0100750842807C0DE000740E41FFC24883C204453BD57310EBB3420FB70C538B048F4903C0488906488B1E4885DB750883C8FFE9E1020000488D0D47340000E8D6FEFFFF488BD3488BC8E89BFCFFFF488D0D5034000048898690000000E8B8FEFFFF488B16488BC8E87DFCFFFF488D0D5A34000048898698000000E89AFEFFFF488B16488BC8E85FFCFFFF488D0D6C34000048894608E87FFEFFFF488B16488BC8E844FCFFFF488D0D8934000048894610E864FEFFFF488B16488BC8E829FCFFFF488D0D9E34000048894618E849FEFFFF488B16488BC8E80EFCFFFF488D0DAB34000048894620E82EFEFFFF488B16488BC8E8F3FBFFFF488D0DC834000048894628E813FEFFFF488B16488BC8E8D8FBFFFF488D0DE534000048894630E8F8FDFFFF488B16488BC8E8BDFBFFFF488D0D0235000048894638E8DDFDFFFF488B16488BC8E8A2FBFFFF488D0DF734000048894640E8C2FDFFFF488B16488BC8E887FBFFFF488D0DFC34000048894648E8A7FDFFFF488B16488BC8E86CFBFFFF488D0D0935000048894650E88CFDFFFF488B16488BC8E851FBFFFF488D0D0E35000048894658E871FDFFFF488BC8488B16E836FBFFFF488D0D2B35000048894660E856FDFFFF488B16488BC8E81BFBFFFF488D0D5035000048894668E83BFDFFFF488B16488BC8E800FBFFFF488D0D5D35000048894670E820FDFFFF488B16488BC8E8E5FAFFFF488D0D7235000048894678E805FDFFFF488B16488BC8E8CAFAFFFF488D0D8735000048898680000000E8E7FCFFFF488B16488BC8E8ACFAFFFF488D0D8935000048898688000000E8C9FCFFFF488B16488BC8E88EFAFFFF488D0D8B350000488986A0000000E8ABFCFFFF488B16488BC8E870FAFFFF488D0D95350000488986A8000000E88DFCFFFF488B16488BC8E852FAFFFF488D0DA7350000488986B0000000E86FFCFFFF488B16488BC8E834FAFFFF488D0DA1350000488986B8000000E851FCFFFF488B16488BC8E816FAFFFF488D0DA3350000488986C0000000E833FCFFFF488B16488BC8E8F8F9FFFF488D0DA5350000488986C8000000E815FCFFFF488B16488BC8E8DAF9FFFF488986D000000033C0488B5C2460488B742468488B7C24704883C440415D415C5DC348895C24085556574154415541564157488DAC2410FEFFFF4881ECF00200004533FF488BD9498BF8488BF2488D8DE100000041B80301000033D24C897C24504C897C24604C897C24704C897C24684C89BD480200004488BDE0000000E8EFF7FFFF488D4DC0C745C01C010000FF9688000000837DC40675488B45C885C0752780BDDA00000001754D83C8FF488B9C24300300004881C4F0020000415F415E415D415C5F5E5DC383F801742A83F802740583F80375D380BDDA000000017517EBC8837DC40A75C244397DC875BC80BDDA0000000175B3488BD7488BCBFF56384C393F74A541BD300000004C897C243041BE000000084C8D8D380200004C8D442478488D4C2460418D55DEBB00020000448974242848C785380200004729000044896C24784C897D80895D904C897D884C897D984C897DA0C744242040000000FF96900000004C397C24607509418D45CEE937FFFFFF895D90BB040000004C897C24304C8D8D380200004C8D442478488D4C24708D530241BC1F4C1000448974242844896C24784C897D804C897D884C89A5380200004C897D984C897DA0895C2420FF9690000000488B0F4C8D7708498BD64C8975B0FF5678488B4C2460C74424484000000044897C2440C744243802000000488D44245048894424304C8D85480200004533C94883CAFF4C897C242848C744242000200000FF9698000000488B4C2470895C244844897C2440C744243802000000488D44245048894424304C8D4424684533C94883CAFF4C897C24284C897C24504C89642420 } + + $b = { E800000000582D051040000500104000C3558BEC8B45082D001040005DC20400558BECFF7508E80A0A000033C05DC20400558BEC8B4D1085C9741F0FB6450C69C0010101018BD153578B7D08C1E902F3AB8BCA83E103F3AA5F5B8B45085DC3558BECE899FFFFFF8B4D0881E90010400003C15DC20400558BEC8B4D0833C066390174084066833C410075F85DC20400558BEC8B450866833800568BF0740983C60266833E0075F78B4D0C2BF10FB7116689140E83C1026685D275F15E5DC20800558BEC8B55088B450C2BD00FB70866890C0283C0026685C975F18B45085DC20800558BEC8B55088B450C2BD08A08880C024084C975F68B45085DC20800558BEC8B4508803800568BF0740646803E0075FA8B4D0C2BF18A1188140E4184D275F65E5DC20800558BEC5633F63975107E2D8B45088B4D0C0FB704700FB70C71663BC174148BD08BC18BCA2BC883F92074072BC283F8207506463B75107CD333C03B75105E0F95C05DC20C00558BEC8B450C8B550850894204E8FAFEFFFF03C066890283C002668942025DC20800558BEC51515733C0668945F88D7DFAAB33C966AB5F394D08741A394D0C7415FF75088D45F850E8B3FFFFFF8D45F850FF550C8BC88BC1C9C20800558BEC51518B45086AFF9968F0D8FFFF5250E8730A00008945F88D45F8506A006A008955FCFF550CC9C20800558BEC83EC248B4508568945F48D45F4508D45DC5033F668FFFF1F008D45FC508975FC8975F8C745DC180000008975E0C745E8400200008975E48975EC8975F0FF550C3975FC5E740E6A01FF75FCFF5510FF75FCFF5514C9C21000558BEC83EC0C538D45FC5033DB538D45F8506A05895DF8895DFCFF55108945F88B45FC3BC3750733C0E99E000000565303C05053FF55148BF08D45FC508B45FC03C050566A05897514FF55108945F83BC374095356FF551833C0EB6F8B45FC33D2B9F8000000F7F1578945FC8B7E3C3BFB742E0FB746383B450C7C252B450C992BC28BC8D1F978198B450C992BC2D1F850FF75088D044F50E83BFEFFFF85C0740A8B063BC3740903F0EBC18B7E44EB028BFB8B451C3BC374083BFB74048930EB0753FF7514FF55188BC75F5E5BC9C21800C21400558BEC837D100074178B4D088B450C2BC88A10FF4D1088140140837D100075F15DC20C00558BECE8B3FCFFFF8B4D0881E90010400003C15DC20400558BEC83EC2C538B5D088B433CB90B010000568B750CC745D44D6D4765C745D874537973C745DC74656D52C745E06F757469C745E46E654164C745E86472657366C745EC730066394C18180F858F0000008B44187803C38B501C8B482003D3578B78248B40188955F033D203CB03FB8955FC8945F485C07466EB038B5D088B149183650C0003D3803A0074238D5DD42BDA8BC2895DF8EB038B5DF88A1C0384DB740D38187509FF450C4080380075E98B450C803C10007507807C05D400740E8B55FC428955FC3B55F472B0EB128B45FC0FB704478B4DF08B048103450889065F8B0685C0750883C8FFE9230200005068D0414000E8F0FEFFFF50E831FDFFFFFF3689464868F0414000E8DBFEFFFF50E81CFDFFFFFF3689464C6818424000E8C6FEFFFF50E807FDFFFFFF368946046844424000E8B1FEFFFF50E8F2FCFFFFFF368946086878424000E89CFEFFFF50E8DDFCFFFFFF3689460C68A8424000E887FEFFFF50E8C8FCFFFFFF3689461068CC424000E872FEFFFF50E8B3FCFFFFFF368946146800434000E85DFEFFFF50E89EFCFFFFFF368946186834434000E848FEFFFF50E889FCFFFFFF3689461C686C434000E833FEFFFF50E874FCFFFFFF36894620687C434000E81EFEFFFF50E85FFCFFFFFF36894624689C434000E809FEFFFF50E84AFCFFFFFF3689462868C0434000E8F4FDFFFF50E835FCFFFFFF3689462C68DC434000E8DFFDFFFF50E820FCFFFFFF368946306810444000E8CAFDFFFF50E80BFCFFFFFF36894634684C444000E8B5FDFFFF50E8F6FBFFFFFF368946386874444000E8A0FDFFFF50E8E1FBFFFFFF3689463C68A0444000E88BFDFFFF50E8CCFBFFFFFF3689464068D0444000E876FDFFFF50E8B7FBFFFFFF3689464468EC444000E861FDFFFF50E8A2FBFFFFFF368946506808454000E84CFDFFFF50E88DFBFFFFFF368946546830454000E837FDFFFF50E878FBFFFFFF36894658685C454000E822FDFFFF50E863FBFFFFFF3689465C6870454000E80DFDFFFF50E84EFBFFFFFF368946606890454000E8F8FCFFFF50E839FBFFFFFF3689466468AC454000E8E3FCFFFF50E824FBFFFF89466833C05E5BC9C20800558BEC81EC5C020000535633DB5768030100008D85A5FDFFFF5350895DF8895DE8895DDC895DF4895DFC889DA4FDFFFFE889F9FFFF8B7D0C83C40C8D85A8FEFFFF50C785A8FEFFFF1C010000FF574483BDACFEFFFF05751283BDB0FEFFFF02743983BDB0FEFFFF01EB2E83BDACFEFFFF06750E399DB0FEFFFF7510807DC201751983C8FF5F5E5BC9C20C0083BDB0FEFFFF0175ED807DC20175E78B751056FF7508FF571C391E74D95368000000086A408D45EC508D45C4506A0E8D45E850C745EC47250000895DF0C745C418000000895DC8C745D000020000895DCC895DD4895DD8FF5748395DE875056AFE58EB955368000000086A048D45EC508D45C4506A068D45DCBE0B4C1000508975EC895DF0C745C418000000895DC8C745D000020000895DCC895DD4895DD8FF57488B45108D480451FF30894DE0FF573C6A40536A028D45F850536800200000538D45FC506AFFFF75E8FF574C6A04536A028D45F8505356538D45F4506AFFFF75DC895DF88975EC895DF0FF574C395DFC0F84330200008B75F43BF30F8428020000895E048B85B4FEFFFF8946108B85ACFEFFFF8946088B85B0FEFFFF89460C6A0C5889462C8946308B4510C7060C3C1000C7462830000000C746342C000000C7463818000000C7463CA80100008B401C894618895D0C6840464000E800F8FFFF8BC88B450C8A0C0180F10D888C05A4FDFFFF4089450C3D040100007CD98D8DA4FDFFFF8D46405150E855F8FFFF6844474000E8C9F7FFFF508D464050E85DF8FFFF8B45108B40283BC3742C8B4E1883F902750A8B40200504020000EB0D83F90375158B40200500010000508D860001000050E80BF8FFFFE825F7FFFFB9881C400081E90010400003C189450C33C9EB038B450C8A04088B55FC88040A4181F94825000072EB535353680C3C100056FF572C8BF03BF37460536A0156FF57386A1053536A015356FF57348B75108946203BC37447C680040200004E8B4620C68005020000538B4620C680060200002E8B4620C68007020000658B4620C68008020000788B4620C68009020000658B462088980A020000EB038B75108B46243BC30F8497000000895D083958040F868B000000895D0C8B46248B4D0C8B8401DC0000008D4D105150895D10FF5714395D107455FF7510FF57683B06754B536A3053FF57048945E43BC3743DE833F6FFFF53B91E13400081E90010400003C18B4DFC6A0183C12051535053FF7510FF75E4FF57245353FF75F4FF75E4FF5728FF770C6A01E8C1F7FFFFFF45088B46248B4D0883450C403B48040F8278FFFFFFFF75E0FF574033C0E9CFFCFFFFFF75E0FF57406AFDE92AFDFFFF558BEC81EC0C020000565733F66A688D8540FFFFFF565089B53CFFFFFFE8DAF5FFFF83C40C6A0A5933C06A0A8975A88D7DACF3AB5989B510FFFFFF8DBD14FFFFFFF3AB8D45A8898538FFFFFF8D853CFFFFFF50FF7508C745C401000000C7852CFFFFFF02000000E8BBF8FFFF85C00F8582010000538D85F4FDFFFF50C785F4FDFFFF1C010000FF5580BBEC45400083BDF8FDFFFF05750353EB0568D0454000E86CF8FFFF8D4DCC51FFB54CFFFFFFFFB540FFFFFFFFB544FFFFFF6A1850E856F7FFFFFFB548FFFFFF8BF83BFE750C68D0070000E8B9F6FFFFEBB46888130000E8ADF6FFFF8D45A8508D853CFFFFFF5057E849FBFFFF85C00F85F8000000EB10FFB548FFFFFF68D0070000E882F6FFFF8B45C883781C0175E783BDF8FDFFFF05750E6808464000E8E5F7FFFF6A16EB0C68D0454000E8D7F7FFFF6A18598D9534FFFFFF52FFB54CFFFFFFFFB540FFFFFFFFB544FFFFFF5150E8BCF6FFFF } + condition: + filesize < 1KB and + any of them +} \ No newline at end of file diff --git a/yaraRules/CoinMiner.CryptoELF.yar b/yaraRules/CoinMiner.CryptoELF.yar new file mode 100644 index 0000000..858ca57 --- /dev/null +++ b/yaraRules/CoinMiner.CryptoELF.yar @@ -0,0 +1,14 @@ +rule Rule_Coinminer_ELF_Format { + meta: + description = "Detect the risk of CoinMiner ELF Rule 1" + detail= "Detects Crypto Miner ELF format" + strings: + $str1 = "mining.set_difficulty" ascii + $str2 = "mining.notify" ascii + $str3 = "GhostRider" ascii + $str4 = "cn/turtle-lite" ascii + $str5 = "spend-secret-key" ascii + condition: + uint16(0) == 0x457f and + 4 of them +} diff --git a/yaraRules/CoinMiner.Monero.yar b/yaraRules/CoinMiner.Monero.yar new file mode 100644 index 0000000..7cca172 --- /dev/null +++ b/yaraRules/CoinMiner.Monero.yar @@ -0,0 +1,88 @@ +rule MINER_monero_mining_detection { + + meta: + description = "Detect the risk of CoinMiner Monero Rule 1" + detail= "Monero mining software" + strings: + $1 = "* COMMANDS: 'h' hashrate, 'p' pause, 'r' resume" fullword ascii + $2 = "--cpu-affinity set process affinity to CPU core(s), mask 0x3 for cores 0 and 1" fullword ascii + $3 = "* THREADS: %d, %s, av=%d, %sdonate=%d%%%s" fullword ascii + $4 = "--user-agent set custom user-agent string for pool" fullword ascii + $5 = "-O, --userpass=U:P username:password pair for mining server" fullword ascii + $6 = "--cpu-priority set process priority (0 idle, 2 normal to 5 highest)" fullword ascii + $7 = "-p, --pass=PASSWORD password for mining server" fullword ascii + $8 = "* VERSIONS: XMRig/%s libuv/%s%s" fullword ascii + $9 = "-k, --keepalive send keepalived for prevent timeout (need pool support)" fullword ascii + $10 = "--max-cpu-usage=N maximum CPU usage for automatic threads mode (default 75)" fullword ascii + $11 = "--nicehash enable nicehash/xmrig-proxy support" fullword ascii + $12 = "" fullword ascii + $13 = "* CPU: %s (%d) %sx64 %sAES-NI" fullword ascii + $14 = "-r, --retries=N number of times to retry before switch to backup server (default: 5)" fullword ascii + $15 = "-B, --background run the miner in the background" fullword ascii + $16 = "* API PORT: %d" fullword ascii + $17 = "--api-access-token=T access token for API" fullword ascii + $18 = "-t, --threads=N number of miner threads" fullword ascii + $19 = "--print-time=N print hashrate report every N seconds" fullword ascii + $20 = "-u, --user=USERNAME username for mining server" fullword ascii + + condition: + + ( uint16(0) == 0x5a4d and + filesize < 4000KB and + ( 8 of them )) or + ( all of them ) +} + +import "hash" + +rule xmrig_moneroocean_prebuild: elf mining xmrig +{ + meta: + description = "Detect the risk of CoinMiner Monero Rule 2" + condition: + hash.md5(0, filesize) == "5a818e75dff6adfe9f645cc49d6c0b70" +} + +rule setup_moneroocean_miner: bash mining xmrig +{ + meta: + description = "Detect the risk of CoinMiner Monero Rule 3" + strings: + $ = "MoneroOcean mining setup script" + $ = "setup_moneroocean_miner.sh " + $ = "TOTAL_CACHE=$(( $CPU_THREADS*$CPU_L1_CACHE + $CPU_SOCKETS" + $ = "$HOME/moneroocean/xmrig" + $ = "$LATEST_XMRIG_LINUX_RELEASE" + $ = "moneroocean_miner.service" + condition: + any of them or hash.md5(0, filesize) == "75363103bb838ca8e975d318977c06eb" +} + + +rule uninstall_moneroocean_miner: bash mining xmrig +{ + meta: + description = "Detect the risk of CoinMiner Monero Rule 4" + strings: + $default1 = "moneroocean" + $default2 = "mining uninstall script" + $s1 = "sudo systemctl stop" + $s2 = "sudo systemctl disable" + $s3 = "rm -f /etc/systemd/system/" + $s4 = "sudo systemctl daemon-reload" + condition: + ($default1 or $default2) and any of ($s*) or hash.md5(0, filesize) == "b059718f365d30a559afacf2d86bc379" +} + +rule moneroocean_miner_service: mining xmrig +{ + meta: + description = "Detect the risk of CoinMiner Monero Rule 5" + strings: + $default1 = "ExecStart=" + $default2 = "moneroocean" + $s1 = "[Service]" + $s2 = "[Unit]" + condition: + all of ($default*) and any of ($s*) +} \ No newline at end of file diff --git a/yaraRules/CoinMiner.Trojan.yar b/yaraRules/CoinMiner.Trojan.yar new file mode 100644 index 0000000..6e9fbe2 --- /dev/null +++ b/yaraRules/CoinMiner.Trojan.yar @@ -0,0 +1,138 @@ +import "pe" +rule CoinMiner01 { + meta: + description = "Detects the risk of CoinMiner Trojan rule 1" + detail = "Detects coinminer payload" + strings: + $s1 = "-o pool." ascii wide + $s2 = "--cpu-max-threads-hint" ascii wide + $s3 = "-P stratum" ascii wide + $s4 = "--farm-retries" ascii wide + $dl = "github.com/ethereum-mining/ethminer/releases/download" ascii wide + condition: + uint16(0) == 0x5a4d and (3 of ($s*) or ($dl)) +} + +rule win_coinminer_auto { + + meta: + description = "Detects the risk of CoinMiner Trojan rule 2" + strings: + $sequence_0 = { 56 85c0 7511 e8???????? 83c404 32c0 5e } + // n = 7, score = 100 + // 56 | push esi + // 85c0 | test eax, eax + // 7511 | jne 0x13 + // e8???????? | + // 83c404 | add esp, 4 + // 32c0 | xor al, al + // 5e | pop esi + + $sequence_1 = { e8???????? 8d8c24500b0000 8bf0 e8???????? } + // n = 4, score = 100 + // e8???????? | + // 8d8c24500b0000 | lea ecx, [esp + 0xb50] + // 8bf0 | mov esi, eax + // e8???????? | + + $sequence_2 = { 09c0 744a 8b5f04 48 8d8c3000700800 48 } + // n = 6, score = 100 + // 09c0 | or eax, eax + // 744a | je 0x4c + // 8b5f04 | mov ebx, dword ptr [edi + 4] + // 48 | dec eax + // 8d8c3000700800 | lea ecx, [eax + esi + 0x87000] + // 48 | dec eax + + $sequence_3 = { 8bf1 8b0d???????? 85ff 7527 85c9 7523 e8???????? } + // n = 7, score = 100 + // 8bf1 | mov esi, ecx + // 8b0d???????? | + // 85ff | test edi, edi + // 7527 | jne 0x29 + // 85c9 | test ecx, ecx + // 7523 | jne 0x25 + // e8???????? | + + $sequence_4 = { 8bcb e8???????? 57 ff15???????? 5f b001 5b } + // n = 7, score = 100 + // 8bcb | mov ecx, ebx + // e8???????? | + // 57 | push edi + // ff15???????? | + // 5f | pop edi + // b001 | mov al, 1 + // 5b | pop ebx + + $sequence_5 = { f30f6f05???????? 56 57 f30f7f442440 b920000000 be???????? f30f6f05???????? } + // n = 7, score = 100 + // f30f6f05???????? | + // 56 | push esi + // 57 | push edi + // f30f7f442440 | movdqu xmmword ptr [esp + 0x40], xmm0 + // b920000000 | mov ecx, 0x20 + // be???????? | + // f30f6f05???????? | + + $sequence_6 = { 756e 56 e8???????? 83c404 33c0 5f } + // n = 6, score = 100 + // 756e | jne 0x70 + // 56 | push esi + // e8???????? | + // 83c404 | add esp, 4 + // 33c0 | xor eax, eax + // 5f | pop edi + + $sequence_7 = { 6b45e430 8945e0 8d8098589000 8945e4 803800 8bc8 7435 } + // n = 7, score = 100 + // 6b45e430 | imul eax, dword ptr [ebp - 0x1c], 0x30 + // 8945e0 | mov dword ptr [ebp - 0x20], eax + // 8d8098589000 | lea eax, [eax + 0x905898] + // 8945e4 | mov dword ptr [ebp - 0x1c], eax + // 803800 | cmp byte ptr [eax], 0 + // 8bc8 | mov ecx, eax + // 7435 | je 0x37 + + $sequence_8 = { 7314 33c0 8974241c 85f6 } + // n = 4, score = 100 + // 7314 | jae 0x16 + // 33c0 | xor eax, eax + // 8974241c | mov dword ptr [esp + 0x1c], esi + // 85f6 | test esi, esi + + $sequence_9 = { 83c102 ebe2 8d8df8fdffff b8???????? 90 668b10 } + // n = 6, score = 100 + // 83c102 | add ecx, 2 + // ebe2 | jmp 0xffffffe4 + // 8d8df8fdffff | lea ecx, [ebp - 0x208] + // b8???????? | + // 90 | nop + // 668b10 | mov dx, word ptr [eax] + + condition: + 7 of them and filesize < 1523712 +} + +rule CoinMiner_imphash { + meta: + description = "Detects the risk of CoinMiner Trojan rule 3" + condition: + pe.imphash() == "563557d99523e4b1f8aab2eb9b79285e" +} + +rule Trojan_CoinMiner { + meta: + description = "Detects the risk of CoinMiner Trojan rule 4" + hash1 = "3bdac08131ba5138bcb5abaf781d6dc7421272ce926bc37fa27ca3eeddcec3c2" + hash2 = "d60766c4e6e77de0818e59f687810f54a4e08505561a6bcc93c4180adb0f67e7" + strings: + $seq0 = { df 75 ab 7b 80 bf 83 c1 48 b3 18 74 70 01 24 5c } + $seq1 = { 08 37 4e 6e 0f 50 0b 11 d0 98 0f a8 b8 27 47 4e } + $seq2 = { bf 17 5a 08 09 ab 80 2f a1 b0 b1 da 47 9f e1 61 } + $seq3 = { 53 36 34 b2 94 01 cc 05 8c 36 aa 8a 07 ff 06 1f } + $seq4 = { 25 30 ae c4 44 d1 97 82 a5 06 05 63 07 02 28 3a } + $seq5 = { 01 69 8e 1c 39 7b 11 56 38 0f 43 c8 5f a8 62 d0 } + condition: + ( uint16(0) == 0x5a4d and filesize < 5000KB and pe.imphash() == "e4290fa6afc89d56616f34ebbd0b1f2c" and 3 of ($seq*) + ) +} \ No newline at end of file diff --git a/yaraRules/CoinMiner.Wannamine.yar b/yaraRules/CoinMiner.Wannamine.yar new file mode 100644 index 0000000..3a9fff1 --- /dev/null +++ b/yaraRules/CoinMiner.Wannamine.yar @@ -0,0 +1,36 @@ +rule RULE_ETERNALBLUE_GENERIC_SHELLCODE +{ + meta: + description = "Detect the risk of Wannamine Rule 1" + detail = "Detecta una shellcode genérica de EternalBlue, con payload variable" + strings: + $sc = { 31 c0 40 0f 84 ?? ?? ?? ?? 60 e8 00 00 00 00 5b e8 23 00 00 00 b9 + 76 01 00 00 0f 32 8d 7b 39 39 } + condition: + all of them +} + +rule RULE_XMRIG +{ + meta: + description = "Detect the risk of Wannamine Rule 2" + detail = "Minero XMRig WannaMine" + strings: + $xmrig = "xmrig" + $randomx = "randomx" + condition: + uint16(0) == 0x5A4D and + all of them +} + +rule CoinMiner_WannaMine_Opcodes +{ + meta: + description = "Detect the risk of Wannamine Rule 3" + strings: + $s1 = {558BEC83EC10A05BE241008B550C8BCA} + $s2 = {8B45008954243C03D081FAA00500000F} + $s3 = {558BEC6AFF68786F410064A100000000} + condition: + uint16(0) == 0x5a4d and all of them + } \ No newline at end of file diff --git a/yaraRules/CoinMiner.givemexyz.yar b/yaraRules/CoinMiner.givemexyz.yar new file mode 100644 index 0000000..a6c7117 --- /dev/null +++ b/yaraRules/CoinMiner.givemexyz.yar @@ -0,0 +1,215 @@ +import "hash" +rule givemexyz_family_hash +{ + meta: + description ="Detect the risk of CoinMiner givemexyz Rule 1" + condition: + hash.sha256(0,filesize) =="599393e258d8ba7b8f8633e20c651868258827d3a43a4d0712125bc487eabf92" or + hash.sha256(0,filesize) =="2c356d4621626e3de5f268aea9e7736840bbfcdc02e15d2b3cda1050f4f50798" or + hash.sha256(0,filesize) =="2fc3be782b1803c6e1c17e386136e6b2fb7e5054e2a81eee8f866eeaa44beab1" or + hash.sha256(0,filesize) =="8a877dc7afbfb6701ac42630c2adafb9ef46e8942e5b17372f07c892a7bee1b3" or + hash.sha256(0,filesize) =="1225cc15a71886e5b11fca3dc3b4c4bcde39f4c7c9fbce6bad5e4d3ceee21b3a" or + hash.sha256(0,filesize) =="11547e36146e0b0956758d48faeb19d4db5e737dc942bc7498ed86a8010bdc8b" or + hash.sha256(0,filesize) =="86f57444e6f4a40378fd0959a54794c7384d04678f8c66dfb7801f3d0cfc0152" or + hash.sha256(0,filesize) =="86859ad5e3115893e5878e91168367d564c1eb937af0d1e4c29dd38fb9647362" or + hash.sha256(0,filesize) =="f8744257415d256512c8b2f3501be20a0a30e37357e71df3986e2918fd53ef5e" or + hash.sha256(0,filesize) =="b6154d25b3aa3098f2cee790f5de5a727fc3549865a7aa2196579fe39a86de09" or + hash.sha256(0,filesize) =="a5604893608cf08b7cbfb92d1cac20868808218b3cc453ca86da0abaeadc0537" or + hash.sha256(0,filesize) =="f994135b5285cc481f2bfc213395e81c656542d1b6b5f23551565d524f3cdb89" or + hash.sha256(0,filesize) =="ceb3a7a521dc830a603037c455ff61e8849235f74db3b5a482ad5dcf0a1cdbc5" +} + + +rule XmrigCnrigOptions: mining xmrig cnrig +{ + meta: + description ="Detect the risk of CoinMiner givemexyz Rule 2" + + strings: + $s1 = "--donate-level" ascii + $s2 = "--nicehash" ascii + $s3 = "--algo" ascii + $s4 = "--threads" ascii + $s5 = "--cpu-max-threads-hint" ascii + $x = "xmrig" ascii fullword + condition: + 3 of ($s*) and $x +} + +import "hash" + + + +// xmrig_md5_5_9_0 +private rule tar_gz_5_9_0 +{ + meta: + description = "xmrig-5.9.0-xenial-x64.tar.gz" + condition: + hash.md5(0, filesize) == "b63ead42823ae63c93ac401e38937323" +} + +private rule xmrig_5_9_0 +{ + meta: + description = "xmrig.elf" + condition: + hash.md5(0, filesize) == "d351de486d4bb4e80316e1524682c602" +} + +private rule xmrig_notls_5_9_0 +{ + meta: + description = "xmrig-notls.elf" + condition: + hash.md5(0, filesize) == "187ed1d112e4a9dff0241368f2868615" +} + + +rule xmrig_md5_5_9_0: mining md5 xmrig +{ + meta: + description ="Detect the risk of CoinMiner givemexyz Rule 3" + condition: + tar_gz_5_9_0 or xmrig_5_9_0 or xmrig_notls_5_9_0 +} + + + +// xmrig_md5_5_10_0 +private rule tar_gz_5_10_0 +{ + meta: + description = "xmrig-5.10.0-xenial-x64.tar.gz" + condition: + hash.md5(0, filesize) == "416079fd0c7b45307556198f3f67754d" +} + +private rule xmrig_5_10_0 +{ + meta: + description = "xmrig.elf" + condition: + hash.md5(0, filesize) == "3939395192972820ce2cf99db0c239d7" +} + +private rule xmrig_notls_5_10_0 +{ + meta: + description = "xmrig-notls.elf" + condition: + hash.md5(0, filesize) == "0456ef39240c75e0862b30419d4c6359" +} + + +rule xmrig_md5_5_10_0: mining md5 xmrig +{ + meta: + description ="Detect the risk of CoinMiner givemexyz Rule 4" + condition: + tar_gz_5_10_0 or xmrig_5_10_0 or xmrig_notls_5_10_0 +} + + + +// xmrig_md5_5_11_0 +private rule tar_gz_5_11_0 +{ + meta: + description = "xmrig-5.11.0-xenial-x64.tar.gz" + condition: + hash.md5(0, filesize) == "abf7feaf1e456c0fc6e8f1e40af9211c" +} + +private rule xmrig_5_11_0 +{ + meta: + description = "xmrig.elf" + condition: + hash.md5(0, filesize) == "56aec7d8d2aba5ba2b82930408f0b5d3" +} + +private rule xmrig_notls_5_11_0 +{ + meta: + description = "xmrig-notls.elf" + condition: + hash.md5(0, filesize) == "9a5c0a5d960b676ba4db535f71ee7cef" +} + + +rule xmrig_md5_5_11_0: mining md5 xmrig +{ + meta: + description ="Detect the risk of CoinMiner givemexyz Rule 5" + condition: + tar_gz_5_11_0 or xmrig_5_11_0 or xmrig_notls_5_11_0 +} + + + +// xmrig_md5_5_11_1 +private rule tar_gz_5_11_1 +{ + meta: + description = "xmrig-5.11.1-xenial-x64.tar.gz" + condition: + hash.md5(0, filesize) == "820022ba985b4d21637bf6d3d1e53001" +} + +private rule xmrig_5_11_1 +{ + meta: + description = "xmrig.elf" + condition: + hash.md5(0, filesize) == "0090962752b93454093239f770628006" +} + +private rule xmrig_notls_5_11_1 +{ + meta: + description = "xmrig-notls.elf" + condition: + hash.md5(0, filesize) == "54158be61b8011a10d1a94432ead208c" +} + + +rule xmrig_md5_5_11_1: mining md5 xmrig +{ + meta: + description ="Detect the risk of CoinMiner givemexyz Rule 6" + condition: + tar_gz_5_11_1 or xmrig_5_11_1 or xmrig_notls_5_11_1 +} + +rule xmrig_md5_samples_1: mining md5 xmrig +{ + meta: + description ="Detect the risk of CoinMiner givemexyz Rule 7" + condition: + hash.md5(0, filesize) == "6f2a2ff340fc1307b65174a3451f8c9a" +} + + +rule xmrig_md5_samples_2: mining md5 xmrig +{ + meta: + description ="Detect the risk of CoinMiner givemexyz Rule 8" + condition: + hash.md5(0, filesize) == "22a213bfd093c402312d75f5f471505e" +} + +rule XmrigConfig: json mining xmrig +{ + meta: + description ="Detect the risk of CoinMiner givemexyz Rule 9" + detail = "xmrig config.json" + strings: + $ = "\"worker-id\":" ascii + $ = "\"randomx\":" ascii + $ = "\"donate-level\":" ascii + $ = "\"rig-id\":" ascii + $ = "\"donate-over-proxy\":" ascii + condition: + 3 of them +} \ No newline at end of file diff --git a/yaraRules/Malicious.tools.yar b/yaraRules/Malicious.tools.yar new file mode 100644 index 0000000..efb9665 --- /dev/null +++ b/yaraRules/Malicious.tools.yar @@ -0,0 +1,2198 @@ +import "pe" +import "math" + +rule Mimikatz_Memory_Rule_1 { + meta: + description = "Detect the risk of Malware Mimikatz Rule 1" + strings: + $s1 = "sekurlsa::msv" fullword ascii + $s2 = "sekurlsa::wdigest" fullword ascii + $s4 = "sekurlsa::kerberos" fullword ascii + $s5 = "sekurlsa::tspkg" fullword ascii + $s6 = "sekurlsa::livessp" fullword ascii + $s7 = "sekurlsa::ssp" fullword ascii + $s8 = "sekurlsa::logonPasswords" fullword ascii + $s9 = "sekurlsa::process" fullword ascii + $s10 = "ekurlsa::minidump" fullword ascii + $s11 = "sekurlsa::pth" fullword ascii + $s12 = "sekurlsa::tickets" fullword ascii + $s13 = "sekurlsa::ekeys" fullword ascii + $s14 = "sekurlsa::dpapi" fullword ascii + $s15 = "sekurlsa::credman" fullword ascii + condition: + 1 of them +} + +rule Mimikatz_Memory_Rule_2 { + meta: + description = "Detect the risk of Malware Mimikatz Rule 2" + strings: + $s0 = "sekurlsa::" ascii + $x1 = "cryptprimitives.pdb" ascii + $x2 = "Now is t1O" ascii fullword + $x4 = "ALICE123" ascii + $x5 = "BOBBY456" ascii + condition: + $s0 and 2 of ($x*) +} + +rule mimikatz +{ + meta: + description = "Detect the risk of Malware Mimikatz Rule 3" + + strings: + $exe_x86_1 = { 89 71 04 89 [0-3] 30 8d 04 bd } + $exe_x86_2 = { 8b 4d e? 8b 45 f4 89 75 e? 89 01 85 ff 74 } + + $exe_x64_1 = { 33 ff 4? 89 37 4? 8b f3 45 85 c? 74} + $exe_x64_2 = { 4c 8b df 49 [0-3] c1 e3 04 48 [0-3] 8b cb 4c 03 [0-3] d8 } + + $sys_x86 = { a0 00 00 00 24 02 00 00 40 00 00 00 [0-4] b8 00 00 00 6c 02 00 00 40 00 00 00 } + $sys_x64 = { 88 01 00 00 3c 04 00 00 40 00 00 00 [0-4] e8 02 00 00 f8 02 00 00 40 00 00 00 } + + condition: + (all of ($exe_x86_*)) or (all of ($exe_x64_*)) + or (any of ($sys_*)) +} + +rule wce +{ + meta: + description = "Detect the risk of Malware Mimikatz Rule 4" + strings: + $hex_legacy = { 8b ff 55 8b ec 6a 00 ff 75 0c ff 75 08 e8 [0-3] 5d c2 08 00 } + $hex_x86 = { 8d 45 f0 50 8d 45 f8 50 8d 45 e8 50 6a 00 8d 45 fc 50 [0-8] 50 72 69 6d 61 72 79 00 } + $hex_x64 = { ff f3 48 83 ec 30 48 8b d9 48 8d 15 [0-16] 50 72 69 6d 61 72 79 00 } + condition: + any of them +} + +rule power_pe_injection +{ + meta: + description = "Detect the risk of Malware Mimikatz Rule 5" + strings: + $str_loadlib = "0x53, 0x48, 0x89, 0xe3, 0x48, 0x83, 0xec, 0x20, 0x66, 0x83, 0xe4, 0xc0, 0x48, 0xb9" + condition: + $str_loadlib +} + +rule Mimikatz_Logfile +{ + meta: + description = "Detect the risk of Malware Mimikatz Rule 6" + strings: + $s1 = "SID :" ascii fullword + $s2 = "* NTLM :" ascii fullword + $s3 = "Authentication Id :" ascii fullword + $s4 = "wdigest :" ascii fullword + condition: + all of them +} + +rule Mimikatz_Strings { + meta: + description = "Detect the risk of Malware Mimikatz Rule 7" + strings: + $x1 = "sekurlsa::logonpasswords" fullword wide ascii + $x2 = "List tickets in MIT/Heimdall ccache" fullword ascii wide + $x3 = "kuhl_m_kerberos_ptt_file ; LsaCallKerberosPackage %08x" fullword ascii wide + $x4 = "* Injecting ticket :" fullword wide ascii + $x5 = "mimidrv.sys" fullword wide ascii + $x6 = "Lists LM & NTLM credentials" fullword wide ascii + $x7 = "\\_ kerberos -" fullword wide ascii + $x8 = "* unknow :" fullword wide ascii + $x9 = "\\_ *Password replace ->" fullword wide ascii + $x10 = "KIWI_MSV1_0_PRIMARY_CREDENTIALS KO" ascii wide + $x11 = "\\\\.\\mimidrv" wide ascii + $x12 = "Switch to MINIDUMP :" fullword wide ascii + $x13 = "[masterkey] with password: %s (%s user)" fullword wide + $x14 = "Clear screen (doesn't work with redirections, like PsExec)" fullword wide + $x15 = "** Session key is NULL! It means allowtgtsessionkey is not set to 1 **" fullword wide + $x16 = "[masterkey] with DPAPI_SYSTEM (machine, then user): " fullword wide + condition: + ( + ( uint16(0) == 0x5a4d and 1 of ($x*) ) or + ( 3 of them ) + ) + and not pe.imphash() == "77eaeca738dd89410a432c6bd6459907" +} + +rule AppInitHook { + meta: + description = "Detect the risk of Malware Mimikatz Rule 8" + strings: + $s0 = "\\Release\\AppInitHook.pdb" ascii + $s1 = "AppInitHook.dll" fullword ascii + $s2 = "mimikatz.exe" fullword wide + $s3 = "]X86Instruction->OperandSize >= Operand->Length" fullword wide + $s4 = "mhook\\disasm-lib\\disasm.c" fullword wide + $s5 = "mhook\\disasm-lib\\disasm_x86.c" fullword wide + $s6 = "VoidFunc" fullword ascii + condition: + uint16(0) == 0x5a4d and filesize < 500KB and 4 of them +} + +rule HKTL_Mimikatz_SkeletonKey_in_memory_Aug20_1 { + meta: + description = "Detect the risk of Malware Mimikatz Rule 9" + strings: + $x1 = { 60 ba 4f ca c7 44 24 34 dc 46 6c 7a c7 44 24 38 + 03 3c 17 81 c7 44 24 3c 94 c0 3d f6 } + condition: + 1 of them +} + +rule HKTL_mimikatz_memssp_hookfn { + meta: + description = "Detect the risk of Malware Mimikatz Rule 10" + strings: + $xc1 = { 48 81 EC A8 00 00 00 C7 84 24 88 00 00 00 ?? ?? + ?? ?? C7 84 24 8C 00 00 00 ?? ?? ?? ?? C7 84 24 + 90 00 00 00 ?? ?? ?? 00 C7 84 24 80 00 00 00 61 + 00 00 00 C7 44 24 40 5B 00 25 00 C7 44 24 44 30 + 00 38 00 C7 44 24 48 78 00 3A 00 C7 44 24 4C 25 + 00 30 00 C7 44 24 50 38 00 78 00 C7 44 24 54 5D + 00 20 00 C7 44 24 58 25 00 77 00 C7 44 24 5C 5A + 00 5C 00 C7 44 24 60 25 00 77 00 C7 44 24 64 5A + 00 09 00 C7 44 24 68 25 00 77 00 C7 44 24 6C 5A + 00 0A 00 C7 44 24 70 00 00 00 00 48 8D 94 24 80 + 00 00 00 48 8D 8C 24 88 00 00 00 48 B8 A0 7D ?? + ?? ?? ?? 00 00 FF D0 } + condition: + $xc1 +} + +rule mimikatz_lsass_mdmp_file +{ + meta: + description = "Detect the risk of Malware Mimikatz Rule 11" + + strings: + $lsass = "System32\\lsass.exe" wide nocase + + condition: + (uint32(0) == 0x504d444d) and $lsass +} + +rule mimikatz_kirbi_ticket +{ + meta: + description = "Detect the risk of Malware Mimikatz Rule 12" + + strings: + $asn1 = { 76 82 ?? ?? 30 82 ?? ?? a0 03 02 01 05 a1 03 02 01 16 } + + condition: + $asn1 at 0 +} + +rule lsadump +{ + meta: + description = "Detect the risk of Malware Mimikatz Rule 13" + remarks = "LSA dump programe (bootkey/syskey) - pwdump and others" + strings: + $str_sam_inc = "\\Domains\\Account" ascii nocase + $str_sam_exc = "\\Domains\\Account\\Users\\Names\\" ascii nocase + $hex_api_call = {(41 b8 | 68) 00 00 00 02 [0-64] (68 | ba) ff 07 0f 00 } + $str_msv_lsa = { 4c 53 41 53 52 56 2e 44 4c 4c 00 [0-32] 6d 73 76 31 5f 30 2e 64 6c 6c 00 } + $hex_bkey = { 4b 53 53 4d [20-70] 05 00 01 00} + + condition: + ($str_sam_inc and not $str_sam_exc) or $hex_api_call or $str_msv_lsa or $hex_bkey +} + +rule mimilove { + meta: + description = "Detect the risk of Malware Mimikatz Rule 14" + strings: + $s1 = "$http://blog.gentilkiwi.com/mimikatz 0" fullword ascii + $s2 = "mimilove.exe" fullword wide + $s3 = " '## v ##' https://blog.gentilkiwi.com/mimikatz (oe.eo)" fullword wide + $s4 = "ERROR wmain ; OpenProcess (0x%08x)" fullword wide + $s5 = "ERROR mimilove_lsasrv ; kull_m_memory_copy / KIWI_MSV1_0_LOGON_SESSION_TABLE_50 (0x%08x)" fullword wide + $s6 = "ERROR mimilove_lsasrv ; LogonSessionTable is NULL" fullword wide + $s7 = "ERROR mimilove_kerberos ; kull_m_memory_copy / KERB_HASHPASSWORD_5 (0x%08x)" fullword wide + $s8 = "ERROR mimilove_kerberos ; kull_m_memory_copy / KIWI_KERBEROS_LOGON_SESSION_50 (0x%08x)" fullword wide + $s9 = "ERROR mimilove_kerberos ; KerbLogonSessionList is NULL" fullword wide + $s10 = "ERROR mimilove_kerberos ; kull_m_memory_copy / KIWI_KERBEROS_KEYS_LIST_5 (0x%08x)" fullword wide + $s11 = "ERROR kull_m_kernel_ioctl_handle ; DeviceIoControl (0x%08x) : 0x%08x" fullword wide + $s12 = "UndefinedLogonType" fullword wide + $s13 = "ERROR wmain ; GetVersionEx (0x%08x)" fullword wide + $s14 = "ERROR mimilove_lsasrv ; kull_m_memory_copy / KIWI_MSV1_0_PRIMARY_CREDENTIALS (0x%08x)" fullword wide + $s15 = "ERROR mimilove_lsasrv ; kull_m_memory_copy / KIWI_MSV1_0_CREDENTIALS (0x%08x)" fullword wide + $s16 = "KERBEROS Credentials (no tickets, sorry)" fullword wide + $s17 = "Copyright (c) 2007 - 2021 gentilkiwi (Benjamin DELPY)" fullword wide + $s18 = "benjamin@gentilkiwi.com0" fullword ascii + $s19 = " * Username : %wZ" fullword wide + $s20 = "http://subca.ocsp-certum.com01" fullword ascii + + $op0 = { 89 45 cc 6a 34 8d 45 cc 50 8d 45 c4 8d 4d 80 50 } + $op1 = { 89 45 b8 c7 45 bc f7 ff ff ff 89 5d d4 89 5d f4 } + $op2 = { 89 45 d4 c7 45 d8 f8 ff ff ff 89 7d f0 89 7d f4 } + condition: + uint16(0) == 0x5a4d and filesize < 100KB and + ( 8 of them and all of ($op*) ) +} + +rule mimi_anti { + meta: + description = "Detect the risk of Malware Mimikatz Rule 15" + strings: + $s1 = "curity>true" fullword ascii + $s4 = "Copyright (c) 2007 - 2020 bIJ9xgPw5o (eTZHxXXY 52DdH)" fullword wide + $s5 = "GcircTRv" fullword ascii + $s6 = "acossqrt" fullword ascii + $s7 = "baagqqq" fullword ascii + $s8 = "nnmdjjj" fullword ascii + $s9 = "jklmnop" fullword ascii + $s10 = "onoffalsey" fullword ascii + $s11 = "NCKeyD`true" fullword ascii + $s13 = "mimikatz" fullword wide + $s14 = "Copyright (c) 2007 - 2019 gentilkiwi (Benjamin DELPY)" fullword wide + $s15 = "mimikatz for Windows" fullword wide + $s16 = "U:\"QS6" fullword ascii + $s17 = "fjN.TRl" fullword ascii + $s18 = "^f:\"Oh" fullword ascii + $s19 = "QZ0S.aLe" fullword ascii + $s20 = "3%i:^3" fullword ascii + condition: + uint16(0) == 0x5a4d and filesize < 18000KB and 8 of them +} + +rule mimi_anti2 { + meta: + description = "Detect the risk of Malware Mimikatz Rule 17" + strings: + $s1 = "mimikatz.exe" fullword wide + $s2 = "curity>true" fullword ascii + $s6 = "mimikatz" fullword wide + $s7 = "Copyright (c) 2007 - 2019 gentilkiwi (Benjamin DELPY)" fullword wide + $s8 = "msncucx" fullword ascii + $s9 = "ashcjsm" fullword ascii + $s10 = "lsmcpst" fullword ascii + $s11 = "iRNG9+ >" fullword ascii + $s12 = "mzhn9+ " fullword ascii + $s13 = "mimikatz for Windows" fullword wide + $s14 = "yDT:\\pE" fullword ascii + $s15 = "RiRC 512 and + math.entropy(pe.sections[pe.section_index(".data")].raw_data_offset, 512 ) >= 7 +} + +private rule cobaltstrike_beacon_raw +{ + strings: + $s1 = "%d is an x64 process (can't inject x86 content)" fullword + $s2 = "Failed to impersonate logged on user %d (%u)" fullword + $s3 = "powershell -nop -exec bypass -EncodedCommand \"%s\"" fullword + $s4 = "IEX (New-Object Net.Webclient).DownloadString('http://127.0.0.1:%u/'); %s" fullword + $s5 = "could not run command (w/ token) because of its length of %d bytes!" fullword + $s6 = "could not write to process memory: %d" fullword + $s7 = "%s.4%08x%08x%08x%08x%08x.%08x%08x%08x%08x%08x%08x%08x.%08x%08x%08x%08x%08x%08x%08x.%08x%08x%08x%08x%08x%08x%08x.%x%x.%s" fullword + $s8 = "Could not connect to pipe (%s): %d" fullword + + $b1 = "beacon.dll" fullword + $b2 = "beacon.x86.dll" fullword + $b3 = "beacon.x64.dll" fullword + + condition: + uint16(0) == 0x5a4d and + filesize < 1000KB and + ( + any of ($b*) or + 5 of ($s*) + ) +} + +private rule cobaltstrike_beacon_exe +{ + condition: + cobaltstrike_template_exe and + filesize > 100KB and filesize < 500KB and + pe.sections[pe.section_index(".data")].raw_data_size > 200000 and + math.entropy(pe.sections[pe.section_index(".data")].raw_data_offset + 1024, 150000 ) >= 7 +} + +private rule cobaltstrike_beacon_b64 +{ + strings: + $s1a = "JWQgaXMgYW4geDY0IHByb2Nlc3MgKGNhbid0IGluam" + $s1b = "ZCBpcyBhbiB4NjQgcHJvY2VzcyAoY2FuJ3QgaW5qZW" + $s1c = "IGlzIGFuIHg2NCBwcm9jZXNzIChjYW4ndCBpbmplY3" + + $s2a = "RmFpbGVkIHRvIGltcGVyc29uYXRlIGxvZ2dlZCBvbi" + $s2b = "YWlsZWQgdG8gaW1wZXJzb25hdGUgbG9nZ2VkIG9uIH" + $s2c = "aWxlZCB0byBpbXBlcnNvbmF0ZSBsb2dnZWQgb24gdX" + + $s3a = "cG93ZXJzaGVsbCAtbm9wIC1leGVjIGJ5cGFzcyAtRW" + $s3b = "b3dlcnNoZWxsIC1ub3AgLWV4ZWMgYnlwYXNzIC1Fbm" + $s3c = "d2Vyc2hlbGwgLW5vcCAtZXhlYyBieXBhc3MgLUVuY2" + + $s4a = "SUVYIChOZXctT2JqZWN0IE5ldC5XZWJjbGllbnQpLk" + $s4b = "RVggKE5ldy1PYmplY3QgTmV0LldlYmNsaWVudCkuRG" + $s4c = "WCAoTmV3LU9iamVjdCBOZXQuV2ViY2xpZW50KS5Eb3" + + condition: + filesize < 1000KB and + 5 of ($s*) +} + +rule hacktool_windows_cobaltstrike_beacon +{ + meta: + description = "Detect the risk of Malware Cobalt Strike Rule 2" + condition: + cobaltstrike_beacon_b64 or + cobaltstrike_beacon_raw or + cobaltstrike_beacon_exe +} + +rule hacktool_windows_cobaltstrike_postexploitation +{ + meta: + description = "Detect the risk of Malware Cobalt Strike Rule 3" + strings: + $s1 = "\\devcenter\\aggressor\\external\\" + + condition: + filesize > 10KB and filesize < 1000KB and + all of ($s*) +} + +rule hacktool_windows_cobaltstrike_powershell +{ + meta: + description = "Detect the risk of Malware Cobalt Strike Rule 4" + strings: + $ps1 = "Set-StrictMode -Version 2" + $ps2 = "func_get_proc_address" + $ps3 = "func_get_delegate_type" + $ps4 = "FromBase64String" + $ps5 = "VirtualAlloc" + $ps6 = "var_code" + $ps7 = "var_buffer" + $ps8 = "var_hthread" + + condition: + $ps1 at 0 and + filesize < 1000KB and + 7 of ($ps*) +} + +rule beacon32 +{ + meta: + description = "Detect the risk of Malware Cobalt Strike Rule 5" + strings: + $name = "%c%c%c%c%c%c%c%c%cMSSE-%d-server" + condition: + uint16(0) == 0x5A4D and pe.entry_point == 0x8b0 and filesize > 277KB and filesize < 304KB and $name +} + + +rule ps +{ + meta: + description = "Detect the risk of Malware Cobalt Strike Rule 6" + strings: + $str1 = "$var_va.Invoke([IntPtr]::Zero, $var_code.Length, 0x3000, 0x40)" + $str2 = "[System.Runtime.InteropServices.Marshal]::Copy($var_code, 0, $var_buffer, $var_code.length)" + condition: + uint16(0) != 0x5A4D and $str1 and $str2 +} + +rule CobaltStrike_hta_pe +{ + meta: + description = "Detect the risk of Malware Cobalt Strike Rule 7" + strings: + $reg1 = /var_tempexe = var_basedir & \"\\\" & \"[A-z]{1,20}.exe\"\s*Set var_stream = var_obj.CreateTextFile\(var_tempexe, true , false\)/ + condition: + uint16(0) != 0x5A4D and $reg1 +} + +rule hta_VBS +{ + meta: + description = "Detect the risk of Malware Cobalt Strike Rule 8" + strings: + $str = "myAr\"&\"ray \"&Chr(61)&\" Array\"&Chr(40)&Chr(45)&\"4\"&Chr(44)&Chr(45)&\"24\"&Chr(44)&Chr(45)&\"119\"&Chr(44)" + condition: + uint16(0) != 0x5A4D and $str +} + + +rule hta_ps1 +{ + meta: + description = "Detect the risk of Malware Cobalt Strike Rule 9" + strings: + $str = "var_shell.run \"powershell -nop -w hidden -encodedcommand JABzAD0ATgBlAHcALQBPAGIAagBlAGMAdAAgAEkATwAuAE0AZQBtAG8A" + condition: + uint16(0) != 0x5A4D and $str +} + +rule hacktool_windows_cobaltstrike_powershell_2 +{ + meta: + description = "Detect the risk of Malware Cobalt Strike Rule 10" + strings: + $ps1 = "'System.dll'" ascii + $ps2 = "Set-StrictMode -Version 2" ascii + $ps3 = "GetProcAddress" ascii + $ps4 = "start-job" ascii + $ps5 = "VirtualAlloc" ascii + condition: + $ps2 at 0 and + filesize < 1000KB and + all of ($ps*) +} + +rule hacktool_windows_cobaltstrike_in_memory +{ + meta: + description = "Detect the risk of Malware Cobalt Strike Rule 11" + strings: + $s1 = "IEX (New-Object Net.Webclient).DownloadString('http://127.0.0.1:%u/'); %s" + $s2 = "powershell -nop -exec bypass -EncodedCommand \"%s\"" + $s3 = "%d is an x86 process (can't inject x64 content)" + $s4 = "%d.%d %s %s %s %s" + $s5 = "could not upload file: %d" + $s7 = "KVK...................................0.-.n" + $s8 = "%d is an x64 process (can't inject x86 content)" + $op1 = {C7 45 F0 0? 00 00 00 E9 BF A3 BC FF} + condition: + 6 of them +} + +rule cobaltstrike_beacon_in_memory +{ + meta: + description = "Detect the risk of Malware Cobalt Strike Rule 12" + strings: + $s1 = "beacon.x64.dll" fullword + $s2 = "F %I64d %02d/%02d/%02d %02d:%02d:%02d %s" fullword + condition: + all of them +} + +rule APT_CobaltStrike_Beacon_Indicator { + meta: + description = "Detect the risk of Malware Cobalt Strike Rule 13" + strings: + $v1 = { 73 70 72 6E 67 00 } + $v2 = { 69 69 69 69 69 69 69 69 } + condition: + uint16(0) == 0x5a4d and filesize < 300KB and all of them +} +rule CobaltStrike_ShellCode +{ + meta: + description = "Detect the risk of Malware Cobalt Strike Rule 14" + strings: + $ = {8B 58 24 01 D3 66 8B 0C 4B 8B 58 1C 01 D3 8B 04 8B} + $ = {68 6E 65 74 00 68 77 69 6E 69 54 68 4C 77 26 07 FF D5} + condition: + any of them +} + +rule CobaltStrike_Payload +{ + meta: + description ="Detect the risk of Malware Cobalt Strike Rule 15" + strings: + $ = "%c%c%c%c%c%c%c%c%cMSSE-%d-server" fullword ascii + $ = {B9 AA 26 00 00 31 D2 C7 44 24 28 5C 00 00 00 C7 44 24 24 65 00 00 00 C7 44 24 20 70 00 00 00 C7 44 24 1C 69 00 00 00 C7 44 24 18 70 00 00 00 F7 F1 C7 44 24 14 5C 00 00 00 C7 44 24 10 2E 00 00 00 C7 44 24 0C 5C 00 00 00 C7 44 24 08 5C 00 00 00 C7 44 24 04 44 40 40 00 C7 04 24 F0 53 40 00 89 54 24} + condition: + any of them +} + +rule CobaltStrike_Malicious_HTA { + meta: + description = "Detect the risk of Malware Cobalt Strike Rule 16" + strings: + $var_shell = "CreateObject(\"Wscript.Shell\")" nocase + $RunPowerShell = "powershell -nop -w hidden -encodedcommand " nocase + $DropFile = ".Write Chr(CLng(\"&H\" & Mid(" nocase + $Obfuscator = "&\"Long\"&Chr(44)&" nocase + $Script = "