Skip to content

Commit

Permalink
Add secedit virtual table for windows (#657)
Browse files Browse the repository at this point in the history
Add secedit virtual table for windows. This is based on the dataflatten tools.
  • Loading branch information
terracatta committed Sep 15, 2020
1 parent daef6c4 commit 2365105
Show file tree
Hide file tree
Showing 5 changed files with 176 additions and 1 deletion.
2 changes: 2 additions & 0 deletions Makefile
Expand Up @@ -53,6 +53,8 @@ grpc-extension: .pre-build
# Convenience tools
osqueryi-tables: table.ext
osqueryd -S --allow-unsafe --verbose --extension ./build/darwin/tables.ext
osqueryi-tables-windows: table.ext
osqueryd.exe -S --allow-unsafe --verbose --extension .\build\windows\tables.exe
sudo-osqueryi-tables: table.ext
sudo osqueryd -S --allow-unsafe --verbose --extension ./build/darwin/tables.ext
launchas-osqueryi-tables: table.ext
Expand Down
5 changes: 4 additions & 1 deletion go.mod
@@ -1,7 +1,7 @@
module github.com/kolide/launcher

require (
cloud.google.com/go v0.43.0
cloud.google.com/go v0.43.0 // indirect
github.com/Masterminds/semver v1.4.2
github.com/Microsoft/go-winio v0.4.11 // indirect
github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d // indirect
Expand Down Expand Up @@ -66,6 +66,7 @@ require (
github.com/prometheus/client_golang v0.9.2 // indirect
github.com/serenize/snaker v0.0.0-20171204205717-a683aaf2d516
github.com/sirupsen/logrus v1.4.0 // indirect
github.com/smartystreets/goconvey v1.6.4 // indirect
github.com/spf13/viper v1.2.1 // indirect
github.com/stretchr/testify v1.5.1
github.com/theupdateframework/notary v0.6.1
Expand All @@ -76,11 +77,13 @@ require (
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297
golang.org/x/sync v0.0.0-20190423024810-112230192c58
golang.org/x/sys v0.0.0-20200803150936-fd5f0c170ac3
golang.org/x/text v0.3.2
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4
google.golang.org/grpc v1.23.0
gopkg.in/dancannon/gorethink.v3 v3.0.5 // indirect
gopkg.in/fatih/pool.v2 v2.0.0 // indirect
gopkg.in/gorethink/gorethink.v3 v3.0.5 // indirect
gopkg.in/ini.v1 v1.61.0 // indirect
howett.net/plist v0.0.0-20181124034731-591f970eefbb
)

Expand Down
11 changes: 11 additions & 0 deletions go.sum
Expand Up @@ -118,6 +118,8 @@ github.com/google/uuid v1.1.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8=
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
github.com/gorilla/mux v1.6.2 h1:Pgr17XVTNXAk3q/r4CpKzC5xBM/qW1uVLV+IhRZpIIk=
Expand All @@ -143,6 +145,8 @@ github.com/jinzhu/now v0.0.0-20181116074157-8ec929ed50c3 h1:xvj06l8iSwiWpYgm8MbP
github.com/jinzhu/now v0.0.0-20181116074157-8ec929ed50c3/go.mod h1:oHTiXerJ20+SfYcrdlBO7rzZRJWGwSTQ0iUY2jI6Gfc=
github.com/jmoiron/sqlx v0.0.0-20180406164412-2aeb6a910c2b/go.mod h1:IiEW3SEiiErVyFdH8NTuWjSifiEQKUoyK3LNqr2kCHU=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1 h1:PJPDf8OUfOK1bb/NeTKd4f1QXZItOX389VN3B6qC8ro=
github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
github.com/knightsc/system_policy v1.1.1-0.20191030190822-139971392acb h1:Xu+ciFy0JPiPCm2uk3TNUjE7rgBLA3eMNzrsR8J6ZSQ=
Expand Down Expand Up @@ -224,6 +228,10 @@ github.com/serenize/snaker v0.0.0-20171204205717-a683aaf2d516 h1:ofR1ZdrNSkiWcMs
github.com/serenize/snaker v0.0.0-20171204205717-a683aaf2d516/go.mod h1:Yow6lPLSAXx2ifx470yD/nUe22Dv5vBvxK/UK9UUTVs=
github.com/sirupsen/logrus v1.4.0 h1:yKenngtzGh+cUSSh6GWbxW2abRqhYUSR/t/6+2QqNvE=
github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/cast v1.2.0 h1:HHl1DSRbEQN2i8tJmtS6ViPyHx35+p51amrdsiTCrkg=
Expand Down Expand Up @@ -323,6 +331,7 @@ golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
Expand Down Expand Up @@ -362,6 +371,8 @@ gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/gorethink/gorethink.v3 v3.0.5 h1:e2Uc/Xe+hpcVQFsj6MuHlYog3r0JYpnTzwDj/y2O4MU=
gopkg.in/gorethink/gorethink.v3 v3.0.5/go.mod h1:+3yIIHJUGMBK+wyPH+iN5TP+88ikFDfZdqTlK3Y9q8I=
gopkg.in/ini.v1 v1.61.0 h1:LBCdW4FmFYL4s/vDZD1RQYX7oAR6IjujCYgMdbHBR10=
gopkg.in/ini.v1 v1.61.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
Expand Down
2 changes: 2 additions & 0 deletions pkg/osquery/table/platform_tables_windows.go
Expand Up @@ -3,6 +3,7 @@
package table

import (
"github.com/kolide/launcher/pkg/osquery/tables/secedit"
"github.com/kolide/launcher/pkg/osquery/tables/wmitable"

"github.com/go-kit/kit/log"
Expand All @@ -13,6 +14,7 @@ import (
func platformTables(client *osquery.ExtensionManagerClient, logger log.Logger, currentOsquerydBinaryPath string) []*table.Plugin {
return []*table.Plugin{
ProgramIcons(),
secedit.TablePlugin(client, logger),
wmitable.TablePlugin(client, logger),
}
}
157 changes: 157 additions & 0 deletions pkg/osquery/tables/secedit/secedit.go
@@ -0,0 +1,157 @@
// +build windows

package secedit

import (
"bytes"
"context"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"strconv"
"strings"
"time"

"github.com/go-kit/kit/log"
"github.com/go-kit/kit/log/level"
"github.com/kolide/launcher/pkg/dataflatten"
"github.com/kolide/launcher/pkg/osquery/tables/tablehelpers"
"github.com/kolide/osquery-go"
"github.com/kolide/osquery-go/plugin/table"
"github.com/pkg/errors"
"golang.org/x/text/encoding/unicode"
"golang.org/x/text/transform"
)

const seceditCmd = "secedit"

type Table struct {
client *osquery.ExtensionManagerClient
logger log.Logger
}

func TablePlugin(client *osquery.ExtensionManagerClient, logger log.Logger) *table.Plugin {

columns := []table.ColumnDefinition{
table.TextColumn("fullkey"),
table.TextColumn("parent"),
table.TextColumn("key"),
table.TextColumn("value"),
table.TextColumn("query"),
table.TextColumn("mergedpolicy"),
}

t := &Table{
client: client,
logger: logger,
}

return table.NewPlugin("kolide_secedit", columns, t.generate)
}

func (t *Table) generate(ctx context.Context, queryContext table.QueryContext) ([]map[string]string, error) {
var results []map[string]string

for _, mergedpolicy := range tablehelpers.GetConstraints(queryContext, "mergedpolicy", tablehelpers.WithDefaults("")) {
useMergedPolicy, err := strconv.ParseBool(mergedpolicy)
if err != nil {
level.Info(t.logger).Log("msg", "Cannot convert mergedpolicy constraint into a boolean value. Try passing \"true\"", "err", err)
continue
}

for _, dataQuery := range tablehelpers.GetConstraints(queryContext, "query", tablehelpers.WithDefaults("")) {
secEditResults, err := t.execSecedit(ctx, useMergedPolicy)
if err != nil {
level.Info(t.logger).Log("msg", "secedit failed", "err", err)
continue
}

flatData, err := t.flattenOutput(dataQuery, secEditResults)
if err != nil {
level.Info(t.logger).Log("msg", "flatten failed", "err", err)
continue
}

for _, row := range flatData {
p, k := row.ParentKey("/")

res := map[string]string{
"fullkey": row.StringPath("/"),
"parent": p,
"key": k,
"value": row.Value,
"query": dataQuery,
"mergedpolicy": mergedpolicy,
}
results = append(results, res)
}
}
}
return results, nil
}

func (t *Table) flattenOutput(dataQuery string, systemOutput []byte) ([]dataflatten.Row, error) {
flattenOpts := []dataflatten.FlattenOpts{}

if dataQuery != "" {
flattenOpts = append(flattenOpts, dataflatten.WithQuery(strings.Split(dataQuery, "/")))
}

if t.logger != nil {
flattenOpts = append(flattenOpts,
dataflatten.WithLogger(level.NewFilter(t.logger, level.AllowInfo())),
)
}

return dataflatten.Ini(systemOutput, flattenOpts...)
}

func (t *Table) execSecedit(ctx context.Context, mergedPolicy bool) ([]byte, error) {
// The secedit.exe binary does not support outputting the data we need to stdout
// Instead we create a tmp directory and pass it to secedit to write the data we need
// in INI format.
dir, err := ioutil.TempDir("", "kolide_secedit_config")
if err != nil {
return nil, errors.Wrap(err, "creating kolide_secedit_config tmp dir")
}
defer os.RemoveAll(dir)

dst := filepath.Join(dir, "tmpfile.ini")
var stdout bytes.Buffer
var stderr bytes.Buffer

ctx, cancel := context.WithTimeout(ctx, 30*time.Second)
defer cancel()

args := []string{"/export", "/cfg", dst}
if mergedPolicy {
args = append(args, "/mergedpolicy")
}

cmd := exec.CommandContext(ctx, seceditCmd, args...)
cmd.Stdout = &stdout
cmd.Stderr = &stderr

level.Debug(t.logger).Log("msg", "calling secedit", "args", cmd.Args)

if err := cmd.Run(); err != nil {
return nil, errors.Wrapf(err, "calling secedit. Got: %s", stderr.String())
}

file, err := os.Open(dst)
if err != nil {
return nil, errors.Wrapf(err, "error opening secedit output file: %s", dst)
}
defer file.Close()

// By default, secedit outputs files encoded in UTF16 Little Endian. Sadly the Go INI parser
// cannot read this format by default, therefore we decode the bytes into UTF-8
rd := transform.NewReader(file, unicode.UTF16(unicode.LittleEndian, unicode.UseBOM).NewDecoder())
data, err := ioutil.ReadAll(rd)
if err != nil {
return nil, errors.Wrapf(err, "error reading secedit output file: %s", err)
}

return data, nil
}

0 comments on commit 2365105

Please sign in to comment.