diff --git a/README.md b/README.md index 88f52ab..4dbd9aa 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,10 @@ This is a **'free time'** project, for study propose only. [![https://travis-ci.com/github/pyperanger/gorootcheck](https://api.travis-ci.com/pyperanger/gorootcheck.svg?branch=master&status=passed)](https://travis-ci.com/github/pyperanger/gorootcheck)
Standalone rootcheck by **OSSEC** wrtitten in Go -2020-04-05 | v0.5.0 - Some false positives(**rootkit_files.txt**) and bugs +#### 2020-04-05 | v0.6.0 +- Some false positives(**rootkit_files.txt**) and bugs persist +- Improve performance in general + ### Install ``` diff --git a/internal/gorootcheck/args.go b/internal/gorootcheck/args.go index b53bcbb..89b110f 100644 --- a/internal/gorootcheck/args.go +++ b/internal/gorootcheck/args.go @@ -2,6 +2,7 @@ package gorootcheck import ( "flag" + "os" "fmt" ) @@ -10,7 +11,7 @@ var ( version = flag.Bool("version", false, "Show version") debug = flag.Bool("v", false, "Debug mode") help = flag.Bool("h", false, "This massage") - VERSION = "0.5.0" + VERSION = "0.6.0" ) func argsUsage() { @@ -21,6 +22,10 @@ v` + VERSION + ` - github.com/pyperanger/gorootcheck func Args() bool { argsUsage() + if os.Getuid() != 0 { + fmt.Println("- Run gorootcheck as root") + bye() + } flag.Parse() if *help { flag.Usage() diff --git a/internal/gorootcheck/hiddenport.go b/internal/gorootcheck/hiddenport.go index a023355..2b88859 100644 --- a/internal/gorootcheck/hiddenport.go +++ b/internal/gorootcheck/hiddenport.go @@ -5,7 +5,7 @@ to check every tcp and udp port on the system. If we can’t bind to the port (it’s being used), but netstat does not show it, we probably have a rootkit installed -Check TCP/UDP ports +Check TCP/UDP ports [X] TCP [ ] UDP @@ -14,20 +14,20 @@ Check TCP/UDP ports package gorootcheck import ( - "syscall" - "os/exec" - "strings" "fmt" + "net" + "os/exec" "regexp" "strconv" - "net" + "strings" + "syscall" ) -// check port in ss output +// Return TRUE is NOT FOUND port in output func inssstd(std string, port int) bool { ss := strings.Split(std, "\n") - spgex, _ := regexp.Compile(`(?m)(\S+$)`) - for _, p := range ss { + spgex, _ := regexp.Compile(`(?m)(\d+$)`) + for _, p := range ss[1:len(ss)-1] { ssport, err := strconv.Atoi(spgex.FindString(p)) if err != nil { return false @@ -39,10 +39,16 @@ func inssstd(std string, port int) bool { return true } +func closefd(fd int) { + if err := syscall.Close(fd); err != nil { + return + } +} + // Execute `ss` command -// protocol -> t[cp] or u[dp] +// protocol -> t[cp] or u[dp] func inss(protocol string, port int) bool { - ss := exec.Command("ss", "-l", protocol, "n") + ss := exec.Command("ss", "-l", protocol, "-n") awk := exec.Command("awk", "{print $4}") pipe, err := ss.StdoutPipe() if err != nil { @@ -57,39 +63,57 @@ func inss(protocol string, port int) bool { if err != nil { return false } + if inssstd(string(std), port) { return true } return false } -// Check if port is already in use -func ssport(port int) bool { +// Check if TCP port is already in use +func tcpssport(port int) bool { fd, err := syscall.Socket(syscall.AF_INET, syscall.O_NONBLOCK|syscall.SOCK_STREAM, 0) if err != nil { - return false + return false } defer syscall.Close(fd) if err = syscall.SetNonblock(fd, true); err != nil { - return false + return false } addr := syscall.SockaddrInet4{Port: port} copy(addr.Addr[:], net.ParseIP("0.0.0.0").To4()) if err = syscall.Bind(fd, &addr); err != nil { - // TCP if inss("-t", port) { + closefd(fd) return true } } + closefd(fd) + return false +} + +// Check if UDP port is already in use +func udpssport(port int) bool { + pc, err := net.ListenPacket("udp", ":" + strconv.Itoa(port)) + if err != nil { + if inss("-u", port) { + return true + } + return false // invalid memory address or nil pointer dereference + } + defer pc.Close() return false } func hidden_port() { fmt.Println("#6 - Searching for hidden ports [ TCP/UDP - IPV4/IPV6 ]") - for i := 0; i <= 65535 ; i++ { - if ssport(i) { - fmt.Println("\t- Hidden Port: ", i) + for i := 0; i <= 65535; i++ { + if tcpssport(i) { + fmt.Println("\t- Hidden TCP Port: ", i) + } + if udpssport(i) { + fmt.Println("\t- Hidden UDP Port: ", i) } } } \ No newline at end of file diff --git a/internal/gorootcheck/promisc.go b/internal/gorootcheck/promisc.go index 21e9d77..e25e7b5 100644 --- a/internal/gorootcheck/promisc.go +++ b/internal/gorootcheck/promisc.go @@ -9,7 +9,7 @@ we probably have a rootkit installed. file: /sys/class/net//flags -ref: +ref: https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-class-net https://github.com/torvalds/linux/blob/master/include/uapi/linux/if.h */ @@ -17,10 +17,10 @@ package gorootcheck import ( "fmt" - "regexp" - "strconv" "io/ioutil" "os/exec" + "regexp" + "strconv" ) // return all interfaces name @@ -33,18 +33,18 @@ func listinterfaces() ([]string, error) { for _, i := range ifacedirs { iface = append(iface, i.Name()) } - return iface, nil + return iface, nil } // return TRUE if given interface is in promisc mode // promisc mode bitmask 100 func scaninterface(iface string) bool { - flags, err := ioutil.ReadFile("/sys/class/net/"+iface+"/flags") + flags, err := ioutil.ReadFile("/sys/class/net/" + iface + "/flags") if err != nil { fmt.Println(" - Error reading flags from interface: ", iface) return false } - bytemark := flags[2:len(flags)-1] + bytemark := flags[2 : len(flags)-1] if len(bytemark) < 3 { return false } @@ -52,13 +52,13 @@ func scaninterface(iface string) bool { if err != nil { return false } - if bitmark / 100 == 11 || bitmark / 100 == 1 { + if bitmark/100 == 11 || bitmark/100 == 1 { return true } return false } -// return TRUE if interface is promisc mode +// return TRUE if interface is promisc mode // in ifconfig command func ifconfigface(iface string) bool { cmd := exec.Command("ifconfig", iface) @@ -84,4 +84,4 @@ func promisc() { fmt.Println("\t- Interface in hidden promisc mode: ", i) } } -} \ No newline at end of file +}