Skip to content

Commit

Permalink
feat: Better formatted output for detected events. (#573)
Browse files Browse the repository at this point in the history
* feat: Better formatted output for detected events.

Signed-off-by: Simarpreet Singh <simar@linux.com>

* fix: Format time as UTC in RFC3339

Signed-off-by: Simarpreet Singh <simar@linux.com>

* fix: Add a testcase for unsupport input event

Signed-off-by: Simarpreet Singh <simar@linux.com>

* feat: Include signature ID in detection output

Signed-off-by: Simarpreet Singh <simar@linux.com>

* feat: Rework fields for display

Signed-off-by: Simarpreet Singh <simar@linux.com>
  • Loading branch information
simar7 committed Feb 24, 2021
1 parent 28fbc66 commit 5dc1352
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 3 deletions.
14 changes: 13 additions & 1 deletion tracee-rules/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,23 @@ import (
"os"
"os/signal"
"syscall"
"time"

"github.com/aquasecurity/tracee/tracee-rules/engine"
"github.com/urfave/cli/v2"
)

type Clock interface {
Now() time.Time
}

type realClock struct {
}

func (realClock) Now() time.Time {
return time.Now()
}

func main() {
app := &cli.App{
Name: "tracee-rules",
Expand Down Expand Up @@ -56,7 +68,7 @@ func main() {
if inputs == (engine.EventSources{}) {
return err
}
output, err := setupOutput(c.String("webhook"))
output, err := setupOutput(os.Stdout, realClock{}, c.String("webhook"))
if err != nil {
return err
}
Expand Down
30 changes: 28 additions & 2 deletions tracee-rules/output.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package main
import (
"encoding/json"
"fmt"
"io"
"log"
"net/http"
"strings"
Expand All @@ -12,11 +13,36 @@ import (
"github.com/aquasecurity/tracee/tracee-rules/types"
)

func setupOutput(webhook string) (chan types.Finding, error) {
const DetectionOutput string = `
*** Detection ***
Time: %s
Signature ID: %s
Signature: %s
Data: %s
Command: %s
Hostname: %s
`

func setupOutput(resultWriter io.Writer, clock Clock, webhook string) (chan types.Finding, error) {
out := make(chan types.Finding)
go func() {
for res := range out {
fmt.Printf("%+v\n", res)
sigMetadata, err := res.Signature.GetMetadata()
if err != nil {
log.Println("invalid signature metadata: ", err)
continue
}

switch res.Context.(type) {
case tracee.Event:
command := res.Context.(tracee.Event).ProcessName
hostName := res.Context.(tracee.Event).HostName
fmt.Fprintf(resultWriter, DetectionOutput, clock.Now().UTC().Format(time.RFC3339), sigMetadata.ID, sigMetadata.Name, res.Data, command, hostName)
default:
log.Printf("unsupported event detected: %T\n", res.Context)
continue
}

if webhook != "" {
payload, err := prepareJSONPayload(res)
if err != nil {
Expand Down
84 changes: 84 additions & 0 deletions tracee-rules/output_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package main

import (
"bytes"
"testing"
"time"

"github.com/aquasecurity/tracee/tracee-ebpf/tracee/external"

"github.com/aquasecurity/tracee/tracee-rules/types"
"github.com/stretchr/testify/assert"

"github.com/stretchr/testify/require"
)

type fakeClock struct {
}

func (fakeClock) Now() time.Time {
return time.Unix(1614045297, 0)
}

type fakeSignature struct {
types.Signature
}

func (f fakeSignature) GetMetadata() (types.SignatureMetadata, error) {
return types.SignatureMetadata{
ID: "FOO-666",
Name: "foo bar signature",
Description: "the most evil",
}, nil
}

func Test_setupOutput(t *testing.T) {
var testCases = []struct {
name string
inputContext interface{}
expectedOutput string
}{
{
name: "happy path with tracee event",
inputContext: external.Event{
Timestamp: 12345678,
ProcessName: "foobar.exe",
HostName: "foobar.local",
},
expectedOutput: `
*** Detection ***
Time: 2021-02-23T01:54:57Z
Signature ID: FOO-666
Signature: foo bar signature
Data: map[foo1:bar1, baz1 foo2:[bar2 baz2]]
Command: foobar.exe
Hostname: foobar.local
`,
},
{
name: "sad path with unknown context",
inputContext: struct {
foo string
}{foo: "bad input context"},
expectedOutput: ``,
},
}

for _, tc := range testCases {
var actualOutput bytes.Buffer
findingCh, err := setupOutput(&actualOutput, fakeClock{}, "")
require.NoError(t, err, tc.name)

findingCh <- types.Finding{
Data: map[string]interface{}{
"foo1": "bar1, baz1",
"foo2": []string{"bar2", "baz2"},
},
Context: tc.inputContext,
Signature: fakeSignature{},
}

time.Sleep(time.Millisecond)
assert.Equal(t, tc.expectedOutput, actualOutput.String(), tc.name)
}
}

0 comments on commit 5dc1352

Please sign in to comment.