Skip to content

Commit

Permalink
Added test for encrypted offline collector. (Velocidex#2149)
Browse files Browse the repository at this point in the history
  • Loading branch information
scudette authored Oct 10, 2022
1 parent 0b422a3 commit c25418b
Show file tree
Hide file tree
Showing 6 changed files with 298 additions and 131 deletions.
140 changes: 83 additions & 57 deletions artifacts/definitions/Server/Utils/CreateCollector.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,10 @@ parameters:
- name: template
default:
description: The HTML report template to use.

- name: encryption_scheme
description: |
Encryption scheme to use. Currently supported are Passowrd and PGP
Encryption scheme to use. Currently supported are Passowrd, X509 or PGP
- name: encryption_args
description: |
Expand Down Expand Up @@ -121,7 +121,9 @@ parameters:
- name: opt_cpu_limit
default: "0"
type: int
description: A number between 0 to 100 representing the target maximum CPU utilization during running of this artifact.
description: |
A number between 0 to 100 representing the target maximum CPU
utilization during running of this artifact.
- name: opt_progress_timeout
default: "1800"
Expand All @@ -141,28 +143,9 @@ parameters:
- name: StandardCollection
type: hidden
default: |
// Add all the tools we are going to use to the inventory.
LET _ <= SELECT inventory_add(tool=ToolName, hash=ExpectedHash)
FROM parse_csv(filename="/inventory.csv", accessor="me")
WHERE log(message="Adding tool " + ToolName)
LET baseline <= SELECT Fqdn FROM info()
// Make the filename safe on windows but we trust the OutputPrefix.
LET filename <= OutputPrefix + regex_replace(
source=format(format="Collection-%s-%s",
args=[baseline[0].Fqdn,
timestamp(epoch=now()).MarshalText]),
re="[^0-9A-Za-z\\-]", replace="_")
LET _ <= log(message="Will collect package " + filename)
LET report_filename <= if(condition=Template, then=filename + ".html")
LET X <= SELECT format(format="%02x", args=rand(range=255)) AS A FROM range(end=25)
LET pass = SELECT * FROM switch(a={SELECT join(array=X.A) as Pass From scope() WHERE encryption_scheme =~ "pgp|x509"},
b={SELECT encryption_args.password as Pass FROM scope() WHERE encryption_scheme =~ "password"},
c={SELECT Null as Pass FROM scope()})
SELECT * FROM collect(artifacts=Artifacts, report=report_filename,
args=Parameters, output=filename + ".zip", template=Template,
cpu_limit=CpuLimit,
Expand All @@ -171,13 +154,7 @@ parameters:
password=pass[0].Pass,
level=Level,
format=Format,
metadata=if(condition=encryption_args.public_key, then={
SELECT pk_encrypt(data=pass[0].Pass, public_key=encryption_args.public_key,
scheme=encryption_scheme) AS EncryptedPass,
encryption_scheme as Scheme,
encryption_args.public_key as PublicKey FROM scope()
})
)
metadata=ContainerMetadata)
- name: S3Collection
type: hidden
Expand Down Expand Up @@ -220,16 +197,15 @@ parameters:
endpoint=TargetArgs.endpoint,
hostkey = TargetArgs.hostkey)
- name: CloudCollection
- name: CommonCollections
type: hidden
default: |
// Add all the tools we are going to use to the inventory.
LET _ <= SELECT inventory_add(tool=ToolName, hash=ExpectedHash)
FROM parse_csv(filename="/inventory.csv", accessor="me")
WHERE log(message="Adding tool " + ToolName)
FROM parse_csv(filename="/inventory.csv", accessor="me")
WHERE log(message="Adding tool " + ToolName)
LET baseline <= SELECT Fqdn, basename(path=Exe) AS Exe FROM info()
LET TargetArgs <= target_args
// Make the filename safe on windows but we trust the OutputPrefix.
LET filename <= OutputPrefix + regex_replace(
Expand All @@ -238,6 +214,47 @@ parameters:
timestamp(epoch=now()).MarshalText]),
re="[^0-9A-Za-z\\-]", replace="_")
-- Make a random hex string as a random password
LET RandomPassword <= SELECT format(format="%02x",
args=rand(range=255)) AS A
FROM range(end=25)
LET pass = SELECT * FROM switch(a={
-- For X509 encryption we use a random session password.
SELECT join(array=RandomPassword.A) as Pass From scope()
WHERE encryption_scheme =~ "pgp|x509"
AND log(message="I will generate a container password using the %v scheme",
args=encryption_scheme)
}, b={
-- Otherwise the user specified the password.
SELECT encryption_args.password as Pass FROM scope()
WHERE encryption_scheme =~ "password"
}, c={
-- No password specified.
SELECT Null as Pass FROM scope()
})
-- For X509 encryption_scheme, store the encrypted
-- password in the metadata file for later retrieval.
LET ContainerMetadata = if(
condition=encryption_args.public_key,
then=dict(
EncryptedPass=pk_encrypt(data=pass[0].Pass,
public_key=encryption_args.public_key,
scheme=encryption_scheme),
Scheme=encryption_scheme,
PublicKey=encryption_args.public_key))
- name: CloudCollection
type: hidden
default: |
LET TargetArgs <= target_args
// Try to upload the log file now to see if we are even able to
// upload at all - we do this to avoid having to collect all the
// data and then failing the upload step.
Expand All @@ -251,11 +268,6 @@ parameters:
" and upload to cloud bucket " + TargetArgs.bucket)
LET report_filename <= if(condition=Template, then=tempfile(extension=".html"))
LET X <= SELECT format(format="%02x", args=rand(range=255)) AS A FROM range(end=25)
LET pass = SELECT * FROM switch(a={SELECT join(array=X.A) as Pass From scope() WHERE encryption_scheme =~ "pgp"},
b={SELECT encryption_args.password as Pass FROM scope() WHERE encryption_scheme =~ "password"},
c={SELECT Null as Pass FROM scope()})
LET collect_and_upload = SELECT
upload_file(filename=Container,
name=filename+".zip",
Expand All @@ -267,6 +279,7 @@ parameters:
upload_file(filename=baseline[0].Exe + ".log",
name=filename+".log",
accessor="file") AS LogUpload
FROM collect(artifacts=Artifacts,
report=report_filename,
args=Parameters,
Expand All @@ -278,15 +291,13 @@ parameters:
timeout=Timeout,
password=pass[0].Pass,
level=Level,
metadata=if(condition=encryption_args.public_key, then={
SELECT pk_encrypt(data=pass.Pass, public_key=encryption_args.public_key, scheme=encryption_scheme) AS EncryptedPass, encryption_scheme as Scheme FROM scope()
})
)
metadata=ContainerMetadata)
SELECT * FROM if(condition=upload_test.Path,
then=collect_and_upload,
else={SELECT log(message="Aborting collection: Failed to upload to cloud bucket!")
FROM scope()})
else={SELECT log(
message="Aborting collection: Failed to upload to cloud bucket!")
FROM scope()})
- name: PackageToolsArtifact
description: Collects and uploads third party binaries.
Expand Down Expand Up @@ -392,20 +403,35 @@ sources:
artifact_definitions=PackageToolsArtifact)
LET CollectionArtifact <= SELECT Value FROM switch(
a = { SELECT StandardCollection AS Value FROM scope() WHERE target = "ZIP" },
b = { SELECT S3Collection + CloudCollection AS Value FROM scope() WHERE target = "S3" },
c = { SELECT GCSCollection + CloudCollection AS Value FROM scope() WHERE target = "GCS" },
d = { SELECT SFTPCollection + CloudCollection AS Value FROM scope() WHERE target = "SFTP" },
e = { SELECT "" AS Value FROM scope() WHERE log(message="Unknown collection type " + target) }
a = { SELECT CommonCollections + StandardCollection AS Value
FROM scope()
WHERE target = "ZIP" },
b = { SELECT S3Collection + CommonCollections + CloudCollection AS Value
FROM scope()
WHERE target = "S3" },
c = { SELECT GCSCollection + CommonCollections + CloudCollection AS Value
FROM scope()
WHERE target = "GCS" },
d = { SELECT SFTPCollection + CommonCollections + CloudCollection AS Value
FROM scope()
WHERE target = "SFTP" },
e = { SELECT "" AS Value FROM scope()
WHERE log(message="Unknown collection type " + target) }
)
LET use_server_cert = SELECT log(message="Pubkey encryption specified, but no cert/key provided. Defaulting to server frontend cert") FROM scope() WHERE encryption_scheme =~ "x509" AND encryption_args.public_key =~ ""
LET updated_encryption_args <= if(condition=use_server_cert,
then=dict(public_key=server_frontend_cert(),
scheme="x509"),
else=encryption_args
)
LET use_server_cert = encryption_scheme =~ "x509"
AND encryption_args.public_key =~ ""
AND log(message="Pubkey encryption specified, but no cert/key provided. Defaulting to server frontend cert")
-- For x509, if no public key cert is specified, we use the
-- server's own key. This makes it easy for the server to import
-- the file again.
LET updated_encryption_args <= if(
condition=use_server_cert,
then=dict(public_key=server_frontend_cert(),
scheme="x509"),
else=encryption_args
)
LET definitions <= SELECT * FROM chain(
a = { SELECT name, description, tools, parameters, sources, reports
Expand Down Expand Up @@ -433,7 +459,7 @@ sources:
type="json"),
dict(name="Template", default=template),
dict(name="encryption_scheme", default=encryption_scheme),
dict(name="encryption_args",
dict(name="encryption_args",
default=serialize(format='json', item=updated_encryption_args),
type="json"
),
Expand Down
Loading

0 comments on commit c25418b

Please sign in to comment.