以下の内容はhttps://yocchin.hatenablog.com/entry/2024/12/16/073042より取得しました。


niteCTF 2024 Writeup

この大会は2024/12/13 21:00(JST)~2024/12/15 21:00(JST)に開催されました。
今回もチームで参戦。結果は110点で1174チーム中251位でした。
自分で解けた問題をWriteupとして書いておきます。

Warmup (Miscellaneous)

Discordに入り、#announcementsチャネルのメッセージを見ると、フラグが書いてあった。

nite{n1t3_1n_sh1n1ng_arm0ur}

RSAabc (Cryptography)

暗号処理の概要は以下の通り

・language: 'A'~'Z', 'a'~'z'に対する文字を辞書型で定義
・ct=[] 
・nlist=[]
・flagの各文字chに対して、以下を実行
 ・chのASCIIコードが素数以外の場合
  ・transformed_char = reverse_alphabet(ch)
  ・transformed_charをout.txtに書き込み
 ・pre: chのASCIIコードを26で割った余り
 ・pre: preが5より小さい場合、5プラス
 ・p: preビット素数
 ・q: 1024ビット素数
 ・n = p * q
 ・phi_n = (p - 1) * (q - 1)
 ・e = 65537
 ・d = sp.mod_inverse(e, phi_n)
 ・pubkey = (n, e)
 ・privkey = (n, d)
 ・message = ch
 ・ciphertext = rsa_encrypt(message, pubkey)
  ・n, e = public_key
  ・message_as_int: messageのASCIIコード
  ・ciphertext = pow(message_as_int, e, n)
  ・ciphertextを返却
 ・chのASCIIコードが素数の場合
  ・chが英大文字の場合
   ・eng=chr(65+ciphertext%26)
   ・lan=language.get(eng)
   ・lanをout.txtに書き込み
   ・ciphertext=googly(ciphertext,ciphertext.bit_length()-ord(eng))
  ・chが英小文字の場合
   ・eng=chr(97+ciphertext%26)
   ・lan=language.get(eng)
   ・lanをout.txtに書き込み
   ・ciphertext=googly(ciphertext,ciphertext.bit_length()-ord(eng))
 ・ctにciphertextを追加
 ・nlistにnを追加
・ctの各要素を","区切りで出力
・nlistの各要素を","区切りで出力

1文字ずつブルートフォースで条件を満たすものを探す。

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

language = {
    'A': 'Α', 'a': 'α',
    'B': 'Β', 'b': 'β',
    'C': 'Σ', 'c': 'σ',
    'D': 'Δ', 'd': 'δ',
    'E': 'Ε', 'e': 'ε',
    'F': 'Φ', 'f': 'φ',
    'G': 'Γ', 'g': 'γ',
    'H': 'Η', 'h': 'η',
    'I': 'Ι', 'i': 'ι',
    'J': 'Ξ', 'j': 'ξ',
    'K': 'Κ', 'k': 'κ',
    'L': 'Λ', 'l': 'λ',
    'M': 'Μ', 'm': 'μ',
    'N': 'Ν', 'n': 'ν',
    'O': 'Ο', 'o': 'ο',
    'P': 'Π', 'p': 'π',
    'Q': 'Θ', 'q': 'θ',
    'R': 'Ρ', 'r': 'ρ',
    'S': 'Σ', 's': 'ς',  
    'T': 'Τ', 't': 'τ',
    'U': 'Υ', 'u': 'υ',
    'V': 'Ω', 'v': 'ω',
    'W': 'Ψ', 'w': 'ψ',
    'X': 'Χ', 'x': 'χ',
    'Y': 'Υ', 'y': 'υ',
    'Z': 'Ζ', 'z': 'ζ'
}

def googly(number, position):
    mask = 1 << position
    return number ^ mask

def string_to_int(message):
    return int.from_bytes(message.encode('utf-8'), byteorder='big')

def rsa_encrypt(message, public_key):
    n, e = public_key
    message_as_int = string_to_int(message)
    ciphertext = pow(message_as_int, e, n)
    return ciphertext

def reverse_alphabet(char):
    if char.isupper():
        return chr(155 - ord(char))
    elif char.islower():
        return chr(219 - ord(char))
    elif char == '_' or '{' or '}':
        return 'e'

with open('out.txt', 'r', encoding='utf-8') as f:
    params = f.read().splitlines()

out = params[0]
ct = list(map(int, params[2][:-1].split(', ')))
nlist = list(map(int, params[4].split(', ')[:-1]))

flag = ''
for i in range(len(out)):
    for code in range(32, 127):
        if not sp.isprime(code):
            transformed_char = reverse_alphabet(chr(code))
            if transformed_char != out[i]:
                continue
        n = nlist[i]
        e = 65537
        pubkey = (n, e)
        message = chr(code)
        ciphertext = rsa_encrypt(message, pubkey)
        if sp.isprime(code):
            if chr(code).isupper():
                eng = chr(65 + ciphertext % 26)
            else:
                eng = chr(97 + ciphertext % 26)
            lan = language.get(eng)
            if lan != out[i]:
                continue
            ciphertext = googly(ciphertext, ciphertext.bit_length() - ord(eng))
        if ciphertext == ct[i]:
            flag += chr(code)
            break

print(flag)
nite{quICklY_grab_the_codE5_sgOqkA}

La Casa de Papel (Cryptography)

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

・secret_key = secret().encode()
 ※長さ21の文字列
・menu(secret_key)
 ・以下繰り返し
  ・choice: 入力
   ・choiceが"1"の場合
    ・practice_convo(secret)
     ・message: 入力
     ・hash = md5(secret, message)
      ・hash: secret + messageのmd5ダイジェストの16進数表記
      ・hashのbase64エンコード文字列を返却
     ・hashを表示
   ・choiceが"2"の場合
    ・fool_alice(secret)
     ・user_name: 入力
     ・user_hmac: 入力
     ・user_nameに"Bob"が含まれている場合
      ・hash: md5(secret, user_name)のbase64デコード文字列
      ・user_hmacがhashと一致する場合
       ・secret.txtの内容を表示
   ・choiceが"3"の場合
    ・crack_the_vault()
     ・passs: 入力
     ・secret_content: secret.txtの内容
     ・passsとsecret_contentが一致する場合、flag.txtの内容を表示

1で取得したhashをbase64デコードし、2のHMACで指定すれば、secret.txtの内容が取得できる。あとは3でその内容を指定すればフラグを取得できる。

$ ncat --ssl la-casa-de-papel.chals.nitectf2024.live 1337
 _             ____                      _        ____                  _ 
| |    __ _   / ___|__ _ ___  __ _    __| | ___  |  _ \ __ _ _ __   ___| |
| |   / _` | | |   / _` / __|/ _` |  / _` |/ _ \ | |_) / _` | '_ \ / _ \ |
| |__| (_| | | |__| (_| \__ \ (_| | | (_| |  __/ |  __/ (_| | |_) |  __/ |
|_____\__,_|  \____\__,_|___/\__,_|  \__,_|\___| |_|   \__,_| .__/ \___|_|
                                                            |_|           


1. Practice Convo
2. Let's Fool Alice!
3. Crack the Vault
4. Exit
Choose an option: 1
Send a message: Bob
Here is your encrypted message: YjRlMGE4MDI0MjhjYjM1ZjY5YzBlOTUyZDk2MTcyZDY=

ここでbase64デコードする。

>>> from base64 import *
>>> b64decode('YjRlMGE4MDI0MjhjYjM1ZjY5YzBlOTUyZDk2MTcyZDY=')
b'b4e0a802428cb35f69c0e952d96172d6'
1. Practice Convo
2. Let's Fool Alice!
3. Crack the Vault
4. Exit
Choose an option: 2

Bot: Okay, let's see if you're the real deal. What's your name?
Your name: Bob

Bot: Please provide your HMAC
Your HMAC: b4e0a802428cb35f69c0e952d96172d6

Alice: Oh hey Bob! Here is the vault code you wanted:
G0t_Th3_G0ld_B3rl1nale

1. Practice Convo
2. Let's Fool Alice!
3. Crack the Vault
4. Exit
Choose an option: 3

Vault Person: Enter password
Password: G0t_Th3_G0ld_B3rl1nale

Vault Unlocked! The flag is: nite{El_Pr0f3_0f_Prec1s10n_Pl4ns}
nite{El_Pr0f3_0f_Prec1s10n_Pl4ns}



以上の内容はhttps://yocchin.hatenablog.com/entry/2024/12/16/073042より取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14