GithubHelp home page GithubHelp logo

abguthrie / goquery Goto Github PK

View Code? Open in Web Editor NEW
81.0 3.0 10.0 143 KB

Provide a shell like interface by utilizing osquery's distributed API

License: MIT License

Go 97.37% Makefile 0.82% Dockerfile 1.81%
golang osquery remote-shell

goquery's Introduction

goquery

goquery is a remote investigation client that uses your existing osquery deployment to provide remote shell level functionality with fewer risks than SSH.

Using osquery's distributed API, hosts can be targeted for single queries to pull back specific information without having to modify the osquery schedule. goquery uses this API and abstracts it into a shell like experience that investigators are more used to while retaining all the power of osquery tables, extensions, and features like Auto Table Construction.

With goquery you can connect to hosts via UUID, and remotely interact with a host's osquery instance in an interactive session. This works over osquery's asynchronous distributed API. The concept of node keys, discovery queries, and the osquery schedule is abstracted away (or not used) to provide a clean, efficient way to remotely interrogate hosts for abuse, compromise investigation, or fleet management.

goquery

To get up and running, view the building and running section

Features:

  • Interactive prompt with typeahead and help text (courtesy of go-prompt)
  • osctrl integration
  • Command aliasing
  • Print modes
  • Both interactive and non interactive scheduling modes

Commands

The following is a list of all goquery commands and their calling requirements.

.connect <UUID>

This opens a session with a remote host. It will ask the backend if a host with that UUID is registered and if not return to the user saying it doesn't exist. If the backend returns that the host exists then a session is opened and that machine is set as the active host. All future commands will interact with this host until it's disconnected from or the user changes to another host. Supports suggestions.

.disconnect <UUID>

Close a session with a remote host. Fails if you're not connected to a host with that UUID. Supports suggestions.

.exit

Exit goquery. Shell state will not be saved but command history is.

.help

Show goquery help formatted with the currently selected printing mode.

.clear

Clear the terminal screen

.history

Show all past queries in the current session for the current host.

.hosts

Show all hosts you are connected to with their osquery version, hostname, UUID, and platform

.mode <print_mode>

Change the printing mode. goquery supports multiple printing modes to help you make sense of data at a glance. We currently support: Line, JSON, and Pretty (default).

.query <query>

Runs a query on a remote host and waits for the result before returning control to the REPL. Equivalent to running .schedule and .resume together. query_table_suggestion

.resume <query_name>

This will either wait for a query to complete or fetch the results and display them if the query has already posted results. This is used in conjunction with .schedule to pull the results of queries that are running asynchronously. This can also be used to display the results of any previously run query.

.schedule <query>

Run a query asynchronously on the remote host. The query will be tracked in the session for that host so results can be fetched at any point in time, but this allows the investigator to kick off a bunch of things without waiting for each one to complete first.

.alias <alias_name> <command> <interpolated_args>

List current aliases when called with no arguments or flags. To create a new alias, call with --add flag and provide arguments as follows: .alias --add ALIAS_NAME command_string

Positional arguments with $# placeholders are interpolated when the command is run, for example the following alias .all with command .query select * from $# will evaluate to .query select * from processes when called with .all processes.

Command name must not contain any spaces in order to preserve the space delimited arguments

To remove an alias, use .alias --remove ALIAS_NAME

cd <dir>

Change directories on a remote host. This affects other pseudo-commands like ls.

ls

List the files in the current directory. The current directory is set by using the cd command and starts at /.

Integration

Take a look at out one of the runnable examples in /examples.

To use goquery, import the dependency and pass an API struct that implements the GoQueryAPI interface. Provide your own or use the provided built ins. You can also build a version of goquery that works with the mock server by running make mock. To support the various features of goquery, your backend will need to support a number of APIs to interact with your fleet. The core APIs are required for basic functionality but future APIs may focus on more fringe features such as ATC, file pulling, etc. goquery can work without these APIs and that functionality will be disabled.

Core API

The following endpoints are required to enable goquery to talk to a host's osquery instance. See goserver/mock_osquery_server.go for a reference implementation.

checkHost

Description: Verify a host exists in the fleet.

goquery Provides: UUID

goquery Expects: Information on that UUID: if it exists or not, osquery version, hostname, operating system version.


scheduleQuery

Description: Schedule a query on a remote machine.

goquery Provides: UUID, query

goquery Expects: A unique identifier for that query will be passed to fetchResults for updates on the query.


fetchResults

Description: Pull the results of a query by the name returned from scheduleQuery

goquery Provides: queryName

goquery Expects: The query results if they are available

Config

Goquery can be configured via a configuration json file. Debug mode, defaults, and aliases can be set in the structure of the provided config.template.json. Valid print modes are as follows "json", "line", and "pretty".

By default, goquery will check for a config file at the following path: ~/.goquery/config.json. This can be overidden when calling the binary or running with the following flags: --config ./path_to_file.json

Building and Running

Docker Testing Infra

Hopefully one day goquery will be plug'n'play with the most popular osquery backends, but for now it'll take a little work to integrate. To get up and running playing with goquery as quickly as possible, you can use the docker test infra.

Running make docker will build a set of nodes used to create a simulated osquery deployment with two Ubuntu hosts, a central osquery server, along with a SAML IdP. goquery's docker infra contains its own osquery server written in Go which is designed to be lightweight and easy to understand to help you learn how to integrate goquery into your enterprise.

Deploy it locally with make deploy (which uses docker swarm) and then you're ready to start testing by running goquery.

Running goquery

Use go run cmd/main.go --config ./config.template.json to simply run from the root of the directory, or build a binary if you wish with go build -o goquery ./cmd/main.go

For a quick demo, try the following commands:

  • .connect uuid
  • ls
  • .mode line
  • .query select * from system_info

Slack

Slack Status

There is a goquery channel in the osquery slack for discussion and help. If you have questions about deployment, integration, or usage, you can ask there.

Bugs?

File an issue!

License

goquery is licensed under the MIT License.

goquery's People

Contributors

abguthrie avatar carlv-stripe avatar obelisk avatar zwass avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

goquery's Issues

Implement SSO Properly

The correct implementation for service protected by SSO or SAML auth is with a reverse proxy. The fact that goserver implements SAML on its own is at best inelegant.

This should be refactored into an nginx reverse proxy that handles saml and will pass along calls when authentication is successful. This would also mean another docker container for this service.

Use different user agent for HTTP requests

Overview

When using goquery the default user agent is the one inherited from go, which is Go-http-client/1.1. It would be cool to customize it to be custom with version or something like that.

Great project! kudos!

Allow calls to schedule query to squelch from history

Commands like cd must issue a command to the host to verify directory existence which means they end up in the query history. There should be an API that allows you to mark a query and not wanting to appear in the history (though it would be nice if there was a way to request the full history and have them shown)

goserver Doesn't Accelerate Hosts

goserver should be accelerating hosts because that's how real infra would work. Right now we're just hacking around it by setting the checkin time to something absurdly low.

goquery Needs Carver Support

The ability to pull files from remote hosts is one of the most useful features of osquery. goquery should support it, recognize valid paths, track file requests and pull them down to the local host.

Don't Revalidate Host on Switch

To switch between hosts you use the .connect command which means that it issues the validation query to pull hosts from the remote machine again.

Ideally this shouldn't happen as we already know what they are.

Allow printing code to specify column order

Right now we print all columns in alphabetical order which works decently but isn't very flexible. We should improve the printing code so defined order can be passed in and printed out that way.

This will allow us to reorder .hosts fields in pretty and line print as well as eventually use the ordering that osquery defaults do (for example if path is present, it is almost always first)

Document How To Integrate With A New Backend

There are many backends available for osquery and while we support osctrl out of the box (though you need to write your own authentication code), there isn't a lot of support that explains how to do it.

This should be filled out so people can integrate goquery with their backends more easily and with fewer mistakes.

ATC Support

ATC is one of the most powerful functions of osquery and is currently unsupported by goquery.

We should definitely support targeted ATC on hosts. For goquery this will require a new command (which will pair very nicely with the alias system) but mock server will need a few updates as well.

  • Implement New API Handler for ATC in Mock Server
  • Implement New Command in goquery taking: Name, Query, Path, Duration
  • Implement Mock Server Configuration Generation
  • Implement New Command in goquery: Refresh Host (to pull new ATC table into suggestions)

Create Docker Environment For goquery

We need a docker environment set up that contains at least 3 but preferably 4 hosts.

  • One osquery host running ubuntu
  • One osquery host running macOS
  • One server running our mock server (which also needs a better name because it doesn't mock)
  • One server running goquery.

We could get away with a single server for goquery and the mock server but more will sell the point better.

Choose A Licence

The project needs a licence and I'm not quite sure which we should use.

Likely options are:
MIT
Apache 2.0
GPL 2.0

Multiple API implementation should be implemented as an interface

GoQueryAPI should be of type interface.
We can't rely on init function call order, so main should grab the config, and call an initialize function in the API module that creates an internal auth object based on the config. The internal api object will have the CheckHost, ScheduleQuery, etc functions bound to it.

Use REPL Library

We need to use a proper REPL library so we can get things like arrow keys, tab complete, and history

Implement a Help Command

New users to goquery should have an help command that lists all commands along with their help strings to help them get acquainted with the shell.

In future it should probably also list loaded aliases.

Integrate with osctrl

osctrl by default uses it's own database to handle authentication and is just a series of post requests. This is likely what other smaller deployments use so we should natively support that in goquery.

Finish Path Normalization

Right now CD doesn't handle .. or . properly. This needs to be handled to allow efficient navigation of the filesystem.

Support piping query results to files

Add a syntax to allow piping the result of query to a file, saving on disk.
For example: .query select * from processes |> ./queries/out.txt --json

This will allow the larger queries to potentially be easily parsed with external tools, and avoid printing a huge amount of data.
This feature could support flags for the output print mode, for example --json and --csv

Auth Failure Should Be Handled Better

Sometimes you typo your password, this shouldn't mean we give up and back out.

We should put the user back at the shell and they can try again if they wish.

Integrate with Fleet

Kolide's Fleet is pretty popular and it would make sense to have native support for it if possible.

List all previous queries of host

We track all queries for each host but we need a way to list them all out so they can have their results fetched again, or just get a history for what's happened.

Implement Aliasing

Aliasing allows you to abstract long and complicated goquery commands into your own short aliases. This helps reduce errors and speed up usage.

Aliases should be loaded from the .goquery folder on start up and should be capable of taking parameters as well. Possible usage could look like:

goquery > .alias .all .query select * from {}
goquery > .alias .quit .exit
goquery > .all system_info
Running: select * from system_info
.
.
.
goquery > .quit
Goodbye!

We can assert that aliases may contain no spaces which means parsing the command to process the new alias name and content should be straight forward. It should also be the case that command code is completely separate from the alias code (alias replacement and processing happens before calling into command/ code)

Search For Hosts From Within goquery

If you're using goquery in a vacuum (such as using mock server), it may be hard to find what host to connect to.

A new command and new API to pull hosts from the backend that you can connect to would be useful in these circumstances, especially depending on how searching works (can you search by username/hostname for example)

Commands Should Be Their Own File

Commands shouldn't be created in main.go like they are. They should be in their own file where ideally the map would be stored as well.

This will clean up main to focus on REPL improvements.

Sort each row before printing

Right now in line mode each row is in a different order making it difficult to look at multiple rows and determine what's happening. The JSON printer solves this by sorting by keys first so line should do something similar OR preserve the order that is given to it by the backend.

Schedule Doesn't Have Table Completion

This is an interesting issue because we need to consider if we prefer code duplication, more complex dependencies, or a refactor which would be quite odd.

Option One: Code Duplication
We copy paste all the code from querySuggest to scheduleSuggest.

This is certainly the easiest to understand but means that when we have to update that code (we will), we'll end up right back here where something is supported in one but not the other.

Option Two: More Complex Dependencies
We have scheduleSuggest call directly into querySuggest.

This is the most expeditious thing to do, and it has no code duplication. The issue here is that now commands can rely on other commands in hard to reason about ways. I can't think of a time where editing querySuggest would cause problems with scheduleSuggest but the fact that a developer might not realize that is sub optimal.

Option Three: A Refactor
We take our query suggestion code and refactor it out into another file or module.

This solves both the above problems which is good, but creates a new question: where would that code live? Where ever it is, it needs access to the hosts module so there might be some reason to put it there. Utils is much lower level and would probably create a circular dependency between utils and hosts. We could create a command utils, but it seems such a function would be useful even outside of commands, along with conceptually not fitting.

I tend to think that Option Two is the best one here but I think that Option Three also needs to be strongly considered. Option One is definitely out though.

Save osctrl Token Between Runs

An osctrl token is valid for over a day by default so we can get away with storing it, checking if it's valid, and if not, then running the authentication flow. This will make it much easier to jump in and out goquery when using the osctrl backend.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.