3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Full Weak Engineer CTF 2025 Writeup

Posted at

Full Weak Engineer CTF 2025のWriteupです。
image.png
自分で解けた問題のみのWriteupです。

baby-crypto (Crypt, Beginner)

sjrpgs{ebg13rq_zrffntr!}

rot13で解ける

fwectf{rot13ed_message!}

base🚀 (Crypt, Easy)

🪛🔱🛜🫗🚞👞🍁🎩🚎🐒🌬🧨🖱🥚🫁🧶🪛🔱👀🔧🚞👛😄🎩🚊🌡🌬🧮🤮🥚🫐🛞🪛🔱👽🔧🚞🐻🔳🎩😥🪨🌬🩰🖖🥚🫐🪐🪛🔱👿🫗🚞🏵📚🎩🚊🎄🌬🧯🕺🥚🫁📑🪛🔰🐀🫗🚞💿🔳🎩🚲🚟🌬🧲🚯🥚🫁🚰🪛🔱💀🔧🚞🏓🛼🎩🚿🪻🌬🧪🙊🥚🫐🧢🪛🔱🛟🔧🚞🚋🫳🎩😆🏉🌬🧶🚓🥚🫅💛🪛🔱🔌🐃🚞🐋🥍🎩😱🤮🌬🩰🛳🥚🫀📍🪛🔰🐽🫗🚞💿🍁🎩🚊🌋🌬🧵🔷🚀🚀🚀

% unzip base.zip
Archive:  base.zip
  inflating: base🚀/emoji.txt
  inflating: __MACOSX/base🚀/._emoji.txt
  inflating: base🚀/chall.py
  inflating: __MACOSX/base🚀/._chall.py

emoji.txtchall.pyの中身を見てみる

base🚀/emoji.txt
⭐⭕🀄🃏🌀🌁🌂🌃🌄🌅🌆🌇🌈🌉🌊🌋🌌🌍🌐🌑🌓🌕🌗🌙🌚🌛🌜🌝🌞🌟🌠🌡🌤🌥🌦🌧🌨🌩🌪🌬🌭🌮🌯🌰🌱🌲🌳🌴🌵🌶🌷🌸🌹🌺🌻🌼🌽🌾🌿🍀🍁🍂🍃🍄🍅🍆🍇🍈🍉🍊🍋🍌🍍🍎🍏🍐🍑🍒🍓🍔🍕🍖🍗🍘🍙🍚🍛🍜🍝🍞🍟🍠🍡🍢🍣🍤🍥🍦🍧🍨🍩🍪🍫🍬🍭🍮🍯🍰🍱🍲🍳🍴🍵🍶🍷🍸🍹🍺🍻🍼🍽🍾🍿🎀🎁🎂🎃🎄🎅🎆🎇🎈🎉🎊🎋🎌🎍🎎🎏🎐🎑🎒🎓🎖🎗🎙🎚🎛🎞🎟🎠🎡🎢🎣🎤🎥🎦🎧🎨🎩🎪🎫🎬🎭🎮🎯🎰🎱🎲🎳🎴🎵🎶🎷🎸🎹🎺🎻🎼🎽🎾🎿🏀🏁🏂🏃🏄🏅🏆🏇🏈🏉🏊🏋🏌🏍🏎🏏🏐🏑🏒🏓🏔🏕🏖🏗🏘🏙🏚🏛🏜🏝🏞🏟🏠🏡🏢🏣🏤🏥🏦🏧🏨🏪🏫🏬🏭🏮🏯🏰🏳🏴🏵🏷🏸🏹🏺🐀🐁🐂🐃🐄🐅🐆🐇🐈🐉🐊🐋🐌🐍🐎🐏🐐🐑🐒🐓🐔🐕🐖🐗🐘🐙🐚🐛🐜🐝🐞🐟🐠🐡🐢🐣🐤🐥🐦🐧🐨🐩🐪🐫🐬🐭🐮🐯🐰🐱🐲🐳🐴🐵🐶🐷🐸🐹🐺🐻🐼🐽🐾🐿👀👁👂👃👄👅👆👇👈👉👊👋👌👍👎👏👐👑👒👓👔👕👖👗👘👙👚👛👜👝👞👟👠👡👢👣👤👥👦👧👨👩👪👫👬👭👮👯👰👱👲👳👴👵👶👷👸👹👺👻👼👽👾👿💀💁💂💃💄💅💆💇💈💉💊💋💌💍💎💏💐💑💒💔💕💖💘💙💚💛💜💝💞💟💠💡💢💣💤💥💦💧💨💩💪💫💬💭💮💯💰💳💴💵💶💷💸💹💺💻💼💽💾💿📀📅📆📇📈📉📊📋📌📍📎📏📐📑📒📓📔📕📖📚📛📜📝📞📟📠📡📢📣📦📧📨📪📮📯📰📱📲📵📶📷📸📹📺📻📼📽📿🔅🔆🔇🔈🔉🔊🔋🔌🔍🔎🔏🔐🔑🔒🔓🔔🔕🔖🔗🔘🔞🔥🔦🔧🔨🔩🔪🔫🔬🔭🔮🔯🔰🔱🔲🔳🔴🔵🔶🔷🔸🔹🔺🔻🔼🔽🕉🕊🕋🕌🕍🕎🕐🕯🕰🕳🕴🕵🕶🕷🕸🕹🕺🖇🖊🖋🖌🖍🖐🖕🖖🖤🖥🖨🖱🖲🖼🗂🗃🗄🗑🗒🗓🗜🗝🗞🗡🗣🗨🗯🗳🗺🗻🗼🗽🗾🗿😂😃😄😅😆😇😈😊😍😎😐😓😘😜😡😢😥😨😪😫😬😭😮😰😱😳😵🙄🙅🙆🙇🙈🙉🙊🙋🙌🙍🙎🙏🚁🚂🚃🚄🚅🚆🚇🚈🚉🚊🚋🚌🚍🚎🚏🚐🚑🚒🚓🚔🚕🚖🚗🚘🚙🚚🚛🚜🚝🚞🚟🚠🚡🚢🚣🚤🚥🚦🚧🚨🚩🚪🚫🚬🚭🚮🚯🚰🚱🚲🚳🚴🚵🚶🚷🚸🚽🚿🛀🛁🛌🛍🛎🛏🛐🛑🛒🛕🛖🛜🛝🛞🛟🛠🛡🛣🛤🛥🛩🛫🛬🛰🛳🛴🛵🛶🛷🛸🛹🛺🛻🛼🟠🟡🟢🟣🟤🟥🟦🟧🟨🤌🤏🤐🤑🤒🤔🤕🤖🤗🤘🤙🤚🤛🤝🤞🤟🤠🤡🤢🤣🤦🤧🤩🤪🤬🤮🤯🤰🤱🤲🤳🤴🤵🤶🤷🤸🤹🤺🤼🤽🤾🤿🥀🥁🥂🥃🥄🥅🥇🥈🥉🥊🥋🥌🥍🥎🥏🥐🥑🥒🥓🥔🥕🥖🥗🥘🥙🥚🥛🥜🥝🥞🥟🥠🥡🥢🥣🥤🥥🥦🥧🥨🥩🥪🥫🥬🥭🥮🥯🥰🥲🥳🥴🥵🥶🥷🥸🥹🥺🥻🥼🥽🥾🥿🦀🦁🦂🦃🦄🦅🦆🦇🦈🦉🦊🦋🦌🦍🦎🦏🦐🦑🦒🦓🦔🦕🦖🦗🦘🦙🦚🦛🦜🦝🦞🦟🦠🦡🦢🦣🦤🦥🦦🦧🦨🦩🦪🦫🦬🦭🦮🦯🦰🦱🦲🦳🦴🦵🦶🦷🦸🦹🦺🦻🦼🦽🦾🦿🧀🧁🧂🧃🧄🧅🧆🧇🧈🧉🧊🧋🧕🧖🧗🧘🧙🧚🧛🧜🧝🧞🧟🧠🧡🧢🧣🧤🧥🧦🧧🧨🧩🧪🧫🧬🧭🧮🧯🧰🧱🧲🧳🧴🧵🧶🧷🧸🧹🧺🧻🧼🧽🧾🧿🩰🩱🩲🩳🩴🩹🩺🩻🩼🪀🪁🪂🪃🪄🪅🪆🪇🪈🪐🪑🪒🪓🪔🪕🪖🪗🪘🪙🪚🪛🪜🪝🪞🪟🪠🪡🪢🪣🪤🪥🪦🪧🪨🪩🪪🪫🪬🪭🪮🪯🪱🪴🪵🪶🪷🪸🪹🪺🪻🪼🪽🪿🫀🫁🫂🫅🫎🫏🫐🫑🫒🫓🫔🫕🫖🫗🫘🫙🫚🫛🫠🫡🫦🫧🫰🫱🫲🫳🫵🫶🫷
base🚀/chall.py
#!/usr/bin/env python🚀

with open('emoji.txt', 'r', encoding='utf-8') as f:
    emoji = list(f.read().strip())

table = {i: ch for i, ch in enumerate(emoji)}

def encode(data):
    bits = ''.join(f'{b:08b}' for b in data)
    pad = (-len(bits)) % 10
    bits += '0' * pad
    out = [table[int(bits[i:i+10], 2)] for i in range(0, len(bits), 10)]
    r = (-len(out)) % 4
    if r:
        out.extend('🚀' * r)
    return ''.join(out)

if __name__ == '__main__':
    # msg = 'Hello!'
    msg = 'hello'
    enc = encode(msg.encode())
    print('msg:', msg)
    print('enc:', enc)

暗号化と逆の順番で処理させて復号する。

decode.py
#!/usr/bin/env python🚀
import sys

try:
    with open('emoji.txt', 'r', encoding='utf-8') as f:
        emoji = list(f.read().strip())
except FileNotFoundError:
    print("エラー: 'emoji.txt' が見つかりません。スクリプトと同じディレクトリに配置してください。", file=sys.stderr)
    sys.exit(1)

# エンコード用テーブル {0: '😀', 1: '😁', ...}
table = {i: ch for i, ch in enumerate(emoji)}

# デコード用の逆引きテーブル {'😀': 0, '😁': 1, ...}
inv_table = {ch: i for i, ch in table.items()}

def encode(data: bytes) -> str:
    # 1. バイトデータを8ビットの2進数文字列に変換
    bits = ''.join(f'{b:08b}' for b in data)

    # 2. 長さが10の倍数になるように '0' でパディング
    pad = (-len(bits)) % 10
    bits += '0' * pad

    # 3. 10ビットずつに区切り、対応する絵文字に変換
    out = [table[int(bits[i:i+10], 2)] for i in range(0, len(bits), 10)]

    # 4. 絵文字リストの長さが4の倍数になるように '🚀' でパディング
    r = (-len(out)) % 4
    if r:
        out.extend('🚀' * r)

    return ''.join(out)

def decode(encoded_data: str) -> bytes:
    """絵文字でエンコードされた文字列を元のバイトデータにデコードします。"""

    # 1. 末尾の '🚀' パディングを除去
    s = encoded_data.rstrip('🚀')

    # 2. 各絵文字を10ビットの2進数文字列に戻し、結合してビット文字列を再構築
    bits = "".join(f'{inv_table[char]:010b}' for char in s)

    # 3. 元のデータは8ビット(1バイト)単位なので、全体の長さを8の倍数に切り詰める
    # これにより、エンコード時に追加された '0' のパディングが除去される
    num_bytes = len(bits) // 8
    bits = bits[:num_bytes * 8]

    # 4. 8ビットずつに区切り、整数に変換してからバイトオブジェクトに戻す
    original_bytes = bytes(int(bits[i:i+8], 2) for i in range(0, len(bits), 8))

    return original_bytes

if __name__ == '__main__':
    msg = 'Hello, world! こんにちは、世界!'

    # エンコード
    encoded = encode(msg.encode('utf-8'))
    print('Original:', msg)
    print('Encoded: ', encoded)
    print("-" * 30)

    # デコード
    decoded_bytes = decode(encoded)
    flag = decode('🪛🔱🛜🫗🚞👞🍁🎩🚎🐒🌬🧨🖱🥚🫁🧶🪛🔱👀🔧🚞👛😄🎩🚊🌡🌬🧮🤮🥚🫐🛞🪛🔱👽🔧🚞🐻🔳🎩😥🪨🌬🩰🖖🥚🫐🪐🪛🔱👿🫗🚞🏵📚🎩🚊🎄🌬🧯🕺🥚🫁📑🪛🔰🐀🫗🚞💿🔳🎩🚲🚟🌬🧲🚯🥚🫁🚰🪛🔱💀🔧🚞🏓🛼🎩🚿🪻🌬🧪🙊🥚🫐🧢🪛🔱🛟🔧🚞🚋🫳🎩😆🏉🌬🧶🚓🥚🫅💛🪛🔱🔌🐃🚞🐋🥍🎩😱🤮🌬🩰🛳🥚🫀📍🪛🔰🐽🫗🚞💿🍁🎩🚊🌋🌬🧵🔷🚀🚀🚀')
    decoded_msg = decoded_bytes.decode('utf-8')
    print('Decoded: ', decoded_msg)
    print("flag? ", flag.decode('utf-8'))
    print("flag_1 ", decode(flag.decode('utf-8')).decode('utf-8'))
    # 検証
    print("\n✅ Success:", msg == decoded_msg)

実行する

% python decode.py
Original: Hello, world! こんにちは、世界!
Encoded:  🐴🙅🥬🍴🎺🕉🔇🧄📌😍🍍🏮🔽👑🏫🚳🧩🌜🥉🧜🚧🗾🍰🫀🔹🌠👁🎠🧹👫🦍🪕🔻🚀🚀🚀
------------------------------
Decoded:  Hello, world! こんにちは、世界!
flag?  🪛🔰🛏🍈📛🤵🔈🚁📷🦨🥩💇💼🥇🧷🥳🎆🚇🔅👶📷🚇🤧🗣💐🥵🌚🦽🏖🧇🪥🦿🏋🛜🙆🧀🏋🔭🥬🍲🔫🚀🚀🚀
flag_1  🚀Congratulations! fwectf{n0_r0ck37_3m0ji_n0_llm}

✅ Success: True

二回デコードする必要があったけどフラグゲット!

fwectf{n0_r0ck37_3m0ji_n0_llm}

unixor (Crypt, Easy)

I wanna be a novelist

% unzip unixor.zip
Archive:  unixor.zip
   creating: dist/
  inflating: dist/encrypted.txt
  inflating: dist/generate.py
dist/encrypted.txt
����Ș���⪼�ؼ�߹������������Љ�����μı>���������ރ����ʧ������ڗ������������ҧ����Ւ���Ќƀ��ą����ޢ����ȑ�ב�ȃ���͎����������������ò������������ؔ�Ó�ۇ��������ԧ������Ȓ�ʇ¿��ހ����̧��������އ�������鱗���Ɣ���܁̽����������������~l����������������҂���Ŝ���ż��Ӻ���œ�����ŀ������������ɼŝ��م�������ƹ��Ӹ�йҪ��ƅ�ŀ��������ҹ���Ķ��������������������߹ʡ������������ͼ�޼ś�����������Ŝ��ӹ�ػ����օ�̀�Ř���Ӗ��꼰������ց���Г���Œ����޼Ŭ��́�̀�Ș���ŵ����Ŭ���l����ā����Ӄ����ާ�������͑���ּ�������秲����EUS��̍ļ��ׅ������������ɑ���¯��������觳���Δ�����ò��������������͔�̗������������ެ���������Ձ᳧�ͅ����Ƨ��������Ќ����ׅ����Ч�������˗���²��ԅ����ۧ��������އ���������ԧ����Ȕ�̑�ڌ妬������ɡ����ߔ�͓������ȅ����������֔�������lX��ӼŮ��Ӏ����������������ŝ��ߎ���Ȝ���î�������͸��օ�������É��ͼ�ѹ����Ӏ����������Ҷ���ـ�DŽ�Ý���ŝ��ݼ�Ƽř�����������ŷ��ټ�¼IJ������������̊�����иѿ����������ƹ��켰�ٖ��ۅ����������ἰ����������������ŝ��ȼ���IJ�������ȝ���Ř�����ƼƱ�������̘���ı��ͼ��IJ��Dž�ͅ�ј���́��޹��Ţ�����������ѿ����������Յ���̘���Ÿ�����ۼŵ��փ�������ŕ��ּ�ؼı>n�����܅�נ����ջ�����֑���������姍����ˉ���֗Ԟ�ن����⠱���ı܍���зؔ�Ć�����������߳���ж�������̠�����փ���ۼݙ������Ơ�����ޒ���Իڞ������櫸����ޚ���ԡԘ�ʆ�ڀ�����Դ���е˚������Š����ױ޽���ж������l��������ۼ���������������ŝ��뼳��������������Ƹ�����иѿ����π�Ϙ���ŷ��ټ���ƻ�����Ί�Ԙ���Ŕ��ּ��Ŭ�����������̿������ơ��υ�ڋ�ژ���IJ��ͼ��̊��̅��������Ő��ͼ�ѹġ������������������Һ���ׁ�ߋ������ſ��꼰��������ƀ������������ŝ�����ˀ������ř��ּ���Ř������������ŷ��͸���Ҡ�����������ſ��ͼ��ƿ�����ˀ�Ƙ��:N��������д��؆�߀�ߠ����α߰���՝��܀���堲����ޮ���ے��Ά��������ʹ�����еǞ�ц���������ñ޵���֧Ş����������ֱݣ���е���������礥�����࠰��Մ����Ѕ��������ޙ���е������ׅ���������ޟ���еʘ�҆�߅�ˠ����ñߴ���е��߆�˃�젱���ȵɃ���е��׆���蠱����ޮ���9>�������������ԅ����ߠ�������ԑ�ȇ����܅����������۔������ʅ����ӧ��������ò������𡨉��ȑ�ٗ���¯��Ņ����ݧ������������������񢩚������Ռ⼢������ħ�������ė���²���������Nд�������������ޖ���е������܅�媷���ɷӦ���ո�������������ݺ���ՁӞ�܂���ˠ�����߳���ж��ن�ۅ�奍���ȴ갰��е̔�߆�ڃ�栱����ެ���е�͌���觍���űޮ���ԡ��׆���Ġ��9��ҹ�ػ����҅�Ѐ�Θ���Ù��Լ�߹؟����Ά�����Ŭ��ּ���Ŝ����؀�ȝ���ľ�������Ÿ������������Ʊ��ͼ��Ŀ����������Ʋ������ľ��ׅ�ˀ�����İ��ڼ�̼ı������ɘ���œ��輰��ŷ��������Ƙ���ܽ�����ѹ����փ�߀�����ƾ��Լ�Ѻ�����ˆ������ŵ�������IJ���������������ź�ɼż��ӏ��������ŷ�����׼Ƹ�����������Ÿ��ۼ��
generate.py
FLAG = b"fwectf{**REDACTED**}"

assert len(FLAG) < 30

"""
novel.txtはChatGPT 5 Autoによって生成された、UTF-8(BOMなし、改行LF)で書かれた小説です。

プロンプト(一部修正):
「**REDACTED**」という単語から連想される、1500字程度の小説を書いてください。
"""
novel = open("novel.txt", "rb").read()

encrypted = bytes([a ^ FLAG[i % len(FLAG)] for i, a in enumerate(novel)])
open("encrypted.txt", "wb").write(encrypted)

復号スクリプトを書く(Geminiが)

solve_unixor.py
#!/usr/bin/env python3
import sys
from pathlib import Path
from collections import Counter, defaultdict

def try_build_key(ct: bytes, L: int):
    # seed known prefix "fwectf{"
    seed = b"fwectf{"
    key = [None] * L
    for i, b in enumerate(seed):
        key[i % L] = b

    # voting using frequent Japanese punctuation
    triples = [
        (0xE3, 0x80, 0x82),  # "。"
        (0xE3, 0x80, 0x81),  # "、"
    ]

    votes = [Counter() for _ in range(L)]

    n = len(ct)
    for i in range(n - 2):
        for t in triples:
            k0 = ct[i]   ^ t[0]
            k1 = ct[i+1] ^ t[1]
            k2 = ct[i+2] ^ t[2]
            votes[(i    ) % L][k0] += 1
            votes[(i + 1) % L][k1] += 1
            votes[(i + 2) % L][k2] += 1

    # also vote for newline 0x0A (line feeds common)
    for i in range(n):
        k = ct[i] ^ 0x0A
        votes[i % L][k] += 1

    # apply highest votes where key not fixed by seed
    for pos in range(L):
        if key[pos] is None and votes[pos]:
            key[pos] = votes[pos].most_common(1)[0][0]

    # if still some Nones, fill with 0 as placeholder (will likely fail and be discarded)
    for pos in range(L):
        if key[pos] is None:
            key[pos] = 0

    return bytes(key), votes

def score_utf8(decoded_bytes: bytes) -> float:
    # returns fraction of bytes that are part of a successfully decoded UTF-8 string
    # We attempt to decode; if fails, we do a tolerant pass counting valid sequences.
    total = len(decoded_bytes)
    i = 0
    good = 0
    while i < total:
        b = decoded_bytes[i]
        if b < 0x80:
            good += 1
            i += 1
        elif 0xC2 <= b <= 0xDF:
            if i + 1 < total and 0x80 <= decoded_bytes[i+1] <= 0xBF:
                good += 2; i += 2
            else:
                i += 1
        elif 0xE0 <= b <= 0xEF:
            if (i + 2 < total and
                0x80 <= decoded_bytes[i+1] <= 0xBF and
                0x80 <= decoded_bytes[i+2] <= 0xBF):
                good += 3; i += 3
            else:
                i += 1
        elif 0xF0 <= b <= 0xF4:
            if (i + 3 < total and
                0x80 <= decoded_bytes[i+1] <= 0xBF and
                0x80 <= decoded_bytes[i+2] <= 0xBF and
                0x80 <= decoded_bytes[i+3] <= 0xBF):
                good += 4; i += 4
            else:
                i += 1
        else:
            i += 1
    return good / max(1, total)

def decrypt_with_key(ct: bytes, key: bytes) -> bytes:
    L = len(key)
    return bytes([ct[i] ^ key[i % L] for i in range(len(ct))])

def main():
    enc_path = Path("encrypted.txt")
    if not enc_path.exists():
        print("[-] encrypted.txt not found in current directory.")
        print("    Put encrypted.txt next to this script and run again.")
        sys.exit(1)
    ct = enc_path.read_bytes()
    best = None

    # flags are shorter than 30, try reasonable lengths
    for L in range(8, 30):
        key, votes = try_build_key(ct, L)

        # enforce known prefix
        if key[:7] != b"fwectf{":
            # if voting overwrote the prefix, fix it
            key = b"fwectf{" + key[7:]
        pt = decrypt_with_key(ct, key)
        score = score_utf8(pt)
        # simple heuristic: decoded text should be largely valid UTF-8 (>0.85)
        if best is None or score > best[0]:
            best = (score, L, key, pt)

    score, L, key, pt = best
    print(f"[+] Best key length = {L} with UTF-8 score = {score:.3f}")
    # Try to refine trailing key bytes by searching for '}' in key (flags end with })
    # We'll read off the ASCII flag characters from key directly if it looks plausible.
    try:
        flag_text = key.decode("ascii", errors="strict")
    except Exception:
        # make a more robust extraction by assuming it starts with fwectf{ and ends with }
        flag_text = ''.join(chr(b) if 32 <= b <= 126 else '?' for b in key)
    # Extract fwectf{...} substring
    import re
    m = re.search(r"fwectf\{[ -~]{0,50}\}", flag_text)
    if m:
        print(f"[+] FLAG (from key): {m.group(0)}")
    else:
        print("[!] Could not confidently parse FLAG as ASCII from key bytes.")
        print("    Key guess:", flag_text)

    # Write decrypted novel for sanity check
    out = Path("decrypted_novel.txt")
    out.write_bytes(pt)
    print(f"[+] Wrote decrypted novel to {out.resolve()}")

if __name__ == "__main__":
    main()

実行する

% python solve_unixor.py
[+] Best key length = 24 with UTF-8 score = 1.000
[+] FLAG (from key): fwectf{dC0D3_fR_1S_D34d}
[+] Wrote decrypted novel to /home/saku0512/Desktop/CTF/Full_Weak_Engineer_CTF/Crypt/unixor/dist/decrypted_novel.txt

一応flagゲット

fwectf{dC0D3_fR_1S_D34d}

Adversarial Login (Misc, Medium)

The strange mascot seems to be trying to impersonate its way out of the venue. Your mission is to intentionally confuse an AI. Take the provided image and, with the utmost subtlety, modify it just enough to make the classifier believe it's looking at a gibbon.

http://chal1.fwectf.com:8005

英語分からんから日本語翻訳する

その奇妙なマスコットは、なりすましで会場を出ようとしているようだ。あなたのミッションは、AIを意図的に混乱させることです。提供された画像を、細心の注意を払いながら、分類機にテナガザルを見ていると思わせるのに十分な程度に修正してください。

http://chal1.fwectf.com:8005

AIの敵対的サンプルを作る問題っぽい

サイトを開くと画像をアップロードできることが分かる
image.png

% unzip adversarial_login.zip
Archive:  adversarial_login.zip
   creating: adversarial_login/
   creating: adversarial_login/templates/
  inflating: adversarial_login/templates/login.html
  inflating: adversarial_login/templates/index.html
  inflating: adversarial_login/Dockerfile
  inflating: adversarial_login/image.jpg
  inflating: adversarial_login/requirements.txt
  inflating: adversarial_login/app.py
  inflating: adversarial_login/compose.yml

image.jpgはミャクミャクの画像

adversarial_login/app.py
import os
from flask import Flask, flash, redirect, request, render_template, session, url_for
from PIL import Image
import numpy as np
import tensorflow as tf

FLAG = os.environ.get("FLAG", "fwectf{fake_flag}")
IMG_HEIGHT, IMG_WIDTH = 224, 224
ORIGINAL_IMAGE_PATH = 'image.jpg'
TARGET_CLASS_ID = 101
MSE_THRESHOLD = 0.05

app = Flask(__name__)
app.secret_key = os.urandom(16).hex()
app.config['MAX_CONTENT_LENGTH'] = 100 * 1024  # 100KB

def preprocess_image(img):
    img = img.convert('RGB').resize((IMG_HEIGHT, IMG_WIDTH))
    img_array = np.array(img)
    preprocessed_img = tf.keras.applications.mobilenet_v2.preprocess_input(img_array)
    return tf.convert_to_tensor(preprocessed_img, dtype=tf.float32)

original_image = Image.open(ORIGINAL_IMAGE_PATH)
original_image_tensor = preprocess_image(original_image)
model = tf.keras.applications.MobileNetV2(weights="imagenet")

@app.route("/login", methods=["GET", "POST"])
def login():
    if request.method == "POST":
        try:
            file = request.files['file']
            image = Image.open(file.stream)
            image_tensor = preprocess_image(image)
            if image_tensor is None:
                return render_template("login.html")

            mse = tf.reduce_mean(tf.square(original_image_tensor - image_tensor))
            if mse.numpy() > MSE_THRESHOLD:
                flash(
                    f"[-] AUTH FAILED (Stage 1): Image is too different from the original.\n"
                    f"    MSE: {mse.numpy():.4f} > Threshold: {MSE_THRESHOLD}\n"
                )
                return render_template("login.html")

            prediction = model.predict(np.expand_dims(image_tensor, axis=0), verbose=0)
            predicted_class_id = np.argmax(prediction[0])

            if predicted_class_id == TARGET_CLASS_ID:
                session["is_admin"] = True
                return redirect(url_for("index"))
            decoded_preds = tf.keras.applications.mobilenet_v2.decode_predictions(prediction, top=1)[0]
            predicted_class_name = decoded_preds[0][1]
            flash(
                f"[-] AUTH FAILED (Stage 2): Image was not classified as the target class.\n"
                f"    Predicted as: '{predicted_class_name}' (ID: {predicted_class_id})\n"
            )
        except Exception as e:
            flash(f"Error occured: {e}")
    return render_template("login.html")



@app.route("/")
def index():
    if not session.get("is_admin"):
        return redirect(url_for("login"))
    return render_template("index.html", flag=FLAG)

やはり敵対的サンプルを作成し、アップロードすればいいっぽい

adversarial_login/solve.py
import numpy as np
import tensorflow as tf
from PIL import Image

IMG_HEIGHT, IMG_WIDTH = 224, 224
ORIGINAL_IMAGE_PATH = 'image.jpg'
TARGET_CLASS_ID = 101
MSE_THRESHOLD = 0.05
OUTPUT_IMAGE_PATH = 'adversarial.png'

def preprocess_image(img):
    img = img.convert('RGB').resize((IMG_HEIGHT, IMG_WIDTH))
    img_array = np.array(img)
    preprocessed_img = tf.keras.applications.mobilenet_v2.preprocess_input(img_array)
    return tf.convert_to_tensor(preprocessed_img, dtype=tf.float32)

def deprocess_image(tensor):
    tensor = tensor.numpy()
    tensor = (tensor + 1.0) * 127.5
    tensor = np.clip(tensor, 0, 255)
    return Image.fromarray(tensor.astype('uint8'))

def main():
    original_image = Image.open(ORIGINAL_IMAGE_PATH)
    original_image_tensor = preprocess_image(original_image)

    model = tf.keras.applications.MobileNetV2(weights="imagenet")

    # 元の画像の分類結果を確認
    initial_prediction = model.predict(np.expand_dims(original_image_tensor, axis=0))
    initial_class_id = np.argmax(initial_prediction[0])
    decoded_preds = tf.keras.applications.mobilenet_v2.decode_predictions(initial_prediction, top=1)[0]
    print(f"[*] Original image is classified as: '{decoded_preds[0][1]}' (ID: {initial_class_id})")

    adversarial_image_tensor = tf.Variable(original_image_tensor)

    optimizer = tf.keras.optimizers.Adam(learning_rate=0.1)

    loss_fn = tf.keras.losses.SparseCategoricalCrossentropy()

    print("[*] Generating adversarial image...")
    for i in range(200):
        with tf.GradientTape() as tape:
            tape.watch(adversarial_image_tensor)
            prediction = model(tf.expand_dims(adversarial_image_tensor, axis=0))
            # ターゲットクラスに対する損失を計算
            loss = loss_fn(tf.constant([TARGET_CLASS_ID]), prediction)

        grads = tape.gradient(loss, adversarial_image_tensor)
        optimizer.apply_gradients([(grads, adversarial_image_tensor)])

        # 元画像との差分が大きくなりすぎないように制約をかける
        perturbation = adversarial_image_tensor - original_image_tensor
        perturbation = tf.clip_by_value(perturbation, -MSE_THRESHOLD, MSE_THRESHOLD)
        adversarial_image_tensor.assign(original_image_tensor + perturbation)

        # 前処理されたテンソルが[-1, 1]の範囲に収まるようにクリップ
        adversarial_image_tensor.assign(tf.clip_by_value(adversarial_image_tensor, -1.0, 1.0))

        if (i + 1) % 20 == 0:
            final_prediction = model.predict(np.expand_dims(adversarial_image_tensor, axis=0), verbose=0)
            final_class_id = np.argmax(final_prediction[0])
            mse = tf.reduce_mean(tf.square(original_image_tensor - adversarial_image_tensor)).numpy()
            print(f"    Step {i+1:3d}: MSE = {mse:.4f}, Predicted Class ID = {final_class_id}")
            if final_class_id == TARGET_CLASS_ID and mse <= MSE_THRESHOLD:
                print("[+] Adversarial image generated successfully!")
                break

    final_prediction = model.predict(np.expand_dims(adversarial_image_tensor, axis=0))
    final_class_id = np.argmax(final_prediction[0])
    decoded_final_preds = tf.keras.applications.mobilenet_v2.decode_predictions(final_prediction, top=1)[0]

    mse = tf.reduce_mean(tf.square(original_image_tensor - adversarial_image_tensor))

    print(f"[*] Final prediction: '{decoded_final_preds[0][1]}' (ID: {final_class_id})")
    print(f"[*] MSE with original image: {mse.numpy():.4f}")

    if final_class_id == TARGET_CLASS_ID and mse.numpy() <= MSE_THRESHOLD:
        print(f"[+] Conditions met. Saving image to '{OUTPUT_IMAGE_PATH}'")
        adversarial_image = deprocess_image(adversarial_image_tensor)
        adversarial_image.save(OUTPUT_IMAGE_PATH)
    else:
        print("[-] Failed to generate an adversarial image that meets the conditions.")

if __name__ == '__main__':
    main()

実行して生成された画像をアップロードすればフラグゲット!

image.png

fwectf{1s_y0ur_br41n_d33p_l34rn1ng?}

Osaka Expo Pavilion Quiz! (OSINT, Easy)

大阪万博…だけど様子がちょっと変? この映像が放送された館を答えよ
Flag形式:fwectf{館名(日本語可)}

画像だけが配布される

IMG_3591.jpg

perplexityで調べる

この画像が大阪万博(1970年開催)の会場で放送された館は「みどり館」です。

みどり館について
「みどり館」はドーム形の球体施設で、内部全体が巨大なスクリーンとなっていたため、広角映像や天井への投影が特徴的でした。

ドームの内装全体に映像が映し出される構造で、大変印象的な内部空間が創出されていました。

当時の技術を駆使して360度・上下210度に映像を投影できた点が特徴とされています。

ドーム天井装飾との関係
画像にも見られるような天井全体の映像や装飾は、みどり館ならではの大規模映像空間によるものです。

みどり館は多くの来場者に強い印象を残したパビリオンです。

したがって、画像のドーム天井およびその放送元は「みどり館」と特定できます。

フラグゲット!

fwectf{みどり館}

QR (Forensic, Beginner)

RGB RGB RGB

RGB RGB RGB

RGB RGB RGB

qrgb (1).png

よみとってみる

367 294 815

おそらく各ブロックに対応している。

3 6 7
2 9 4
8 1 5

各ブロックの色をアイビスペイントのスポイト機能で調べる。

#7b5152 #6f6c6f #75725F
#637466 #36657D #5F616E
#393837 #667765 #645F63

各ブロックを読み取った順番で並べ替える。
復号スクリプトを書く。

solve.py
def decrypt_from_hex(hex_codes):
    """
    ヘックスコードのリストをデコードしてフラグ文字列を生成する関数
    """
    decrypted_chars = []

    # リスト内の各ヘックスコードを処理
    for hex_code in hex_codes:
        # '#' を取り除く
        clean_hex = hex_code.lstrip('#')

        # 2文字ずつ(RR, GG, BB)に分割して処理
        for i in range(0, len(clean_hex), 2):
            # 2文字の16進数文字列を取得 (例: "66")
            hex_byte = clean_hex[i:i+2]

            # 16進数文字列を10進数の整数に変換
            decimal_value = int(hex_byte, 16)

            # 整数をASCII文字に変換してリストに追加
            decrypted_chars.append(chr(decimal_value))

    # 文字リストを一つの文字列に結合して返す
    return "".join(decrypted_chars)

# ユーザーが提供した、並べ替え後のヘックスコードのリスト
reordered_hex_codes = [
    "#667765",
    "#637466",
    "#7b5152",
    "#5F616E",
    "#645F63",
    "#6f6c6f",
    "#75725F",
    "#393837",
    "#36657D",
]

# 関数を実行してフラグを復号
final_flag = decrypt_from_hex(reordered_hex_codes)

# 結果を出力
print("復号結果:")
print(final_flag) 
% python solve.py
復号結果:
fwectf{QR_and_colour_9876e}

フラグゲット!

fwectf{QR_and_colour_9876e}

No need Logical Thinking (Rev, Easy)

論理的思考はどんな物事にも必要。

% unzip No_need_Logical_Thinking.zip
Archive:  No_need_Logical_Thinking.zip
 extracting: output.txt
  inflating: Challenge.pl

各ファイルをみる

Challenge.pl
process_flag(FileName) :-
    open(FileName, read, Stream),
    read_string(Stream, _, Content),
    close(Stream),
    string_codes(Content, Codes),
    transform_codes(Codes, 1, Transformed),
    string_codes(NewString, Transformed),
    writeln(NewString).


transform_codes([], _, []).
transform_codes([H|T], Index, [NewH|NewT]) :-
    NewH is H + Index,
    NextIndex is Index + 1,
    transform_codes(T, NextIndex, NewT).


%EXECUTE
%?- process_flag('flag.txt').
output.txt
gyhgyl|qoj\>@@xqDD|zyJyg}UD¡

output.txtをデコードする。

solve.py
import sys

def solve(input_filename, output_filename):
    """
    Reads the encrypted content from input_filename, reverses the
    transformation from Challenge.pl, and writes the result to
    output_filename.
    """
    try:
        # Open the input file and read the encrypted string
        with open(input_filename, 'r', encoding='utf-8') as f:
            encrypted_str = f.read().strip()

        decrypted_flag = ""

        # Loop through each character with its index
        for i, char in enumerate(encrypted_str):
            # Get the character code (ASCII/Unicode value)
            encrypted_code = ord(char)

            # The original script added the index (starting from 1),
            # so we subtract it to reverse the process.
            index_to_subtract = i + 1
            original_code = encrypted_code - index_to_subtract

            # Convert the code back to a character and append it
            decrypted_flag += chr(original_code)

        # Write the final decrypted string to the output file
        with open(output_filename, 'w', encoding='utf-8') as f:
            f.write(decrypted_flag)

        print(f"Successfully decoded '{input_filename}' to '{output_filename}'.")
        print(f"Decoded content: {decrypted_flag}")

    except FileNotFoundError:
        print(f"Error: The file '{input_filename}' was not found.")
    except Exception as e:
        print(f"An error occurred: {e}")

if __name__ == '__main__':
    # Check if a filename was provided as a command-line argument
    if len(sys.argv) > 1:
        input_file = sys.argv[1]
        solve(input_file, 'flag.txt')
    else:
        # Default to 'output.txt' if no argument is given
        solve('output.txt', 'flag.txt')
% python solve.py output.txt
Successfully decoded 'output.txt' to 'flag.txt'.
Decoded content: fwectf{the_Pr010g_10gica1_Languag3!}

フラグゲット!

fwectf{the_Pr010g_10gica1_Languag3!}

Mystery Zone (Rev, Medium)

よぉ~みんな! HelloWorld だぜ!!!
flag を探してたら変な所に迷い込んじまったみてぇだ……。
俺を操作して flag を見つけてくれ~!!
お前たち最高だぜ!

% unzip Mystery_Zone.zip
Archive:  Mystery_Zone.zip
  inflating: chall/Challenge.exe
   creating: chall/Challenge_Data/
 extracting: chall/Challenge_Data/app.info
  inflating: chall/Challenge_Data/boot.config
  inflating: chall/Challenge_Data/globalgamemanagers
  inflating: chall/Challenge_Data/globalgamemanagers.assets
  inflating: chall/Challenge_Data/globalgamemanagers.assets.resS
  inflating: chall/Challenge_Data/level0
  inflating: chall/Challenge_Data/level1
  inflating: chall/Challenge_Data/level2
   creating: chall/Challenge_Data/Managed/
  inflating: chall/Challenge_Data/Managed/Assembly-CSharp.dll
  inflating: chall/Challenge_Data/Managed/Mono.Security.dll
  inflating: chall/Challenge_Data/Managed/mscorlib.dll
  inflating: chall/Challenge_Data/Managed/netstandard.dll
  inflating: chall/Challenge_Data/Managed/System.ComponentModel.Composition.dll
  inflating: chall/Challenge_Data/Managed/System.Configuration.dll
  inflating: chall/Challenge_Data/Managed/System.Core.dll
  inflating: chall/Challenge_Data/Managed/System.Data.DataSetExtensions.dll
  inflating: chall/Challenge_Data/Managed/System.Data.dll
  inflating: chall/Challenge_Data/Managed/System.dll
  inflating: chall/Challenge_Data/Managed/System.Drawing.dll
  inflating: chall/Challenge_Data/Managed/System.EnterpriseServices.dll
  inflating: chall/Challenge_Data/Managed/System.IO.Compression.dll
  inflating: chall/Challenge_Data/Managed/System.IO.Compression.FileSystem.dll
  inflating: chall/Challenge_Data/Managed/System.Net.Http.dll
  inflating: chall/Challenge_Data/Managed/System.Numerics.dll
  inflating: chall/Challenge_Data/Managed/System.Runtime.dll
  inflating: chall/Challenge_Data/Managed/System.Runtime.Serialization.dll
  inflating: chall/Challenge_Data/Managed/System.Security.dll
  inflating: chall/Challenge_Data/Managed/System.ServiceModel.Internals.dll
  inflating: chall/Challenge_Data/Managed/System.Transactions.dll
  inflating: chall/Challenge_Data/Managed/System.Xml.dll
  inflating: chall/Challenge_Data/Managed/System.Xml.Linq.dll
  inflating: chall/Challenge_Data/Managed/Unity.2D.Animation.Runtime.dll
  inflating: chall/Challenge_Data/Managed/Unity.2D.Common.Runtime.dll
  inflating: chall/Challenge_Data/Managed/Unity.2D.IK.Runtime.dll
  inflating: chall/Challenge_Data/Managed/Unity.2D.PixelPerfect.dll
  inflating: chall/Challenge_Data/Managed/Unity.2D.SpriteShape.Runtime.dll
  inflating: chall/Challenge_Data/Managed/Unity.2D.Tilemap.Extras.dll
  inflating: chall/Challenge_Data/Managed/Unity.Burst.dll
  inflating: chall/Challenge_Data/Managed/Unity.Burst.Unsafe.dll
  inflating: chall/Challenge_Data/Managed/Unity.Collections.dll
  inflating: chall/Challenge_Data/Managed/Unity.Collections.LowLevel.ILSupport.dll
  inflating: chall/Challenge_Data/Managed/Unity.InputSystem.dll
  inflating: chall/Challenge_Data/Managed/Unity.InputSystem.ForUI.dll
  inflating: chall/Challenge_Data/Managed/Unity.InternalAPIEngineBridge.001.dll
  inflating: chall/Challenge_Data/Managed/Unity.Mathematics.dll
  inflating: chall/Challenge_Data/Managed/Unity.Multiplayer.Center.Common.dll
  inflating: chall/Challenge_Data/Managed/Unity.Rendering.LightTransport.Runtime.dll
  inflating: chall/Challenge_Data/Managed/Unity.RenderPipeline.Universal.ShaderLibrary.dll
  inflating: chall/Challenge_Data/Managed/Unity.RenderPipelines.Core.Runtime.dll
  inflating: chall/Challenge_Data/Managed/Unity.RenderPipelines.Core.Runtime.Shared.dll
  inflating: chall/Challenge_Data/Managed/Unity.RenderPipelines.Core.ShaderLibrary.dll
  inflating: chall/Challenge_Data/Managed/Unity.RenderPipelines.GPUDriven.Runtime.dll
  inflating: chall/Challenge_Data/Managed/Unity.RenderPipelines.ShaderGraph.ShaderGraphLibrary.dll
  inflating: chall/Challenge_Data/Managed/Unity.RenderPipelines.Universal.2D.Runtime.dll
  inflating: chall/Challenge_Data/Managed/Unity.RenderPipelines.Universal.Config.Runtime.dll
  inflating: chall/Challenge_Data/Managed/Unity.RenderPipelines.Universal.Runtime.dll
  inflating: chall/Challenge_Data/Managed/Unity.RenderPipelines.Universal.Shaders.dll
  inflating: chall/Challenge_Data/Managed/Unity.TextMeshPro.dll
  inflating: chall/Challenge_Data/Managed/Unity.Timeline.dll
  inflating: chall/Challenge_Data/Managed/Unity.VisualScripting.Antlr3.Runtime.dll
  inflating: chall/Challenge_Data/Managed/Unity.VisualScripting.Core.dll
  inflating: chall/Challenge_Data/Managed/Unity.VisualScripting.Flow.dll
  inflating: chall/Challenge_Data/Managed/Unity.VisualScripting.State.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.AccessibilityModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.AIModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.AMDModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.AndroidJNIModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.AnimationModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.ARModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.AssetBundleModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.AudioModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.ClothModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.ClusterInputModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.ClusterRendererModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.ContentLoadModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.CoreModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.CrashReportingModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.DirectorModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.DSPGraphModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.GameCenterModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.GIModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.GraphicsStateCollectionSerializerModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.GridModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.HierarchyCoreModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.HotReloadModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.ImageConversionModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.IMGUIModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.InputForUIModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.InputLegacyModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.InputModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.JSONSerializeModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.LocalizationModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.MarshallingModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.MultiplayerModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.NVIDIAModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.ParticleSystemModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.PerformanceReportingModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.Physics2DModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.PhysicsModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.PropertiesModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.RuntimeInitializeOnLoadManagerInitializerModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.ScreenCaptureModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.ShaderVariantAnalyticsModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.SharedInternalsModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.SpriteMaskModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.SpriteShapeModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.StreamingModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.SubstanceModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.SubsystemsModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.TerrainModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.TerrainPhysicsModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.TextCoreFontEngineModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.TextCoreTextEngineModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.TextRenderingModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.TilemapModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.TLSModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.UI.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.UIElementsModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.UIModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.UmbraModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.UnityAnalyticsCommonModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.UnityAnalyticsModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.UnityConnectModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.UnityCurlModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.UnityTestProtocolModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.UnityWebRequestAssetBundleModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.UnityWebRequestAudioModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.UnityWebRequestModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.UnityWebRequestTextureModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.UnityWebRequestWWWModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.VehiclesModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.VFXModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.VideoModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.VirtualTexturingModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.VRModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.WindModule.dll
  inflating: chall/Challenge_Data/Managed/UnityEngine.XRModule.dll
   creating: chall/Challenge_Data/Plugins/
   creating: chall/Challenge_Data/Plugins/x86_64/
  inflating: chall/Challenge_Data/Plugins/x86_64/lib_burst_generated.dll
  inflating: chall/Challenge_Data/resources.assets
  inflating: chall/Challenge_Data/resources.assets.resS
   creating: chall/Challenge_Data/Resources/
  inflating: chall/Challenge_Data/Resources/unity default resources
  inflating: chall/Challenge_Data/Resources/unity_builtin_extra
  inflating: chall/Challenge_Data/RuntimeInitializeOnLoads.json
  inflating: chall/Challenge_Data/ScriptingAssemblies.json
  inflating: chall/Challenge_Data/sharedassets0.assets
  inflating: chall/Challenge_Data/sharedassets0.assets.resS
  inflating: chall/Challenge_Data/sharedassets0.resource
  inflating: chall/Challenge_Data/sharedassets1.assets
  inflating: chall/Challenge_Data/sharedassets1.assets.resS
  inflating: chall/Challenge_Data/sharedassets1.resource
  inflating: chall/Challenge_Data/sharedassets2.assets
  inflating: chall/Challenge_Data/sharedassets2.assets.resS
  inflating: chall/Challenge_Data/sharedassets2.resource
   creating: chall/D3D12/
  inflating: chall/D3D12/D3D12Core.dll
   creating: chall/MonoBleedingEdge/
   creating: chall/MonoBleedingEdge/EmbedRuntime/
  inflating: chall/MonoBleedingEdge/EmbedRuntime/mono-2.0-bdwgc.dll
  inflating: chall/MonoBleedingEdge/EmbedRuntime/MonoPosixHelper.dll
   creating: chall/MonoBleedingEdge/etc/
   creating: chall/MonoBleedingEdge/etc/mono/
   creating: chall/MonoBleedingEdge/etc/mono/2.0/
   creating: chall/MonoBleedingEdge/etc/mono/2.0/Browsers/
  inflating: chall/MonoBleedingEdge/etc/mono/2.0/Browsers/Compat.browser
  inflating: chall/MonoBleedingEdge/etc/mono/2.0/DefaultWsdlHelpGenerator.aspx
  inflating: chall/MonoBleedingEdge/etc/mono/2.0/machine.config
  inflating: chall/MonoBleedingEdge/etc/mono/2.0/settings.map
  inflating: chall/MonoBleedingEdge/etc/mono/2.0/web.config
   creating: chall/MonoBleedingEdge/etc/mono/4.0/
   creating: chall/MonoBleedingEdge/etc/mono/4.0/Browsers/
  inflating: chall/MonoBleedingEdge/etc/mono/4.0/Browsers/Compat.browser
  inflating: chall/MonoBleedingEdge/etc/mono/4.0/DefaultWsdlHelpGenerator.aspx
  inflating: chall/MonoBleedingEdge/etc/mono/4.0/machine.config
  inflating: chall/MonoBleedingEdge/etc/mono/4.0/settings.map
  inflating: chall/MonoBleedingEdge/etc/mono/4.0/web.config
   creating: chall/MonoBleedingEdge/etc/mono/4.5/
   creating: chall/MonoBleedingEdge/etc/mono/4.5/Browsers/
  inflating: chall/MonoBleedingEdge/etc/mono/4.5/Browsers/Compat.browser
  inflating: chall/MonoBleedingEdge/etc/mono/4.5/DefaultWsdlHelpGenerator.aspx
  inflating: chall/MonoBleedingEdge/etc/mono/4.5/machine.config
  inflating: chall/MonoBleedingEdge/etc/mono/4.5/settings.map
  inflating: chall/MonoBleedingEdge/etc/mono/4.5/web.config
  inflating: chall/MonoBleedingEdge/etc/mono/browscap.ini
  inflating: chall/MonoBleedingEdge/etc/mono/config
   creating: chall/MonoBleedingEdge/etc/mono/mconfig/
  inflating: chall/MonoBleedingEdge/etc/mono/mconfig/config.xml
  inflating: chall/UnityCrashHandler64.exe
  inflating: chall/UnityPlayer.dll

chall/Challenge_Data/Managed/Assembly-CSharp.dllが怪しい

Unityのゲームだと分かるのでdnSpyで解析する。

Shellmoveというスクリプトを見つけた
UPdate関数にゲームオーバー条件と勝利条件がかかれている。

Shellmove(Update)
public class Shellmove : MonoBehaviour
{
	// Token: 0x06000004 RID: 4 RVA: 0x00002074 File Offset: 0x00000274
	private void Update()
	{
		Vector3 position = base.gameObject.transform.position;
		if (Input.GetKey(KeyCode.Delete))
		{
			SceneManager.LoadScene("Main");
		}
		if (this.Len(position) >= 50.0)
		{
			this.TransError();
		}
		if (position == new Vector3(65535f, 65535f))
		{
			this.TransFlag();
		}
		if (!this.ismoving && this.canmove)
		{
			Vector3 zero = Vector3.zero;
			if (Input.GetKeyDown(KeyCode.W))
			{
				zero = new Vector3(0f, this.grid);
				this.walksound.Play();
			}
			if (Input.GetKeyDown(KeyCode.S))
			{
				zero = new Vector3(0f, -this.grid);
				this.walksound.Play();
			}
			if (Input.GetKeyDown(KeyCode.D))
			{
				zero = new Vector3(this.grid, 0f);
				this.walksound.Play();
			}
			if (Input.GetKeyDown(KeyCode.A))
			{
				zero = new Vector3(-this.grid, 0f);
				this.walksound.Play();
			}
			if (zero != Vector3.zero)
			{
				base.StartCoroutine(this.MoveSmooth(zero));
			}
		}
	}

最初にスポーンする原点(0,0)から距離が50以上離れるとゲームオーバー。
(65535f, 65535f)に到達するとthis.TransFlag();が呼び出され、ゲームクリア。

if (Input.GetKeyUp(KeyCode.W))
{
	zero = new Vector3(0f, this.grid);
	this.walksound.Play();
	this.TransFlag();
}

w(前進)を押したら、クリア画面を表示するように変更。

image.png

QRコードを書いてを読み取ってフラグゲット!

fwectf{K494ku_no_Ch1k4r4_t7e_5u63h!}

所感

全体的に難易度が高い気がした(多分自分の実力不足)
PWN問題を一問も解けなかったのが悔しい

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?