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

Discussion