picoCTF 2024 writeup

面白かった問題だけ

# Cryptography 02 Custom encryption

```python: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 の１番目の t (=116)
151146 = 125 ^ 116 * key * 311 を解けば、keyが得られる。
enc_flag で与えられた a と b の値はどうでもいい


```python: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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1163572/870ae47b-a611-acd2-772d-f764e865f35b.png)

ビンゴ！

# Reverse Engineering 03 WinAntiDbg0x100

APIの確認

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1163572/3be784d1-83ee-0d1e-e230-18f267413e57.png)

まず、IsDebuggerPresentから確認する

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



![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1163572/89e3a256-6fb7-4f1c-7ced-9b5625211f6f.png)