OperationBreadcrumbs

4 minute read

🌐 Operation Breadcrumbs

Category Author
🌐 Web The Cyber Mentor

Challenge Prompt

Operation Breadcrumbs

Welcome, operator. Your flag is prepared on demand, straight from the TCM flag service.

Request your drop with the button below. When it arrives, submit it in the field underneath.

Flags follow the format TCM{…}. Good luck!

Problem Type

  • Web
  • OSINT
  • Cryptography

Solve

We start out with a page showing a Download Flag button, but when we click it, we get a toast notification with:

1
2
3
⚠️ Something went wrong

The flag service is temporarily unavailable. Our team has been notified.

2026-05-27_19-34-23

If we click the button with the Developer Tools open (F12), under the console tab, we see: XHR GET https://ctf.tcmsecurity.com/api/flag

2026-05-27_19-34-57

If we expand that, under the response headers there is a x-debug-trace header with

1
aHR0cHM6Ly9naXN0LmdpdGh1YnVzZXJjb250ZW50LmNvbS9NYWx3YXJlQ3ViZS9mYjA3NDM0YzFmYmEzYjkxNDNjYWU4ZjAxMzA5YTU3Zi9yYXcvNTk4MTRkMGY0MTU4MTMyNWJhZTVjODBiMGRlOTg0NDk2M2Q0NGI0Ny9mbGFnLXNlcnZpY2UtZGVidWctbm90ZXMubWQ=

2026-05-27_19-35-10

Also, the status returned is 418 (I’m a Teapot).

If we put that into CyberChef and use the from Base64 recipe, we get:

1
https://gist.githubusercontent.com/MalwareCube/fb07434c1fba3b9143cae8f01309a57f/raw/59814d0f41581325bae5c80b0de9844963d44b47/flag-service-debug-notes.md

2026-05-27_19-35-49

Visiting that site gives us a note with:

1
2
3
4
5
6
7
8
# upload worker - queue stalls

worker keeps choking on the bulk import. the per-item debug dump sits on the
internal api:
/api/internal/ff9d9e38a38333145e46b49aa4a5f4b6?_=1718041920473&rid=7f3c9a2b1e&debug=1

grabbed that this morning, was useful. came back after lunch and it's 404.
of course it is. this is what I get for vibe-coding the whole thing...

If we attempt to go to the API link, as suggested in the note, we get a 404 error.

2026-05-27_19-36-48

Next I took a look at the API url: ff9d9e38a38333145e46b49aa4a5f4b6 this looked like a hash, so I went to Crack Station to check it.

2026-05-27_20-58-48

This turned out to be a MD5 hash for IMG27. From there I checked the API against hashes from 1 to 100:

1
for i in $(seq 1 100); do hash=$(echo -n "IMG$i" | md5sum | cut -d' ' -f1); echo "IMG$i ($hash): "; curl -s "https://ctf.tcmsecurity.com/api/internal/$hash"; echo ""; sleep 1; done

All of those except IMG28 resulted in a 404:

1
2
IMG28 (ce148ab4b8a20f6d0005775ad6320ceb): 
{"auth_payload":"H4sIAAAAAAAA/wTA7wqCMBAA8He5z6kthUiISiEiUIJGfz6JXtOGbRd6wzR6935fuHkyzTxJrbIQQ/05hdGlwcRMeXFY7cXiuJRVc72bfI6ijZKIREJTCDN46Z61bSCGJ/O7j4NgGAZ/JMeuUj6SCbYyzc4KXad53GH5UGbc9K4qkGytO1OyJrsW8PsHAAD//71EzlGFAAAA","service":"image-processor","status":"ok"}

Back to CyberChef and this time I used the magic recipe to determine this was both From Base64 and Gunzip:

1
{"X-TCM-Token":"fxP34VgcBmzN_H9F12J7TbgWYmN0c1k4B4o1Boz3","listing":"https://www.youtube.com/@TCMSecurityAcademy?sub_confirmation=1"}

2026-05-27_21-00-53

I visited the YouTube page and in the links near the header there was a link called BREADCRUMB.

2026-05-30_21-27-49

This link directed us to https://ctf.tcmsecurity.com/tcm-prod-media/4ee5f8ff6d6a23deb9d829479b54c8e3.jpg

Which displayed an XML error page:

1
2
3
4
5
6
7
8
<Error>
<Code>AccessDenied</Code>
<Message>Access Denied</Message>
<RequestId>9F3A2C1D7E4B8A60</RequestId>
<HostId>
Uf3pK2mWqL8xY1nZ7bV4tR6sD0gH5jC9aE2oP1iM3kS8wB7vN4xQ6lT0yU2rA1c=
</HostId>
</Error>

2026-05-30_21-28-35

Next I used curl to send the X-TCM-Token header and used -o to download the file:

1
2
3
4
5
curl https://ctf.tcmsecurity.com/tcm-prod-media/4ee5f8ff6d6a23deb9d829479b54c8e3.jpg \
  -H "X-TCM-Token: fxP34VgcBmzN_H9F12J7TbgWYmN0c1k4B4o1Boz3" -o image.jpg
  % Total    % Received % Xferd  Average Speed  Time    Time    Time   Current
                                 Dload  Upload  Total   Spent   Left   Speed
100 627.4k   0 627.4k   0      0 650.0k      0                              0

Once I had the image I opened it up and saw that it was some leaves against a plain background:

image

I ran exiftool against it and found it had coordinates in the output:

1
2
3
GPS Latitude                    : 34 deg 8' 2.76" N
GPS Longitude                   : 118 deg 19' 17.40" W
GPS Position                    : 34 deg 8' 2.76" N, 118 deg 19' 17.40" W

I put this location into CalTopo and saw it was in Hollywood, CA:
Screenshot 2026-06-03 at 6 17 53β€―AM

Next I checked to see if it was really a JPG, and it was not:

1
2
file image.jpg        
image.jpg: Zip archive, with extra data prepended

I renamed the file to a ZIP:

1
mv image.jpg image.zip 

Then I unzipped the file revealing flag.xor:

1
2
3
4
5
unzip image.zip                                                         
Archive:  image.zip
warning [image.zip]:  642481 extra bytes at beginning or within zipfile
  (attempting to process anyway)
  inflating: flag.xor

Back to CyberChef and I added the flag.xor file and then used the XOR operation with the key HOLLYWOOD to reveal the flag:
Screenshot 2026-06-03 at 6 24 29β€―AM


2026-05-30_21-50-48

Alterative Solve

Since we know the flag starts with TCM{ we can try a known plaintext attack.

1
2
3
4
5
6
7
8
9
10
with open('flag.xor', 'rb') as f:
    ciphertext = f.read()

known_plaintext = b"TCM{"
key_prefix = bytearray()

for i in range(len(known_plaintext)):
    key_prefix.append(ciphertext[i] ^ known_plaintext[i])

print(f"[*] The first 4 characters of the key are: {key_prefix}")

This gives us that the first 4 characters are HOLL. Then we can use the Webster’s Dictionary to find words that start with HOLL. We could also use a file like rockyou.txt to do this too. We pick some words in that list that we think might be the key:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
with open('flag.xor', 'rb') as f:
    ciphertext = f.read()

key = b"HOLL"
decrypted = bytearray([ciphertext[i] ^ key[i % len(key)] for i in range(len(ciphertext))])
print(f"[*] Testing exact 4-byte key 'HOLL': {decrypted}\n")

key = b"HOLLY"
decrypted = bytearray([ciphertext[i] ^ key[i % len(key)] for i in range(len(ciphertext))])
print(f"[*] Testing exact 4-byte key 'HOLL': {decrypted}\n")

key = b"HOLLYWOOD"
decrypted = bytearray([ciphertext[i] ^ key[i % len(key)] for i in range(len(ciphertext))])
print(f"[*] Testing exact 4-byte key 'HOLL': {decrypted}\n")

key = b"HOLLAND"
decrypted = bytearray([ciphertext[i] ^ key[i % len(key)] for i in range(len(ciphertext))])
print(f"[*] Testing exact 4-byte key 'HOLL': {decrypted}\n")

key = b"HOLLOW"
decrypted = bytearray([ciphertext[i] ^ key[i % len(key)] for i in range(len(ciphertext))])
print(f"[*] Testing exact 4-byte key 'HOLL': {decrypted}\n")

Flag

TCM{WH3R3_DR34M5_ARE_M4D3}