Summary
The ExplainGlobExpression API endpoint (POST /api/v2/clients/<client_id>/glob-expressions:explain) does not require a client approval. When a glob expression containing KnowledgeBase interpolation variables (e.g., %%users.homedir%%, %%users.username%%, %%fqdn%%) is submitted, the handler expands those variables against the client's stored KnowledgeBase -- exposing user account details, home directories, domain names, and environment paths to any authenticated GRR user without an approval.
Details
Every other client-data endpoint in ApiCallRouterWithApprovalChecks calls self.approval_checker.CheckClientAccess(context, args.client_id) before delegating to the handler. ExplainGlobExpression at lines 687-694 has an explicit comment acknowledging no approval is done, but the justification is that it "only exposes the KnowledgeBase":
grr/server/grr_response_server/gui/api_call_router_with_approval_checks.py, lines 687-694:
def ExplainGlobExpression(
self,
args: api_flow_pb2.ApiExplainGlobExpressionArgs,
context: Optional[api_call_context.ApiCallContext] = None,
) -> api_flow.ApiExplainGlobExpressionHandler:
# ExplainGlobExpression only exposes the KnowledgeBase, which does not need
# approval.
return self.delegate.ExplainGlobExpression(args, context=context)
The handler (ApiExplainGlobExpressionHandler, flow.py, lines 1356-1373) calls GetClientKnowledgeBase(args.client_id) (data_store_utils.py, line 49), which reads the full ClientSnapshot.knowledge_base from the database and passes it to GlobExpression.ExplainComponents. The KnowledgeBase proto (knowledge_base.proto, lines 99-204) includes:
users[].username, users[].homedir, users[].userprofile, users[].userdomain, users[].sid
fqdn, os, os_major_version, os_minor_version
environ_path, environ_temp, environ_allusersprofile
- Windows-specific:
environ_commonprogramfiles, environ_windir, environ_programfiles
The KnowledgeBase is populated by the Interrogate flow and often contains detailed enumeration of all local user accounts. This data is normally protected by the approval requirement on all client endpoints that return ClientSnapshot or ClientFullInfo.
The assessment that the KnowledgeBase "does not need approval" is incorrect: it discloses the usernames and home directories of all accounts on the monitored endpoint, which is sensitive information in a DFIR context (investigators may be monitoring specific accounts, and the KnowledgeBase enumeration reveals the full account list to any peer analyst).
PoC
Prerequisites: GRR server with ApiCallRouterWithApprovalChecks, an enrolled client C.aabbccddeeff0011 whose KnowledgeBase has been populated (via Interrogate flow). User bob has no approval on this client.
Bob calls ExplainGlobExpression with a KB-variable glob:
POST /api/v2/clients/C.aabbccddeeff0011/glob-expressions:explain HTTP/1.1
Authorization: Basic Ym9iOi4uLg==
X-CSRFToken: <bob's csrf token>
Content-Type: application/json
{"globExpression": "%%users.homedir%%/.bash_history", "exampleCount": 5}
Response (HTTP 200) -- returns expanded examples drawn from the client's KnowledgeBase:
{"components": [{"globExpression": "%%users.homedir%%", "examples": ["/home/alice", "/home/bob.admin", "/root", "/home/svc-backup"]}, {"globExpression": ".bash_history"}]}
The response reveals all usernames/home directories stored in the KnowledgeBase without an approval. For comparison, GET /api/v2/clients/C.aabbccddeeff0011/flows (which also reads client data) returns HTTP 403 for bob.
Additionally, simpler globs (e.g., /etc/*.conf) that do not use KB variables still succeed with HTTP 200, confirming the endpoint is entirely unapproved:
POST /api/v2/clients/C.1234567890abcdef/glob-expressions:explain
Authorization: Basic <bob>
{"globExpression": "/etc/*.conf", "exampleCount": 3}
Response: HTTP 200, {"components": [{"globExpression": "/etc/"}, {"globExpression": "*"}, {"globExpression": ".conf"}]}
Tested live on commit 9f8f797 (GRR 4.0.0.0).
Impact
Any authenticated GRR user can read the KnowledgeBase of any enrolled client (usernames, home directories, domain membership, OS details) by submitting a glob expression with KnowledgeBase interpolation variables. In incident-response contexts, the KnowledgeBase enumerates all user accounts on a monitored endpoint. This information is normally gated behind the approval workflow; this endpoint bypasses it.
Summary
The
ExplainGlobExpressionAPI endpoint (POST /api/v2/clients/<client_id>/glob-expressions:explain) does not require a client approval. When a glob expression containing KnowledgeBase interpolation variables (e.g.,%%users.homedir%%,%%users.username%%,%%fqdn%%) is submitted, the handler expands those variables against the client's stored KnowledgeBase -- exposing user account details, home directories, domain names, and environment paths to any authenticated GRR user without an approval.Details
Every other client-data endpoint in
ApiCallRouterWithApprovalCheckscallsself.approval_checker.CheckClientAccess(context, args.client_id)before delegating to the handler.ExplainGlobExpressionat lines 687-694 has an explicit comment acknowledging no approval is done, but the justification is that it "only exposes the KnowledgeBase":grr/server/grr_response_server/gui/api_call_router_with_approval_checks.py, lines 687-694:The handler (
ApiExplainGlobExpressionHandler, flow.py, lines 1356-1373) callsGetClientKnowledgeBase(args.client_id)(data_store_utils.py, line 49), which reads the fullClientSnapshot.knowledge_basefrom the database and passes it toGlobExpression.ExplainComponents. The KnowledgeBase proto (knowledge_base.proto, lines 99-204) includes:users[].username,users[].homedir,users[].userprofile,users[].userdomain,users[].sidfqdn,os,os_major_version,os_minor_versionenviron_path,environ_temp,environ_allusersprofileenviron_commonprogramfiles,environ_windir,environ_programfilesThe KnowledgeBase is populated by the Interrogate flow and often contains detailed enumeration of all local user accounts. This data is normally protected by the approval requirement on all client endpoints that return
ClientSnapshotorClientFullInfo.The assessment that the KnowledgeBase "does not need approval" is incorrect: it discloses the usernames and home directories of all accounts on the monitored endpoint, which is sensitive information in a DFIR context (investigators may be monitoring specific accounts, and the KnowledgeBase enumeration reveals the full account list to any peer analyst).
PoC
Prerequisites: GRR server with
ApiCallRouterWithApprovalChecks, an enrolled clientC.aabbccddeeff0011whose KnowledgeBase has been populated (via Interrogate flow). Userbobhas no approval on this client.Bob calls
ExplainGlobExpressionwith a KB-variable glob:Response (HTTP 200) -- returns expanded examples drawn from the client's KnowledgeBase:
{"components": [{"globExpression": "%%users.homedir%%", "examples": ["/home/alice", "/home/bob.admin", "/root", "/home/svc-backup"]}, {"globExpression": ".bash_history"}]}The response reveals all usernames/home directories stored in the KnowledgeBase without an approval. For comparison,
GET /api/v2/clients/C.aabbccddeeff0011/flows(which also reads client data) returns HTTP 403 for bob.Additionally, simpler globs (e.g.,
/etc/*.conf) that do not use KB variables still succeed with HTTP 200, confirming the endpoint is entirely unapproved:Response: HTTP 200,
{"components": [{"globExpression": "/etc/"}, {"globExpression": "*"}, {"globExpression": ".conf"}]}Tested live on commit 9f8f797 (GRR 4.0.0.0).
Impact
Any authenticated GRR user can read the KnowledgeBase of any enrolled client (usernames, home directories, domain membership, OS details) by submitting a glob expression with KnowledgeBase interpolation variables. In incident-response contexts, the KnowledgeBase enumerates all user accounts on a monitored endpoint. This information is normally gated behind the approval workflow; this endpoint bypasses it.