===== Brute-Force Attacke ===== **Ziele:** * 'richtiges' Python installieren * Python-Module mit `pip` installieren können * Mit Brute-Force Passwörter hacken In dieser Aufgabe geht es darum, **geheime Passwörter** mithilfe der Brute-Force Methode zu hacken, über welche man Zugriff auf **geheime Nachrichten** (Achtung: Flachwitz-Alarm!) erhält. Insgesamt gibt es mind. fünf solcher Passwörter / Nachrichten, die man hacken kann. Beachte, dass alle Passwörter ausschliesslich die **Grossbuchstaben** `'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` verwenden. Es gibt also *keine* Kleinbuchstaben, Umlaute, Leerzeichen, Zahlen, Sonderzeichen, ... Für diese Aufgabe gibt es **zwei Versionen**: 1. **Online-Hack**: Hier wird eine Website gehackt, die auf einem Schulserver läuft. 1. **Offline-Hack** Die (verschlüsselten) Daten, die gehackt werden sollen, werden auf den Computer heruntergeladen, es ist also kein Zugriff auf eine Website nötig. **Wähle eine der beiden Optionen** (online oder offline) und löse die Aufgaben weiter unten. Für jede Option gibt es ein Template mit vordefiniertem Code, den man verwenden soll. Lasse dich von diesem Code nicht einschüchtern: Du musst diesen nur anwenden aber *nicht verstehen*. ==== Templates für Hack ==== === Online (Website) === [[https://bottom.ch/ksr/hackme/]] * Benötigt Python-Modul **Selenium**: `pip install selenium` * Benötigt aktuelle Version von **Google Chrome** * Erklärung: * Jedes Mal, wenn man auf der Website ein Passwort eingibt und den Button drückt, wird im JavaScript-File die Funktion `check_pw(...)` ausgeführt, die überprüft, ob das eingegebene Passwort korrekt ist oder nicht. Die Funktion gibt zwei Werte zurück: * Code: $201$ falls korrekt, $401$ falls falsch * Message * Der Code unten verbindet sich mit der Website und ruft die Funktion `check_pw(...)` auf und erhält den Code und die Message zurück. ++++Code| ### requires: `pip install selenium` ### DON'T CHANGE CODE FROM HERE ... from selenium import webdriver from selenium.webdriver.common.by import By import time # url to website url_website = "https://bottom.ch/ksr/hackme/" # Open the webpage options = webdriver.ChromeOptions() #options.add_argument("--headless=new") # enable to make Chrome a bit faster driver = webdriver.Chrome(options=options) driver.get(url_website) # Find buttons input_field = driver.find_element(By.ID,"textInput") # find the input box ... code_field = driver.find_element(By.ID, "responseCode") # find the response code box ... decrypted_field = driver.find_element(By.ID, "encryptedTextArea") # find the encrypted text box ... button = driver.find_element(By.ID,"btnSend") # find the button ... def try_with_clicking(pw): """Enters password and clicks the button, performs 10-20 clicks per second.""" # 1) Enter text in the input field input_field.clear() input_field.send_keys(pw) # 2) Click the button button.click() # 3) Read response and output code = code_field.get_attribute("value") message = decrypted_field.get_attribute("value") return code, message def try_with_js(pw): """Tests a password by executing the relevant JS function, performs around 500 attempts per second.""" return driver.execute_script(f'return check_pw("{pw}")') ### ... UNTIL HERE ### WRITE YOUR CODE BETWEEN HERE ... def hack_password(): pw = "my secret password" code, message = try_with_clicking(pw) if int(code) < 400: return code, message, pw return code, "not found", pw start = time.time() code, message, pw = hack_password() elapsed = time.time() - start print(f"Code: {code}, Message: {message}, Password: {pw}, Elapsed: {elapsed:.1f}s") ### ... AND HERE. DON'T CHANGE LAST LINE: driver.quit() # Close the browser ++++ === Offline (verschlüsselte Daten) === * Benötigt Python-Modul **PyCryptoDome**: `pip install pycryptodome` * Erklärung: Die Python-Funktion `check_pw(...)` überprüft ein Passwort und erhält einen Code und eine Message (gleich wie bei Online-Version oben) zurück. ++++Code| ### requires: pip install pycryptodome ### DON'T CHANGE CODE FROM HERE ... from Crypto.Cipher import AES from Crypto.Util.Padding import pad, unpad import hashlib encoding = 'utf-8' # 'latin-1' data_encrypted = [ { "pw_hashed" : "4ae81572f06e1b88fd5ced7a1a000945432e83e1551e6f721ee9c00b8cc33260", "message_encrypted" : b'\xa5\x8a\xb6i\xfb\xe4\x1c\xeeN [\xcb\xb8\xe9\x85-' }, { "pw_hashed" : "ccc09a134cf88bae7be3f6d62cf24b9476a044c375a76d53b78eef18ea772f5f", "message_encrypted" : b'\x98I\x10\xb3\xbaW\x03V\x9e\x96;\xb0\xb2#\xc7\x04AA\xf4S\xf9H\x10\xf6\x9c\x8e\xd3jf\xfa\x17\xa1\xba\xb5\xae\xc5\n\xc0\xd4\xc8\x02,U\x10\xc2\xd62\xbe\xa6!l\x82\x82Hs\xde\xb7\x97\xf6\x0c\xa6\x85\xf2\xd0' }, { "pw_hashed" : "516a8d1c497179956af1feddc603960155d26aad82fa8c184dd27a14fc59da82", "message_encrypted" : b'\x89\xd55H\xb3\xab\x0b\x99\x19oW\x00\xfd\xc9*\xdc`\xb2\xb0N\xf7+m\xce\x8c\xf7\xd7k\xc5\x01\xec\xbf+f\x94\xd0\xb1\x04\xcd\xd2$Z\xf6\xdf\xee\xca\xa5V\xf6b\xce\n\x1f\xbc\x1c\xe4\x00zi\xe8:\xcb\x000' }, { "pw_hashed" : "1f40dc75353dade02cab2a64cc014d058bc16b3eec3b52b723dc1db5cfdc7875", "message_encrypted" : b'\x0c\xe0hb%\xe9E\xdb\x97\x10I\x17\xc2\xdbH4\x03\xf3M\xb20_\xa3\x13\xbd\x87\xd5\xe0\xc8\xcb\xab+\x89\r\x938@2\x0b.{t\x1a3\x85u\x14\xd3' }, { "pw_hashed" : "cb059e3e1d77a76665eaaeb7d289f54936ecb301a5ede2a0ac887c204b7bd4e4", "message_encrypted" : b'\x0fr\xbd~\x0b C\xd1\xdc\x83y\x0e\xf5Im\xf3U\x94\x7f\xd6\x8e\xde\xb6\xf5\x97\xf6\x06\x16\xd8o\xc4Q\x12[k%\xcf\xb2\x14\xea)Zi/e\x1buX?\xc4\x0e\xf9\\\xf9\xa5\xfb\x1e5\xecPi\xe8\x89Ty63`4\x89\x87\x08\x9b\xccj\xcd1y/\xc5\xdc#\x1fS\xa8\xe99\x07\x85\xda\xf5:\xd5' } ] def normalize_key(key): if len(key) < 16: key = key + (16-len(key)) * "a" elif len(key) < 64: key = key + (16-len(key)) * "a" else: key = key[:64] return key def encrypt(key: str, message: str): key = normalize_key(key).encode(encoding) cipher = AES.new(key, AES.MODE_ECB) # Using ECB mode padded_message = pad(message.encode(encoding), AES.block_size) # Pad message encrypted_message = cipher.encrypt(padded_message) # Encrypt the data return encrypted_message def decrypt(key: str, message: bytes): key = normalize_key(key).encode(encoding) cipher = AES.new(key, AES.MODE_ECB) # Using ECB mode decrypted_message = cipher.decrypt(message) decrypted_unpadded_message = unpad(decrypted_message, AES.block_size) return decrypted_unpadded_message.decode(encoding) # Decode bytes to string def hashme(s): return hashlib.sha256(s.encode(encoding)).hexdigest() def check_pw(pw): for data in data_encrypted: if hashme(pw) == data['pw_hashed']: return 201,decrypt(pw,data["message_encrypted"]) return 401,None ### ... UNTIL HERE ############################################## ### WRITE YOUR CODE BELOW: code, message = check_pw("WRONGPASSWORD") print(code) print(message) ++++ ==== Hilfe benötigt? ==== * [[gf_informatik:programmieren_ii|Dossier Programmieren aus 1M]] * Verwende KI als Tutor (z.B. ChatGPT, Bing-Chat, ...) ==== Aufgabe 0 ==== **Ziel:** richtiges Python & VSCode einrichten 1. [[gf_informatik:python_vscode_setup|Richte Python & VSCode ein]] 1. Entscheide dich für eine Hack-Variante ("Online" oder "Offline") ... 1. ... und [[gf_informatik:python_vscode_setup#python_module_installieren|installiere das benötigte Modul]] (siehe oben, welches Modul benötigt wird). 1. Optional aber empfohlen: Finde heraus, wie man [[gf_informatik:python_vscode_setup#jupyter-notebooks_optional|Jupyter-Notebooks]] verwendent. Mit diesen kann man Code und Text miteinander kombinieren. ==== Aufgabe 1: Zufällige Zeichenkette ==== 1. Lade das passende Template oben herunter / kopiere es in ein Python oder Jupyter-Notebook File und führe es aus. 1. Finde das erste Passwort durch *ausprobieren* heraus: **Passwort 1**: ein einziger Grossbuchstabe 1. Schreibe nun den Code, der das zweite Passwort hackt: **Passwort 2**: drei zufällige Grossbuchstaben. Schreibe deinen eigenen Code, verwende keine Module wie itertools. ==== Aufgabe 2: Deutsches Wort ==== Das folgende Dokument enthält kapp $10000$ der am meisten verwendeten deutschen Wörtern: {{ :gf_informatik:web_sca:woerter_top10000de_upper.txt.zip |}} (muss zuerst *entzippt* werden!) 1. Finde heraus, wie man in Python ein **Text-File einliest** und Zeile für Zeile durchgeht. Verwende dazu **KI als Tutor**. 1. Hacke damit **Passwort 3:** Besteht aus einem Wort (nur Grossbuchstaben) aus der Liste oben. ==== Aufgabe 3 (optional) ==== Hacke die verbleibenden Passwörter: * **Passwort 4:** besteht aus mehr als drei zufälligen Grossbuchstaben. * Knacke Passwort 4 mithilfe einer **rekursiven Funktion**. Recherchiere selbst, was dies bedeutet. * **Passwort 5:** besteht auf zwei aneinandergereihten Wörtern aus der Liste von oben Andere Aufgaben: * Mache eine **Laufzeitanalyse**: Mithilfe des `time` Moduls (`import time`, kein pip nötig) kann man bestimmen, wie lange die Ausführung eines Codes dauert. Wie lange dauert es im schlechtesten Fall, um ein Passwort mit $1,2,3,4,5,\ldots$ Zufallszeichen (Grossbuchstaben) zu bestimmen? * Versuche, einen (oder beide) der **Codes**, die für diese Aufgaben zur Verfügung gestellt werden, zu **verstehen**.