2025-10-17

๐Ÿ“ฆ vx-underground

image.png

Notion | Where teams and agents work together
A collaborative AI workspace, built on your company context. Build and orchestrate agents right alongside your team
https://app.notion.com
๐Ÿ“Šfixed_list.csv31KB
Challenge Solution Summary

https://www.lost-cluster.org/shattered_secrets/

Shamir's Secret Sharing Scheme (SSSS) - a cryptographic method to split a secret across multiple shares
Each cat image contained one share: position number (x-coordinate) and SHA-256 hash (y-coordinate)
Prime modulus: 0x010000000000000000000000000000000000000000000000000000000000000129

Solution Steps

Extract EXIF data from all images to get position-hash pairs
Apply Lagrange interpolation with the prime modulus to recover the secret
Recovered secret (in hex): 2a5a49502070617373776f72643a20464170656b4a21794a363959616a5773
Decoded to text: *ZIP password: FApekJ!yJ69YajWs
Extracted password: FApekJ!yJ69YajWs
Unzipped flag.zip successfully

The Flag

File contained Meow-encoded data (esoteric programming language)
flag{...} hidden in the Meow syntax
ssss_recovery.py 

#!/usr/bin/env python3
"""
Recover the secret using Shamir's Secret Sharing Scheme
"""

import csv
import subprocess

# Prime from prime_mod.jpg
PRIME = 0x010000000000000000000000000000000000000000000000000000000000000129

def extended_gcd(a, b):
    if a == 0:
        return b, 0, 1
    gcd, x1, y1 = extended_gcd(b % a, a)
    x = y1 - (b // a) * x1
    y = x1
    return gcd, x, y

def mod_inverse(a, m):
    gcd, x, _ = extended_gcd(a % m, m)
    if gcd != 1:
        raise Exception('Modular inverse does not exist')
    return (x % m + m) % m

def recover_secret(shares, prime):
    """
    Recover secret using Lagrange interpolation
    shares: dict of {x: y} where x is position, y is the share value
    """
    secret = 0
    
    for i, (x_i, y_i) in enumerate(shares.items()):
        numerator = 1
        denominator = 1
        
        for j, (x_j, y_j) in enumerate(shares.items()):
            if i != j:
                numerator = (numerator * (-x_j)) % prime
                denominator = (denominator * (x_i - x_j)) % prime
        
        # Calculate Lagrange basis polynomial
        lagrange = (numerator * mod_inverse(denominator, prime)) % prime
        secret = (secret + y_i * lagrange) % prime
    
    return secret

# Load all shares
shares = {}
with open('fixed_list.csv') as f:
    for row in csv.reader(f):
        if len(row) >= 2:
            x = int(row[0])
            y_hex = row[1]
            y = int(y_hex, 16)
            shares[x] = y

print("="*60)
print("Shamir's Secret Sharing Recovery")
print("="*60)
print(f"Prime: {hex(PRIME)}")
print(f"Total shares: {len(shares)}")

# Try with all shares
print("\nRecovering secret with all shares...")
secret = recover_secret(shares, PRIME)
secret_hex = hex(secret)[2:]
if len(secret_hex) % 2:
    secret_hex = '0' + secret_hex

print(f"Recovered secret (hex): {secret_hex}")

# Convert to bytes and try as password
try:
    secret_bytes = bytes.fromhex(secret_hex)
    password = secret_bytes.decode('utf-8', errors='ignore')
    print(f"As UTF-8: {password}")
except:
    password = secret_hex
    print(f"Using hex as password")

# Also try just the hex
passwords_to_try = [
    secret_hex,
    secret_bytes.hex() if 'secret_bytes' in locals() else secret_hex,
]

if 'secret_bytes' in locals():
    # Try ASCII interpretation
    passwords_to_try.append(''.join(chr(b) for b in secret_bytes if 32 <= b <= 126))

print("\n" + "="*60)
print("Testing passwords...")
print("="*60)

for i, pwd in enumerate(passwords_to_try):
    print(f"\nAttempt {i+1}: {pwd[:60]}...")
    result = subprocess.run(['7z', 'x', f'-p{pwd}', 'flag.zip', '-aoa'],
                          capture_output=True, text=True, timeout=5)
    
    if 'Everything is Ok' in result.stdout:
        print(f"\n{'='*60}")
        print(f"โœ“โœ“โœ“ SUCCESS! โœ“โœ“โœ“")
        print(f"{'='*60}")
        print(f"Password: {pwd}")
        print(f"{'='*60}\n")
        
        with open('SOLUTION.txt', 'w') as f:
            f.write(pwd)
        
        # Read the flag
        print("\nFlag content:")
        with open('cute-kitty-noises.txt', 'r') as f:
            print(f.read())
        break
    else:
        print("โœ— Wrong password")

print("\nDone!")

image.png

image.png

image.png

def decode_meow():
    with open("cute-kitty-noises.txt", "r") as f:
        content = f.read().strip()

    parts = content.split(';')
    numbers = []
    for part in parts:
        if not part:
            numbers.append(0)
        else:
            numbers.append(part.count("Meow"))

    decoded_string = ""
    i = 0
    while i < len(numbers):
        if numbers[i] == 2 and i + 3 < len(numbers) and numbers[i+2] == 1 and numbers[i+3] == 0:
            char_code = numbers[i+1]
            decoded_string += chr(char_code)
            i += 4
        else:
            i += 1

    print(decoded_string)

if __name__ == "__main__":
    decode_meow()

image.png

flag{35dcba13033459ca799ae2d990d33dd3}
g

โœ“  Shell python3 -c "                                                                          โ”‚
 โ”‚    import random                                                                               โ”‚
 โ”‚                                                                                                โ”‚
 โ”‚    PRIME = 0x010000000000000000000000000000000000000000000000000000000000000129                โ”‚
 โ”‚                                                                                                โ”‚
 โ”‚    def _mod_inverse(a, m):                                                                     โ”‚
 โ”‚        if a == 0:                                                                              โ”‚
 โ”‚            raise ValueError('Cannot compute inverse of 0.')                                    โ”‚
 โ”‚        return pow(a, -1, m)                                                                    โ”‚
 โ”‚                                                                                                โ”‚
 โ”‚    def reconstruct_secret(shares, prime=PRIME):                                                โ”‚
 โ”‚        if not shares:                                                                          โ”‚
 โ”‚            raise ValueError('No shares provided for reconstruction.')                          โ”‚
 โ”‚                                                                                                โ”‚
 โ”‚        k = len(shares)                                                                         โ”‚
 โ”‚        secret = 0                                                                              โ”‚
 โ”‚                                                                                                โ”‚
 โ”‚        for j in range(k):                                                                      โ”‚
 โ”‚            xj, yj = shares[j]                                                                  โ”‚
 โ”‚                                                                                                โ”‚
 โ”‚            numerator = 1                                                                       โ”‚
 โ”‚            denominator = 1                                                                     โ”‚
 โ”‚            for m in range(k):                                                                  โ”‚
 โ”‚                if j == m:                                                                      โ”‚
 โ”‚                    continue                                                                    โ”‚
 โ”‚                xm, _ = shares[m]                                                               โ”‚
 โ”‚                numerator = (numerator * (-xm % prime)) % prime                                 โ”‚
 โ”‚                denominator = (denominator * ((xj - xm) % prime)) % prime                       โ”‚
 โ”‚                                                                                                โ”‚
 โ”‚            term = (yj * numerator * _mod_inverse(denominator, prime)) % prime                  โ”‚
 โ”‚            secret = (secret + term) % prime                                                    โ”‚
 โ”‚                                                                                                โ”‚
 โ”‚        return secret                                                                           โ”‚
 โ”‚                                                                                                โ”‚
 โ”‚    with open('/mnt/tmp/CTF/2025-Huntress-CTF/17/all_user_comments.txt', 'r') as f:             โ”‚
 โ”‚        lines = f.readlines()                                                                   โ”‚
 โ”‚                                                                                                โ”‚
 โ”‚    shares = []                                                                                 โ”‚
 โ”‚    for line in lines:                                                                          โ”‚
 โ”‚        if '-' in line:                                                                         โ”‚
 โ”‚            parts = line.strip().split('-')                                                     โ”‚
 โ”‚            x = int(parts[0])                                                                   โ”‚
 โ”‚            y = int(parts[1], 16)                                                               โ”‚
 โ”‚            shares.append((x, y))                                                               โ”‚
 โ”‚                                                                                                โ”‚
 โ”‚    secret = reconstruct_secret(shares)                                                         โ”‚
 โ”‚                                                                                                โ”‚
 โ”‚    # Convert the secret to a string                                                            โ”‚
 โ”‚    flag = secret.to_bytes((secret.bit_length() + 7) // 8, 'big').decode('utf-8')               โ”‚
 โ”‚                                                                                                โ”‚
 โ”‚    print(flag)                                                                                 โ”‚
 โ”‚    "                                                                                           โ”‚
 โ”‚                                                                                                โ”‚
 โ”‚    *ZIP password: FApekJ!yJ69YajWs