LoginSignup
0
0

picoCTF 2024 writeup

Posted at

面白かった問題だけ

Cryptography 02 Custom encryption

custom_encryption.py
from random import randint
import sys

def generator(g, x, p):
    return pow(g, x) % p

# この中でplaintextは、key倍され、さらに311倍される
def encrypt(plaintext, key):
    cipher = []
    for char in plaintext:
        cipher.append(((ord(char) * key*311)))
    return cipher

def is_prime(p):
    v = 0
    for i in range(2, p + 1):
        if p % i == 0:
            v = v + 1
    if v > 1:
        return False
    else:
        return True

# この中でplaintextはreverseされ、引数"trudeau"とxorされる
def dynamic_xor_encrypt(plaintext, text_key): 
    cipher_text = ""
    key_length = len(text_key)
    for i, char in enumerate(plaintext[::-1]):
        key_char = text_key[i % key_length]
        encrypted_char = chr(ord(char) ^ ord(key_char))
        cipher_text += encrypted_char
    return cipher_text

def test(plain_text, text_key):
    p = 97
    g = 31
    if not is_prime(p) and not is_prime(g):
        print("Enter prime numbers")
        return
    a = randint(p-10, p)
    b = randint(g-10, g)
    print(f"a = {a}")
    print(f"b = {b}")
    u = generator(g, a, p)
    v = generator(g, b, p)
    key = generator(v, a, p)
    b_key = generator(u, b, p)
    shared_key = None
    if key == b_key:
        shared_key = key
    else:
        print("Invalid key")
        return
    semi_cipher = dynamic_xor_encrypt(plain_text, text_key)
    cipher = encrypt(semi_cipher, shared_key)
    print(f'cipher is: {cipher}')

if __name__ == "__main__":
    message = sys.argv[1]
    test(message, "trudeau") #引数はxor鍵
enc_flag
a = 97
b = 22
cipher is: [151146, 1158786, 1276344, 1360314, 1427490, 1377108, 1074816, 1074816, 386262, 705348, 0, 1393902, 352674, 83970, 1141992, 0, 369468, 1444284, 16794, 1041228, 403056, 453438, 100764, 100764, 285498, 100764, 436644, 856494, 537408, 822906, 436644, 117558, 201528, 285498]

cipher配列の最初の要素 151146 は } (=125) を暗号化したもの
xor鍵は trudeau の1番目の t (=116)
151146 = 125 ^ 116 * key * 311 を解けば、keyが得られる。
enc_flag で与えられた a と b の値はどうでもいい

solver.py
#enc_flagより
cipher = [151146, 1158786, 1276344, 1360314, 1427490, 1377108, 1074816, 1074816, 386262, 705348, 0, 1393902, 352674, 83970, 1141992, 0, 369468, 1444284, 16794, 1041228, 403056, 453438, 100764, 100764, 285498, 100764, 436644, 856494, 537408, 822906, 436644, 117558, 201528, 285498]

#custom_encryption.pyより
argument = "trudeau"

#shared_keyを求める
shared_key = cipher[0] / 311 / (ord(argument[0])^ ord('}'))
#print(f'shared_key is: {int(shared_key)}')

#復号
for i in range(len(cipher)):
    cipher[i] = chr(int(cipher[i] / 311 / shared_key) ^ ord(argument[i % len(argument)]))
#print(f'cipher is: {cipher}')
cipher.reverse()

#フラグの出力
print("".join(cipher))

Reverse Engineering 01 packer

動かしてみる

┌──(kali㉿kali)-[~/share]
└─$ ./out      
Enter the password to unlock this file: aaa
You entered: aaa

Access denied

strings みてみる

┌──(kali㉿kali)-[~/share]
└─$ strings out | grep "entered"

パックされてる?

┌──(kali㉿kali)-[~/share]
└─$ strings out
(中略)
UPX!
UPX!

展開してみる

┌──(kali㉿kali)-[~/share]
└─$ upx -d ./out 
                       Ultimate Packer for eXecutables
                          Copyright (C) 1996 - 2024
UPX 4.2.2       Markus Oberhumer, Laszlo Molnar & John Reiser    Jan 3rd 2024

        File size         Ratio      Format      Name
   --------------------   ------   -----------   -----------
[WARNING] bad b_info at 0x4b718

[WARNING] ... recovery at 0x4b714

    877724 <-    336520   38.34%   linux/amd64   out

Unpacked 1 file.

ここからGhidra
Symbol Tree で main を検索
あっさり発見

  if (iVar3 == 0) {
    *(undefined8 *)(puVar4 + -0x78) = 0x401f57;
    puts(
        "Password correct, please see flag: 7069636f4354467b5539585f556e5034636b314e365f42316e345269 33535f62646438343839337d"
        );

Reverse Engineering 02 packer

stringsすると、 picoCTF{wELF_d0N3_mate_ が見えるが、続きのパーツが見つからない。

とりあえず実行

┌──(kali㉿kali)-[~/share]
└─$ ./bin

なるほど、フラグの復号はするけど、printしないって感じか。
gdbで、デバッグすると見えそうだ。

image.png

ビンゴ!

Reverse Engineering 03 WinAntiDbg0x100

APIの確認

image.png

まず、IsDebuggerPresentから確認する

x32dbg の Command に bp IsDebuggerPresent を入力し、F9
止まったら、Execute till return
F7
test eax.eaxに戻るので、IsDebuggerPresentの戻り値を 0x0にして F7
F8を数回押してフラグの復号ルーチンを抜けると、フラグが見える。

image.png

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0