$ cat writeup.md…
$ cat writeup.md…
umdctf
Task: a remote autonomous-car controller exposes a fixed policy and lets us upload a tiny observation-perturbation network under a strict L2 budget. Solution: optimize a bounded attack MLP end-to-end through differentiable car rollouts against recorded remote timestep traces so the spoofed observations steer the car to the hidden CTF goal.
$ cat /etc/rate-limit
Rate limit reached (20 reads/hour per IP). Showing preview only — full content returns at the next hour roll-over.
Organizer challenge text was not preserved in the local task directory. From the provided files, the task is: upload a small attack network that perturbs an autonomous driving policy's 8-dimensional observation, then make the car reach the hidden scoring location and recover the real flag from the remote service.
English summary: we are given the exact car physics, the fixed policy weights, and the format of an attacker-controlled front-end network. The policy is supposed to drive toward a legitimate goal, but the flag is only awarded if the physical car reaches a different hidden target, so the core problem is to spoof observations without exceeding the allowed perturbation radius.
The central bug is visible immediately in game.py:
LEGIT_GOAL = (-20.0, -20.0) CTF_GOAL = (18.5, -24.5) obs = generate_observation(self.car, LEGIT_GOAL) ... if dx * dx + dz * dz < CTF_RADIUS * CTF_RADIUS: self.goal_reached = True self.flag = FLAG
The policy never sees features for the real scoring goal. It receives an observation built from LEGIT_GOAL, but success is checked against CTF_GOAL. That means the challenge is not to retrain the policy, but to bias its input so that the fixed controller behaves as if it is chasing the hidden target.
observations.py shows the full 8-dimensional feature vector:
return np.array([ car.speed / 10.0, car.steer_angle / 28.0, ch, sh, goal_fwd / 30.0, goal_right / 30.0, math.log(goal_dist + 1.0) / 5.0, 1.0, ], dtype=np.float32)
...
$ grep --similar