# 2025-12-15_"Flag Printer 2100": 251217 {%preview https://alpacahack.com/daily/challenges/flag-printer-2100 %} Level: Medium Type: Rev solved day: 2025,12,17 ## solution ```sh $ file ./print_flag ./print_flag: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=4779e9456734b25b443894084d1ef12e88a94719, for GNU/Linux 3.2.0, not stripped $ ldd ./print_flag /work/fakesleep.so (0x00007fffff7bb000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fffff5c2000) /lib64/ld-linux-x86-64.so.2 (0x00007ffffffc8000) $ strings -a ./print_flag | egrep -i 'flag|sleep|show_flag|year|2100|75' sleep I'll sleep for 75 years... show_flag sleep@GLIBC_2.2.5 ``` ``` # sleep/nanosleep を無効化する共有ライブラリを作成 $ cat > fakesleep.c <<'EOF' #define _GNU_SOURCE #include <time.h> #include <unistd.h> unsigned int sleep(unsigned int s){ return 0; } int nanosleep(const struct timespec *req, struct timespec *rem){ return 0; } EOF $ gcc -shared -fPIC -o fakesleep.so fakesleep.c # 実行(LD_PRELOAD と実行コマンドを同じ行で) $ chmod +x print_flag $ export LD_PRELOAD=$PWD/fakesleep.so $ ./print_flag I'll sleep for 75 years... Alpaca{G00d_Morning_AlpacaH4ck!} ```` ## How I thought. ```sh # 重要な観察 file # → ELF 64-bit, PIE, dynamically linked ldd # → libc.so.6 に依存(GLIBC)→ LD_PRELOAD が効く strings # → "sleep" / "I'll sleep for 75 years..." / "show_flag" ``` * **仮説**: 「75年後にフラグ」= 実装は `sleep()` / `nanosleep()` による**長時間待機** → その後 `show_flag` * **戦術**: 動的リンクなので **`LD_PRELOAD`** で `sleep()` / `nanosleep()` を**即リターン**に差し替え、待機をスキップして**フラグ表示** * **ポイント**: * `LD_PRELOAD=<so> ./binary` の形で**同じ行**に実行コマンドを書く。 * もし時刻比較型(2100年判定)なら、`time()/clock_gettime()` を **2100‑01‑01** の epoch(`4102444800`)に偽装するフックで突破可能 * 静的リンク/フック不可なら、`objdump/gdb` で `sleep` 呼び出し直前の **`edi=0`** にして `sleep(0)` にする(または条件ジャンプ反転で直接フラグ側へ)