===== 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**.