Fusion level06
About
Threaded stack overwrite fun :) Just another way to clutch at straws ;)
This level introduces the danger of inappropriate (or complete lack of) sharing/locking data across multiple connections/threads.
Vulnerability Type | Stack |
Position Independent Executable | Yes |
Read only relocations | No |
Non-Executable stack | Yes |
Non-Executable heap | Yes |
Address Space Layout Randomisation | Yes |
Source Fortification | Yes |
Source code
1#define THREADED 2#include "../common/common.c" 3 4// Taken some code from gnu tls documentation, 5// This example is a very simple echo server which supports X.509 6// authentication, using the RSA ciphersuites. 7// This file has the leading comment of... /* This example code is 8// placed in the public domain. */ 9// so there :> 10 11#include <gcrypt.h> 12#include <gnutls/gnutls.h> 13 14#include <libHX/init.h> 15#include <libHX/defs.h> 16#include <libHX/map.h> 17#include <libHX/string.h> 18 19#define KEYFILE "/opt/fusion/ssl/key.pem" 20#define CERTFILE "/opt/fusion/ssl/cert.pem" 21#define CAFILE "/opt/fusion/ssl/ca.pem" 22#define CRLFILE "/opt/fusion/ssl/crl.pem" 23 24gnutls_certificate_credentials_t x509_cred; 25gnutls_priority_t priority_cache; 26 27static gnutls_session_t 28initialize_tls_session (void) 29{ 30 gnutls_session_t session; 31 32 gnutls_init (&session, GNUTLS_SERVER); 33 34 gnutls_priority_set (session, priority_cache); 35 36 gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, x509_cred); 37 38 /* 39 *request client certificate if any. 40 */ 41 gnutls_certificate_server_set_request (session, GNUTLS_CERT_REQUEST); 42 43 return session; 44} 45 46 47struct HXmap *dict; 48 49struct data { 50 void *data; 51 size_t length; 52}; 53 54struct data *gather_data(gnutls_session_t session, char *key, size_t length) 55{ 56 unsigned char buffer[length]; 57 int offset, ret; 58 struct data *data; 59 60 for(offset = 0; offset < length; ) { 61 ret = gnutls_record_recv(session, buffer + offset, (length - 62 offset) > 65535 ? 65535 : (length - offset)); 63 if(ret <= 0) return NULL; 64 offset += ret; 65 } 66 67 data = malloc(sizeof(struct data)); 68 if(! data) return NULL; 69 data->data = HX_memdup(buffer, length); 70 if(!data->data) { 71 free(data); 72 return NULL; 73 } 74 data->length = length; 75 76 //printf("gather data: returning %08x, data->length = %d\n", data, 77 // data->length); 78 //fflush(stdout); 79 80 return data; 81} 82 83#define NOKEY "// No key was specified\n" 84#define NOTFOUND "// Key was not found\n" 85#define KEYFOUND "// Key exists\n" 86#define NOMEM "// Not enough memory to allocate\n" 87#define UPDATEOK "// Updated successfully\n" 88 89int update_data(gnutls_session_t session, char *key, size_t length) 90{ 91 struct data *data; 92 size_t offset; 93 int ret; 94 95 data = HXmap_get(dict, key); 96 if(! data) { 97 gnutls_record_send(session, NOTFOUND, strlen(NOTFOUND)); 98 return -1; 99 } 100 101 if(length > data->length) { 102 void *tmp; 103 tmp = realloc(data->data, length); 104 if(! tmp) { 105 gnutls_record_send(session, NOMEM, strlen(NOMEM)); 106 return -1; 107 } 108 data->data = tmp; 109 } 110 111 for(offset = 0; offset < length; ) { 112 ret = gnutls_record_recv(session, data->data + offset, 113 (length - offset) > 65535 ? 65535 : (length - offset)); 114 if(ret <= 0) return 0; 115 offset += ret; 116 } 117 118 gnutls_record_send(session, UPDATEOK, strlen(UPDATEOK)); 119 120 data->length = length; 121 return 0; 122} 123 124int send_data(gnutls_session_t session, char *key, struct data *data) 125{ 126 int offset, ret; 127 int to_send; 128 129 char *msg; 130 131 asprintf(&msg, "// Sending %d bytes\n", data->length); 132 gnutls_record_send(session, msg, strlen(msg)); 133 free(msg); 134 135 for(offset = 0; offset < data->length; ) { 136 int tosend; 137 tosend = (data->length - offset) > 65535 ? 65535 : 138 (data->length - offset); 139 ret = gnutls_record_send(session, data->data + offset, 140 tosend); 141 if(ret <= 0) return -1; 142 offset += ret; 143 } 144 return 0; 145} 146 147void *free_data(void *ptr) 148{ 149 struct data *data; 150 data = (struct data *)(ptr); 151 152 //printf("in free data, got %08x\n", (unsigned int)data); 153 if(data) { 154 if(data->data) { 155 free(data->data); 156 } 157 free(data); 158 } 159} 160 161void new_dict() 162{ 163 struct HXmap_ops mops; 164 if(dict) HXmap_free(dict); 165 166 memset(&mops, 0, sizeof(mops)); 167 mops.d_free = free_data; 168 169 dict = HXmap_init5(HXMAPT_HASH, HXMAP_SKEY | HXMAP_CKEY, &mops, 170 0, sizeof(struct data)); 171} 172 173 174void *keyval_thread(void *arg) 175{ 176 int fd = (int)arg; 177 int ret; 178 struct data *data; 179 int cont; 180 181 gnutls_session_t session; 182 session = initialize_tls_session (); 183 184 gnutls_transport_set_ptr (session, (gnutls_transport_ptr_t) fd); 185 ret = gnutls_handshake (session); 186 187 if (ret < 0) { 188 char *msg; 189 190 close (fd); 191 gnutls_deinit (session); 192 193 msg = NULL; 194 asprintf(&msg, "*** Handshake has failed (%s)\n\n", 195 gnutls_strerror(ret)); 196 write(fd, msg, strlen(msg)); 197 close(fd); 198 free(msg); 199 } 200 201#define BANNER "// Welcome to KeyValDaemon. Type 'h' for help information\n" 202 gnutls_record_send(session, BANNER, strlen(BANNER)); 203 204 cont = 1; 205 while(cont) { 206 char cmdbuf[512], *p; 207 char *args[6], *msg; 208 int argcnt, i; 209 210 memset(cmdbuf, 0, sizeof(cmdbuf)); 211 ret = gnutls_record_recv(session, cmdbuf, sizeof(cmdbuf)); 212 if(ret <= 0) break; 213 214 p = strchr(cmdbuf, '\r'); 215 if(p) *p = 0; 216 p = strchr(cmdbuf, '\n'); 217 if(p) *p = 0; 218 219 memset(args, 0, sizeof(args)); 220 argcnt = HX_split5(cmdbuf, " ", 6, args); 221 222#if 0 223 for(i = 0; i < argcnt; i++) { 224 asprintf(&msg, "args[%d] = \"%s\"\n", i, args[i]); 225 gnutls_record_send(session, msg, strlen(msg)); 226 free(msg); 227 } 228#endif 229 230 231 232 switch(args[0][0]) { 233 case 'h': 234#define HELP \ 235"// f <key> - find entry and see if it exists\n" \ 236"// s <key> <bytes> - store an entry with key and <bytes> lenght of data\n" \ 237"// g <key> - read data from key\n" \ 238"// d <key> - delete key/data\n" \ 239"// X - delete all data and restart\n" 240// XXX, loop over HXmap and display data? 241 242 gnutls_record_send(session, HELP, strlen(HELP)); 243 break; 244 case 'd': 245 if(! args[1]) { 246 gnutls_record_send(session, NOKEY, strlen(NOKEY)); 247 } else { 248 void *data; 249 250 data = HXmap_del(dict, args[1]); 251 if(data) { 252 gnutls_record_send(session, KEYFOUND, 253 strlen(KEYFOUND)); 254 } else { 255 gnutls_record_send(session, NOTFOUND, 256 strlen(NOTFOUND)); 257 } 258 } 259 break; 260 case 's': // set 261 data = gather_data(session, args[1], atoi(args[2])); 262 if(data != NULL) { 263#define NEWKEY "// New key added!\n" 264 printf("args[1] = %08x/%s, data = %08x\n", 265 args[1], args[1], data); 266 HXmap_add(dict, args[1], data); 267 gnutls_record_send(session, NEWKEY, 268 strlen(NEWKEY)); 269 } else { 270#define ADDERROR "// Unable to add new entry, problem getting data\n" 271 gnutls_record_send(session, ADDERROR, 272 strlen(ADDERROR)); 273 } 274 break; 275 case 'u': // update 276 update_data(session, args[1], atoi(args[2])); 277 break; 278 case 'f': // find 279 if(! args[1]) { 280 gnutls_record_send(session, NOKEY, 281 strlen(NOKEY)); 282 } else { 283 if(HXmap_find(dict, args[1]) == NULL) { 284 gnutls_record_send(session, 285 NOTFOUND, strlen(NOTFOUND)); 286 } else { 287 gnutls_record_send(session, 288 KEYFOUND, strlen(KEYFOUND)); 289 } 290 } 291 292 break; 293 294 case 'g': // get 295 if(! args[1]) { 296 gnutls_record_send(session, NOKEY, 297 strlen(NOKEY)); 298 } else { 299 if((data = HXmap_get(dict, args[1])) 300 == NULL) { 301 gnutls_record_send(session, NOTFOUND, 302 strlen(NOTFOUND)); 303 } else { 304 send_data(session, args[1], data); 305 } 306 } 307 break; 308 case 'e': 309 cont = 0; 310 break; 311 case 'X': 312 new_dict(); 313#define NEWDICT "// New dictionary installed\n" 314 gnutls_record_send(session, NEWDICT, 315 strlen(NEWDICT)); 316 break; 317 default: 318#define UC "// Unknown Command, please see 'h' for help information\n" 319 320 gnutls_record_send(session, UC, strlen(UC)); 321 break; 322 } 323 } 324 325 326#define GB "// Good bye!\n" 327 gnutls_record_send(session, GB, strlen(GB)); 328 gnutls_bye(session, GNUTLS_SHUT_WR); 329 330 close(fd); 331 gnutls_deinit(session); 332 333 return NULL; 334} 335 336#define DH_BITS 512 337 338static gnutls_dh_params_t dh_params; 339 340static int generate_dh_params (void) 341{ 342 /* 343 * Generate Diffie-Hellman parameters - for use with DHE 344 * kx algorithms. When short bit length is used, it might 345 * be wise to regenerate parameters. 346 * 347 */ 348 gnutls_dh_params_init (&dh_params); 349 gnutls_dh_params_generate2 (dh_params, DH_BITS); 350 351 return 0; 352} 353 354GCRY_THREAD_OPTION_PTHREAD_IMPL; 355 356int main(int argc, char **argv) 357{ 358 int fd, i; 359 360 HX_init(); 361 362 gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread); 363 gnutls_global_init(); 364 365 gnutls_certificate_allocate_credentials (&x509_cred); 366 gnutls_certificate_set_x509_trust_file (x509_cred, CAFILE, 367 GNUTLS_X509_FMT_PEM); 368 369 gnutls_certificate_set_x509_crl_file (x509_cred, CRLFILE, 370 GNUTLS_X509_FMT_PEM); 371 372 gnutls_certificate_set_x509_key_file (x509_cred, CERTFILE, KEYFILE, 373 GNUTLS_X509_FMT_PEM); 374 375 generate_dh_params (); 376 377 gnutls_priority_init (&priority_cache, "NORMAL", NULL); 378 gnutls_certificate_set_dh_params (x509_cred, dh_params); 379 380 new_dict(); 381 382 signal(SIGPIPE, SIG_IGN); 383 384 background_process(NAME, UID, GID); 385 serve_forever_threaded(PORT, keyval_thread); 386} 387