arrow_backUS Cyber Games 2026
Forensicsmedium

Meshage In A Bottle

by Pavel Knespl (capyplivl)

A 3D asset portal exposes a "deprecated" versioned directory with live directory indexing. A backup file named .sys is actually certutil -encode armored base64 of a binary STL model. The flag is spelled out by the model's extruded geometry, not present as a string in the bytes.

Solve

  1. Map the app. The landing page hints that /assets_production_system_v2/ is deprecated in favor of a v3 pipeline. Indexing is claimed "disabled" but is live on v3. Start the instance, then:
    curl -s https://<target>/assets_production_system_v3/
    curl -s https://<target>/assets_production_system_v3/bak/
    
    The v3 listing contains bak/, which holds file_backup.sys.
  2. Download the backup. Its header is -----BEGIN CERTIFICATE----- followed by base64, i.e. certutil -encode output, not a real cert:
    curl -s https://<target>/assets_production_system_v3/bak/file_backup.sys -o file_backup.sys
    head -c 60 file_backup.sys
    
  3. Strip the PEM lines and base64-decode to recover a binary STL (OpenSCAD Model header, 5952 triangles). strings shows no flag; it is pure geometry. Bounding box X 0-160, Y 0-25, Z 0-3 (flat extruded text):
    import base64, re
    body = re.sub(r'-----[^-]+-----', '', open('file_backup.sys').read())
    open('decoded.stl','wb').write(base64.b64decode(''.join(body.split())))
    
  4. Render the model. Project only the vertical wall faces (triangles with |normal.z| < 0.3) onto the XY plane to reveal the extruded text:
    import struct, matplotlib; matplotlib.use('Agg')
    import matplotlib.pyplot as plt
    from matplotlib.collections import LineCollection
    raw = open('decoded.stl','rb').read(); n = struct.unpack('<I', raw[80:84])[0]
    off, segs = 84, []
    for _ in range(n):
        rec = raw[off:off+50]; off += 50
        nx,ny,nz = struct.unpack('<3f', rec[:12]); v = struct.unpack('<9f', rec[12:48])
        if abs(nz) < 0.3:
            p = [v[0:2], v[3:5], v[6:8]]
            segs += [(p[0],p[1]),(p[1],p[2]),(p[2],p[0])]
    ax = plt.subplots(figsize=(32,6))[1]
    ax.add_collection(LineCollection(segs, colors='black', linewidths=0.6))
    ax.set_xlim(-2,162); ax.set_ylim(-2,27); ax.set_aspect('equal'); ax.axis('off')
    plt.savefig('render_outline.png', dpi=150, bbox_inches='tight', facecolor='white')
    
    The rendered text reads the flag.

Flag: SVIBGR{n3v3r_d1sm1ss_th3_f1n3_4rts}