๐ŸŽฏ UIUCTF 2022: AR Pwny

Contest Date: 30.07.2022 Solved: During The Contest Score: 50 Difficulty: Beginner

๐Ÿงพ Description


Welcome to the meataverse!


author: ian5v

๐Ÿฆ Solution TL;DR

๐Ÿ”Ž Detailed Solution

๐Ÿ“Œ Step 1 : Web Inspection

Navigating to the challenge using a regular MS Edge browser, the webpage is basically a fancy SIGpwny logo in interactive 3D view.


Switch to mobile device? That's interesting! Open view source page with CTRL + U hotkey.

<!-- redacted section -->
<meta name="twitter:card" content="player" />
<meta name="twitter:title" content="hey there ctf player >:o) why dont u solve my challenge :^)" />
<meta name="twitter:image" content="0" />

<!-- redacted section -->
<meta name="twitter:player:stream" content="https://video.twimg.com/ext_tw_video/1553060639530225664/pu/vid/920x720/qT8hHQq3KZUFi7uo.mp4?tag=12" />

<!-- redacted section -->
<script type="module" src="model-viewer.min.js"></script>

<model-viewer style="width: 100%; height: 80%" src="pwny.glb" ar ar-modes="webxr scene-viewer quick-look" seamless-poster shadow-intensity="1" camera-controls enable-pan></model-viewer>

<!-- redacted section -->

Sweet! Looks like there are couple of suspicious signs with useful info:

๐Ÿ“Œ Step 2 : What's in the Blackbox? ๐Ÿ—ƒ

Before proceeding into forensics of the .glb data, let's follow the challenge instructions first.

๐Ÿ“Œ Step 3 : Whitebox ๐Ÿ“ฆ Forensics

Running a quick string check with strings tool gives following results:

bijoy@kali:~/Desktop/uiuctf_22/web/pwny$ strings pwny.glb
JSON{"asset":{"generator":"Khronos glTF Blender I/O v3.2.40","version":"2.0"},"scene":0,"scenes":[{"name":"Scene","nodes":[0,1,2,3,4,5,6,7,8,9,10,11,12]}],"nodes":[{"mesh":0,"name":"flag-firsthalf","rotation":[-0.7071068286895752,-0.7071068286895752,0,3.0908616110991716e-08],"scale":[2.5827651023864746,2.5827651023864746,2.582765579223633],"translation":[2.0828332901000977,-0.5367418527603149,-2.838243007659912]}


It's clear that the file contains some JSON data (will come in handy), and a web search reveals that it is generated via a Blender add-on called glTF Importer and Exporter from Khronos Group.

Digging up a bit more, this glTF (GL Transmission Format) format turns out to be the clue. Basically, it's a stripped down JSON file that references the corresponding mesh, animation, and texture data in internal files for quick transmission needs. In contrast, it's distant cousin, our GLB format contains the glTF asset (JSON object, .bin and images) in a binary blob, just like the output suggested.

Opening the file in Visual Studio Code editor thankfully invokes a suggestion for glTF Tools extension for processing and analysis. (and that's why I always love VS Code โค)!



Using the tool, apply Import from glb operation on the file to convert it to equivalent glTF file (with a .bin file popping up as expected). Let's inspect the JSON structure. What do we have here?



Looks like the flag is sliced in two and placed into the model, but the associated data needs to be graphically reconstructed for interpretation.

๐Ÿ“Œ Step 4 : Lost in Babylon ๐Ÿ•Œ

Peeking through the extension docs, the Preview 3D Model function should render the model through the common four rendering engines (namely Babylon.js, Cesium, Filament and Three.js ).

Adding a bit of context, BabylonJS is a powerful open source GUI system for displaying 3D gaming graphics in a web browser.


Switching into the glTF outline view reveals the tree structure of the scene nodes.


Hierarchically, the data structure is arranged in the following order:

scene > node > mesh > primitive > vertices & triangles

The structural pattern suggests that rendering only the flag-firsthalf and flag-secondhalf nodes minus the rest of the scene should bring the flag to light.

BabylonJS comes with a dedicated visual debugging tool called Inspector to show model wireframes, normal vectors, texture channels and allows scene exploration.

Cool! Just the thing we need. Toggle the Inspector icon on top right.


Expand the nodes until flag primitives are visible. Then use the show/hide toggle to remove all the other non-flag nodes one by one and voila!


The model was not solid after all, rather a hollow container for the flags! Those QR codes have been hiding inside the object all along!


Scan and decode the codes, and the flag slices are obtained.

Slice 1: uiuctf{welcome_2_the_meataverse_

Slice 2: erm_i_meant_pwnyverse}

Combining both, the final flag is obtained. โœŒ

โ›ณ Flag


๐Ÿงฒ Alternative Solutions

Since the model was hollow, looking carefully inside the object using an AR app (see ๐Ÿ“Œ STEP-2) would have given away the QR codes pretty early (and save a lot of time โŒš)! My teammate solved it this way.


๐Ÿ™ Acknowledgements

Regardless of approach, the challenge is pretty fun to solve. Credit goes to ian5v from SIGpwny.