-
Notifications
You must be signed in to change notification settings - Fork 9
Add PotentiallyUnguardedProtocolHandler query for Java and C++ #32
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
ex0dus-0x
wants to merge
6
commits into
main
Choose a base branch
from
alan/untrusted-protocol-handle
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
05212aa
init: add PotentiallyUnguardedProtocolHandler query
ex0dus-0x 4664d38
add legacy protocol handler support
ex0dus-0x b2d7c37
add support for C++/Qt, and genericize shell execution models for all…
ex0dus-0x 7efd379
fix java tests
ex0dus-0x 4d28876
Add docs and fix CI/CD issue
ex0dus-0x e0d42d1
Fix up tests, and enhance query with better isBarrier
ex0dus-0x File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
87 changes: 87 additions & 0 deletions
87
...rity/PotentiallyUnguardedProtocolHandler/PotentiallyUnguardedProtocolHandler.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,87 @@ | ||
| # Potentially unguarded protocol handler invocation | ||
|
|
||
| This query detects calls to URL protocol handlers with untrusted input that may not be properly validated for dangerous protocols. This vulnerability is related to CWE-939 (Improper Authorization in Handler for Custom URL Scheme) and aligns with CVE-2022-43550. | ||
|
|
||
| When applications invoke protocol handlers (like `rundll32 url.dll,FileProtocolHandler` on Windows, `xdg-open` on Linux, `open` on macOS, or Qt's `QDesktopServices::openUrl()`), untrusted URLs can potentially trigger dangerous protocols such as `file://`, `smb://`, or other custom handlers that may lead to unauthorized file access, command execution, or other security issues. | ||
|
|
||
| ## Detected patterns | ||
|
|
||
| The query identifies several common protocol handler invocation patterns: | ||
|
|
||
| - **Windows**: `rundll32 url.dll,FileProtocolHandler` via system calls | ||
| - **Linux**: `xdg-open` via system calls | ||
| - **macOS**: `open` command via system calls | ||
| - **Qt applications**: `QDesktopServices::openUrl()` | ||
|
|
||
| ## Recommendation | ||
|
|
||
| Always validate URL schemes before passing them to protocol handlers. Only allow safe protocols like `http://` and `https://`. Reject or sanitize URLs containing potentially dangerous protocols. | ||
|
|
||
| ## Example | ||
|
|
||
| The following vulnerable code passes untrusted input directly to a protocol handler: | ||
|
|
||
| ```cpp | ||
| #include <QDesktopServices> | ||
| #include <QUrl> | ||
|
|
||
| void openUserUrl(const QString& userInput) { | ||
| // VULNERABLE: No validation of the URL scheme | ||
| QDesktopServices::openUrl(QUrl(userInput)); | ||
| } | ||
| ``` | ||
|
|
||
| An attacker could provide a URL like `file:///etc/passwd` or `smb://attacker-server/share` to access unauthorized resources. | ||
|
|
||
| The corrected version validates the URL scheme before opening: | ||
|
|
||
| ```cpp | ||
| #include <QDesktopServices> | ||
| #include <QUrl> | ||
|
|
||
| void openUserUrl(const QString& userInput) { | ||
| QUrl url(userInput); | ||
| QString scheme = url.scheme().toLower(); | ||
|
|
||
| // Only allow safe protocols | ||
| if (scheme == "http" || scheme == "https") { | ||
| QDesktopServices::openUrl(url); | ||
| } else { | ||
| // Log error or show warning to user | ||
| qWarning() << "Rejected unsafe URL scheme:" << scheme; | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| For system command invocations: | ||
|
|
||
| ```cpp | ||
| void openUserUrlViaShell(const char* userInput) { | ||
| // VULNERABLE: Untrusted input passed to xdg-open | ||
| char cmd[512]; | ||
| snprintf(cmd, sizeof(cmd), "xdg-open '%s'", userInput); | ||
| system(cmd); | ||
| } | ||
| ``` | ||
|
|
||
| Should be corrected to validate the scheme: | ||
|
|
||
| ```cpp | ||
| bool isValidScheme(const char* url) { | ||
| return (strncasecmp(url, "http://", 7) == 0 || | ||
| strncasecmp(url, "https://", 8) == 0); | ||
| } | ||
|
|
||
| void openUserUrlViaShell(const char* userInput) { | ||
| if (isValidScheme(userInput)) { | ||
| char cmd[512]; | ||
| snprintf(cmd, sizeof(cmd), "xdg-open '%s'", userInput); | ||
| system(cmd); | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ## References | ||
|
|
||
| - [CWE-939: Improper Authorization in Handler for Custom URL Scheme](https://cwe.mitre.org/data/definitions/939.html) | ||
| - [CVE-2022-43550: USB Creator has insufficiently protected credentials](https://ubuntu.com/security/CVE-2022-43550) |
124 changes: 124 additions & 0 deletions
124
cpp/src/security/PotentiallyUnguardedProtocolHandler/PotentiallyUnguardedProtocolHandler.ql
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,124 @@ | ||
| /** | ||
| * @name Potentially unguarded protocol handler invocation | ||
| * @id tob/cpp/unguarded-protocol-handler | ||
| * @description Detects calls to URL protocol handlers with untrusted input that may not be properly validated for dangerous protocols | ||
| * @kind path-problem | ||
| * @tags security | ||
| * external/cwe/cwe-939 | ||
| * @precision medium | ||
| * @problem.severity warning | ||
| * @security-severity 6.5 | ||
| * @group security | ||
| */ | ||
|
|
||
| import cpp | ||
| private import semmle.code.cpp.ir.dataflow.TaintTracking | ||
| private import semmle.code.cpp.security.FlowSources | ||
| private import semmle.code.cpp.security.CommandExecution | ||
| private import semmle.code.cpp.controlflow.IRGuards | ||
|
|
||
| /** | ||
| * Holds when `call` invokes a system function (system, popen, exec*) with a command string | ||
| * that contains a URL protocol handler, `sink` is the argument carrying the URL, and | ||
| * `handlerType` describes which handler is invoked. | ||
| */ | ||
| predicate isShellProtocolHandlerSink(FunctionCall call, Expr sink, string handlerType) { | ||
| call.getTarget() instanceof SystemFunction and | ||
| exists(StringLiteral sl | | ||
| sl.getParent*() = call.getArgument(0) and | ||
| ( | ||
| sl.getValue().regexpMatch("(?i).*rundll32.*url\\.dll.*FileProtocolHandler.*") and | ||
| handlerType = "rundll32 url.dll,FileProtocolHandler" | ||
| or | ||
| sl.getValue().regexpMatch("(?i).*xdg-open.*") and | ||
| handlerType = "xdg-open" | ||
| or | ||
| sl.getValue().regexpMatch("(?i).*\\bopen\\b.*") and | ||
| handlerType = "open" | ||
| ) | ||
| ) and | ||
| sink = call.getArgument(0) | ||
| } | ||
|
|
||
| /** | ||
| * Holds when `call` invokes QDesktopServices::openUrl and `sink` is the URL argument. | ||
| */ | ||
| predicate isQtProtocolHandlerSink(FunctionCall call, Expr sink) { | ||
| call.getTarget().hasQualifiedName("", "QDesktopServices", "openUrl") and | ||
| sink = call.getArgument(0) | ||
| } | ||
|
|
||
| /** | ||
| * Gets the sink expression for a given DataFlow::Node matching either Qt or shell handler sinks. | ||
| */ | ||
| Expr getSinkExpr(DataFlow::Node sink) { | ||
| result = sink.asExpr() or | ||
| result = sink.asIndirectExpr() | ||
| } | ||
|
|
||
| /** | ||
| * Holds when `g` is a guard condition that validates the URL scheme of expression `e`. | ||
| * Flow is considered safe on the `branch` edge. | ||
| */ | ||
| predicate urlSchemeGuardChecks(IRGuardCondition g, Expr e, boolean branch) { | ||
| branch = [true, false] and | ||
| exists(FunctionCall fc | g.getUnconvertedResultExpression().getAChild*() = fc | | ||
| // C string comparison on the URL (strcmp, strncmp, etc.) | ||
| fc.getTarget().getName() = | ||
| [ | ||
| "strcmp", "strncmp", "strcasecmp", "strncasecmp", "strstr", "strcasestr", "_stricmp", | ||
| "_strnicmp" | ||
| ] and | ||
| e = fc.getAnArgument() | ||
| or | ||
| // Qt QString::startsWith check | ||
| fc.getTarget().hasQualifiedName("", "QString", "startsWith") and | ||
| e = fc.getQualifier() | ||
| or | ||
| // Qt QUrl::scheme() comparison | ||
| exists(FunctionCall schemeCall | | ||
| schemeCall.getTarget().hasQualifiedName("", "QUrl", "scheme") and | ||
| fc.getAnArgument() = schemeCall and | ||
| e = schemeCall.getQualifier() | ||
| ) | ||
| ) | ||
| } | ||
|
|
||
| /** | ||
| * Configuration for tracking untrusted data to protocol handler invocations. | ||
| */ | ||
| module PotentiallyUnguardedProtocolHandlerConfig implements DataFlow::ConfigSig { | ||
| predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource } | ||
|
|
||
| predicate isSink(DataFlow::Node sink) { | ||
| isQtProtocolHandlerSink(_, getSinkExpr(sink)) | ||
| or | ||
| isShellProtocolHandlerSink(_, getSinkExpr(sink), _) | ||
| } | ||
|
|
||
| predicate isBarrier(DataFlow::Node node) { | ||
| node = DataFlow::BarrierGuard<urlSchemeGuardChecks/3>::getABarrierNode() | ||
| or | ||
| node = DataFlow::BarrierGuard<urlSchemeGuardChecks/3>::getAnIndirectBarrierNode() | ||
| } | ||
| } | ||
|
|
||
| module PotentiallyUnguardedProtocolHandlerFlow = | ||
| TaintTracking::Global<PotentiallyUnguardedProtocolHandlerConfig>; | ||
|
|
||
| import PotentiallyUnguardedProtocolHandlerFlow::PathGraph | ||
|
|
||
| from | ||
| PotentiallyUnguardedProtocolHandlerFlow::PathNode source, | ||
| PotentiallyUnguardedProtocolHandlerFlow::PathNode sink, FunctionCall call, string callType | ||
| where | ||
| PotentiallyUnguardedProtocolHandlerFlow::flowPath(source, sink) and | ||
| ( | ||
| isQtProtocolHandlerSink(call, getSinkExpr(sink.getNode())) and | ||
| callType = "QDesktopServices::openUrl()" | ||
| or | ||
| isShellProtocolHandlerSink(call, getSinkExpr(sink.getNode()), callType) | ||
| ) | ||
| select call, source, sink, | ||
| callType + " is called with untrusted input from $@ without proper URL scheme validation.", | ||
| source.getNode(), "this source" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,6 +7,8 @@ | |
| extern "C" { | ||
| #endif | ||
|
|
||
| ssize_t read(int, void *, size_t); | ||
|
|
||
| void _exit(int); | ||
|
|
||
| #ifdef __cplusplus | ||
|
|
||
12 changes: 12 additions & 0 deletions
12
...security/PotentiallyUnguardedProtocolHandler/PotentiallyUnguardedProtocolHandler.expected
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| edges | ||
| | PotentiallyUnguardedProtocolHandler.cpp:27:11:27:13 | read output argument | PotentiallyUnguardedProtocolHandler.cpp:28:29:28:31 | *buf | provenance | | | ||
| | PotentiallyUnguardedProtocolHandler.cpp:39:11:39:13 | read output argument | PotentiallyUnguardedProtocolHandler.cpp:42:31:42:33 | *buf | provenance | | | ||
| nodes | ||
| | PotentiallyUnguardedProtocolHandler.cpp:27:11:27:13 | read output argument | semmle.label | read output argument | | ||
| | PotentiallyUnguardedProtocolHandler.cpp:28:29:28:31 | *buf | semmle.label | *buf | | ||
| | PotentiallyUnguardedProtocolHandler.cpp:39:11:39:13 | read output argument | semmle.label | read output argument | | ||
| | PotentiallyUnguardedProtocolHandler.cpp:42:31:42:33 | *buf | semmle.label | *buf | | ||
| subpaths | ||
| #select | ||
| | PotentiallyUnguardedProtocolHandler.cpp:28:3:28:27 | call to openUrl | PotentiallyUnguardedProtocolHandler.cpp:27:11:27:13 | read output argument | PotentiallyUnguardedProtocolHandler.cpp:28:29:28:31 | *buf | QDesktopServices::openUrl() is called with untrusted input from $@ without proper URL scheme validation. | PotentiallyUnguardedProtocolHandler.cpp:27:11:27:13 | read output argument | this source | | ||
| | PotentiallyUnguardedProtocolHandler.cpp:42:5:42:29 | call to openUrl | PotentiallyUnguardedProtocolHandler.cpp:39:11:39:13 | read output argument | PotentiallyUnguardedProtocolHandler.cpp:42:31:42:33 | *buf | QDesktopServices::openUrl() is called with untrusted input from $@ without proper URL scheme validation. | PotentiallyUnguardedProtocolHandler.cpp:39:11:39:13 | read output argument | this source | | ||
1 change: 1 addition & 0 deletions
1
...ts/security/PotentiallyUnguardedProtocolHandler/PotentiallyUnguardedProtocolHandler.qlref
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| security/PotentiallyUnguardedProtocolHandler/PotentiallyUnguardedProtocolHandler.ql |
99 changes: 99 additions & 0 deletions
99
...rity/PotentiallyUnguardedProtocolHandler/PotentiallyUnguardedProtocolHandler.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,99 @@ | ||
| # Potentially unguarded protocol handler invocation | ||
|
|
||
| This query detects calls to URL protocol handlers with untrusted input that may not be properly validated for dangerous protocols. This vulnerability is related to CWE-939 (Improper Authorization in Handler for Custom URL Scheme) and aligns with CVE-2022-43550. | ||
|
|
||
| When Java applications invoke protocol handlers (like `Desktop.browse()`, `Runtime.exec()` with `xdg-open`/`open`, or `rundll32 url.dll,FileProtocolHandler` on Windows), untrusted URLs can potentially trigger dangerous protocols such as `file://`, `smb://`, or other custom handlers that may lead to unauthorized file access, command execution, or other security issues. | ||
|
|
||
| ## Detected patterns | ||
|
|
||
| The query identifies several common protocol handler invocation patterns: | ||
|
|
||
| - **Java AWT**: `Desktop.browse(URI)` - the platform-agnostic standard | ||
| - **Windows**: `Runtime.exec()` with `rundll32 url.dll,FileProtocolHandler` | ||
| - **Linux**: `Runtime.exec()` with `xdg-open` | ||
| - **macOS**: `Runtime.exec()` with `open` command | ||
|
|
||
| ## Recommendation | ||
|
|
||
| Always validate URL schemes before passing them to protocol handlers. Only allow safe protocols like `http://` and `https://`. Reject or sanitize URLs containing potentially dangerous protocols. | ||
|
|
||
| ## Example | ||
|
|
||
| The following vulnerable code passes untrusted input directly to a protocol handler: | ||
|
|
||
| ```java | ||
| import java.awt.Desktop; | ||
| import java.net.URI; | ||
|
|
||
| public class UrlOpener { | ||
| public void openUserUrl(String userInput) throws Exception { | ||
| // VULNERABLE: No validation of the URL scheme | ||
| Desktop.getDesktop().browse(new URI(userInput)); | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| An attacker could provide a URL like `file:///etc/passwd` or `smb://attacker-server/share` to access unauthorized resources. | ||
|
|
||
| The corrected version validates the URL scheme before opening: | ||
|
|
||
| ```java | ||
| import java.awt.Desktop; | ||
| import java.net.URI; | ||
|
|
||
| public class UrlOpener { | ||
| public void openUserUrl(String userInput) throws Exception { | ||
| URI uri = new URI(userInput); | ||
| String scheme = uri.getScheme(); | ||
|
|
||
| // Only allow safe protocols | ||
| if ("http".equalsIgnoreCase(scheme) || "https".equalsIgnoreCase(scheme)) { | ||
| Desktop.getDesktop().browse(uri); | ||
| } else { | ||
| throw new SecurityException("Rejected unsafe URL scheme: " + scheme); | ||
| } | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| For system command invocations: | ||
|
|
||
| ```java | ||
| public class UrlOpener { | ||
| public void openUserUrlViaShell(String userInput) throws Exception { | ||
| // VULNERABLE: Untrusted input passed to xdg-open | ||
| Runtime.getRuntime().exec(new String[]{"xdg-open", userInput}); | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| Should be corrected to validate the scheme: | ||
|
|
||
| ```java | ||
| import java.net.URI; | ||
|
|
||
| public class UrlOpener { | ||
| private boolean isValidScheme(String url) { | ||
| try { | ||
| URI uri = new URI(url); | ||
| String scheme = uri.getScheme(); | ||
| return "http".equalsIgnoreCase(scheme) || "https".equalsIgnoreCase(scheme); | ||
| } catch (Exception e) { | ||
| return false; | ||
| } | ||
| } | ||
|
|
||
| public void openUserUrlViaShell(String userInput) throws Exception { | ||
| if (isValidScheme(userInput)) { | ||
| Runtime.getRuntime().exec(new String[]{"xdg-open", userInput}); | ||
| } else { | ||
| throw new SecurityException("Invalid or unsafe URL scheme"); | ||
| } | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ## References | ||
|
|
||
| - [CWE-939: Improper Authorization in Handler for Custom URL Scheme](https://cwe.mitre.org/data/definitions/939.html) | ||
| - [CVE-2022-43550: USB Creator has insufficiently protected credentials](https://ubuntu.com/security/CVE-2022-43550) |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.