👾
Elijah's CTF Blog
  • 👋Home
  • 🇲🇾Wargames.MY CTF 2024
    • Credentials (crypto)
    • Stones (rev)
    • Rick'S Algorithm (crypto)
    • Rick'S Algorithm 2 (crypto)
    • Hohoho 3 continue (crypto)
  • 🎄Advent of CTF 2024
    • Jingle Bell ROP (pwn)
    • help (pwn)
  • Backdoor CTF 24
    • [rev] Ratatouille
  • 🇭🇰HKCERT CTF 24
    • Shellcode Runner 3 + Revenge (pwn)
    • ISH (1) (pwn)
    • Cyp.ress (rev)
    • Void (rev)
  • 🇮🇹ECSC 2024
    • ➕OffTopic (crypto)
  • 🎩Greyhats WelcomeCTF 24
    • EE2026 (misc)
  • 🚆UIUCTF 24
    • Syscalls (pwn)
    • Summarize (rev)
    • X Marked the Spot (crypto)
    • Without a Trace (crypto)
    • Determined (crypto)
    • Naptime (crypto)
    • Snore Signatures (crypto)
  • 🪼Jelly CTF 24
    • Cherry (crypto)
    • the_brewing_secrets (crypto)
  • 👨‍🦯vsCTF 24
    • Dream (crypto)
    • Cosmic Ray V3 (pwn)
  • 😎AKASEC CTF 24
    • Warmup (pwn)
    • Good_trip (pwn)
    • Sperm Rev (rev)
    • Paranoia (rev)
    • Grip (rev)
    • Risks (rev)
    • Lost (crypto)
  • 😁L3AK CTF 24
    • oorrww (pwn)
    • angry (rev)
    • Related (crypto)
    • BatBot (web-misc)
    • Matrix Magic (crypto)
  • 🥹CDDC Qualifiers 2024
    • WASM (rev)
    • crashMe (pwn)
Powered by GitBook
On this page
  1. HKCERT CTF 24

Cyp.ress (rev)

You will get sser.pyc when you reverse the title. Now reverse it back for me.

Last updated 6 months ago

We are given a compiled .pyc file. On running it, it prints What is the flag?> and waits for our input. After providing our input, the binary takes some time to respond. Finally, it responds with a crossed arms emoji to tell us that our input was wrong.

Seeing as to how this is a .pyc file, my first instinct was to use tools such as uncompyle6, pycdc and to get python code from it. Unfortunately, these all did not work since the version of Python used was 3.12, which was too new. Therefore, the best I could do was use pycdas to give me byte-code disassembly. This was the disassembler output:

import os
import requests
from Crypto.Cipher import AES
import hashlib
# WARNING: Decompyle incomplete
elijah@soyabean:/mnt/c/Users/chiae/Downloads/hkcert24/rev/cypress_5788c6411dc79b08e280746a07306538/pycdc$ ./pycdas ../sser.cpython-312.pyc
sser.cpython-312.pyc (Python 3.12)
[Code]
    File Name: sser.py
    Object Name: <module>
    Qualified Name: <module>
    Arg Count: 0
    Pos Only Arg Count: 0
    KW Only Arg Count: 0
    Stack Size: 6
    Flags: 0x00000000
    [Names]
        'os'
        'requests'
        'Crypto.Cipher'
        'AES'
        'hashlib'
        'get_nonce'
        'input'
        'encode'
        'flag'
        'nonce'
        'post'
        'hex'
        'r'
        'bytes'
        'fromhex'
        'text'
        'c0'
        'sha256'
        'digest'
        'key'
        'iv'
        'new'
        'MODE_CFB'
        'cipher'
        'encrypt'
        'c1'
        'print'
    [Locals+Names]
    [Constants]
        0
        None
        (
            'AES'
        )
        [Code]
            File Name: sser.py
            Object Name: get_nonce
            Qualified Name: get_nonce
            Arg Count: 0
            Pos Only Arg Count: 0
            KW Only Arg Count: 0
            Stack Size: 4
            Flags: 0x00000003 (CO_OPTIMIZED | CO_NEWLOCALS)
            [Names]
                'os'
                'urandom'
                'hashlib'
                'sha256'
                'digest'
            [Locals+Names]
                'nonce'
            [Constants]
                None
                16
                b'pow/'
                3
                b'\x00\x00\x00'
            [Disassembly]
                0       RESUME                          0
                2       NOP
                4       LOAD_GLOBAL                     1: NULL + os
                14      LOAD_ATTR                       2: urandom
                34      LOAD_CONST                      1: 16
                36      CALL                            1
                44      STORE_FAST                      0: nonce
                46      LOAD_GLOBAL                     5: NULL + hashlib
                56      LOAD_ATTR                       6: sha256
                76      LOAD_CONST                      2: b'pow/'
                78      LOAD_FAST                       0: nonce
                80      BINARY_OP                       0 (+)
                84      CALL                            1
                92      LOAD_ATTR                       9: digest
                112     CALL                            0
                120     LOAD_CONST                      0: None
                122     LOAD_CONST                      3: 3
                124     BINARY_SLICE
                126     LOAD_CONST                      4: b'\x00\x00\x00'
                128     COMPARE_OP                      40 (==)
                132     POP_JUMP_IF_FALSE               2 (to 138)
                134     LOAD_FAST                       0: nonce
                136     RETURN_VALUE
                138     JUMP_BACKWARD                   68 (to 4)
        'What is the flag?> '
        'https://c12-cypress.hkcert24.pwnable.hk/'
        'nonce'
        (
            'json'
        )
        b'key/'
        16
        b'iv/'
        '🙆🙅'
    [Disassembly]
        0       RESUME                          0
        2       LOAD_CONST                      0: 0
        4       LOAD_CONST                      1: None
        6       IMPORT_NAME                     0: os
        8       STORE_NAME                      0: os
        10      LOAD_CONST                      0: 0
        12      LOAD_CONST                      1: None
        14      IMPORT_NAME                     1: requests
        16      STORE_NAME                      1: requests
        18      LOAD_CONST                      0: 0
        20      LOAD_CONST                      2: ('AES',)
        22      IMPORT_NAME                     2: Crypto.Cipher
        24      IMPORT_FROM                     3: AES
        26      STORE_NAME                      3: AES
        28      POP_TOP
        30      LOAD_CONST                      0: 0
        32      LOAD_CONST                      1: None
        34      IMPORT_NAME                     4: hashlib
        36      STORE_NAME                      4: hashlib
        38      LOAD_CONST                      4: 'What is the flag?> '
        40      CALL_INTRINSIC_1                1 (INTRINSIC_PRINT)
        42      POP_TOP
        44      LOAD_CONST                      3: <CODE> get_nonce
        46      MAKE_FUNCTION                   0
        48      STORE_NAME                      5: get_nonce
        50      PUSH_NULL
        52      LOAD_NAME                       6: input
        54      BUILD_STRING                    0
        56      CALL                            1
        64      LOAD_ATTR                       15: encode
        84      CALL                            0
        92      STORE_NAME                      8: flag
        94      PUSH_NULL
        96      LOAD_NAME                       5: get_nonce
        98      CALL                            0
        106     STORE_NAME                      9: nonce
        108     PUSH_NULL
        110     LOAD_NAME                       1: requests
        112     LOAD_ATTR                       20: post
        132     LOAD_CONST                      5: 'https://c12-cypress.hkcert24.pwnable.hk/'
        134     LOAD_CONST                      6: 'nonce'
        136     LOAD_NAME                       9: nonce
        138     LOAD_ATTR                       23: hex
        158     CALL                            0
        166     BUILD_MAP                       1
        168     KW_NAMES                        7: ('json',)
        170     CALL                            2
        178     STORE_NAME                      12: r
        180     LOAD_NAME                       13: bytes
        182     LOAD_ATTR                       29: fromhex
        202     LOAD_NAME                       12: r
        204     LOAD_ATTR                       30: text
        224     CALL                            1
        232     STORE_NAME                      16: c0
        234     PUSH_NULL
        236     LOAD_NAME                       4: hashlib
        238     LOAD_ATTR                       34: sha256
        258     LOAD_CONST                      8: b'key/'
        260     LOAD_NAME                       9: nonce
        262     BINARY_OP                       0 (+)
        266     CALL                            1
        274     LOAD_ATTR                       37: digest
        294     CALL                            0
        302     LOAD_CONST                      1: None
        304     LOAD_CONST                      9: 16
        306     BINARY_SLICE
        308     STORE_NAME                      19: key
        310     PUSH_NULL
        312     LOAD_NAME                       4: hashlib
        314     LOAD_ATTR                       34: sha256
        334     LOAD_CONST                      10: b'iv/'
        336     LOAD_NAME                       9: nonce
        338     BINARY_OP                       0 (+)
        342     CALL                            1
        350     LOAD_ATTR                       37: digest
        370     CALL                            0
        378     LOAD_CONST                      1: None
        380     LOAD_CONST                      9: 16
        382     BINARY_SLICE
        384     STORE_NAME                      20: iv
        386     PUSH_NULL
        388     LOAD_NAME                       3: AES
        390     LOAD_ATTR                       42: new
        410     LOAD_NAME                       19: key
        412     LOAD_NAME                       3: AES
        414     LOAD_ATTR                       44: MODE_CFB
        434     LOAD_NAME                       20: iv
        436     CALL                            3
        444     STORE_NAME                      23: cipher
        446     LOAD_NAME                       23: cipher
        448     LOAD_ATTR                       49: encrypt
        468     LOAD_NAME                       8: flag
        470     CALL                            1
        478     STORE_NAME                      25: c1
        480     PUSH_NULL
        482     LOAD_NAME                       26: print
        484     LOAD_CONST                      11: '🙆🙅'
        486     LOAD_NAME                       16: c0
        488     LOAD_NAME                       25: c1
        490     COMPARE_OP                      55 (!=)
        494     BINARY_SUBSCR
        498     CALL                            1
        506     POP_TOP
        508     RETURN_CONST                    1: None

Providing this to ChatGPT and asking for the Python code, we get:

import os
import requests
from Crypto.Cipher import AES
import hashlib

# Function to generate a nonce meeting specific conditions
def get_nonce():
    while True:
        # Generate a 16-byte random nonce
        nonce = os.urandom(16)
        
        # Calculate SHA-256 hash of the prefix b'pow/' and the nonce
        hash_val = hashlib.sha256(b'pow/' + nonce).digest()
        
        # Check if the first three bytes of the hash are b'\x00\x00\x00'
        if hash_val[:3] == b'\x00\x00\x00':
            return nonce

# Prompt the user for the flag and encode it
flag = input("What is the flag?> ").encode()

# Generate the nonce
nonce = get_nonce()

# Send nonce to server and receive response
url = "https://c12-cypress.hkcert24.pwnable.hk/"
response = requests.post(url, json={"nonce": nonce.hex()})

# Server returns a hexadecimal string in the response text, convert it to bytes
c0 = bytes.fromhex(response.text)

# Derive the AES encryption key and IV from the nonce
key = hashlib.sha256(b'key/' + nonce).digest()[:16]
iv = hashlib.sha256(b'iv/' + nonce).digest()[:16]

# Initialize AES cipher in CFB mode
cipher = AES.new(key, AES.MODE_CFB, iv)

# Encrypt the flag with the cipher
c1 = cipher.encrypt(flag)

# Compare the encrypted flag with the server-provided value and print appropriate emoji
print("🙆" if c0 == c1 else "🙅")

The Python code takes the user's input and converts it into bytes and stores it in the variable flag. Then, it generates a nonce, stopping only when the first 3 bytes of the SHA256 hash of b'pow/' + nonce are null bytes. The nonce is then sent to the server, which sends back a ciphertext within response.text. Using the nonce, a key and iv are generated, and used to encrypt the user's input (flag) using AES CFB mode. The binary then checks if the server-provided ciphertext matches the user's encrypted input.

Once we understand the code, getting the plaintext flag is trivial. We simply need to send some valid nonce to the server and get the correct ciphertext. Using our nonce, we can compute the key and iv ourselves, and decrypt the server's ciphertext for the flag. Below is my solve script:

import os
import requests
from Crypto.Cipher import AES
import hashlib

# Function to generate a nonce meeting specific conditions
def get_nonce():
    while True:
        # Generate a 16-byte random nonce
        nonce = os.urandom(16)
        
        # Calculate SHA-256 hash of the prefix b'pow/' and the nonce
        hash_val = hashlib.sha256(b'pow/' + nonce).digest()
        
        # Check if the first three bytes of the hash are b'\x00\x00\x00'
        if hash_val[:3] == b'\x00\x00\x00':
            return nonce

# Generate the nonce
nonce = bytes.fromhex("c5f4b55e8094602125df24bfc40b16c0")
# obtain the ciphertext from the server
ct = bytes.fromhex("852c4b3055dbd46474d2a5ba72927066c895784c91b733fd3add727e292300b1a692ad56def986e394be34f3d564435665c214b30d92157144527cbcddbf27d3e5")

# Derive the AES encryption key and IV from the nonce
key = hashlib.sha256(b'key/' + nonce).digest()[:16]
iv = hashlib.sha256(b'iv/' + nonce).digest()[:16]

# Initialize AES cipher in CFB mode
cipher = AES.new(key, AES.MODE_CFB, iv)

# Decrypt the ciphertext with the key and iv
print(cipher.decrypt(ct)) # hkcert24{y0u_c4n_h00k_func710ns_t0_35c4p3_fr0m_r3v3r5e_3n9e3r1n9}

🇭🇰
https://pylingual.io
1KB
sser.cpython-312.pyc