Fusion level08
About
This process runs chrooted in it's home directory, can you break out of it?
As a side note, it's always interesting to watch how things fail, and what you can do with that :)
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 | No |
Source code
1#include "../common/common.c" 2#include <tcr/threaded_cr.h> 3#include "crypto_box.h" 4 5/* 6 * Design: 7 * 8 * One stdin-reader 9 * Many decryption processes 10 * Many command parsers / executors 11 * Many encryptor processes 12 * One stdout-writer 13 */ 14 15 16struct buffer { 17 unsigned char *data; 18 size_t len; 19 CIRCLEQ_ENTRY(buffer) ll; 20}; 21 22#define free_buf(x) \ 23 do { \ 24 if((x)) { \ 25 if((x)->data) free(x->data); \ 26 memset((x), 0xdf, sizeof(struct buffer)); \ 27 free((x)); \ 28 (x) = NULL; \ 29 } \ 30 } while(0) 31 32unsigned char public_key[crypto_box_PUBLICKEYBYTES]; 33unsigned char secret_key[crypto_box_SECRETKEYBYTES]; 34 35static struct tc_waitq decryption_waitq; 36static CIRCLEQ_HEAD(, buffer) decryption_queue; 37static spinlock_t decryption_sl; 38 39static struct tc_waitq process_waitq; 40static CIRCLEQ_HEAD(, buffer) process_queue; 41static spinlock_t process_sl; 42 43static struct tc_waitq encryption_waitq; 44static CIRCLEQ_HEAD(, buffer) encryption_queue; 45static spinlock_t encryption_sl; 46 47static struct tc_waitq output_waitq; 48static CIRCLEQ_HEAD(, buffer) output_queue; 49static spinlock_t output_sl; 50 51int devurandom_fd = -1; 52 53 54ssize_t tc_read(struct tc_fd *t, void *buf, ssize_t buflen) 55{ 56 ssize_t ret, len = buflen; 57 enum tc_rv rv; 58 59 while (1) { 60 ret = read(tc_fd(t), buf, len); 61 if (ret > 0) { 62 buf += ret; 63 len -= ret; 64 if (len == 0) 65 return buflen; 66 } else if (ret < 0) { 67 if (errno != EAGAIN) 68 return buflen - len ? buflen - len : ret; 69 } else /* ret == 0 */ 70 return buflen - len; 71 72 rv = tc_wait_fd_prio(EPOLLIN, t); 73 if (rv != RV_OK) { 74 errno = EINTR; 75 return -1; 76 } 77 } 78} 79 80ssize_t tc_write(struct tc_fd *t, void *buf, ssize_t buflen) 81{ 82 ssize_t ret, len = buflen; 83 enum tc_rv rv; 84 85 while (1) { 86 ret = write(tc_fd(t), buf, len); 87 if (ret > 0) { 88 buf += ret; 89 len -= ret; 90 if (len == 0) 91 return buflen; 92 } else if (ret < 0) { 93 if (errno != EAGAIN) 94 return buflen - len ? buflen - len : ret; 95 } else /* ret == 0 */ 96 return buflen - len; 97 98 rv = tc_wait_fd_prio(EPOLLIN, t); 99 if (rv != RV_OK) { 100 errno = EINTR; 101 return -1; 102 } 103 } 104} 105 106ssize_t randombytes(void *buf, ssize_t len) 107{ 108 struct tc_fd *tcfd; 109 ssize_t ret; 110 ssize_t max; 111 112 if(devurandom_fd == -1) errx(EXIT_FAILURE, "devurandom_fd has not been setup"); 113 max = len; 114 while(len) { 115 ret = read(devurandom_fd, buf, len); 116 if(ret == -1) { 117 if(errno == EAGAIN || errno == EINTR) continue; 118 err(EXIT_FAILURE, "randombytes failed"); 119 } 120 121 buf += ret; 122 len -= ret; 123 } 124 125 return max; 126} 127 128static void read_stdin(void *arg) 129{ 130 struct buffer *buf; 131 132 struct tc_fd *tcfd = (struct tc_fd *)(arg); 133 134 ssize_t rr; 135 size_t ltr; 136 137 // printf("in read_stdin\n"); 138 139 while(1) { 140 /* no clean ups since program will exit once this function returns */ 141 142 if(tc_read(tcfd, <r, sizeof(ltr)) != sizeof(ltr)) { 143 fprintf(stderr, "unable to tc_read %d bytes\n", sizeof(ltr)); 144 break; 145 } 146 147 buf = calloc(sizeof(struct buffer), 1); 148 if(! buf) { 149 fprintf(stderr, "unable to calloc %d bytes\n", sizeof(struct buffer)); 150 break; 151 } 152 153 buf->data = malloc(ltr); 154 if(! buf->data) { 155 fprintf(stderr, "unable to malloc %d bytes\n", ltr); 156 break; 157 } 158 159 buf->len = ltr; 160 161 if(tc_read(tcfd, buf->data, ltr) != ltr) { 162 fprintf(stderr, "Unable to tc_read %d bytes\n", ltr); 163 break; 164 } 165 166 /* Insert the buffer into the queue */ 167 168 spin_lock(&decryption_sl); 169 CIRCLEQ_INSERT_TAIL(&decryption_queue, buf, ll); 170 spin_unlock(&decryption_sl); 171 172 /* And wake up one of them */ 173 174 tc_waitq_wakeup_one(&decryption_waitq); 175 } 176 177 178} 179 180unsigned char peer_remote_pk[crypto_box_PUBLICKEYBYTES]; 181 182static void decryption_worker(void *arg) 183{ 184 // XXX, exit_all 185 struct buffer *input_buffer; 186 struct buffer *output_buffer; 187 188 size_t tl; 189 unsigned char *tmpout; 190 191 while(1) { 192 input_buffer = output_buffer = NULL; 193 tmpout = NULL; 194 195 // printf("decryption_worker: about to wait\n"); 196 197 // XXX, decryption_queue should probably be locked in this case :/ 198 199 if(tc_waitq_wait_event(&decryption_waitq, ! CIRCLEQ_EMPTY(&decryption_queue)) != RV_OK) { 200 fprintf(stderr, "decryption_worker: failed to wait\n"); 201 break; 202 } 203 204 // printf("decryption_worker: removing from list\n"); 205 206 spin_lock(&decryption_sl); 207 input_buffer = CIRCLEQ_FIRST(&decryption_queue); 208 CIRCLEQ_REMOVE(&decryption_queue, input_buffer, ll); 209 spin_unlock(&decryption_sl); 210 211 // printf("decryption_worker: processing\n"); 212 213 // XXX, valgrind this :p 214 // XXX, more sanity checks? :p 215 216 // calculate how many bytes will be processed. 217 tl = input_buffer->len - crypto_box_NONCEBYTES; 218 219 tmpout = malloc(tl); 220 if(! tmpout) { 221 fprintf(stderr, "decryption_worker: unable to malloc %d bytes for tmpout, skipping\n", tl); 222 goto failure; 223 } 224 225 output_buffer = calloc(sizeof(struct buffer), 1); 226 if(! output_buffer) { 227 fprintf(stderr, "decryption_worker: unable to calloc new buffer, skipping\n"); 228 goto failure; 229 } 230 output_buffer->len = tl - crypto_box_ZEROBYTES; 231 output_buffer->data = malloc(output_buffer->len); 232 if(! output_buffer->data) { 233 fprintf(stderr, "decryption_worker: unable to malloc new data buffer of " 234 "%d bytes, skipping\n", tl - crypto_box_ZEROBYTES); 235 goto failure; 236 } 237 238 // printf("attempting to decrypt with length of %d bytes\n", tl); 239 240 if(crypto_box_open(tmpout, input_buffer->data + crypto_box_NONCEBYTES, tl, input_buffer->data, 241 peer_remote_pk, secret_key) != 0) { 242 fprintf(stderr, "decryption_worker: unable to crypto_box_open :s, skipping\n"); 243 goto failure; 244 } 245 246 // printf("decryption_worker: outputting buffer\n"); 247 248 memcpy(output_buffer->data, tmpout + crypto_box_ZEROBYTES, output_buffer->len); 249 250 /* Insert the buffer into the queue */ 251 252 spin_lock(&process_sl); 253 CIRCLEQ_INSERT_TAIL(&process_queue, output_buffer, ll); 254 spin_unlock(&process_sl); 255 256 /* And wake up one of them */ 257 258 tc_waitq_wakeup_one(&process_waitq); 259 260 // printf("decryption_worker: finished, signaled process worker\n"); 261 262 goto alright; 263failure: 264 free_buf(output_buffer); 265alright: 266 free_buf(input_buffer); 267 if(tmpout) free(tmpout); 268 } 269} 270 271static int sanity_check_name(char *s) 272{ 273 char buf[256]; 274 275 int error; 276 error = 0; 277 278 error |= (!! strstr(s, "ssh")); 279 error |= (!! strstr(s, "/.")); 280 281 memset(buf, 0, sizeof(buf)); 282 if((realpath(s, buf) == NULL) && errno != ENOENT) error |= 1; 283 284 error |= (buf[0] == '.'); 285 286 return error; 287} 288 289#define set_str_buffer(tag, buf, string) \ 290do { \ 291 size_t *t; \ 292 buf->len = sizeof(size_t) + strlen(string); \ 293 buf->data = malloc(buf->len + 1); \ 294 if(!buf->data) { \ 295 fprintf(stderr, "process_worker (set_str_buffer): failure to malloc buffer->data\n"); \ 296 goto failure; \ 297 } \ 298 t = (size_t *)(buf->data); \ 299 t[0] = tag; \ 300 strcpy(buf->data + 4, string); \ 301} while(0) 302 303 304 305static void process_worker(void *arg) 306{ 307 struct buffer *input_buffer; 308 struct buffer *output_buffer; 309 size_t *tag; 310 int ret; 311 mode_t mode; 312 unsigned char *f, *g, *h; 313 int fd; 314 char msg[64]; 315 size_t offset; 316 int len; 317 struct tc_fd *tcfd; 318 319 320 while(1) { 321 input_buffer = NULL; 322 323 if(tc_waitq_wait_event(&process_waitq, ! CIRCLEQ_EMPTY(&process_queue)) != RV_OK) { 324 fprintf(stderr, "process_worker: failed to wait\n"); 325 break; 326 } 327 328 spin_lock(&process_sl); 329 input_buffer = CIRCLEQ_FIRST(&process_queue); 330 CIRCLEQ_REMOVE(&process_queue, input_buffer, ll); 331 spin_unlock(&process_sl); 332 333 // printf("process_worker: got one!\n"); 334 335 output_buffer = calloc(sizeof(struct buffer), 1); 336 if(! output_buffer) { 337 fprintf(stderr, "process_worker: can't allocate output buffer :(\n"); 338 goto append_output; 339 } 340 341 tag = ((size_t *)(input_buffer->data))[0]; 342 343 if(input_buffer->len < 4) { 344 set_str_buffer(-1, output_buffer, "input packet length specified"); 345 goto append_output; 346 } 347 348 // printf("process_worker: handling %02x .. input is %s\n", input_buffer->data[4], 349 // input_buffer->data + 4); 350 351 switch(input_buffer->data[4]) { 352 case 'm': 353 // make a directory 354 mode = strtoul(input_buffer->data + 5, (char **) &f, 8); 355 if(f == (input_buffer->data + 5)) { 356 printf("invalid mode\n"); 357 set_str_buffer(tag, output_buffer, "invalid mode specified"); 358 break; 359 } 360 if(f[0] == '\0') { 361 printf("no filename\n"); 362 set_str_buffer(tag, output_buffer, "no filename specified"); 363 break; 364 } 365 366 if(sanity_check_name(f) != 0) { 367 printf("filename specification\n"); 368 set_str_buffer(tag, output_buffer, "invalid filename specified"); 369 break; 370 } 371 372 ret = mkdir(f, mode); 373 set_str_buffer(tag, output_buffer, ret == -1 ? "error in creating directory" : 374 "successfully created directory"); 375 376 break; 377 case 'o': 378 // open specified file, with mode. 379 mode = strtoul(input_buffer->data + 5, (char **) &f, 8); 380 if(f == (input_buffer->data + 5)) { 381 set_str_buffer(tag, output_buffer, "invalid mode specified"); 382 break; 383 } 384 if(f[0] == '\0') { 385 printf("input = %s\n", (input_buffer->data + 5)); 386 set_str_buffer(tag, output_buffer, "no filename specified"); 387 break; 388 } 389 390 if(sanity_check_name(f) != 0) { 391 set_str_buffer(tag, output_buffer, "invalid filename specified"); 392 break; 393 } 394 395 fd = open(f, O_CREAT|O_TRUNC|O_WRONLY, mode); 396 if(fd == -1) { 397 set_str_buffer(tag, output_buffer, "failed to open file"); 398 break; 399 } 400 401 sprintf(msg, "fd is %d", fd); 402 403 set_str_buffer(tag, output_buffer, msg); 404 405 break; 406 407 case 'w': 408 // write to file, offset, data 409 410 fd = strtoul(input_buffer->data + 5, (char **)&f, 10); 411 if(f == (input_buffer->data + 5)) { 412 set_str_buffer(tag, output_buffer, "invalid fd specified"); 413 break; 414 } 415 416 if(f[0] != ',') { 417 set_str_buffer(tag, output_buffer, "invalid protocol"); 418 break; 419 } 420 421 f++; 422 423 offset = strtoul(f, (char **) &g, 10); 424 if(f == g) { 425 set_str_buffer(tag, output_buffer, "no fd specified"); 426 break; 427 } 428 len = input_buffer->len - ((unsigned int)(g) - (unsigned int)(input_buffer->data)); 429 430 while(len) { 431 size_t ret; 432 433 ret = pwrite(fd, g, len, offset); 434 if(ret == -1) { 435 if(errno == EAGAIN || errno == EINTR) continue; 436 break; 437 438 } 439 440 g += ret; 441 len -= ret; 442 } 443 444 set_str_buffer(tag, output_buffer, len == 0 ? "successfully wrote contents to fd\x00" : 445 "failed to write contents to fd\x00"); 446 447 break; 448 449 case 'c': 450 // close file 451 452 fd = strtoul(input_buffer->data + 5, (char **)&f, 10); 453 if(f == (input_buffer->data + 5)) { 454 set_str_buffer(tag, output_buffer, "no fd specified"); 455 break; 456 } 457 458 if(f[0] != '\0') { 459 set_str_buffer(tag, output_buffer, "fd not specified"); 460 break; 461 } 462 463 set_str_buffer(tag, output_buffer, "fd closed"); 464 close(fd); 465 466 break; 467 default: 468 set_str_buffer(tag, output_buffer, "malformed input"); 469 break; 470 471 } 472 473append_output: 474 spin_lock(&encryption_sl); 475 CIRCLEQ_INSERT_TAIL(&encryption_queue, output_buffer, ll); 476 spin_unlock(&encryption_sl); 477 tc_waitq_wakeup_one(&encryption_waitq); 478 479failure: 480 free_buf(input_buffer); 481 } 482} 483 484static void encryption_worker(void *arg) 485{ 486 struct buffer *input_buffer; 487 struct buffer *output_buffer; 488 unsigned char *tmp; 489 490 while(1) { 491 tmp = NULL; 492 493 // dequeue, and remove 494 if(tc_waitq_wait_event(&encryption_waitq, ! CIRCLEQ_EMPTY(&encryption_queue)) != RV_OK) { 495 fprintf(stderr, "encryption_worker: failed to wait\n"); 496 break; 497 } 498 499 spin_lock(&encryption_sl); 500 input_buffer = CIRCLEQ_FIRST(&encryption_queue); 501 CIRCLEQ_REMOVE(&encryption_queue, input_buffer, ll); 502 spin_unlock(&encryption_sl); 503 504 output_buffer = calloc(sizeof(struct buffer), 1); 505 if(output_buffer == NULL) goto failure; 506 output_buffer->len = input_buffer->len + crypto_box_ZEROBYTES + crypto_box_NONCEBYTES; 507 output_buffer->data = malloc(output_buffer->len); 508 if(output_buffer->data == NULL) goto failure; 509 510 randombytes(output_buffer->data, crypto_box_NONCEBYTES); 511 512 tmp = malloc(input_buffer->len + crypto_box_ZEROBYTES); 513 if(! tmp) goto failure; 514 515 516 // printf("input_buffer is %08x\n", input_buffer); 517 // printf("input_buffer->data = %s, input_buffer->len = %d\n", input_buffer->data, input_buffer->len); 518 519 memset(tmp, 0, crypto_box_ZEROBYTES); 520 memcpy(tmp + crypto_box_ZEROBYTES, input_buffer->data, input_buffer->len); 521 522 if(crypto_box(output_buffer->data + crypto_box_NONCEBYTES, tmp, crypto_box_ZEROBYTES + input_buffer->len, 523 output_buffer->data, peer_remote_pk, secret_key) != 0) { 524 fprintf(stderr, "crypto_box failed\n"); 525 goto failure; 526 } 527 528 spin_lock(&output_sl); 529 CIRCLEQ_INSERT_TAIL(&output_queue, output_buffer, ll); 530 spin_unlock(&output_sl); 531 tc_waitq_wakeup_one(&output_waitq); 532 533 goto alright; 534failure: 535 free_buf(output_buffer); 536alright: 537 free_buf(input_buffer); 538 if(tmp) { free(tmp); tmp = NULL; } 539 } 540} 541 542static void write_stdout(void *arg) 543{ 544 struct tc_fd *tcfd = (struct tc_fd *)(arg); 545 struct buffer *buffer; 546 size_t len; 547 548 while(1) { 549 if(tc_waitq_wait_event(&output_waitq, ! CIRCLEQ_EMPTY(&output_queue)) != RV_OK) { 550 fprintf(stderr, "output_worker: failed to wait\n"); 551 break; 552 } 553 554 spin_lock(&output_sl); 555 buffer = CIRCLEQ_FIRST(&output_queue); 556 CIRCLEQ_REMOVE(&output_queue, buffer, ll); 557 spin_unlock(&output_sl); 558 559 len = buffer->len; 560 561 if(tc_write(tcfd, &len, sizeof(size_t)) != sizeof(size_t)) { 562 errx(1, "failed to write"); 563 // xxx, return to tc_main 564 } 565 566 if(tc_write(tcfd, buffer->data, buffer->len) != buffer->len) { 567 errx(1, "failed to write data"); 568 } 569 570 free_buf(buffer); 571 572 } 573} 574 575static void tc_main(void *arg) 576{ 577 struct tc_thread *reader; 578 struct tc_thread_pool decryption_pool; 579 struct tc_thread_pool process_pool; 580 struct tc_thread_pool encryption_pool; 581 struct tc_thread *writer; 582 struct tc_fd *tcfd; 583 584 CIRCLEQ_INIT(&decryption_queue); 585 spin_lock_init(&decryption_sl); 586 tc_waitq_init(&decryption_waitq); 587 588 CIRCLEQ_INIT(&process_queue); 589 spin_lock_init(&process_sl); 590 tc_waitq_init(&process_waitq); 591 592 CIRCLEQ_INIT(&encryption_queue); 593 spin_lock_init(&encryption_sl); 594 tc_waitq_init(&encryption_waitq); 595 596 CIRCLEQ_INIT(&output_queue); 597 spin_lock_init(&output_sl); 598 tc_waitq_init(&output_waitq); 599 600 tcfd = tc_register_fd(fileno(stdin)); 601 602 if(write(fileno(stdin), public_key, crypto_box_PUBLICKEYBYTES) != crypto_box_PUBLICKEYBYTES) 603 err(EXIT_FAILURE, "writing public key"); 604 605 if(tc_read(tcfd, peer_remote_pk, sizeof(peer_remote_pk)) != sizeof(peer_remote_pk)) { 606 fprintf(stderr, "failed to read public key\n"); 607 goto failure; 608 } 609 610 tc_thread_pool_new(&decryption_pool, decryption_worker, NULL, "decryption_worker_%d", 0); 611 tc_thread_pool_new(&process_pool, process_worker, NULL, "process_worker_%d", 0); 612 tc_thread_pool_new(&encryption_pool, encryption_worker, NULL, "encryption_worker_%d", 0); 613 614 if((reader = tc_thread_new(read_stdin, tcfd, "stdin_reader")) == NULL) { 615 errx(1, "tc_thread_new failed to create stdin_reader"); 616 } 617 618 if((writer = tc_thread_new(write_stdout, tcfd, "stdout_writer")) == NULL) { 619 errx(1, "tc_thread_new failed to create stdout_writer"); 620 } 621 622 tc_thread_wait(reader); 623 624failure: 625 tc_unregister_fd(tcfd); 626 627 // signal exit 628 629 // printf("waited on read_stdin\n"); 630 631} 632 633int main(int argc, char **argv, char **envp) 634{ 635 int fd; 636 char *p; 637 638 if(is_restarted_process(argc, argv)) { 639 devurandom_fd = open("/dev/urandom", O_RDONLY); 640 641 crypto_box_keypair(public_key, secret_key); 642 643 if(chroot("/home/level08") == -1) { 644 err(1, "Unable to chroot"); 645 } 646 647 if(chdir("/") == -1) { 648 err(1, "chdir(\"/\")"); 649 } 650 651 drop_privileges(UID, GID); 652 653 tc_run(tc_main, NULL, "tc_main", sysconf(_SC_NPROCESSORS_ONLN)); 654 return 0; 655 } 656 657 if(daemon(0, 0) == -1) { 658 err(EXIT_FAILURE, "Unable to daemon(0, 0)"); 659 } 660 661 fd = serve_forever(PORT); 662 set_io(fd); 663 restart_process(NAME); 664 665}