diff --git a/compile/template.yaml b/compile/template.yaml
index ade082b..c396409 100644
--- a/compile/template.yaml
+++ b/compile/template.yaml
@@ -157,8 +157,8 @@ sources:
/*
# Results From %v
*/
- SELECT * FROM source(source=%q)
- ''', args=[Source, Source]),
+ SELECT * FROM source(source=%q, artifact=%q)
+ ''', args=[Source, Source, split(string=ArtifactName, sep='/')[0]]),
output=format(format='''
Recalculate to show Results from %v with %v rows
''', args=[Source, Records])) AS NotebookModification
diff --git a/definitions/Windows_ActivitiesCache.yaml b/definitions/Windows_ActivitiesCache.yaml
index c907609..2d6a884 100644
--- a/definitions/Windows_ActivitiesCache.yaml
+++ b/definitions/Windows_ActivitiesCache.yaml
@@ -40,7 +40,7 @@ Sources:
EndTime,
Payload,
OSPath[1] AS User,
- base64decode(string=parse_json_array(data=ClipboardPayload)[0].content) AS ClipboardPayload,
+ base64decode(string=parse_json_array(data=ClipboardPayload || '[]')[0].content) AS ClipboardPayload,
OSPath AS Path,
Mtime
FROM Rows
diff --git a/docs/content/docs/rules/index.json b/docs/content/docs/rules/index.json
index 23e4d6d..7815340 100644
--- a/docs/content/docs/rules/index.json
+++ b/docs/content/docs/rules/index.json
@@ -93,7 +93,7 @@
{
"Name": "Chromium_Browser_Extensions",
"Author": "Mike Cohen",
- "Description": "Parses all installed chromium extensions.\n",
+ "Description": "Parses all installed chromium extensions.\n\nManifest V3 extensions list the sites they can read or change in\n`host_permissions` rather than `permissions`, so both are reported.\n`ContentScriptMatches` lists the sites where the extension injects\nits own scripts.\n",
"Categories": [
"Chrome",
"Browser"
@@ -103,7 +103,7 @@
"Name": ""
}
],
- "RawData": "Name: Chromium Browser Extensions\nDescription: |\n Parses all installed chromium extensions.\n\nAuthor: Mike Cohen\nCategories:\n - Chrome\n - Browser\n\nFilenameRegex: \"manifest.json\"\nGlobs:\n - \"{{LinuxChromeProfiles}}/*/Extensions/**/manifest.json\"\n - \"{{WindowsChromeProfiles}}/*/Extensions/**/manifest.json\"\n - \"{{MacOSChromeProfiles}}/*/Extensions/**/manifest.json\"\n\nSources:\n- Preamble: |\n -- Resolve the message string against the Locale dict\n LET ResolveName(Message, Locale) = get(item=Locale,\n field=lowcase(string=parse_string_with_regex(regex=\"^__MSG_(.+)__$\", string=Message).g1),\n default=Message).message || Message\n\n -- Read the manifest files\n LET ManifestData = SELECT OSPath, parse_json(data=read_file(filename=OSPath)) AS Manifest\n FROM Rows\n\n -- Find the Locale file to help with.\n LET LocaleData = SELECT *, if(condition=Manifest.default_locale, else=dict(),\n then=parse_json(data=read_file(\n filename=OSPath.Dirname + \"_locales\" + Manifest.default_locale + \"messages.json\"))) AS Locale\n FROM ManifestData\n\n LET GetIcon(Manifest) = Manifest.icons.`128` || Manifest.icons.`64` || Manifest.icons.`32` || Manifest.icons.`16`\n\n VQL: |\n SELECT OSPath, Manifest.author.email AS Email,\n ResolveName(Message = Manifest.name, Locale=Locale) AS name,\n ResolveName(Message = Manifest.description, Locale=Locale) AS description,\n Manifest.oauth2.scopes as Scopes,\n Manifest.permissions as Permissions,\n Manifest.key as Key, if(condition=GetIcon(Manifest=Manifest),\n then=upload(file=OSPath.Dirname + GetIcon(Manifest=Manifest))) AS Image,\n Manifest AS _Manifest\n FROM LocaleData\n WHERE (name, description) =~ FilterRegex\n"
+ "RawData": "Name: Chromium Browser Extensions\nDescription: |\n Parses all installed chromium extensions.\n\n Manifest V3 extensions list the sites they can read or change in\n `host_permissions` rather than `permissions`, so both are reported.\n `ContentScriptMatches` lists the sites where the extension injects\n its own scripts.\n\nAuthor: Mike Cohen\nCategories:\n - Chrome\n - Browser\n\nFilenameRegex: \"manifest.json\"\nGlobs:\n - \"{{LinuxChromeProfiles}}/*/Extensions/*/*/manifest.json\"\n - \"{{WindowsChromeProfiles}}/*/Extensions/*/*/manifest.json\"\n - \"{{MacOSChromeProfiles}}/*/Extensions/*/*/manifest.json\"\n\nSources:\n- Preamble: |\n -- Resolve the message string against the Locale dict\n LET ResolveName(Message, Locale) = get(item=Locale,\n field=lowcase(string=parse_string_with_regex(regex=\"^__MSG_(.+)__$\", string=Message).g1),\n default=Message).message || Message\n\n -- Read the manifest files\n LET ManifestData = SELECT OSPath, parse_json(data=read_file(filename=OSPath)) AS Manifest\n FROM Rows\n\n -- Message names are case insensitive so lower case the keys to\n -- match ResolveName()\n LET LowerKeys(Item) = to_dict(item={\n SELECT lowcase(string=_key) AS _key, _value FROM items(item=Item)\n })\n\n -- Find the Locale file to help with.\n LET LocaleData = SELECT *, if(condition=Manifest.default_locale, else=dict(),\n then=LowerKeys(Item=parse_json(data=read_file(\n filename=OSPath.Dirname + \"_locales\" + Manifest.default_locale + \"messages.json\")))) AS Locale\n FROM ManifestData\n\n LET GetIcon(Manifest) = Manifest.icons.`128` || Manifest.icons.`64` || Manifest.icons.`32` || Manifest.icons.`16`\n\n -- Flatten the matches of all content scripts into one list of unique sites.\n LET ContentScriptMatches(Manifest) = SELECT * FROM foreach(\n row=Manifest.content_scripts,\n query={ SELECT _value FROM foreach(row=matches) })\n GROUP BY _value\n\n VQL: |\n SELECT OSPath,\n -- Manifests are stored in Extensions/\u003cID\u003e/\u003cVersion\u003e/\n OSPath.Components[-3] AS ID,\n OSPath.Components[-2] AS Version,\n Manifest.author.email AS Email,\n ResolveName(Message = Manifest.name, Locale=Locale) AS name,\n ResolveName(Message = Manifest.description, Locale=Locale) AS description,\n Manifest.manifest_version AS ManifestVersion,\n Manifest.oauth2.scopes as Scopes,\n Manifest.permissions as Permissions,\n Manifest.host_permissions AS HostPermissions,\n ContentScriptMatches(Manifest=Manifest)._value AS ContentScriptMatches,\n Manifest.key as Key, if(condition=GetIcon(Manifest=Manifest),\n then=upload(file=OSPath.Dirname + GetIcon(Manifest=Manifest))) AS Image,\n Manifest AS _Manifest\n FROM LocaleData\n WHERE (name, description) =~ FilterRegex\n"
},
{
"Name": "Chromium_Browser_Favicons",
@@ -548,7 +548,7 @@
"Name": "Clipboard"
}
],
- "RawData": "Name: Windows Activities Cache\nAuthor: Eric Zimmerman\nEmail: saericzimmerman@gmail.com\nReference: https://github.com/EricZimmerman/SQLECmd\nSQLiteIdentifyQuery: |\n SELECT count(*) AS `Check`\n FROM sqlite_master\n WHERE type='table'\n AND (name='Activity' OR name='Activity_PackageId' OR name='ActivityOperation');\nSQLiteIdentifyValue: 3\nCategories:\n - Windows\n\nFilenameRegex: \"ActivitiesCache.db\"\nGlobs:\n - \"C:/Users/*/AppData/Local/ConnectedDevicesPlatform/L.*/ActivitiesCache.db\"\n\nSources:\n- name: ActivityPackageId\n VQL: |\n SELECT format(format=\"%0X-%0X-%0X-%0X-%0X\", args=[\n ActivityId[0:4], ActivityId[4:6], ActivityId[6:8],\n ActivityId[8:10], ActivityId[10:] ]) AS ActivityId,\n Platform, PackageName, ExpirationTime, OSPath\n FROM Rows\n\n SQL: |\n Select ActivityId, Platform, PackageName, ExpirationTime\n FROM Activity_PackageId\n\n- name: Clipboard\n SQL: |\n SELECT * FROM ActivityOperation\n VQL: |\n SELECT\n CreatedTime,\n timestamp(epoch=LastModifiedTime) AS LastModifiedTime,\n timestamp(epoch=LastModifiedOnClient) AS LastModifiedOnClient,\n StartTime,\n EndTime,\n Payload,\n OSPath[1] AS User,\n base64decode(string=parse_json_array(data=ClipboardPayload)[0].content) AS ClipboardPayload,\n OSPath AS Path,\n Mtime\n FROM Rows\n WHERE StartTime \u003e DateAfter\n AND StartTime \u003c DateBefore\n AND ClipboardPayload =~ FilterRegex\n"
+ "RawData": "Name: Windows Activities Cache\nAuthor: Eric Zimmerman\nEmail: saericzimmerman@gmail.com\nReference: https://github.com/EricZimmerman/SQLECmd\nSQLiteIdentifyQuery: |\n SELECT count(*) AS `Check`\n FROM sqlite_master\n WHERE type='table'\n AND (name='Activity' OR name='Activity_PackageId' OR name='ActivityOperation');\nSQLiteIdentifyValue: 3\nCategories:\n - Windows\n\nFilenameRegex: \"ActivitiesCache.db\"\nGlobs:\n - \"C:/Users/*/AppData/Local/ConnectedDevicesPlatform/L.*/ActivitiesCache.db\"\n\nSources:\n- name: ActivityPackageId\n VQL: |\n SELECT format(format=\"%0X-%0X-%0X-%0X-%0X\", args=[\n ActivityId[0:4], ActivityId[4:6], ActivityId[6:8],\n ActivityId[8:10], ActivityId[10:] ]) AS ActivityId,\n Platform, PackageName, ExpirationTime, OSPath\n FROM Rows\n\n SQL: |\n Select ActivityId, Platform, PackageName, ExpirationTime\n FROM Activity_PackageId\n\n- name: Clipboard\n SQL: |\n SELECT * FROM ActivityOperation\n VQL: |\n SELECT\n CreatedTime,\n timestamp(epoch=LastModifiedTime) AS LastModifiedTime,\n timestamp(epoch=LastModifiedOnClient) AS LastModifiedOnClient,\n StartTime,\n EndTime,\n Payload,\n OSPath[1] AS User,\n base64decode(string=parse_json_array(data=ClipboardPayload || '[]')[0].content) AS ClipboardPayload,\n OSPath AS Path,\n Mtime\n FROM Rows\n WHERE StartTime \u003e DateAfter\n AND StartTime \u003c DateBefore\n AND ClipboardPayload =~ FilterRegex\n"
},
{
"Name": "Windows_WPNDatabase___Notifications",
diff --git a/testing/golden.go b/testing/golden_test.go
similarity index 100%
rename from testing/golden.go
rename to testing/golden_test.go
diff --git a/testing/testcases/chrome_extensions.in.yaml b/testing/testcases/chrome_extensions.in.yaml
index 6852011..e74b262 100644
--- a/testing/testcases/chrome_extensions.in.yaml
+++ b/testing/testcases/chrome_extensions.in.yaml
@@ -7,5 +7,5 @@ Queries:
FROM Artifact.Generic.Forensic.SQLiteHunter(
MatchFilename=TRUE, All=FALSE, Chrome=TRUE,
CustomGlob=testFiles + '/Chrome/Extensions/*/*/manifest.json')
- WHERE _Source =~ "Chromium Browser Extensions"
+ WHERE _Source =~ "Chromium_Browser_Extensions"
ORDER BY ID
diff --git a/testing/testcases/chrome_extensions.out.yaml b/testing/testcases/chrome_extensions.out.yaml
index ba7f967..96f5ee9 100644
--- a/testing/testcases/chrome_extensions.out.yaml
+++ b/testing/testcases/chrome_extensions.out.yaml
@@ -5,7 +5,7 @@ Query: SELECT ID, Version, name, description, ManifestVersion,
FROM Artifact.Generic.Forensic.SQLiteHunter(
MatchFilename=TRUE, All=FALSE, Chrome=TRUE,
CustomGlob=testFiles + '/Chrome/Extensions/*/*/manifest.json')
-WHERE _Source =~ "Chromium Browser Extensions"
+WHERE _Source =~ "Chromium_Browser_Extensions"
ORDER BY ID
Output: [