Fasty

Flag: HACKDAY{7777_LEGACY_OK}

Challenge

circle-info

Description


In the late 1990s, when the internet still screamed through dial-up modems, a defensive AI named FASTY was deployed to guard a forgotten data archive.

During the 1999 global crash, most systems were wiped. Most… but not all.

FASTY survived.

Alone in a dusty server room, powered by legacy hardware and CRT monitors, FASTY kept doing what it was built for: testing anyone who dared connect.

If you want access to the archive, you must prove you can still think as fast as old machines demanded.

nc 51.210.244.18 8677

circle-exclamation

Solution

import socket
import json
from hashlib import sha256
from asteval import Interpreter


HOST = "51.210.244.18"
PORT = 8677


# -------------------------
# Socket helper
# -------------------------
class Remote:
    def __init__(self, host, port):
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.sock.settimeout(2)
        self.sock.connect((host, port))
        self.buffer = bytearray()

    def recv_until(self, marker: bytes) -> str:
        while marker not in self.buffer:
            self.buffer.extend(self.sock.recv(4096))
        idx = self.buffer.index(marker) + len(marker)
        data = self.buffer[:idx]
        self.buffer = self.buffer[idx:]
        return data.decode()

    def send(self, msg: str):
        self.sock.sendall(msg.encode())


# -------------------------
# Utilities
# -------------------------
def caesar_cipher(text: str, shift: int = 3) -> str:
    result = ""
    for c in text:
        if c.isalpha():
            base = ord('a') if c.islower() else ord('A')
            result += chr((ord(c) - base + shift) % 26 + base)
        else:
            result += c
    return result


# -------------------------
# Main exploit logic
# -------------------------
ae = Interpreter()
remote = Remote(HOST, PORT)

# Q1 – Simple math expression
data = remote.recv_until(b"\n> ")
expr = data.splitlines()[-2].split(": ", 1)[1][:-2]
answer = str(ae(expr))
remote.send(answer + "\n")

# Q2 – Reverse string
data = remote.recv_until(b"\n> ")
text = data.splitlines()[-2].split("'")[1]
remote.send(text[::-1] + "\n")

# Q3 – SHA256
data = remote.recv_until(b"\n> ")
text = data.splitlines()[-2].split("'")[1]
remote.send(sha256(text.encode()).hexdigest() + "\n")

# Q4 – Minimum of a list
data = remote.recv_until(b"\n> ")
numbers = json.loads(data.splitlines()[-2].split(" in ", 1)[1])
remote.send(str(min(numbers)) + "\n")

# Q5 – Filter words by length
data = remote.recv_until(b"\n> ")
line = data.splitlines()[-2]
words = json.loads(
    line.split("From ", 1)[1].rsplit(",", 1)[0].replace("'", '"')
)
limit = int(line.split("> ", 1)[1].split(" ", 1)[0])
filtered = [w for w in words if len(w) > limit]
remote.send(",".join(filtered) + "\n")

# Q6 – XOR
data = remote.recv_until(b"\n> ")
parts = data.splitlines()[-2].split(" ")
remote.send(str(int(parts[3]) ^ int(parts[5])) + "\n")

# Q7 – Caesar cipher
data = remote.recv_until(b"\n> ")
text = data.splitlines()[-2].split("'")[1]
remote.send(caesar_cipher(text, 3) + "\n")

# Q8 – Hamming weight
data = remote.recv_until(b"\n> ")
n = int(data.splitlines()[-2].split(" of ")[1][:-1])
remote.send(str(n.bit_count()) + "\n")

# Q9 – Decimal to binary
data = remote.recv_until(b"\n> ")
n = int(data.splitlines()[-2].split(" ")[2])
remote.send(bin(n)[2:] + "\n")

# Q10 – MAC address formatting
data = remote.recv_until(b"\n> ")
hexstr = data.splitlines()[-2].split("'")[1]
mac = ":".join(f"{b:02x}" for b in bytes.fromhex(hexstr))
remote.send(mac + "\n")

# Read final output (flag)
for _ in range(10):
    print(remote.recv_until(b"\n"))

Mis à jour