nerdymark's Software Engineering & Cybersecurity Blog

Welcome to my digital homestead - a curated collection of projects, writeups, and experiments in Python, cybersecurity, and creative coding.

Here you'll find CTF writeups covering Azure OAuth privilege escalation, AWS S3 multi-service exploitation, Kubernetes SSRF attack chains, Terraform state poisoning, Go malware reverse engineering, and supply-chain compromises on GitHub Actions runners. You'll also find side projects like the Pokemon Sleep Roster Analyzer, an RDP/VNC network scanner, a LinkedIn feed analyzer powered by Gemini, and word-puzzle solvers for Wordle and Hardle. Plus notes on building this Flask site, migrating to AWS, Bluesky cross-posting, and running a personal AI robot out of my garage.

I'm Mark LaCore - Software Engineer by day, Raspberry Pi tinkerer by night. 25 years of turning caffeine into code, 20+ years of playing guitar, and a growing collection of CTF trophies. Explore the posts below, browse the CTF writeups, or drop me a line.

Update README — scrying-basic-rdp fork, camera flow, ffmpeg Reflect the actual ...

File: README.md
 A local network scanner with a casino-themed web UI that discovers RDP and VNC s
 ## What It Does
-- **Discovery** — Scans subnets for RDP (3389–3390) and VNC (5900–5901) in a single nmap pass
+- **Discovery** — Scans subnets for RDP (3389–3390), VNC (5900–5901), and RTSP (554, 8554) in a single nmap pass
 - **Full Enumeration** — OS detection, open ports, NetBIOS names, domain info, SSL certs, MAC addresses
 - **Auth Checking** — Determines NLA status for RDP and authentication type for VNC (None/password)
-- **Screenshots** — Captures login screens from non-NLA RDP hosts (via FreeRDP) and unauthenticated VNC desktops (via vncdotool)
+- **Screenshots** — Captures login screens from non-NLA RDP hosts (via [patched scrying](#rdp-screenshots--patched-scrying)), unauthenticated VNC desktops (via vncdotool), web admin panels (via Playwright), and IP-camera frames (via ffmpeg over RTSP, with multi-channel NVR enumeration)
 - **Enrichment** — ASN, GeoIP, reverse DNS, and IP type classification for every host
-- **Bluesky Announcements** — Posts discoveries with screenshots to Bluesky via AT Protocol (opt-in)
+- **Bluesky Announcements** — Posts discoveries with screenshots to Bluesky via AT Protocol (opt-in); camera posts carry up to 4 channel frames in a single post
 - **Live Logging** — Real-time scan output streamed to the browser via SSE
 - **External Feeds** — Import scan targets from an external host feed or VNC Resolver's random endpoint
 A local network scanner with a casino-themed web UI that discovers RDP and VNC s

                                     ┌────────────┼────────────┐
                                     │            │            │
-                               SQLite DB    nmap binary   vncdotool
-                              (WAL mode)                  / FreeRDP
+                               SQLite DB    nmap binary   scrying / vncdotool
+                              (WAL mode)                  / ffmpeg / Playwright
 ```
 **Backend** — Python/FastAPI with raw SQLite (no ORM). Scans run in daemon threads because python-nmap is synchronous. Each nmap call creates its own `PortScanner()` instance for thread safety.
 A local network scanner with a casino-themed web UI that discovers RDP and VNC s
 - **Python 3.11+**
 - **Node.js 18+**
 - **nmap** — `brew install nmap` / `apt install nmap`
-- **FreeRDP** (optional, for RDP screenshots) — `brew install freerdp3`
+- **scrying** (for RDP screenshots) — see [RDP Screenshots — patched scrying](#rdp-screenshots--patched-scrying) below. Recommended: install the `scrying-basic-rdp` fork so legacy/no-NLA servers aren't skipped.
+- **ffmpeg** (for IP-camera RTSP frame grabs) — `brew install ffmpeg` / `apt install ffmpeg`
 - **vncdotool** (installed automatically via pip)
+### RDP Screenshots — patched scrying
+
+Upstream [`nccgroup/scrying`](https://github.com/nccgroup/scrying) (and its underlying `rdp-rs` library) only offers `ProtocolSSL` (+ optionally NLA) during RDP negotiation. Servers that only accept legacy `ProtocolRDP` (basic security, no TLS) reject scrying with `ProtocolNegFailure` — even though nmap's `rdp-enum-encryption` reports them as "no NLA". This rules out a meaningful fraction of internet-exposed RDP servers.
+
+Recommended install — the patched fork [`nerdymark/scrying-basic-rdp`](https://github.com/nerdymark/scrying-basic-rdp) adds offer-and-handle support for basic RDP security in `rdp-rs`, plus an automatic retry-on-NegFailure path in scrying:
+
+```bash
+# Requires Rust toolchain (brew install rust)
+cargo install --git https://github.com/nerdymark/scrying-basic-rdp.git --locked
+```
+
+The binary lands at `~/.cargo/bin/scrying`. Make sure that directory is on `PATH` when you launch the backend (e.g. `PATH="$HOME/.cargo/bin:$PATH" uvicorn backend.main:app --reload`). Upstream scrying still works for the SSL/NLA-off case if you don't want to build the fork.
+
+Either way, scrying decodes RDP bitmap updates straight to PNG — no XQuartz, no Screen Recording permission, no FreeRDP install needed.
+
 ## Quick Start
 ```bash
 Each scan executes these phases sequentially per subnet:
 | Phase | What | Scope |
 |-------|------|-------|
-| 1 | **Discovery** — `nmap -Pn --open -p 3389-3390,5900-5901` | All IPs in subnet |
-| 2 | **Full scan** — `nmap -A -Pn` (OS, ports, scripts) | Each RDP host, then VNC-only hosts |
+| 1 | **Discovery** — `nmap -Pn --open -p 3389-3390,5900-5901,554,8554` | All IPs in subnet |
+| 2 | **Full scan** — `nmap -A -Pn` (OS, ports, scripts) | Each RDP host, then VNC- and RTSP-only hosts |
 | 2.25 | **SSL cert** — `nmap --script ssl-cert` | Each RDP host |
 | 2.5 | **NLA check** — `nmap --script rdp-enum-encryption` | Each RDP host |
-| 3 | **RDP screenshot** — FreeRDP + screencapture | Non-NLA RDP hosts |
+| 3 | **RDP screenshot** — patched [scrying](#rdp-screenshots--patched-scrying) | RDP hosts where NLA isn't required |
 | 4 | **VNC auth** — `nmap --script vnc-info,vnc-title` | Each VNC port per host |
 | 4.1 | **VNC screenshot** — `vncdo capture` | No-auth VNC ports |
+| 4.5 | **Web screenshot** — Playwright (Chromium) | Detected web ports |
+| 4.6 | **Camera detect + RTSP probe + frame grab** — ffmpeg/ffprobe across known vendor URL templates, enumerates channels 1–16 on multi-channel NVRs | Hikvision, Dahua, Axis, etc. |
 | 5 | **Enrichment** — ip-api.com + reverse DNS | All discovered hosts |
 The `-Pn` flag is used everywhere because many hosts block ICMP probes.
 rdp-lottery/
 - **`-Pn` is slow** — A /24 probes all 256 IPs without ping, which is slower than default nmap but necessary because many hosts block ICMP
 - **SSE proxy ordering** — The Vite config has a specific entry for `/api/logs/stream` before the general `/api` proxy to prevent buffering issues
 - **nmap must be installed** — `python-nmap` is just a wrapper; the `nmap` binary must be on PATH
-- **macOS screenshots** — FreeRDP screenshot capture requires Screen Recording permission for Terminal/Python in System Settings > Privacy & Security
+- **scrying on PATH** — the backend shells out to `~/.cargo/bin/scrying`; if the backend is launched from a context that doesn't include that path, RDP screenshots silently won't be captured. Easiest fix is `PATH="$HOME/.cargo/bin:$PATH" uvicorn …` in your launch script
 - **VNC displays** — VNC servers can run on non-default ports (5901 for display :1); both 5900 and 5901 are scanned
 - **RDP on alternate ports** — ms-wbt-server sometimes runs on 3390; both 3389 and 3390 are scanned
+- **All-black VNC frames** — discarded automatically; common on headless X11 servers with no active desktop, no amount of mouse/keyboard input over RFB will conjure pixels
 ## License
Read more...