cscg24-flipnote

CSCG 2024 Challenge 'FlipNote'
git clone https://git.sinitax.com/sinitax/cscg24-flipnote
Log | Files | Refs | sfeed.txt

vuln.c (4428B)


      1#include <limits.h>
      2#include <stdio.h>
      3#include <stdlib.h>
      4#include <string.h>
      5#include <sys/mman.h>
      6#include <unistd.h>
      7
      8#define MAX_NOTES 16
      9
     10extern char edata;
     11extern char data_start;
     12
     13static inline char *read_line(char **line_buf, size_t *size) {
     14  *size = getdelim(line_buf, size, '\n', stdin);
     15  if (*size == 0) {
     16    puts("Invalid line");
     17    exit(EXIT_FAILURE);
     18  }
     19  return *line_buf;
     20}
     21
     22void add_note(size_t *sizes, char **notes) {
     23  printf("Note: ");
     24  for (size_t i = 0; i < MAX_NOTES; i++) {
     25    if (sizes[i] == 0) {
     26      notes[i] = NULL;
     27      sizes[i] = getdelim(&notes[i], &sizes[i], '\n', stdin);
     28      printf("Added note: %ld\n", i);
     29      return;
     30    }
     31  }
     32  puts("Too many notes");
     33  exit(EXIT_FAILURE);
     34}
     35
     36void remove_note(char **line_buf, size_t *size, size_t *sizes, char **notes) {
     37  printf("Index: ");
     38  char *line = read_line(line_buf, size);
     39  unsigned long index = strtoul(line, NULL, 0);
     40  if (index >= MAX_NOTES) {
     41    puts("Invalid index");
     42    exit(EXIT_FAILURE);
     43  }
     44  free(notes[index]);
     45  sizes[index] = 0;
     46}
     47
     48void edit_note(char **line_buf, size_t *size, size_t *sizes, char **notes) {
     49  printf("Index: ");
     50  char *line = read_line(line_buf, size);
     51  unsigned long index = strtoul(line, NULL, 0);
     52  if (index >= MAX_NOTES || sizes[index] == 0) {
     53    puts("Invalid index");
     54    exit(EXIT_FAILURE);
     55  }
     56  printf("Note: ");
     57  line = read_line(line_buf, size);
     58  if (*size - 2 > sizes[index]) {
     59    puts("Invalid size");
     60    exit(EXIT_FAILURE);
     61  }
     62  memcpy(notes[index], line, *size - 1);
     63}
     64
     65void flip_bit(char **line_buf, size_t *size, char **notes, int *flips) {
     66  if (*flips == 0) {
     67    puts("The laser malfunctions and kills the program!");
     68    exit(EXIT_FAILURE);
     69  }
     70  printf("Index: ");
     71  unsigned long index = strtoul(read_line(line_buf, size), NULL, 0);
     72  if (index >= MAX_NOTES || notes[index] == NULL) {
     73    puts("Invalid index");
     74    exit(EXIT_FAILURE);
     75  }
     76  printf("Offset: ");
     77  char offset = (char)strtol(read_line(line_buf, size), NULL, 0);
     78  size_t byte = offset / 8;
     79  size_t bit = offset & 0b111;
     80
     81  puts("The laser is positioned and shoots at the selected memory location!");
     82  notes[index][byte] ^= 0b1 << bit;
     83  *flips = *flips - 1;
     84}
     85
     86void exit_handler() {
     87  mprotect(&data_start, (size_t)&edata - (size_t)&data_start,
     88           PROT_READ | PROT_WRITE);
     89}
     90
     91int main() {
     92
     93  char *notes[MAX_NOTES];
     94  size_t sizes[MAX_NOTES];
     95  char *line_buf = NULL;
     96  size_t size = 0;
     97
     98  int flips = 2;
     99
    100  char buf[0x80];
    101
    102  memset(buf, 0, sizeof(buf));
    103  memset(notes, 0, sizeof(notes));
    104  memset(sizes, 0, sizeof(sizes));
    105
    106  setvbuf(stdin, buf, _IOFBF, sizeof(buf));
    107  setvbuf(stdout, NULL, _IONBF, 0);
    108  setvbuf(stderr, NULL, _IONBF, 0);
    109
    110  mprotect(&data_start, (size_t)&edata - (size_t)&data_start, PROT_READ);
    111  on_exit(&exit_handler, NULL);
    112
    113  if (setuid(0)) {
    114    puts("Not running as root :(");
    115  }
    116
    117  puts("╭────────────────────────────────────────────────────╮");
    118  puts("│                  FlipNote                          │");
    119  puts("│                                                    │");
    120  puts("│ Instructions:                                      │");
    121  puts("│   - Type 'a' or 'A' to add a note                  │");
    122  puts("│   - Type 'e' or 'E' to edit a note                 │");
    123  puts("│   - Type 'f' or 'F' to use a laser to flip a bit   │");
    124  puts("│   - Type 'r' or 'R' to remove a note               │");
    125  puts("│   - Type 'q' or 'Q' to quit the program            │");
    126  puts("│                                                    │");
    127  puts("╰────────────────────────────────────────────────────╯");
    128  for (;;) {
    129    printf("> ");
    130    switch (read_line(&line_buf, &size)[0]) {
    131    case 'a':
    132    case 'A':
    133      add_note(sizes, notes);
    134      break;
    135    case 'e':
    136    case 'E':
    137      edit_note(&line_buf, &size, sizes, notes);
    138      break;
    139    case 'f':
    140    case 'F':
    141      flip_bit(&line_buf, &size, notes, &flips);
    142      break;
    143    case 'r':
    144    case 'R':
    145      remove_note(&line_buf, &size, sizes, notes);
    146      break;
    147    case 'q':
    148    case 'Q':
    149      exit(EXIT_SUCCESS);
    150    default:
    151      printf("Invalid option: ");
    152      puts(line_buf);
    153      break;
    154    }
    155  }
    156
    157  free(line_buf);
    158  return 0;
    159}