c00ked d3v Full NexZeroCTF OSINT/4n6 Chain
Full solve for c00ked d3v recovering a scrubbed trail from GHCR layers to a dead host, then from deleted GitHub activity to a staging mirror, DNS TXT dead drop, and the final Gist.
Overview
| Β | Β |
|---|---|
| Event | NexZeroCTF |
| Category | Ronins [OSINT/4n6] |
| Challenge | c00ked d3v [1/2 & 2/2] |
| Initial Lead | kojirou825 |
| Pivot Chain | GHCR -> Docker layers -> favicon hash -> FOFA -> URLScan -> GitHub Events -> Git mirror -> DNS TXT -> Gist |
This challenge chain is built around residual state. The developer surface looks scrubbed, the first host is already offline, and the GitHub UI hides part of the trail. None of that matters if the investigation stays anchored to artifacts instead of presentation layers. The entire solve comes from recovering what earlier systems, registries, and caches retained after the operator tried to clean up.
Part 1 β GHCR as the First Real Artifact
The prerequisite challenge, Vagabond behind laptophada, leaks a single useful lead: the handle kojirou825.
That profile is intentionally sparse. No public repositories, no obvious activity, nothing worth pivoting from on the repositories tab. The useful surface is the one most people ignore: Packages.
The only exposed artifact on the profile is the published package ronins-hash-studio.
The package resolves to a public GHCR image:
GHCR exposes the ronins-hash-studio image family and its published tags.
One of the relevant tags in the chain is:
1
ghcr.io/kojirou825/ronins-hash-studio:2026.02.24-r1
At this point, the investigation stops being account-centric. The image is the first hard artifact, and the solve moves into container forensics.
Part 2 β Layer History, Whiteouts, and the Favicon Pivot
The final filesystem view of a container image is often the least interesting one. What matters is the layer history underneath it.
1
2
3
4
5
docker pull ghcr.io/kojirou825/ronins-hash-studio:2026.02.24-r1
docker save ghcr.io/kojirou825/ronins-hash-studio:2026.02.24-r1 -o ronins.tar
mkdir extracted_image
tar -xf ronins.tar -C extracted_image
cd extracted_image
Iterating over the raw layer tarballs quickly exposes a deleted asset:
1
2
3
for blob in blobs/sha256/*; do
tar -tf "$blob" 2>/dev/null | grep -E 'favicon\.ico|\.wh\.favicon\.ico' && echo "[+] $blob"
done
Two entries matter:
app/static/favicon.ico.wh.favicon.ico
That pairing is decisive. The lower layer contains the real favicon, and the upper layer contains a whiteout marker for the same path. In other words, the icon was present during an earlier build stage and deliberately removed later. The merged runtime view hides it, but the raw layer history does not.
Once the original icon is recovered, it becomes an infrastructure fingerprint. Computing the MurmurHash3 value gives:
1
2
3
4
5
6
7
python3 - <<'PY'
import base64
import mmh3
with open("favicon.ico", "rb") as f:
print(mmh3.hash(base64.b64encode(f.read())))
PY
1
-1359010016
Shodan validates that the fingerprint exists in its corpus, but at this access tier it does not return an operationally useful result:
Shodan confirms the hash, but the host detail is effectively gated off.
FOFA is enough to finish the pivot cleanly:
FOFA resolves the recovered favicon hash to a single exposed deployment.
1
172.236.204.62
The match is not just numerically convenient. It is backed by the recovered page title, the exposed HTTP service, and coherent metadata around the Ronins Hash Studio deployment.
Part 3 β Recovering a Burned Host Through Historical Capture
By the time the IP is identified, the host is already gone. The box no longer answers, so the investigation has to shift from live interaction to preserved telemetry.
URLScan carries the next pivot. Searching the IP returns a historical capture of the server while it was still online:
URLScan preserves the dead hostβs DOM and raw source long after the service disappeared.
The rendered page itself is not the prize. The DOM and source views are. That is where implementation residue survives.
Scrolling the preserved DOM exposes a hidden HTML comment inside the Operator Cache panel:
The first flag is buried in a comment that survives only because the page was archived before the host died.
1
nexus{70uch1n9_9r455_4nd_cur471n9_1mm4cul473_fuck1n9_v1b35_bl3553d_rn}
That closes the first half. The chain so far is tight and consistent: a package artifact leads to an image, the image leads to a deleted favicon, the favicon leads to a host, and the dead host yields to archival recovery.
Part 4 β The Deleted GitHub Comment That the UI No Longer Shows
The second half starts where most people stop. After flag one, kojirou825 looks sterile again: no green graph, no visible public activity, and a staging repository path that appears to go nowhere. The issue thread on ZX41R/ronins-staging-repo is not useful in the web UI because the relevant comment has already been removed.
That presentation layer is not authoritative. GitHubβs recent public events feed is.
1
curl -s https://api.github.com/users/kojirou825/events/public
The public events feed still retains the IssueCommentEvent linking kojirou825 to ZX41R/ronins-staging-repo.
At the time of analysis, the event payload still preserved the deleted comment body:
bro I told you the orange mirror uses a different namespace for the new staging pipeline. i used yifan471 to push the final commits. stop opening issues here, this repo is dead.
That one line is the bridge for the rest of the solve. It contributes three concrete pivots:
orange mirrorpoints away from GitHub and toward the parallel Git workflowyifan471provides the replacement handlethis repo is deadconfirms that staying on the original GitHub surface is a waste of time
Part 5 β Mirror Pivot and Staging Source Leak
Searching the alternate handle on the mirror side surfaces another ronins-staging-repo, now under yifan471:
The staging mirror under yifan471 is the next live development artifact in the chain.
The repository itself is lightweight. The value is not in commit volume or repository history; it is in the deployed content. Inspecting the staged HTML source exposes a comment block that reads like operator spill and, more importantly, names the next host directly:
The staged source contains an embedded note that explicitly drops ronins-data.estin.pro.
1
ronins-data.estin.pro
That pivot matters because the target does not behave like a normal website. Once the hostname is identified, the right move is no longer to keep browsing source trees. It is to enumerate the domain itself.
Part 6 β DNS TXT as a Dead Drop
ronins-data.estin.pro does not present useful web content, which is usually a sign that the subdomain is being used as a storage or signaling surface rather than as an application endpoint. TXT is the obvious place to look next.
1
dig TXT ronins-data.estin.pro
The domain returns a single base64-encoded TXT payload rather than a normal web response.
Decoding the returned value yields a full GitHub Gist URL:
1
2
base64 -d <(echo -n "aHR0cHM6Ly9naXN0LmdpdGh1Yi5jb20vWlg0MVIvZWRlNjdhMjBjOGViNDE0ZGE5OWZiZDE0ZmY5NmJlOTI=")
echo
The TXT payload decodes directly into the final Gist location.
1
https://gist.github.com/ZX41R/ede67a20c8eb414da99fbd14ff96be92
Opening that Gist, run the code that yields the final flag:
1
nexus{l37_h1m_c00k_7h3_dn5_r3c0rd5_4r3_5p1cy_4f}
Sum up
- GitHub Packages exposes the GHCR artifact when the profile itself is dry
- raw image layers recover a favicon that the final container view hides
- the favicon hash identifies the dead deployment through FOFA
- URLScan preserves the first flag after the host is gone
- GitHub public events recover a deleted coordination comment
- the alternate handle leads to the active staging mirror
- staged source leaks the DNS endpoint
- DNS TXT points directly to the final Gist