Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions actions/vql.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ func (self VQLClientAction) StartQuery(

builder := services.ScopeBuilder{
Config: &config_proto.Config{
Client: config_obj.Client,
Remappings: config_obj.Remappings,
},
// Only provide the client config since we are running in
Expand Down
28 changes: 21 additions & 7 deletions vql/common/shell.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,20 +69,20 @@ func (self ShellPlugin) Call(
return
}

// Check the config if we are allowed to execve at all.
config_obj, ok := artifacts.GetConfig(scope)
if ok && config_obj.PreventExecve {
scope.Log("shell: Not allowed to execve by configuration.")
return
}

arg := &ShellPluginArgs{}
err = arg_parser.ExtractArgsWithContext(ctx, scope, args, arg)
if err != nil {
scope.Log("shell: %v", err)
return
}

// Check the config if we are allowed to execve at all.
config_obj, ok := artifacts.GetConfig(scope)
if ok && config_obj.PreventExecve && !alwaysAllow(arg) {
scope.Log("shell: Not allowed to execve by configuration.")
return
}

var env *ordereddict.Dict
if arg.Env != nil {
env = vfilter.RowToDict(ctx, scope, arg.Env.Reduce(ctx))
Expand Down Expand Up @@ -387,6 +387,20 @@ func defaultPipeReader(
return nil
}

// alwaysAllow returns true for execve calls required by artifacts.
func alwaysAllow(args *ShellPluginArgs) bool {
if args.Env != nil || args.Cwd != "" || len(args.Argv) < 2 {
return false
}

switch strings.Join(args.Argv[:2], " ") {
case "systemctl show", "systemctl list-timers":
return true
}

return false
}

func init() {
vql_subsystem.RegisterPlugin(&ShellPlugin{
pipeReader: defaultPipeReader,
Expand Down
22 changes: 22 additions & 0 deletions vql/common/shell_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/stretchr/testify/suite"
"www.velocidex.com/golang/velociraptor/json"
"www.velocidex.com/golang/velociraptor/vtesting/assert"
"www.velocidex.com/golang/vfilter"
)

type ShellTestSuite struct {
Expand Down Expand Up @@ -95,6 +96,27 @@ func (self *ShellTestSuite) TestSplit() {
assert.Equal(self.T(), 4, offset)
}

func (self *ShellTestSuite) TestAlwaysAllow() {
testCases := []struct {
argv []string
env vfilter.LazyExpr
cwd string
expect bool
}{
{[]string{"systemctl", "show", "apache"}, nil, "", true},
{[]string{"systemctl", "list-timers"}, nil, "", true},
{[]string{"systemctl", "stop", "firewalld"}, nil, "", false},
{[]string{"ls", "-l"}, nil, "", false},
{[]string{"systemctl", "show", "apache"}, nil, "/tmp", false},
{[]string{"systemctl", "show", "apache"}, &vfilter.LazyExprImpl{}, "", false},
}

for _, tc := range testCases {
args := &ShellPluginArgs{Argv: tc.argv, Env: tc.env, Cwd: tc.cwd}
assert.Equal(self.T(), tc.expect, alwaysAllow(args), "args: %+v, expected: %v", args, tc.expect)
}
}

func TestExecvePlugin(t *testing.T) {
suite.Run(t, &ShellTestSuite{})
}
Loading