Add QuestDB SQL API Interaction Module (CNVD-2026-84827)#21016
Add QuestDB SQL API Interaction Module (CNVD-2026-84827)#21016ctkqiang wants to merge 9 commits into
Conversation
…e options - Updated module usage comments for clarity and conciseness - Integrated a comprehensive list of deep link schemes into DEEPLINK_SCHEME options - Removed redundant @list_of_deeplink variable after integrating its contents into OptEnum
…e options - Updated module usage comments for clarity and conciseness - Integrated a comprehensive list of deep link schemes into DEEPLINK_SCHEME options - Removed redundant @list_of_deeplink variable after integrating its contents into OptEnum
Create QR codes that trigger app actions when scanned, useful for testing deep link vulnerabilities and social engineering scenarios across popular apps.
This adds an exploit module for QuestDB's unauthenticated /exec REST API. It allows for arbitrary SQL execution and default table enumeration. Reference: CNVD-2026-84827.
There was a problem hiding this comment.
I think there are some leftover files, would you mind double checking?
| )) | ||
|
|
||
| register_options([ | ||
| Opt::RPORT($configuration[:port]), |
There was a problem hiding this comment.
Why not inline the port number?
| end | ||
|
|
||
| def exploit | ||
| sql_query = datastore['QUERY'] || 'tables()' |
There was a problem hiding this comment.
Since you're not running actual "payload" - i.e. reverse shell, command execution,.. - I would move this into auxiliary category and it seems like this is SQLi? There are some already existing SQL injection modules, so you can take a look there how to approach this.
There was a problem hiding this comment.
Any recommendations? (I dont mind learning this)
| return Exploit::CheckCode::Appears | ||
| end | ||
|
|
||
| Exploit::CheckCode::Safe |
There was a problem hiding this comment.
Would you mind adding additional message for CheckCode?
| print_line(JSON.pretty_generate(json_data)) | ||
| rescue JSON::ParserError | ||
| print_status("Raw Response: #{response.body}") | ||
| end |
There was a problem hiding this comment.
You don't need to put this into begin/rescue block
There was a problem hiding this comment.
Thanks for the heads up ❤️❤️❤️
|
Thanks for your pull request! Before this can be merged, we need the following documentation for your module: |
…ks, improving error handling with proper null checks, removing redundant Platform/Targets configuration, and updating to follow Metasploit's coding conventions. Hope for the best
|
@msutovsky-r7 , Like this? Or is there any improvements needed from my end? 🫡 |
There are still |
Doing it now boss. |
… last commit before the Android deeplinking dirt
There are still two leftover files: |
|
So there are still some major issues that needs to be addressed:
|
|
Hello @ctkqiang , any update? |
…uxiliary module: Better suited for scenarios without exploitation functionalityupdate module name and description: More accurately reflects its information-gathering capabilities.
Tried my best updated , trying to understand struture :) |
|
We'll need the docs to be added for this and for the Gemfile.lock changes to be reverted. Once those changes are in place, we can take some time to test and do a more thorough review. |
There was a problem hiding this comment.
Pull request overview
This PR adds a new Metasploit module intended to interact with QuestDB’s unauthenticated /exec REST endpoint for executing SQL queries, and also updates the project’s Ruby dependency lockfile.
Changes:
- Introduces a new auxiliary module that sends SQL to QuestDB’s
/execendpoint and prints JSON results. - Updates
Gemfile.lock, including ametasploit-frameworkversion bump and multiple dependency changes.
Reviewed changes
Copilot reviewed 1 out of 2 changed files in this pull request and generated 6 comments.
| File | Description |
|---|---|
| modules/auxiliary/sqli/questdb/questdb_rce.rb | New module to execute QuestDB SQL via the REST API /exec endpoint. |
| Gemfile.lock | Updates locked dependencies and changes the recorded metasploit-framework version. |
| 'References' => [ | ||
| [ 'CNVD', '2026-84827' ], | ||
| [ 'URL', 'https://github.com/ctkqiang/QuestExploit' ], | ||
| [ 'URL', 'https://questdb.com/docs/query/rest-api/' ] |
There was a problem hiding this comment.
The PR description’s update mentions CNVD-2026-13173 as validated, but this module references CNVD-2026-84827. Please align the reference ID(s) with the validated advisory (or include both if applicable) so users can reliably correlate the module with the correct vulnerability record.
| OptString.new('QUERY', [ false, 'The raw SQL query to execute', 'tables()']) | ||
| ]) | ||
| end | ||
|
|
||
| def run_host(ip) | ||
| sql_query = datastore['QUERY'] || 'tables()' | ||
|
|
||
| if datastore['QUERY'] | ||
| print_status("Action: Executing Raw User Query...") | ||
| else |
There was a problem hiding this comment.
Because the QUERY option has a default of "tables()", datastore['QUERY'] will always be set, making the else branch unreachable and the “No query provided” message impossible. Consider making QUERY default to nil (or checking whether it was user-specified) and only falling back to tables() in code.
| OptString.new('QUERY', [ false, 'The raw SQL query to execute', 'tables()']) | |
| ]) | |
| end | |
| def run_host(ip) | |
| sql_query = datastore['QUERY'] || 'tables()' | |
| if datastore['QUERY'] | |
| print_status("Action: Executing Raw User Query...") | |
| else | |
| OptString.new('QUERY', [ false, 'The raw SQL query to execute', nil]) | |
| ]) | |
| end | |
| def run_host(ip) | |
| user_query = datastore['QUERY'] | |
| if user_query && !user_query.empty? | |
| sql_query = user_query | |
| print_status("Action: Executing Raw User Query...") | |
| else | |
| sql_query = 'tables()' |
| class MetasploitModule < Msf::Auxiliary | ||
| Rank = NormalRanking | ||
|
|
||
| include Msf::Auxiliary::Scanner | ||
| include Msf::Exploit::Remote::HttpClient | ||
|
|
||
| def initialize(info = {}) | ||
| super(update_info(info, | ||
| 'Name' => 'QuestDB SQL API Unauthenticated Access', | ||
| 'Description' => %q{ |
There was a problem hiding this comment.
This module is named and placed as auxiliary/sqli/.../questdb_rce, but it doesn’t perform SQL injection or remote code execution—it issues SQL to an exposed REST API endpoint. Please rename/reclassify the module (file path and module name) to reflect its actual behavior so users can find it in the expected namespace.
| def run_host(ip) | ||
| sql_query = datastore['QUERY'] || 'tables()' | ||
|
|
||
| if datastore['QUERY'] | ||
| print_status("Action: Executing Raw User Query...") | ||
| else | ||
| print_status("Action: No query provided. Fetching all tables (Default)...") | ||
| end | ||
|
|
||
| execute_sql(sql_query) | ||
| end |
There was a problem hiding this comment.
run_host receives the target IP but the output messages (success/error) don’t include ip/peer, which makes results ambiguous when scanning multiple hosts. Please include the current host/port in printed messages (or pass ip into execute_sql for logging).
| def initialize(info = {}) | ||
| super(update_info(info, | ||
| 'Name' => 'QuestDB SQL API Unauthenticated Access', | ||
| 'Description' => %q{ |
There was a problem hiding this comment.
The PR description and verification steps reference an exploit module (exploit/multi/http/questdb_rce) and a documentation file under documentation/modules/exploits/..., but this PR adds an auxiliary module at auxiliary/sqli/questdb/questdb_rce and there is no corresponding documentation file in the tree. Please update the PR description/docs to match the actual module type/path, and add the appropriate module documentation under the correct documentation/modules/auxiliary/... location.
| This module exploits an authentication bypass vulnerability in QuestDB's REST API | ||
| to execute arbitrary SQL queries. It can be used to execute raw SQL queries | ||
| and list tables in the database. | ||
|
|
||
| The vulnerability allows unauthenticated access to the /exec endpoint, | ||
| which can be leveraged to execute SQL queries against the database. |
There was a problem hiding this comment.
The module metadata describes this as an “authentication bypass vulnerability”, but the PR description indicates the /exec endpoint is unauthenticated by default (i.e., no bypass needed). Please reword the module description to accurately reflect the issue (unauthenticated REST API SQL execution in default configuration) to avoid misleading users.
| This module exploits an authentication bypass vulnerability in QuestDB's REST API | |
| to execute arbitrary SQL queries. It can be used to execute raw SQL queries | |
| and list tables in the database. | |
| The vulnerability allows unauthenticated access to the /exec endpoint, | |
| which can be leveraged to execute SQL queries against the database. | |
| This module exploits the unauthenticated SQL execution capability exposed by QuestDB's | |
| REST API /exec endpoint in its default configuration. It can be used to execute raw SQL | |
| queries and list tables in the database. | |
| In affected configurations, the /exec endpoint does not enforce authentication by default, | |
| allowing remote attackers to execute SQL queries against the database over HTTP. |
| 'Notes' => { | ||
| 'Stability' => [CRASH_SAFE], | ||
| 'SideEffects' => [IOC_IN_LOGS], | ||
| 'Reliability' => [REPEATABLE_SESSION] |
There was a problem hiding this comment.
This module doesn't grant sessions
| 'Reliability' => [REPEATABLE_SESSION] | |
| 'Reliability' => [] |
| ## | ||
|
|
||
| class MetasploitModule < Msf::Auxiliary | ||
| Rank = NormalRanking |
There was a problem hiding this comment.
Ranking is for exploit modules so we can remove this 👍
| Rank = NormalRanking |
| ]) | ||
| end | ||
|
|
||
| def run_host(ip) |
There was a problem hiding this comment.
It it possible to add a check method to detect this software and endpoint? 👀
Metasploit generally expects modules to implement check to verify if a target is vulnerable before exploitation.
| execute_sql(sql_query) | ||
| end | ||
|
|
||
| def execute_sql(sql) |
There was a problem hiding this comment.
This module doesn't appear to store any loot or report any findings to the database (report_vuln, store_loot), which is expected for scanner modules.
|
Putting this to attic as there has not been any activity for some time now and there's a lot of missing components and not addressed issues. |
|
Thanks for your contribution to Metasploit Framework! We've looked at this pull request, and we agree that it seems like a good addition to Metasploit, but it looks like it is not quite ready to land. We've labeled it What does this generally mean? It could be one or more of several things:
Pull requests in the attic are open for community pickup — if you're a community member looking for something to work on, feel free to pick this up and carry it across the finish line. The original author may or may not return, if they do and want to continue the work, we'd welcome that too. |
This Pull Request introduces a new exploit module for QuestDB, an open-source time-series database, targeting an unauthenticated SQL execution vulnerability identified as CNVD-2026-84827. While this identifier is currently in the formal review and verification phase by the China National Vulnerability Database (国家信息安全漏洞共享平台) and may not yet be reflected in public mirrors, the underlying flaw is fully reproducible, allowing an attacker to execute arbitrary DDL and DQL commands via the unauthenticated /exec REST API endpoint. This module provides critical security researchers with a functional tool to verify the exposure of QuestDB instances in their default configurations.
By default, QuestDB's REST API on port
9000does not require authentication for the/execendpoint. This allows an attacker to execute arbitrary Data Definition Language (DDL) and Data Query Language (DQL) commands. The module provides acheckmethod for version fingerprinting and supports both automated table enumeration and raw SQL query execution.Verification
Follow these steps to verify the module's functionality:
docker run -d -p 9000:9000 questdb/questdb:latestmsfconsoleuse exploit/multi/http/questdb_rceset RHOSTS 127.0.0.1checkThe target appears to be vulnerable.runtables()query and returns the database schema in JSON format.set QUERY "CREATE TABLE msf_test(id INT, info STRING)"run{"ddl":"OK"}response.Documentation
.mddocumentation file in this PR atdocumentation/modules/exploits/multi/http/questdb_rce.md.Targets Tested
Demontration & Logs
To assist with the review, I have included the console output below:
Click to view MSF Console Output