MEDIUM
Source
Tracee
ID
TRC-1028
Version
1
Date
10 Dec 2024

Sudoers File Modification Detected

The sudoers file was modified. The sudoers file is a configuration file which controls the permissions and options of the sudo feature. Adversaries may alter the sudoers file to elevate privileges, execute commands as other users or spawn processes with higher privileges.

MITRE ATT&CK

Privilege Escalation: Sudo and Sudo Caching

Go Source

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
package main

import (
	"fmt"
	"strings"

	"github.com/aquasecurity/tracee/signatures/helpers"
	"github.com/aquasecurity/tracee/types/detect"
	"github.com/aquasecurity/tracee/types/protocol"
	"github.com/aquasecurity/tracee/types/trace"
)

type SudoersModification struct {
	cb           detect.SignatureHandler
	sudoersFiles []string
	sudoersDirs  []string
}

func (sig *SudoersModification) Init(ctx detect.SignatureContext) error {
	sig.cb = ctx.Callback
	sig.sudoersFiles = []string{"/etc/sudoers", "/private/etc/sudoers"}
	sig.sudoersDirs = []string{"/etc/sudoers.d/", "/private/etc/sudoers.d/"}
	return nil
}

func (sig *SudoersModification) GetMetadata() (detect.SignatureMetadata, error) {
	return detect.SignatureMetadata{
		ID:          "TRC-1028",
		Version:     "1",
		Name:        "Sudoers file modification detected",
		EventName:   "sudoers_modification",
		Description: "The sudoers file was modified. The sudoers file is a configuration file which controls the permissions and options of the sudo feature. Adversaries may alter the sudoers file to elevate privileges, execute commands as other users or spawn processes with higher privileges.",
		Properties: map[string]interface{}{
			"Severity":             2,
			"Category":             "privilege-escalation",
			"Technique":            "Sudo and Sudo Caching",
			"Kubernetes_Technique": "",
			"id":                   "attack-pattern--1365fe3b-0f50-455d-b4da-266ce31c23b0",
			"external_id":          "T1548.003",
		},
	}, nil
}

func (sig *SudoersModification) GetSelectedEvents() ([]detect.SignatureEventSelector, error) {
	return []detect.SignatureEventSelector{
		{Source: "tracee", Name: "security_file_open", Origin: "*"},
		{Source: "tracee", Name: "security_inode_rename", Origin: "*"},
	}, nil
}

func (sig *SudoersModification) OnEvent(event protocol.Event) error {
	eventObj, ok := event.Payload.(trace.Event)
	if !ok {
		return fmt.Errorf("invalid event")
	}

	path := ""

	switch eventObj.EventName {
	case "security_file_open":

		flags, err := helpers.GetTraceeIntArgumentByName(eventObj, "flags")
		if err != nil {
			return err
		}

		if helpers.IsFileWrite(flags) {
			pathname, err := helpers.GetTraceeStringArgumentByName(eventObj, "pathname")
			if err != nil {
				return err
			}

			path = pathname
		}
	case "security_inode_rename":
		newPath, err := helpers.GetTraceeStringArgumentByName(eventObj, "new_path")
		if err != nil {
			return err
		}

		path = newPath
	}

	for _, sudoersFile := range sig.sudoersFiles {
		if path == sudoersFile {
			return sig.match(event)
		}
	}

	for _, sudoersDir := range sig.sudoersDirs {
		if strings.HasPrefix(path, sudoersDir) {
			return sig.match(event)
		}
	}

	return nil
}

func (sig *SudoersModification) OnSignal(s detect.Signal) error {
	return nil
}
func (sig *SudoersModification) Close() {}

func (sig *SudoersModification) match(event protocol.Event) error {
	metadata, err := sig.GetMetadata()
	if err != nil {
		return err
	}
	sig.cb(&detect.Finding{
		SigMetadata: metadata,
		Event:       event,
		Data:        nil,
	})

	return nil
}