Hash me again

This challenge is quite similar to the last one. So I’ll keep it short, the challenge is almost exactly the same as the last one. The only difference in the instructions is that the message to digest is a string of zeros and ones. The first thing to try i s running the last solution:

curl -sb ../../cookies.txt https://ringzer0ctf.com/challenges/13 | grep -P -A 1 'BEGIN MESSAGE' | tail -1 | sed -re 's/\t|<br \="">.*$//g' | head -c-1 | sha512sum | cut -d ' ' -f 1 | xargs -I {} curl -sb ../../cookies.txt https://ringzer0ctf.com/challenges/13/{} | grep -Po 'FLAG-\w+'$

But it doesn’t work… This can logically only be because of two reasons 1) Our assumption that the challenge is the same is wrong 2) Our nice looking but long pipeline is a bit too long and doesn’t finish within the timing requirements. By measuring the time taken to execute the whole chain of commands and trying to trim down on “unnecessary” flags on some commands I can state that the timing doesn’t seem to be the problem here so there is something wrong with how we have understood the challenge.

Measuring the length of the messages this time we can see that they’re constantly 8184 characters long – this is interesting, a power of two! The number of ones and zeros is evenly divisible by eight so if we were to group the characters by eight we would get bytes that could represent ascii text which could be what we’re supposed to digest. Other than that the message first has to be converted into ascii our pipeline from the last challenge will do the job, and being a pipeline it has the advantage of allowing us just to add another program to do just that in the right moment of processing! Pipes are wonderful!

Now, how would you go about converting a string of binary to ascii? I don’t know of a super simple program that can handle this for us sadly. But I do have a C-program I wrote for a class on software reliability that will come in handy. It’s no way near what I’d like it to be to show it really but it’s something I cobbled together to solve my problem then and it will solve our problem now. It works by two steps, gathering all the input and generating all the output, what would be great would be if it threaded and running the input and output in parallel but the sub-optimal design of my converter was enough to complete the challenge so that’s a project for another time!

The nice thing about the program is that the inputbuffer is handled and allocated in segments as more data comes in, not that great as it’s in no way parallelized, but by small adjustments it can handle near infinite (as infinite as your memory and max range of a long int) string representations of numbers in different bases. More things that could become a project another time 🙂

Well, well, I’ll go through the basics of the operating mechanics of the program so it’s available if you’d like to take a look or perhaps make it better than the enough it provides for us today!

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#define EXIT_SUCCESS 0
#define EXIT_MEMORY_ERROR 1
#define EXIT_READ_ERROR 2

#define BLOCK_SIZE 512
#define BASE 2

typedef char target_t;

int read_input(char **buffer_ptr)
{
  long num_blocks = 0;
  char *buf = malloc(BLOCK_SIZE);
  char *free_index = buf;
  int free_space;

  if (buf == NULL) {
    return EXIT_MEMORY_ERROR;
  } else {
    num_blocks++;
    free_space = BLOCK_SIZE;
  }

  while (fgets(free_index, 9 , stdin)) {
    int len = strlen(free_index);
    free_index += len;

    /* Separate ascii */
    if (len == 8) {
      *free_index = ' ';
      free_index++;
      len++;
    }

    /* If buffer was filled, extend it */
    if (len >= free_space-1) {
      int diff = free_index-buf;
      int new_size = BLOCK_SIZE*(num_blocks+1);
      buf = realloc(buf,new_size);
      if (buf == free_index-diff) {
        if (errno == ENOMEM) {
          return EXIT_MEMORY_ERROR;
        } else {
          /* Successfully extended buffer */
          free_space = buf+BLOCK_SIZE*num_blocks+1 - free_index;
        }
      } else {
        /* Update pointers as realloc moved stuff */
        free_index = buf+diff;
        free_space = buf+new_size - free_index;
      }
      num_blocks++;
    } else {
      free_space -= len;
    }
  }

  *buffer_ptr = buf;
  return 0;
}

int parse_input(char *buf, int base, target_t **array_ptr, long *array_len)
{
  target_t *array;
  target_t *array_index;
  char *startptr, *endptr;
  /* Worst case is all signle digit numbers so max amount of numbers is
   * strlen(buf) / 2 - probably alright to be pessimistic
   */
  array = malloc((strlen(buf)/2)*sizeof(target_t));
  if (array == NULL) {
    return EXIT_MEMORY_ERROR;
  }

  array_index = array;
  startptr = buf;
  while (1) {
    target_t val = strtol(startptr, &endptr, base);
    if (endptr == startptr || endptr == NULL) {   /* Reached end */
      break;
    } else {
      *(array_index++) = val;
      startptr = endptr;
    }
  }

  *array_ptr = array;
  *array_len = array_index - array;
  return 0;
}

int main(long argc, char* argv[])
{
  int i;
  long key;
  long retval;
  char *buf;
  target_t *array;
  long array_length;

  /* Read input */
  retval = read_input(&buf);

  if (retval == EXIT_MEMORY_ERROR) {
    fprintf(stderr, "Memory error, idc\n");
    return retval;
  }

  /* Parse input */
  retval = parse_input(buf, BASE, &array, &array_length);
  if (retval == EXIT_MEMORY_ERROR) {
    fprintf(stderr, "Memory error, idc\n");
    return retval;
  }
  free(buf);

  for (i = 0; i < array_length; i++) {
    printf("%c", array[i]);
  }

  return EXIT_SUCCESS;
}

If you’re on a linux system you can compile the program above by running the command below and putting it the pipeline before we perform the message digest!

gcc -o bin2ascii bin2ascii.c

Good luck!

This entry was posted in CTF, Hacking. Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *