Skip to content

Commit

Permalink
Implement timeout on report generation in the GUI. (Velocidex#514)
Browse files Browse the repository at this point in the history
This prevents the gui from being overloaded by expensive reports.

Backport Generic.Utils.FetchBinary to older clients.
  • Loading branch information
scudette authored Jul 28, 2020
1 parent b5dad23 commit 4bcd98d
Show file tree
Hide file tree
Showing 25 changed files with 265 additions and 165 deletions.
10 changes: 10 additions & 0 deletions api/csrf.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,25 @@ package api
import (
"crypto/sha256"
"net/http"
"os"

"github.com/gorilla/csrf"
config_proto "www.velocidex.com/golang/velociraptor/config/proto"
"www.velocidex.com/golang/velociraptor/logging"
)

// Wrap only a single handler with csrf protection.
func csrfProtect(config_obj *config_proto.Config,
parent http.Handler) http.Handler {

// We may need to disabled CSRF for benchmarking tests.
disable_csrf, pres := os.LookupEnv("VELOCIRAPTOR_DISABLE_CSRF")
if pres && disable_csrf == "1" {
logger := logging.GetLogger(config_obj, &logging.GUIComponent)
logger.Info("Disabling CSRF protection because environment VELOCIRAPTOR_DISABLE_CSRF is set")
return parent
}

// Derive a CSRF key from the hash of the server's public key.
hasher := sha256.New()
hasher.Write([]byte(config_obj.Frontend.PrivateKey))
Expand Down
4 changes: 3 additions & 1 deletion api/notebooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"www.velocidex.com/golang/velociraptor/acls"
api_proto "www.velocidex.com/golang/velociraptor/api/proto"
"www.velocidex.com/golang/velociraptor/artifacts"
artifacts_proto "www.velocidex.com/golang/velociraptor/artifacts/proto"
config_proto "www.velocidex.com/golang/velociraptor/config/proto"
"www.velocidex.com/golang/velociraptor/datastore"
file_store "www.velocidex.com/golang/velociraptor/file_store"
Expand Down Expand Up @@ -841,7 +842,8 @@ func updateCellContents(
switch cell_type {

case "Markdown", "Artifact":
output, err = tmpl.Execute(input)
output, err = tmpl.Execute(
&artifacts_proto.Report{Template: input})
if err != nil {
return nil, err
}
Expand Down
38 changes: 21 additions & 17 deletions artifacts/definitions/Generic/Utils/FetchBinary.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,12 @@ parameters:

sources:
- query: |
-- The following VQL is particularly ancient because it is
-- running on the client and it needs to be compatibile with
-- clients at least back to 0.3.9
LET info_cache <= SELECT * FROM info()
LET inventory_item <= inventory_get(tool=ToolName)
LET inventory_item <= SELECT inventory_get(tool=ToolName) AS Item FROM scope()
LET args <= SELECT * FROM switch(
// Try to get info from the ToolInfo parameter.
Expand All @@ -46,9 +50,9 @@ sources:
FROM scope() WHERE ToolFilename},
// Failing this - try to get it from the inventory service directly.
c={SELECT get(field="Tool_" + ToolName + "_HASH", item=inventory_item) AS ToolHash,
get(field="Tool_" + ToolName + "_FILENAME", item=inventory_item) AS ToolFilename,
get(field="Tool_" + ToolName + "_URL", item=inventory_item) AS ToolURL
c={SELECT get(field="Tool_" + ToolName + "_HASH", item=(inventory_item[0]).Item) AS ToolHash,
get(field="Tool_" + ToolName + "_FILENAME", item=(inventory_item[0]).Item) AS ToolFilename,
get(field="Tool_" + ToolName + "_URL", item=(inventory_item[0]).Item) AS ToolURL
FROM scope() WHERE ToolFilename}
)
Expand All @@ -60,23 +64,23 @@ sources:
)
// Where we should save the file.
LET ToolPath <= path_join(components=[binpath[0].Path, args[0].ToolFilename])
LET ToolPath <= SELECT path_join(components=[(binpath[0]).Path, (args[0]).ToolFilename]) AS Path FROM scope()
// Download the file from the binary URL and store in the local
// binary cache.
LET download = SELECT * FROM if(condition=log(
message="URL for " + args[0].ToolFilename +
" is at " + args[0].ToolURL + " and has hash of " + args[0].ToolHash)
AND binpath AND args[0].ToolHash AND args[0].ToolURL,
message="URL for " + (args[0]).ToolFilename +
" is at " + (args[0]).ToolURL + " and has hash of " + (args[0]).ToolHash)
AND binpath AND (args[0]).ToolHash AND (args[0]).ToolURL,
then={
SELECT hash(path=Content) as Hash,
args[0].ToolFilename AS Name,
(args[0]).ToolFilename AS Name,
"Downloaded" AS DownloadStatus,
copy(filename=Content, dest=ToolPath) AS FullPath
FROM http_client(url=args[0].ToolURL, tempfile_extension=".exe", remove_last=TRUE)
copy(filename=Content, dest=(ToolPath[0]).Path) AS FullPath
FROM http_client(url=(args[0]).ToolURL, tempfile_extension=".exe")
WHERE log(message=format(format="downloaded hash of %v: %v, expected %v", args=[
Content, Hash.SHA256, args[0].ToolHash]))
AND Hash.SHA256 = args[0].ToolHash
Content, Hash.SHA256, (args[0]).ToolHash]))
AND Hash.SHA256 = (args[0]).ToolHash
}, else={
SELECT * FROM scope()
WHERE NOT log(message="No valid setup - is tool " + ToolName +
Expand All @@ -87,10 +91,10 @@ sources:
// the hash.
LET existing = SELECT FullPath, hash(path=FullPath) AS Hash, Name,
"Cached" AS DownloadStatus
FROM stat(filename=ToolPath)
WHERE Hash.SHA256 = args[0].ToolHash AND log(
FROM stat(filename=(ToolPath[0]).Path)
WHERE Hash.SHA256 = (args[0]).ToolHash AND log(
message=format(format="hash of %v: %v, expected %v", args=[
FullPath, Hash.SHA256, args[0].ToolHash]))
FullPath, Hash.SHA256, (args[0]).ToolHash]))
// Find the required_tool either in the local cache or
// download it (and put it in the cache for next time). If we
Expand All @@ -101,7 +105,7 @@ sources:
b={
SELECT rand(range=atoi(string=SleepDuration)) AS timeout
FROM scope()
WHERE args AND args[0].ToolURL AND
WHERE args AND (args[0]).ToolURL AND
log(message=format(format='Sleeping %v Seconds',
args=[timeout])) AND sleep(time=timeout) AND FALSE
},
Expand Down
3 changes: 3 additions & 0 deletions artifacts/definitions/Server/Monitor/Health.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ sources:

reports:
- type: SERVER_EVENT
# Only allow the report to run for 10 seconds - this is plenty for
# the GUI.
timeout: 10
parameters:
- name: Sample
default: "4"
Expand Down
51 changes: 51 additions & 0 deletions artifacts/definitions/Windows/Search/Yara.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
name: Windows.Search.Yara
description: |
Searches for a specific malicious file or set of files by a Yara rule.
You will need to upload your yara file using:
```
velociraptor tools upload --name YaraRules my_yara_file.yara
```
tools:
- name: YaraRules

parameters:
- name: nameRegex
description: Only file names that match this regular expression will be scanned.
default: "(exe|txt|dll|php)$"

precondition:
SELECT * FROM info() WHERE OS =~ "windows"

sources:
- query: |
LET yara_rules <= SELECT read_file(filename=FullPath) AS Rule
FROM Artifact.Generic.Utils.FetchBinary(ToolName="YaraRules")
LET fileList = SELECT FullPath
FROM parse_mft(
accessor="ntfs",
filename="C:\\$MFT")
WHERE InUse
AND FileName =~ nameRegex
AND NOT FullPath =~ "WinSXS"
-- These files are typically short - only report a single hit.
LET search = SELECT Rule, String.Offset AS HitOffset,
str(str=String.Data) AS HitContext,
FileName,
File.Size AS Size,
File.ModTime AS ModTime
FROM yara(
rules=yara_rules[0].Rule, key="A",
files="C:/" + FullPath)
LIMIT 1
-- Only do something when yara rules are available.
SELECT * FROM if(condition=yara_rules,
then={
SELECT *, upload(file=FileName) AS Upload
FROM foreach(row=fileList, query=search)
})
Loading

0 comments on commit 4bcd98d

Please sign in to comment.