L’énoncé nous dit, à la fin :
[…] vous devez retrouver un token caché dans les données d’identification de l’automate […]
On va donc envoyer une requête Modbus de FunctionCode 0x2B (Read Device Identification) à l’aide de ce bout de code :
# Construction d'un paquet Modbus valide
def build_mei_request(transaction_id=1, unit_id=1):
pdu = struct.pack("BBBB", 0x2B, 0x0E, 0x01, 0x00)
mbap = struct.pack(">HHHB", transaction_id, 0, len(pdu) + 1, unit_id)
return mbap + pdu
En l’exécutant, cela nous renvoie bien le token, mais l’énoncé précise également :
[…] vous ne devrez donc pas couper votre connexion TCP […]
En effet, si on garde le code en l’état et qu’on essaye de saisir le token, la page web nous renverra “Token Not Found”.
On va donc maintenir la connexion TCP ouverte en donnant le token en output et en donnant à l’utilisateur le choix de fermer la connexion.
import socket
import struct
import re
HOST = "localhost"
PORT = 4502
# Construction d'un paquet Modbus valide
def build_mei_request(transaction_id=1, unit_id=1):
pdu = struct.pack("BBBB", 0x2B, 0x0E, 0x01, 0x00)
mbap = struct.pack(">HHHB", transaction_id, 0, len(pdu) + 1, unit_id)
return mbap + pdu
with socket.create_connection((HOST, PORT), timeout=5) as s:
s.sendall(build_mei_request())
resp = s.recv(1024)
pdu = resp[7:]
offset = 7
token = None
while offset + 2 <= len(pdu):
obj_id = pdu[offset]
obj_len = pdu[offset + 1]
obj_val = pdu[offset + 2:offset + 2 + obj_len].decode('latin-1', errors='replace')
match = re.search(r'Your token is : ([a-f0-9]+)', obj_val)
if match:
token = match.group(1)
print(f"\n[+] Token : {token}")
offset += 2 + obj_len
print(f"[*] Entrez le token sur la page wbe http://{HOST}:8000/")
input("[*] Appuyez sur entrée une fois le token soumis pour fermer...\n")
print("[*] Connexion fermée.")
🚩 Le flag est présent sur la page après avoir saisit le token !