Created
October 22, 2024 22:18
-
-
Save morkev/2a329dd421f7f3d64166162ca926b19b to your computer and use it in GitHub Desktop.
Recovers the bytes for the cipher key
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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