Skip to content

Instantly share code, notes, and snippets.

@morkev
Created October 22, 2024 22:18
Show Gist options
  • Select an option

  • Save morkev/2a329dd421f7f3d64166162ca926b19b to your computer and use it in GitHub Desktop.

Select an option

Save morkev/2a329dd421f7f3d64166162ca926b19b to your computer and use it in GitHub Desktop.
Recovers the bytes for the cipher key
import requests
import base64
from urllib.parse import quote
from bs4 import BeautifulSoup
def get_ciphertext(session):
"""Fetches the encrypted backup from the server."""
response = session.get("http://challenge.localhost:80/")
if response.status_code != 200:
print(f"Error: Received status code {response.status_code}")
return None
soup = BeautifulSoup(response.text, 'html.parser')
pre = soup.find('pre')
if pre:
ct_b64 = pre.get_text().strip()
ct_bytes = base64.b64decode(ct_b64)
return ct_bytes
else:
print("Error: Could not find ciphertext in the response.")
return None
def post_content(session, content):
"""Posts content to the server."""
data = {'content': content}
response = session.post("http://challenge.localhost:80/", data=data)
return response.status_code == 200
def reset_database(session):
"""Resets the database on the server."""
response = session.post("http://challenge.localhost:80/reset")
return response.status_code == 200
def determine_block_size(session):
"""Determines the block size of the cipher."""
initial_ct_len = len(get_ciphertext(session))
i = 1
while True:
content = 'A' * i
reset_database(session)
post_content(session, content)
ct_len = len(get_ciphertext(session))
if ct_len > initial_ct_len:
block_size = ct_len - initial_ct_len
print(f"Determined block size: {block_size} bytes")
return block_size
i += 1
def recover_flag():
session = requests.Session()
reset_database(session)
block_size = determine_block_size(session)
known_flag = ''
max_flag_length = 100
for i in range(max_flag_length):
print(f"[*] Recovering byte {i + 1}")
padding_length = block_size - (len(known_flag) % block_size) - 1
padding = 'A' * padding_length
reset_database(session)
post_content(session, padding)
ct = get_ciphertext(session)
if ct is None:
print("Failed to get ciphertext.")
return
total_length = len(padding) + len(known_flag) + 1
block_index = (total_length - 1) // block_size
target_block = ct[block_index * block_size : (block_index + 1) * block_size]
found = False
for byte in range(32, 127):
candidate = known_flag + chr(byte)
test_input = padding + candidate
reset_database(session)
post_content(session, test_input)
test_ct = get_ciphertext(session)
if test_ct is None:
continue
test_block = test_ct[block_index * block_size : (block_index + 1) * block_size]
if test_block == target_block:
known_flag += chr(byte)
print(f"[+] Recovered so far: '{known_flag}'")
found = True
break
if not found:
print("[-] Failed to recover next byte. Exiting.")
break
print(f"\n[+] Recovered Flag: '{known_flag}'")
if __name__ == "__main__":
recover_flag()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment