cscg24-flipnote

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

commit 46076ce1822104fb596cca02e8ac890b8fd437e8
Author: Louis Burda <quent.burda@gmail.com>
Date:   Fri,  5 Apr 2024 20:11:32 +0200

Add challenge files

Diffstat:
Achall/description | 1+
Achall/flipnote.zip | 0
Asolve/Dockerfile | 58++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asolve/dropbear_ecdsa_host_key | 0
Asolve/dropbear_ed25519_host_key | 0
Asolve/dropbear_rsa_host_key | 0
Asolve/flag | 1+
Asolve/vuln | 0
Asolve/vuln.c | 160+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
9 files changed, 220 insertions(+), 0 deletions(-)

diff --git a/chall/description b/chall/description @@ -0,0 +1 @@ +I was unable to come up with an interesting vulnerability, so instead I just cheated like all the hardware hackers do and used a laser instead. Have fun ;) diff --git a/chall/flipnote.zip b/chall/flipnote.zip Binary files differ. diff --git a/solve/Dockerfile b/solve/Dockerfile @@ -0,0 +1,57 @@ +FROM ubuntu:jammy-20240227@sha256:77906da86b60585ce12215807090eb327e7386c8fafb5402369e421f44eff17e as builder + +ADD --chmod=0755 --checksum=sha256:4c97fd03a3b181996b1473f3a99b69a1efc6ecaf2b4ede061b6bd60a96b9325a \ + https://raw.githubusercontent.com/reproducible-containers/repro-sources-list.sh/v0.1.0/repro-sources-list.sh \ + /usr/local/bin/repro-sources-list.sh + +RUN \ + --mount=type=cache,target=/var/cache/apt,sharing=locked \ + --mount=type=cache,target=/var/lib/apt,sharing=locked \ + /usr/local/bin/repro-sources-list.sh && \ + apt-get update && apt-get install -y \ + musl-dev \ + musl-tools \ + make \ + xz-utils \ + gcc + +WORKDIR /work + +ADD --chmod=0666 --checksum=sha256:4300f2fbc3996bc389d3c03a74662bfff3106ac1930942c5bd27580c7ba5053d \ + https://yx7.cc/code/ynetd/ynetd-0.1.2.tar.xz \ + /work/ynetd-0.1.2.tar.xz + +RUN tar -xJf ynetd-0.1.2.tar.xz && cd ynetd-0.1.2 && CC="musl-gcc" CFLAGS="-static" make + +COPY vuln.c . +RUN gcc -g -pie -fcf-protection -frandom-seed=0 -fno-plt -fstack-protector-all -fstack-clash-protection -O3 -g -Wl,-O1,--sort-common,--as-needed,-z,relro,-z,now -Wall -Wextra vuln.c -o vuln + +RUN echo "7cdf302e663641c132daaae59f82ceaebd8780f37eccc7844e17ddea3c82b664 /work/vuln" | sha256sum --check + +FROM ubuntu:jammy-20240227@sha256:77906da86b60585ce12215807090eb327e7386c8fafb5402369e421f44eff17e +COPY --from=builder /work/ynetd-0.1.2/ynetd /ynetd +COPY --from=builder /work/vuln /vuln + +ADD --chmod=0755 --checksum=sha256:4c97fd03a3b181996b1473f3a99b69a1efc6ecaf2b4ede061b6bd60a96b9325a \ + https://raw.githubusercontent.com/reproducible-containers/repro-sources-list.sh/v0.1.0/repro-sources-list.sh \ + /usr/local/bin/repro-sources-list.sh + +RUN \ + --mount=type=cache,target=/var/cache/apt,sharing=locked \ + --mount=type=cache,target=/var/lib/apt,sharing=locked \ + /usr/local/bin/repro-sources-list.sh && \ + apt-get update && \ + apt-get install -y dropbear rsync openssh-client && \ + rm /var/cache/ldconfig/aux-cache /var/log/apt/term.log /var/log/apt/history.log /var/log/dpkg.log /var/log/alternatives.log && \ + rm -rf /etc/dropbear/dropbear_*_host_key + +COPY --chmod=600 --chown=root:root dropbear_ecdsa_host_key dropbear_ed25519_host_key dropbear_rsa_host_key /etc/dropbear/ + +RUN chown root /vuln && chmod 4555 /vuln +COPY ./flag /flag +RUN chmod 600 /flag +RUN useradd -d /home/ctf/ -m -s /bin/bash ctf && passwd -d ctf + +WORKDIR /home/ctf + +CMD ["dropbear", "-FBREkwp", "1024"] +\ No newline at end of file diff --git a/solve/dropbear_ecdsa_host_key b/solve/dropbear_ecdsa_host_key Binary files differ. diff --git a/solve/dropbear_ed25519_host_key b/solve/dropbear_ed25519_host_key Binary files differ. diff --git a/solve/dropbear_rsa_host_key b/solve/dropbear_rsa_host_key Binary files differ. diff --git a/solve/flag b/solve/flag @@ -0,0 +1 @@ +CSCG{TESTFLAG} diff --git a/solve/vuln b/solve/vuln Binary files differ. diff --git a/solve/vuln.c b/solve/vuln.c @@ -0,0 +1,159 @@ +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/mman.h> +#include <unistd.h> + +#define MAX_NOTES 16 + +extern char edata; +extern char data_start; + +static inline char *read_line(char **line_buf, size_t *size) { + *size = getdelim(line_buf, size, '\n', stdin); + if (*size == 0) { + puts("Invalid line"); + exit(EXIT_FAILURE); + } + return *line_buf; +} + +void add_note(size_t *sizes, char **notes) { + printf("Note: "); + for (size_t i = 0; i < MAX_NOTES; i++) { + if (sizes[i] == 0) { + notes[i] = NULL; + sizes[i] = getdelim(&notes[i], &sizes[i], '\n', stdin); + printf("Added note: %ld\n", i); + return; + } + } + puts("Too many notes"); + exit(EXIT_FAILURE); +} + +void remove_note(char **line_buf, size_t *size, size_t *sizes, char **notes) { + printf("Index: "); + char *line = read_line(line_buf, size); + unsigned long index = strtoul(line, NULL, 0); + if (index >= MAX_NOTES) { + puts("Invalid index"); + exit(EXIT_FAILURE); + } + free(notes[index]); + sizes[index] = 0; +} + +void edit_note(char **line_buf, size_t *size, size_t *sizes, char **notes) { + printf("Index: "); + char *line = read_line(line_buf, size); + unsigned long index = strtoul(line, NULL, 0); + if (index >= MAX_NOTES || sizes[index] == 0) { + puts("Invalid index"); + exit(EXIT_FAILURE); + } + printf("Note: "); + line = read_line(line_buf, size); + if (*size - 2 > sizes[index]) { + puts("Invalid size"); + exit(EXIT_FAILURE); + } + memcpy(notes[index], line, *size - 1); +} + +void flip_bit(char **line_buf, size_t *size, char **notes, int *flips) { + if (*flips == 0) { + puts("The laser malfunctions and kills the program!"); + exit(EXIT_FAILURE); + } + printf("Index: "); + unsigned long index = strtoul(read_line(line_buf, size), NULL, 0); + if (index >= MAX_NOTES || notes[index] == NULL) { + puts("Invalid index"); + exit(EXIT_FAILURE); + } + printf("Offset: "); + char offset = (char)strtol(read_line(line_buf, size), NULL, 0); + size_t byte = offset / 8; + size_t bit = offset & 0b111; + + puts("The laser is positioned and shoots at the selected memory location!"); + notes[index][byte] ^= 0b1 << bit; + *flips = *flips - 1; +} + +void exit_handler() { + mprotect(&data_start, (size_t)&edata - (size_t)&data_start, + PROT_READ | PROT_WRITE); +} + +int main() { + + char *notes[MAX_NOTES]; + size_t sizes[MAX_NOTES]; + char *line_buf = NULL; + size_t size = 0; + + int flips = 2; + + char buf[0x80]; + + memset(buf, 0, sizeof(buf)); + memset(notes, 0, sizeof(notes)); + memset(sizes, 0, sizeof(sizes)); + + setvbuf(stdin, buf, _IOFBF, sizeof(buf)); + setvbuf(stdout, NULL, _IONBF, 0); + setvbuf(stderr, NULL, _IONBF, 0); + + mprotect(&data_start, (size_t)&edata - (size_t)&data_start, PROT_READ); + on_exit(&exit_handler, NULL); + + if (setuid(0)) { + puts("Not running as root :("); + } + + puts("╭────────────────────────────────────────────────────╮"); + puts("│ FlipNote │"); + puts("│ │"); + puts("│ Instructions: │"); + puts("│ - Type 'a' or 'A' to add a note │"); + puts("│ - Type 'e' or 'E' to edit a note │"); + puts("│ - Type 'f' or 'F' to use a laser to flip a bit │"); + puts("│ - Type 'r' or 'R' to remove a note │"); + puts("│ - Type 'q' or 'Q' to quit the program │"); + puts("│ │"); + puts("╰────────────────────────────────────────────────────╯"); + for (;;) { + printf("> "); + switch (read_line(&line_buf, &size)[0]) { + case 'a': + case 'A': + add_note(sizes, notes); + break; + case 'e': + case 'E': + edit_note(&line_buf, &size, sizes, notes); + break; + case 'f': + case 'F': + flip_bit(&line_buf, &size, notes, &flips); + break; + case 'r': + case 'R': + remove_note(&line_buf, &size, sizes, notes); + break; + case 'q': + case 'Q': + exit(EXIT_SUCCESS); + default: + printf("Invalid option: "); + puts(line_buf); + break; + } + } + + free(line_buf); + return 0; +} +\ No newline at end of file