72 solves / 462 points
Legend has it there is a secret somewhere in this library. Unfortunately, all of our Babel Fishes have gotten lost and the books are full of junk.
Note: You do not need a copy of Minecraft to play this challenge.
The flag is in standard flag format.
Author: WholeWheatBagels
This challenge was based on the Babel library. The objective was to find a flag inside one of an insane number of books based on a Minecraft world. Obviously, it is impossible to read them all in time and get the flag. So, we had to find a way to parse .mca files that contain minecraft's chunks information to extract all the book's content and grep the flag.
For this challenge, I tried a lot of tools, but I didn't find one that makes the job. Thereby, I choised to use the "ansil-parser" python library to make it. The problem ? This lib has no documentation and I had to understand how does it works by my own. So, I had to roll up my sleeves and use python's introspection function to learn how does it works!
# Import .mca file
region = anvil.Region.from_file(absolutePath)
# Select a specific chunk (regions are 32x32 chunks size)
chunk = anvil.Chunk.from_region(region, x, y)
# List chunk informations:
chunk.data
OUTPUT:
{TAG_String('Status'): full, TAG_Int('zPos'): 4, TAG_Long('LastUpdate'): 198515, TAG_Int_Array('Biomes'): [1024 int(s)], TAG_Long('InhabitedTime'): 94595, TAG_Int('xPos'): -14, TAG_Compound('Heightmaps'): {4 Entries}, TAG_List('TileEntities'): [3 TAG_Compound(s)], TAG_Byte('isLightOn'): 1, TAG_List('TileTicks'): [0 _TAG_End(s)], TAG_List('Sections'): [9 TAG_Compound(s)], TAG_List('PostProcessing'): [16 TAG_List(s)], TAG_Compound('Structures'): {2 Entries}, TAG_List('LiquidTicks'): [0 _TAG_End(s)]}
# Get chunk TileEntities (TileEntities are like simplified Entities that are bound to a Block.)
chunk.data.get('TileEntities')
# Select the Book object if insine the block
chunk.data.get('TileEntities')[0].get('Book')
# Get book information
chunk.data.get('TileEntities')[0].get('Book').get('tag')
OUTPUT:
{TAG_String('filtered_title'): test book, TAG_List('pages'): [10 TAG_String(s)], TAG_String('title'): test book, TAG_String('author'): WholeWheatBagels, TAG_Byte('resolved'): 1}
# Get all pages in a list
chunk.data.get('TileEntities')[0].get('Book').get('tag').get('pages')
After taking a little hour, I finally succeeded to understand how to dump all book's content of one .mca file! Let's loop on all of them:
from json import loads
import anvil
import os
library = os.listdir(".")
for elt in library:
if ".mca" in elt:
absolutePath = os.path.join(os.path.abspath("."), elt)
region = anvil.Region.from_file(absolutePath)
for chunk_x in range(32):
for chunk_y in range(32):
try:
chunk = anvil.Chunk.from_region(region, chunk_x, chunk_y)
chunk.data.get('TileEntities')[0].get('Book')
except:
continue
TitleEntities = chunk.data.get('TileEntities')
for book_n in range(len(TitleEntities)):
try:
book = chunk.data.get('TileEntities')[book_n].get('Book').get('tag')
except:
continue
title = book.get('title')
filtered_title = book.get('filtered_title')
author = book.get('author')
pages = book.get('pages')
for page_n in range(len(pages)):
page = loads(str(pages[page_n]))['text']
print(page)
Using a simple grep command on the output and tada the flag appears! 🎉
Flag: dam{b@B3l5-b@bBL3}