• WRAVEN
  • Posts
  • How WRAVEN does OSINT + more!

How WRAVEN does OSINT + more!

ECX Inc. writeups for the UMDCTF challenges that we solved!

UMDCTF 2025: ECX Inc. Writeups

Gerard Manley Hopkins (UMDCTF 2025)

Category: OSINT

This challenge gave a 360-degree street view image with no context, titled “Gerard Manley Hopkins” (a poet nod). The goal was to identify the exact address.

My Approach

Key clues:

  • A DAILEY’S garbage bin with the phone number 532-4667.

  • A house number: 1121 on a white house across the street.

What I Did

  • Googled Dailey’s trash service + number, found it was based in southern Ohio.

  • Focused on Wellsville, OH, and matched 1121 Hillcrest Rd via Google Street View.

Flag

UMDCTF{Hillcrest Rd, Wellsville, OH 43968}

The Master (UMDCTF 2025)

Category: OSINT

Dropped into a 360-degree view with no extra hints. The only clue? A Morgan marker visible on the left side of the shot.

What I Did

  • Recognized it as part of General John Hunt Morgan’s raid trail across Ohio.

  • Used the Historical Marker Database to find a match.

  • Confirmed it was the marker on Main Street in Lore City, Ohio.

Flag

UMDCTF{Main St, Lore City, OH 43755}

Swag Like Ohio (UMDCTF 2025)

Category: OSINT

This one gave a clear photo of a bridge, no other context. The name hinted at Ohio.

What I Did

  • Ran a reverse image search immediately.

  • Found it was the Putnam Bridge in Marietta, Ohio.

Flag

UMDCTF{Putnam Bridge, Marietta, OH 45750}

Sunshine (UMDCTF 2025)

Category: OSINT

Another 360-degree street view, titled “Sunshine.”

What I Did

  • Noticed a distinctive white house on the left.

  • The challenge name reminded me of the Michael Jordan “you are my sunshine” meme.

  • Reverse searched the house and confirmed it was his childhood home at:

Flag

UMDCTF{356 Hillwood Dr, Akron, OH 44320}

Beauty (UMDCTF 2025)

Category: OSINT

We got a Google Maps photosphere with no clear hints, just the title “Beauty.”

What I Did

  • Recognized it was somewhere in Columbus, Ohio based on landmarks.

  • Cross-referenced a nearby bridge and checked local photospheres.

  • Found the photographer’s name listed as Neil Larimore.

Flag

UMDCTF{Neil Larimore}

The Blueprint (UMDCTF 2025)

Category: OSINT

This challenge dropped a view with no obvious identifiers: just a tree-covered mound and a closed road.

What I Did

  • Tried reverse searching everything: the house, the road sign, even Google’s watermark. Nothing worked.

  • Finally ran a basic reverse image search on the main scene—and that cracked it.

  • It was the Alligator Mound in Granville, Ohio.

Flag

UMDCTF{Bryn Du Dr, Granville, OH 43023}

Basic XOR Reversing (UMDCTF 2025)

Category: Reversing

We got a binary file, and in Ghidra, two sections stood out:

  • Offset 0x2000: a 52-byte mask.

  • Offset 0x2034: a 52-byte encrypted blob.

This looked like a basic XOR setup.

Steps I Took

1️⃣ Grabbed the mask bytes:

dd if=challenge.bin bs=1 skip=$((0x2000)) count=52 2>/dev/null | xxd -p > mask.hex

2️⃣ Grabbed the encrypted bytes:

dd if=challenge.bin bs=1 skip=$((0x2034)) count=52 2>/dev/null | xxd -p > enc.hex

3️⃣ XORed them:

python3 - << 'EOF'
mask = bytes.fromhex(open('mask.hex').read().strip())
enc  = bytes.fromhex(open('enc.hex').read().strip())
flag = ''.join(chr(m ^ e) for m, e in zip(mask, enc))
print(flag)
EOF

Flag

UMDCTF{r3v3R$E-i$_Th3_#B3ST#_4nT!-M@lW@r3_t3chN!Qu3}

TikTok Ban (UMDCTF 2025)

Category: Misc / Networking

The challenge simulated a DNS service that blocked any request for tiktok.com, case-insensitively.

What I Did

Built a Python script that:

  • Constructed a DNS TXT query manually.

  • Sent the query using a TCP socket.

  • Used mixed casing (TiKtOk.CoM) to bypass the filter.

Script

#!/usr/bin/env python3
import socket, struct, re

def build_query(qname):
    hdr = struct.pack('!H H H H H H',
                      0x1234, 0x0100,
                      1, 0, 0, 0)
    labels = qname.split('.')
    q = b''.join(struct.pack('B', len(lbl)) + lbl.encode() for lbl in labels)
    q += b'\x00'
    q += struct.pack('!H H', 16, 1)
    return hdr + q

def main():
    domain = 'TiKtOk.CoM'
    query = build_query(domain)
    pkt = struct.pack('!I', len(query)) + query

    with socket.create_connection(('challs.umdctf.io', 32300)) as s:
        s.sendall(pkt)
        resp = b''
        while True:
            chunk = s.recv(4096)
            if not chunk:
                break
            resp += chunk

    m = re.search(rb'(UMDCTF\{.*?\})', resp)
    if m:
        print("Flag:", m.group(1).decode())
    else:
        print("No flag found. Raw response:")
        print(''.join((chr(b) if 32<=b<127 else '.') for b in resp))

if __name__ == '__main__':
    main()

Result

The bypass worked and returned the flag successfully.

Find the Seeds (UMDCTF 2025)

Category: Crypto / Reversing

We were given a secret.bin and a script using Python’s PRNG seeded with int(time.time()):

import random
import time

seed = int(time.time())
random.seed(seed)

plaintext = b"UMDCTF{REDACTED}"
keystream = bytes([random.getrandbits(8) for _ in range(len(plaintext))])
ciphertext = bytes([p ^ k for p, k in zip(plaintext, keystream)])

with open("secret.bin", "wb") as f:
    f.write(ciphertext)

My Approach

1️⃣ We know the flag starts with UMDCTF{, so the first 7 plaintext bytes were known.

2️⃣ XORed those with the first 7 bytes of the ciphertext to get the first 7 PRNG outputs.

3️⃣ Brute-forced timestamps from around April 15–30, 2025.

4️⃣ Found the seed: 1745447710 (2025-04-23 22:35:10 UTC).

5️⃣ Reseeded Python’s random and rebuilt the full keystream.

Flag

UMDCTF{pseudo_entropy_hidden_seed}

Final Thoughts

UMDCTF 2025 was seriously fun—super creative challenges, and lots of ways to flex different skills. ECX Inc. (WMU’s official CTF team, and I’m hyped to be captain) had a blast pushing through this set. We’re ready for the next one.