Catégorie: Hardware
Difficulté: medium
Flag: HTB{AT28C16_EEPROM_s3c23t_1d!!!}
Challenge
Description
After entering the door, you navigate through the building, evading guards, and quickly locate the server room in the basement. Despite easy bypassing of security measures and cameras, laser motion sensors pose a challenge. They're controlled by a small 8-bit computer equipped with AT28C16 a well-known EEPROM as its control unit. Can you uncover the EEPROM's secrets?
Ce challenge tourne sur un docker et n'est pas disponible
Résolution
On a devant nous une mémoire EEPROM de type AT28C16. Un rapide tour sur la documentation nous permet de voir ses caractéristiques :
Tous les input pins fonctionnent en 5V sauf le A9 et le OE qui peuvent être monté jusqu’à 12V
On lit également qu’il existe 32 octets réservés à l’identification, c’est ici que se cache le flag
Pour ce faire il faut :
Mettre le pin A9 à 12V (en HIGH)
Et lire l’adresse de 0x7e0 à 0x7FF
Pour être en mode lecture justement, il faut mettre les pins :
CE et OE à LOW
WE à HIGH (donc 5V)
Concernant l’adresse, ce sont des les pins de A10 à A0 qui servent à la paramétrer (A10 étant le haut de l’adresse) :
from pwnlib.tubes.remote import remote
import re
# On fonction en 5V
LOW = 0
HIGH = 5
def resolve_address(address: int) -> list[int]:
address = [5 if b == '1' else 0 for b in bin(address)[2:].zfill(10)]
# Mettre A9 à 12V pour la lecture
address[1] = 12
return address
def parse_read(data: str) -> str:
b = re.search(r"Read (.*) at", data)
if b is None:
return ""
return bytes.fromhex(b.group(1)[2:]).decode()
def solve(host: str, port: int) -> None:
# Connection au challenge
client = remote(host, port)
# Fonction pour envoyer des commandes et récupérer la sortie
def send_commands(commands: list[str]) -> str:
_output = []
for command in commands:
_output.append(client.sendlineafter(b'> ', command.encode()).decode() + f"{command}")
if "read_byte" in command:
_output.append(client.recvline().decode())
return '\n'.join(_output)
# Envoie des commandes pour Setup les pin CE / OE / WE
print(send_commands([
f"set_ce_pin({LOW})",
f"set_oe_pin({LOW})",
f"set_we_pin({HIGH})"
]))
flag = ""
for address in range(0x7e0, 0x7ff+1):
# Paramètrage de l'adresse à lire puis lecture
output = send_commands([
f"set_address_pins({resolve_address(address)})",
f"read_byte()"
])
print(output)
# Parsing de la sortie pour récupérer l'octer lu
flag += parse_read(output)
print(f"Flag: {flag}")
if __name__ == '__main__':
solve('94.237.53.3', 43523)