Compare commits

..

14 Commits

6 changed files with 101 additions and 33 deletions

12
Dockerfile Normal file
View File

@@ -0,0 +1,12 @@
FROM alpine:3.20
RUN apk add --no-cache gdb strace
WORKDIR /challenge
COPY main ./main
RUN chmod +x ./main
COPY license ./license
CMD ["/bin/sh"]

View File

@@ -11,6 +11,7 @@ FLAG_FORMAT ?= ctf{FLAG_GOES_HERE}
FLAG_SEED ?= false FLAG_SEED ?= false
PYTHON_EXE ?= python PYTHON_EXE ?= python
BUILD_DIR ?= build
# Compilation variables # Compilation variables
RISCV_CC ?= riscv64-unknown-elf-gcc RISCV_CC ?= riscv64-unknown-elf-gcc
@@ -20,16 +21,18 @@ HOST_CFLAGS ?= -Wall -Wextra -O3 -g
HOST_LDFLAGS ?= -Wl,-s HOST_LDFLAGS ?= -Wl,-s
EMU_SRC_FILES := $(wildcard src/emulated/*.c) EMU_SRC_FILES := $(wildcard src/emulated/*.c)
EMU_OBJ_FILES := $(EMU_SRC_FILES:src/emulated/%.c=build/%.riscv.o) EMU_OBJ_FILES := $(EMU_SRC_FILES:src/emulated/%.c=$(BUILD_DIR)/%.riscv.o)
EMU_OBJ := build/emulated.riscv.elf EMU_OBJ := $(BUILD_DIR)/emulated.riscv.elf
EMU_OBJ_LICENSE ?= build/license EMU_OBJ_LICENSE ?= $(BUILD_DIR)/license
EMU_OBJ_LICENSE_IF_EXISTS := $(wildcard $(EMU_OBJ_LICENSE)) EMU_OBJ_LICENSE_IF_EXISTS := $(wildcard $(EMU_OBJ_LICENSE))
ZIP_FILE ?= build/challenge.zip README_FILE ?= $(BUILD_DIR)/README.txt
DOCKERFILE ?= $(BUILD_DIR)/Dockerfile
ZIP_FILE ?= $(BUILD_DIR)/challenge.zip
ZIP_FILE_IF_EXISTS := $(wildcard $(ZIP_FILE)) ZIP_FILE_IF_EXISTS := $(wildcard $(ZIP_FILE))
GENERATED := build/include/generated.h GENERATED := $(BUILD_DIR)/include/generated.h
HOST_SRC_EXTRA := src/elf.c src/hwinfo.c src/util.c tiny-AES-c/aes.c HOST_SRC_EXTRA := src/elf.c src/hwinfo.c src/util.c tiny-AES-c/aes.c
HOST_SRC := src/main.c $(HOST_SRC_EXTRA) HOST_SRC := src/main.c $(HOST_SRC_EXTRA)
@@ -39,18 +42,18 @@ HOST_SRC_SPOOFER := src/spoof/spoofer.c
ifeq ($(OS),Windows_NT) ifeq ($(OS),Windows_NT)
HOST_EXE ?= build/main.exe HOST_EXE ?= $(BUILD_DIR)/main.exe
else else
HOST_EXE ?= build/main HOST_EXE ?= $(BUILD_DIR)/main
endif endif
ifeq ($(OS),Windows_NT) ifeq ($(OS),Windows_NT)
HOST_EXE_ENCRYPTOR ?= build/encryptor.exe HOST_EXE_ENCRYPTOR ?= $(BUILD_DIR)/encryptor.exe
else else
HOST_EXE_ENCRYPTOR ?= build/encryptor HOST_EXE_ENCRYPTOR ?= $(BUILD_DIR)/encryptor
endif endif
HOST_EXE_SPOOFER ?= build/spoofer HOST_EXE_SPOOFER ?= $(BUILD_DIR)/spoofer
# Disassembly # Disassembly
@@ -69,40 +72,43 @@ emulated-riscv: $(EMU_OBJ_LICENSE)
host: $(HOST_EXE) $(HOST_EXE_SPOOFER) host: $(HOST_EXE) $(HOST_EXE_SPOOFER)
# Build the main challenge executable # Build the main challenge executable
$(HOST_EXE): $(HOST_SRC) | build $(HOST_EXE): $(HOST_SRC) | $(BUILD_DIR)
$(HOST_CC) $(HOST_CFLAGS) $(HOST_LDFLAGS) $(HOST_INCLUDE) $(HOST_SRC) -o $@ $(HOST_CC) $(HOST_CFLAGS) $(HOST_LDFLAGS) $(HOST_INCLUDE) $(HOST_SRC) -o $@
# Build the spoofer # Build the spoofer
$(HOST_EXE_SPOOFER): $(HOST_SRC_SPOOFER) | build $(HOST_EXE_SPOOFER): $(HOST_SRC_SPOOFER) | $(BUILD_DIR)
$(HOST_CC) $(HOST_CFLAGS) $(HOST_LDFLAGS) -shared -fPIC $^ -o $@ -ldl $(HOST_CC) $(HOST_CFLAGS) $(HOST_LDFLAGS) -shared -fPIC $^ -o $@ -ldl
# Build the encryptor # Build the encryptor
$(HOST_EXE_ENCRYPTOR): $(HOST_SRC_ENCRYPTOR) | build $(HOST_EXE_ENCRYPTOR): $(HOST_SRC_ENCRYPTOR) | $(BUILD_DIR)
$(HOST_CC) $(HOST_CFLAGS) $(HOST_LDFLAGS) $(HOST_INCLUDE) $(HOST_SRC_ENCRYPTOR) -o $@ $(HOST_CC) $(HOST_CFLAGS) $(HOST_LDFLAGS) $(HOST_INCLUDE) $(HOST_SRC_ENCRYPTOR) -o $@
# Build emulated object files # Build emulated object files
$(EMU_OBJ_FILES): $(EMU_SRC_FILES) $(GENERATED) | build $(EMU_OBJ_FILES): $(EMU_SRC_FILES) $(GENERATED) | $(BUILD_DIR)
$(RISCV_CC) $(RISCV_ARCH_FLAGS) -I $(dir $(GENERATED)) -I src/emulated -c $(EMU_SRC_FILES) -o $@ $(RISCV_CC) $(RISCV_ARCH_FLAGS) -I $(dir $(GENERATED)) -I src/emulated -c $(EMU_SRC_FILES) -o $@
# Encrypt license file # Encrypt license file
$(EMU_OBJ_LICENSE): $(EMU_OBJ) $(HOST_EXE_ENCRYPTOR) | build $(EMU_OBJ_LICENSE): $(EMU_OBJ) $(HOST_EXE_ENCRYPTOR) | $(BUILD_DIR)
ifneq ($(EMU_OBJ_LICENSE_IF_EXISTS),) ifneq ($(EMU_OBJ_LICENSE_IF_EXISTS),)
rm $(EMU_OBJ_LICENSE_IF_EXISTS) rm $(EMU_OBJ_LICENSE_IF_EXISTS)
endif endif
$(HOST_EXE_ENCRYPTOR) $(EMU_OBJ) $@ $(HOST_EXE_ENCRYPTOR) $(EMU_OBJ) $@ $(README_FILE)
# Build (unencrypted) license file # Build (unencrypted) license file
$(EMU_OBJ): $(EMU_OBJ_FILES) | build $(EMU_OBJ): $(EMU_OBJ_FILES) | $(BUILD_DIR)
$(RISCV_CC) $(RISCV_ARCH_FLAGS) -nostdlib -Wl,-e,entry -Wl,-Ttext=0 -Wl,--emit-relocs $(EMU_OBJ_FILES) -o $@ $(RISCV_CC) $(RISCV_ARCH_FLAGS) -nostdlib -Wl,-e,entry -Wl,-Ttext=0 -Wl,--emit-relocs $(EMU_OBJ_FILES) -o $@
# Copy Dockerfile into build dir
$(DOCKERFILE): Dockerfile | $(BUILD_DIR)
cp $< $@
# Bundle the challenge # Bundle the challenge
$(ZIP_FILE): $(HOST_EXE) $(EMU_OBJ_LICENSE) | build $(ZIP_FILE): $(HOST_EXE) $(EMU_OBJ_LICENSE) $(README_FILE) $(DOCKERFILE) | $(BUILD_DIR)
ifneq ($(ZIP_FILE_IF_EXISTS),) ifneq ($(ZIP_FILE_IF_EXISTS),)
rm $(ZIP_FILE_IF_EXISTS) rm $(ZIP_FILE_IF_EXISTS)
endif endif
cd build && 7z a -bso0 $(CURDIR)/$@ $(notdir $^) cd $(BUILD_DIR) && 7z a -bso0 $(CURDIR)/$@ $(notdir $^)
.FORCE: .FORCE:
@@ -111,12 +117,11 @@ $(GENERATED): .FORCE
$(PYTHON_EXE) codegen/generate.py $(FLAG_FORMAT) $(FLAG_LEN) $(FLAG_SEED) > $@ $(PYTHON_EXE) codegen/generate.py $(FLAG_FORMAT) $(FLAG_LEN) $(FLAG_SEED) > $@
build: $(BUILD_DIR):
mkdir -p $@ mkdir -p $@
clean: clean:
rm -rf build rm -rf $(BUILD_DIR)
disas-risc: $(_DISAS_FILES) disas-risc: $(_DISAS_FILES)
$(RISCV_OBJDUMP) -d $^ $(RISCV_OBJDUMP) -d $^

View File

@@ -1,5 +1,6 @@
import random import random
import sys import sys
import os
def generate_flag(length): def generate_flag(length):
characters = list("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") characters = list("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
@@ -13,7 +14,7 @@ def custom_op_xor(value, amount):
return (((value << amount) ^ 0xFF) >> amount) return (((value << amount) ^ 0xFF) >> amount)
manglers = [ hard_manglers = [
(lambda value: custom_op_xor(value, 5), lambda value: f"trunc_xor({value}, 5)"), (lambda value: custom_op_xor(value, 5), lambda value: f"trunc_xor({value}, 5)"),
(lambda value: custom_op_xor(value, 3), lambda value: f"trunc_xor({value}, 3)"), (lambda value: custom_op_xor(value, 3), lambda value: f"trunc_xor({value}, 3)"),
(lambda value: custom_op_xor(value, 2), lambda value: f"trunc_xor({value}, 2)"), (lambda value: custom_op_xor(value, 2), lambda value: f"trunc_xor({value}, 2)"),
@@ -26,7 +27,17 @@ manglers = [
# (lambda value: value, lambda value: f"{value}") # (lambda value: value, lambda value: f"{value}")
] ]
def mangle(value): easy_manglers = [
(lambda value: value + 1, lambda value: f"{value} + 1"),
(lambda value: value - 1, lambda value: f"{value} - 1"),
(lambda value: value * 2, lambda value: f"{value} * 2"),
(lambda value: value ^ 0xAB, lambda value: f"({value} ^ 0xAB)"),
(lambda value: value, lambda value: f"{value}")
]
def mangle(value, manglers):
result = b"" result = b""
c_manglers = [] c_manglers = []
@@ -42,11 +53,18 @@ def mangle(value):
return (result, c_manglers) return (result, c_manglers)
def get_check_code(flag_part, user_part, c_mangler): def get_check_code(flag_part, user_part, c_mangler, difficulty):
if difficulty == "HARD":
variations = [ variations = [
f"custom_jmp_neq({flag_part} ^ 0x7C, {c_mangler(user_part)}, label_false);", f"custom_jmp_neq({flag_part} ^ 0x7C, {c_mangler(user_part)}, label_false);",
f"custom_jmp_neq({flag_part}, {c_mangler(user_part)} ^ 0x7C, label_false);" f"custom_jmp_neq({flag_part}, {c_mangler(user_part)} ^ 0x7C, label_false);"
] ]
else:
variations = [
f"if({flag_part} != {c_mangler(user_part)}) {{ return false; }}"
]
return random.choice(variations) return random.choice(variations)
def main(): def main():
@@ -64,6 +82,8 @@ def main():
if flag_seed.lower() != "false": if flag_seed.lower() != "false":
random.seed("totallysecurepadding" + flag_seed + "sonoonecanguesstheflag!") random.seed("totallysecurepadding" + flag_seed + "sonoonecanguesstheflag!")
difficulty = os.getenv("DIFFICULTY", "EASY")
# Generate a secret # Generate a secret
secret = generate_flag(flag_len) secret = generate_flag(flag_len)
secret = flag_format.replace("FLAG_GOES_HERE", secret) secret = flag_format.replace("FLAG_GOES_HERE", secret)
@@ -71,7 +91,7 @@ def main():
eprint(f"Generated Flag: {secret}") eprint(f"Generated Flag: {secret}")
# Change the bytes of the secret # Change the bytes of the secret
mangled_secret, c_manglers = mangle(secret) mangled_secret, c_manglers = mangle(secret, easy_manglers if difficulty == "EASY" else hard_manglers)
# Shuffle the secret, but keep track of the order # Shuffle the secret, but keep track of the order
# We need this so we know the real location of the characters to compare # We need this so we know the real location of the characters to compare
@@ -89,7 +109,7 @@ def main():
checks = [] checks = []
for i, c_mangler in enumerate(c_manglers): for i, c_mangler in enumerate(c_manglers):
checks.append(get_check_code(f"MANGLED[{i}]", f"userflag[{secret_shuffleorder[i]}]", c_mangler)) checks.append(get_check_code(f"MANGLED[{i}]", f"userflag[{secret_shuffleorder[i]}]", c_mangler, difficulty))
random.shuffle(checks) random.shuffle(checks)
check = "\n".join(checks) check = "\n".join(checks)
@@ -108,7 +128,7 @@ def main():
static volatile uint8_t MANGLED[] = "{mangled_secret}"; static volatile uint8_t MANGLED[] = "{mangled_secret}";
bool check(char* userflag, uint8_t len) {{ bool check(char* userflag, uint8_t len) {{
custom_jmp_neq(len ^ 0x7C, {len(secret)}, label_false); {f"custom_jmp_neq(len ^ 0x7C, {len(secret)}, label_false);" if difficulty == "HARD" else f"if (len != {len(secret)}) {{ return false; }}"}
{check} {check}

View File

@@ -8,12 +8,13 @@
#include "util.h" #include "util.h"
int main(int argc, char** argv) { int main(int argc, char** argv) {
if (argc != 3) { if (argc != 4) {
return 1; return 1;
} }
char* input = argv[1]; char* input = argv[1];
char* output = argv[2]; char* output = argv[2];
char* readme = argv[3];
hw_info_t hwinfo = {0}; hw_info_t hwinfo = {0};
if(get_hw_info(&hwinfo) != 0){ if(get_hw_info(&hwinfo) != 0){
@@ -103,5 +104,17 @@ int main(int argc, char** argv) {
fprintf(stderr, "Wrote encrypted license file to %s\n", output); fprintf(stderr, "Wrote encrypted license file to %s\n", output);
FILE* f_readme = fopen(readme, "w+");
fprintf(f_readme, "Oh, and one more thing you should know...\n");
fprintf(f_readme, "This doesn't just run on any hardware, I don't know how they did it\n");
fprintf(f_readme, "but it only works on my %s processor\n", hwinfo.model_name);
fprintf(f_readme, "running linux (version %s) with %s kb of RAM\n", hwinfo.os_version, hwinfo.mem_total);
fprintf(f_readme, "I also included a dockerfile so you can run all that shi easier.\n");
fprintf(f_readme, "Just unzip that thang and run docker build . -t local-dev and then docker run -it local-dev in the folder you unzipped to.\n");
fprintf(f_readme, "You'll find a way, slime. I'm sorry that I can't give you any more details\n");
fprintf(f_readme, "this is the last message I could get out before they... you know... ⛓️‍👮‍♂️\n");
fprintf(f_readme, "\n");
fprintf(f_readme, "- ASNT aka. Apfelsaftnaturtrüb\n");
return 0; return 0;
} }

View File

@@ -80,6 +80,7 @@ int main(){
if(memcmp(begin, expected, sizeof(begin)) != 0) { if(memcmp(begin, expected, sizeof(begin)) != 0) {
// This happens when decryption fails // This happens when decryption fails
printf(MESSAGE_UNAUTHORIZED); printf(MESSAGE_UNAUTHORIZED);
fflush(stdout);
return 1; return 1;
} }

View File

@@ -2,6 +2,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <dlfcn.h> #include <dlfcn.h>
#include <unistd.h>
static FILE *(*real_fopen)(const char *path, const char *mode) = NULL; static FILE *(*real_fopen)(const char *path, const char *mode) = NULL;
@@ -38,3 +39,19 @@ FILE *fopen(const char *path, const char *mode) {
return real_fopen(path, mode); return real_fopen(path, mode);
} }
FILE *tmpfile(void) {
char path[] = "./tmpfile_XXXXXX";
int fd = mkstemp(path);
if (fd == -1) {
fprintf(stderr, "proc_redirect: mkstemp failed\n");
abort();
}
fprintf(stderr, "proc_redirect: tmpfile created at %s\n", path);
FILE *f = fdopen(fd, "w+");
if (!f) {
close(fd);
abort();
}
return f;
}