Subtract
TL;DR
We’re given a list of pixel coordinates for a 500×500 canvas. Plotting all points looks like noisy blobs.
“Remove some stuff” → remove duplicates / take odd parity (XOR) of repeated coordinates, then strip interior pixels to keep only the outline. The outline spells the flag:
ctf{5ub7r4c7_7h3_n01s3}
Challenge
- Category: Misc
- Given:
coordinates.txt
containing lines like(x, y)
- Hint: “The image size is 500x500. You might want to remove some stuff... Note: Some may call it guessy!”
High-level Idea
- Treat each
(x, y)
as a white pixel on a black 500×500 image.
- Remove some stuff → two interpretations that both help:
- Odd parity (XOR duplicates): if a coordinate appears multiple times, keep it only if it appears an odd number of times.
- Remove interior pixels: keep only pixels that touch background in their 4-neighborhood (an outline).
- The odd-parity outline reveals crisp characters you can read as the flag.
Steps
1) Parse and plot
- Read
coordinates.txt
withreadlines()
.
- Parse integers with a regex.
- Plot raw points (will look like chunky blobs).
2) Odd-parity (XOR) filter
- Count occurrences of each
(x, y)
.
- Keep points whose count is odd.
This “subtracts” duplicates and often removes large filled areas.
3) Outline extraction
- Take the remaining points and drop interior pixels:
- For a point
(x, y)
, if any of its 4-neighbors (up, down, left, right) is missing (or out of bounds), keep it.
- Otherwise, it’s interior → remove it.
- For a point
- The result is a thin outline.
4) (Optional) Odd/Even line split
- Another “guessy” trick: render points from odd vs even lines separately. Sometimes only one subset is meaningful. Here, odd-parity + outline already does the job.
5) Read the flag
- The outline image shows
ctf{5ub7r4c7_7h3_n01s3}
.
Code (single-file, uses Pillow)
# solve.py
# pip install pillow
import re
from collections import Counter
from PIL import Image
W = H = 500
SCALE = 3 # for saving bigger previews
def read_coords(path="coordinates.txt"):
with open(path, "r", encoding="utf-8") as f:
lines = f.readlines()
pts = []
for ln in lines:
nums = re.findall(r"-?\d+", ln)
if len(nums) >= 2:
x, y = int(nums[0]), int(nums[1])
if 0 <= x < W and 0 <= y < H:
pts.append((x, y))
return pts, lines
def save_points_img(points, outname):
im = Image.new("L", (W, H), 0)
px = im.load()
for (x, y) in points:
px[x, y] = 255
if SCALE != 1:
im = im.resize((W*SCALE, H*SCALE), Image.NEAREST)
im.save(outname)
def outline(points):
s = set(points)
out = []
for (x, y) in s:
for dx, dy in ((1,0),(-1,0),(0,1),(0,-1)):
nx, ny = x+dx, y+dy
if not (0 <= nx < W and 0 <= ny < H) or (nx, ny) not in s:
out.append((x, y))
break
return out
def main():
pts, lines = read_coords("coordinates.txt")
print(f"Loaded {len(pts)} pts")
# Raw
save_points_img(pts, "points.png")
# Odd parity (XOR)
c = Counter(pts)
odd_parity = [p for p in c if c[p] % 2 == 1]
save_points_img(odd_parity, "odd_parity.png")
# Outline of odd parity
out_odd = outline(odd_parity)
save_points_img(out_odd, "outline_oddparity.png")
# (Optional) Odd/Even lines split
odd_lines, even_lines = [], []
for i, ln in enumerate(lines, start=1):
nums = re.findall(r"-?\d+", ln)
if len(nums) >= 2:
x, y = int(nums[0]), int(nums[1])
if 0 <= x < W and 0 <= y < H:
(odd_lines if i % 2 == 1 else even_lines).append((x, y))
save_points_img(odd_lines, "odd_lines.png")
save_points_img(even_lines, "even_lines.png")
print("Saved:",
"points.png, odd_parity.png, outline_oddparity.png,",
"odd_lines.png, even_lines.png")
if __name__ == "__main__":
main()
Why this works
- Many misc image/coordinates CTFs hide the signal in the parity of repeated pixels (think XOR).
- Filled areas make reading hard; extracting the outline preserves shape while removing clutter.
- The hint “remove some stuff… guessy” nudges toward trying simple heuristics like dedup, XOR, outline, odd/even splits.
Pitfalls / Gotchas
- Make sure
(0,0)
is top-left (invert Y when plotting with typical math axes).
- Keep coordinates within bounds 0…499.
- If your outline still looks fat, run outline twice or downsample then re-outline.
Artifacts to attach (screens)
points.png
— raw points (blobby).
odd_parity.png
— XORed points.
outline_oddparity.png
— thin outline showing readable text (the flag).
Flag
ctf{5ub7r4c7_7h3_n01s3}