Напиши мне
Напиши мне
Platform: hackerlab | Category: Crypto | Type: Challenge | Difficulty: Medium | OS: NA | Author: XESXOR | Date: 2026-01-21 | Status: Solved Techniques: known_plaintext_attack, shift_cipher_break
Summary
Task: Encryption service uses shift cipher with same key per session. Solution: Known-plaintext attack - send known character, calculate key from encrypted response, decrypt the flag.
Напиши мне — hackerlab
Description
Вы хотите связаться со мной? Используйте данный сервис для шифрования сообщений, которые адресованы мне, пожалуйста. Они слушают и следят за нами.
IP: 62.173.140.174:11004
Analysis
When connecting to the service:
- A banner is displayed with "Пример зашифрованного сообщения" (encrypted message example) — this is the encrypted flag
- The service allows encrypting arbitrary messages
- Encryption is a simple shift of Unicode codes by a random key
- The key is the same for the entire session
Vulnerability: Classic shift cipher (Caesar cipher for Unicode) with the ability to encrypt arbitrary text — ideal conditions for a Known-Plaintext Attack.
Solution
Attack Idea
- Send a known character (e.g., 'A')
- Receive the encrypted result
- Calculate the key:
key = ord(encrypted_A) - ord('A') - Decrypt the example:
decrypted = chr(ord(c) - key)for each character
Exploit
python read-only • copy allowed#!/usr/bin/env python3 """ Solution for "Напиши мне" (hackerlab CTF) Vulnerability: Simple shift cipher with known plaintext Attack: Known-plaintext attack - send a known character, calculate the key """ import socket import re def solve(): s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('62.173.140.174', 11004)) s.settimeout(5) # Receive banner data = b"" while True: try: chunk = s.recv(4096) if not chunk: break data += chunk if b"> " in data: break except: break banner = data.decode('utf-8') # Extract encrypted message example (this is the flag!) match = re.search(r'Пример зашифрованного сообщения: ([^\n.]+)', banner) if not match: print("[-] Could not find encrypted example") return None encrypted_example = match.group(1).strip() if encrypted_example.endswith('.'): encrypted_example = encrypted_example[:-1] # Send 'A' to find the key s.send(b"A\n") # Receive response data = b"" while True: try: chunk = s.recv(4096) if not chunk: break data += chunk if b"> " in data: break except: break response = data.decode('utf-8') # Extract encrypted character match2 = re.search(r'< ([^\n]+)', response) if not match2: print("[-] Could not find encrypted 'A'") return None enc_A = match2.group(1).strip() if len(enc_A) < 1: print("[-] Empty encrypted response") return None # Calculate key: enc(A) = A + key => key = enc(A) - A key = ord(enc_A[0]) - ord('A') # Decrypt example: dec(c) = c - key decrypted = "" for c in encrypted_example: dec_char = chr(ord(c) - key) decrypted += dec_char s.close() return decrypted if __name__ == "__main__": flag = solve() if flag: print(f"[+] FLAG: {flag}") else: print("[-] Failed to solve")
Theory
Shift Cipher (Caesar Cipher):
- Each character is shifted by a fixed value:
E(m) = m + k - Decryption:
D(c) = c - k - Works the same for Unicode as for ASCII
Known-Plaintext Attack:
- If we know a pair (plaintext, ciphertext), we can calculate the key
- For shift cipher:
key = ciphertext - plaintext - A single character is enough to fully break the cipher