Skip to content
Merged
9 changes: 5 additions & 4 deletions apiclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ type DNSRecord struct {
type Tool struct {
Name string `json:"name"`
SHA256 string `json:"sha256"`
Parent *Tool `json:"parent"`
}

type FileEvent struct {
Expand Down Expand Up @@ -59,28 +60,28 @@ func (apiclient *ApiClient) sendDNSRecord(correlationId, repo, domainName, ipAdd
return apiclient.sendApiRequest("POST", url, dnsRecord)
}

func (apiclient *ApiClient) sendNetConnection(correlationId, repo, ipAddress, port, status string, timestamp time.Time, tool, toolChecksum string) error {
func (apiclient *ApiClient) sendNetConnection(correlationId, repo, ipAddress, port, status string, timestamp time.Time, tool Tool) error {

networkConnection := &NetworkConnection{}

networkConnection.IPAddress = ipAddress
networkConnection.Port = port
networkConnection.Status = status
networkConnection.TimeStamp = timestamp
networkConnection.Tool = Tool{Name: tool, SHA256: toolChecksum}
networkConnection.Tool = tool

url := fmt.Sprintf("%s/github/%s/actions/jobs/%s/networkconnection", apiclient.APIURL, repo, correlationId)

return apiclient.sendApiRequest("POST", url, networkConnection)
}

func (apiclient *ApiClient) sendFileEvent(correlationId, repo, fileType string, timestamp time.Time, tool, toolChecksum string) error {
func (apiclient *ApiClient) sendFileEvent(correlationId, repo, fileType string, timestamp time.Time, tool Tool) error {

fileEvent := &FileEvent{}

fileEvent.FileType = fileType
fileEvent.TimeStamp = timestamp
fileEvent.Tool = Tool{Name: tool, SHA256: toolChecksum}
fileEvent.Tool = tool

url := fmt.Sprintf("%s/github/%s/actions/jobs/%s/fileevent", apiclient.APIURL, repo, correlationId)

Expand Down
6 changes: 3 additions & 3 deletions apiclient_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,7 @@ func Test_sendNetConnection(t *testing.T) {
port string
status string
timestamp time.Time
tool string
toolChecksum string
tool Tool
}

apiclient := &ApiClient{Client: &http.Client{}, APIURL: agentApiBaseUrl}
Expand All @@ -102,7 +101,8 @@ func Test_sendNetConnection(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if err := apiclient.sendNetConnection(tt.args.correlationId, tt.args.repo, tt.args.ipAddress, tt.args.port, tt.args.status, tt.args.timestamp, tt.args.tool, tt.args.toolChecksum); (err != nil) != tt.wantErr {
if err := apiclient.sendNetConnection(tt.args.correlationId, tt.args.repo, tt.args.ipAddress,
tt.args.port, tt.args.status, tt.args.timestamp, tt.args.tool); (err != nil) != tt.wantErr {
t.Errorf("sendNetConnection() error = %v, wantErr %v", err, tt.wantErr)
}
})
Expand Down
63 changes: 48 additions & 15 deletions eventhandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ type EventHandler struct {
ProcessMap map[string]*Process
netMutex sync.RWMutex
fileMutex sync.RWMutex
procMutex sync.RWMutex
}

var classAPrivateSubnet, classBPrivateSubnet, classCPrivateSubnet, loopBackSubnet *net.IPNet
Expand Down Expand Up @@ -56,18 +57,27 @@ func (eventHandler *EventHandler) handleFileEvent(event *Event) {
}

if fileType != "" {
toolChecksum, _ := getProgramChecksum(event.Exe)
exe := filepath.Base(event.Exe)
eventHandler.ApiClient.sendFileEvent(eventHandler.CorrelationId, eventHandler.Repo, fileType, event.Timestamp, exe, toolChecksum)
tool := *eventHandler.GetToolChain(event.PPid, event.Exe)
eventHandler.ApiClient.sendFileEvent(eventHandler.CorrelationId, eventHandler.Repo, fileType, event.Timestamp, tool)
eventHandler.ProcessFileMap[event.Pid] = true
}
}

eventHandler.fileMutex.Unlock()
}
func (eventHandler *EventHandler) handleProcessEvent() {

func (eventHandler *EventHandler) handleProcessEvent(event *Event) {
eventHandler.procMutex.Lock()

_, found := eventHandler.ProcessMap[event.Pid]

if !found {
eventHandler.ProcessMap[event.Pid] = &Process{PID: event.Pid, PPid: event.PPid, Exe: event.Exe, Arguments: event.ProcessArguments}
}

eventHandler.procMutex.Unlock()
}

func (eventHandler *EventHandler) handleNetworkEvent(event *Event) {
eventHandler.netMutex.Lock()

Expand All @@ -82,23 +92,18 @@ func (eventHandler *EventHandler) handleNetworkEvent(event *Event) {

if !found {
//writeLog(fmt.Sprintf("handleNetworkEvent %v", event))
tool := Tool{}
image := GetContainerByPid(event.Pid)
checksum := ""
exe := ""
if image == "" {

if event.Exe != "" {
checksum, _ = getProgramChecksum(event.Exe)

tool = *eventHandler.GetToolChain(event.PPid, event.Exe)
}
exe = filepath.Base(event.Exe)

} else {
event.Exe = image
checksum = image
exe = image
tool = Tool{Name: image, SHA256: image} // TODO: Set container image checksum
}

eventHandler.ApiClient.sendNetConnection(eventHandler.CorrelationId, eventHandler.Repo, event.IPAddress, event.Port, "", event.Timestamp, exe, checksum)
eventHandler.ApiClient.sendNetConnection(eventHandler.CorrelationId, eventHandler.Repo, event.IPAddress, event.Port, "", event.Timestamp, tool)
eventHandler.ProcessConnectionMap[cacheKey] = true
}
}
Expand All @@ -113,7 +118,7 @@ func (eventHandler *EventHandler) HandleEvent(event *Event) {
case fileMonitorTag:
eventHandler.handleFileEvent(event)
case processMonitorTag:
eventHandler.handleProcessEvent()
eventHandler.handleProcessEvent(event)
}
}

Expand Down Expand Up @@ -160,6 +165,34 @@ func getProgramChecksum(path string) (string, error) {
return fmt.Sprintf("%x", h.Sum(nil)), nil
}

func (eventHandler *EventHandler) GetToolChain(ppid, exe string) *Tool {
checksum, _ := getProgramChecksum(exe)
tool := Tool{Name: filepath.Base(exe), SHA256: checksum}

// In some cases the process has already exited, so get from map first
parentProcess, found := eventHandler.ProcessMap[ppid]

if found {
tool.Parent = eventHandler.GetToolChain(parentProcess.PPid, parentProcess.Exe)
return &tool
}

// If not in map, may be long running, so get from OS
parentProcessId, err := getParentProcessId(ppid)
if err != nil {
return &tool
}

path, err := getProcessExe(ppid)
if err != nil {
return &tool
}

tool.Parent = eventHandler.GetToolChain(fmt.Sprintf("%d", parentProcessId), path)

return &tool
}

func isPrivateIPAddress(ipAddress string) bool {
if classAPrivateSubnet == nil {
_, classAPrivateSubnet, _ = net.ParseCIDR(classAPrivateAddressRange)
Expand Down
2 changes: 0 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,6 @@ require (
github.com/docker/docker v20.10.9+incompatible
github.com/google/go-cmp v0.5.6 // indirect
github.com/mdlayher/netlink v1.1.0 // indirect
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b // indirect
golang.org/x/net v0.0.0-20210326060303-6b1517762897 // indirect
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 // indirect
)
9 changes: 0 additions & 9 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -431,8 +431,6 @@ github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE
github.com/mdlayher/netlink v1.0.0/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M=
github.com/mdlayher/netlink v1.1.0 h1:mpdLgm+brq10nI9zM1BpX1kpDbh3NLl3RSnVq6ZSkfg=
github.com/mdlayher/netlink v1.1.0/go.mod h1:H4WCitaheIsdF9yOYu8CFmCgQthAPIWZmcKp9uZHgmY=
github.com/miekg/dns v1.1.25 h1:dFwPR6SfLtrSwgDcIq2bcU/gVutB4sNApq2HBdqcakg=
github.com/miekg/dns v1.1.25/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
github.com/miekg/dns v1.1.43 h1:JKfpVSCB84vrAmHzyrsxB5NAr5kLoMXZArPSw7Qlgyg=
github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4=
github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
Expand Down Expand Up @@ -639,14 +637,11 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b h1:7mWr3k41Qtv8XlltBkDkl8LoP3mpSgBW8BUoxtEdbXg=
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
Expand Down Expand Up @@ -697,7 +692,6 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
Expand Down Expand Up @@ -757,8 +751,6 @@ golang.org/x/sys v0.0.0-20190812073006-9eafafc0a87e/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
Expand Down Expand Up @@ -833,7 +825,6 @@ golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgw
golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
Expand Down
4 changes: 3 additions & 1 deletion netmon.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import (
"github.com/pkg/errors"
)

const Unknown = "Unknown"

type NetworkMonitor struct {
CorrelationId string
Repo string
Expand Down Expand Up @@ -88,7 +90,7 @@ func (netMonitor *NetworkMonitor) handlePacket(attrs nflog.Attribute) {

if isSYN {
netMonitor.ApiClient.sendNetConnection(netMonitor.CorrelationId, netMonitor.Repo,
ipv4.DstIP.String(), port, netMonitor.Status, timestamp, "Unknown", "Unknown")
ipv4.DstIP.String(), port, netMonitor.Status, timestamp, Tool{Name: Unknown, SHA256: Unknown})
}
}

Expand Down
1 change: 1 addition & 0 deletions procmon.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ type ProcessMonitor struct {

type Process struct {
PID string
PPid string
Exe string
WorkingDirectory string
Arguments []string
Expand Down
11 changes: 11 additions & 0 deletions procmon_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,17 @@

package main

import (
"fmt"
)

func (p *ProcessMonitor) MonitorProcesses(errc chan error) {
writeLog("Monitor Processes called")
}

func getParentProcessId(pid string) (int, error) {
return -1, fmt.Errorf("not implemented")
}
func getProcessExe(pid string) (string, error) {
return "", fmt.Errorf("not implemented")
}
37 changes: 37 additions & 0 deletions procmon_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ import (
"github.com/elastic/go-libaudit/v2/rule"
"github.com/elastic/go-libaudit/v2/rule/flags"
"github.com/pkg/errors"
"io/ioutil"
"os"
"strings"
)

func (p *ProcessMonitor) MonitorProcesses(errc chan error) {
Expand Down Expand Up @@ -139,3 +142,37 @@ func (p *ProcessMonitor) receive(r *libaudit.AuditClient) error {

}
}

func getParentProcessId(pid string) (int, error) {
statPath := fmt.Sprintf("/proc/%s/stat", pid)
dataBytes, err := ioutil.ReadFile(statPath)
if err != nil {
return -1, err
}

data := string(dataBytes)
binStart := strings.IndexRune(data, '(') + 1
binEnd := strings.IndexRune(data[binStart:], ')')

var ppid, pgrp, sid int
var state rune

// Move past the image name and start parsing the rest
data = data[binStart+binEnd+2:]
_, err = fmt.Sscanf(data,
"%c %d %d %d",
&state,
&ppid,
&pgrp,
&sid)

return ppid, err
}

func getProcessExe(pid string) (string, error) {
path, err := os.Readlink(fmt.Sprintf("/proc/%s/exe", pid))
if err != nil {
return "", err
}
return path, nil
}