keyboard_arrow_up

title: Library of Babel
date: Nov 09, 2021
tags: Writeups DamCTF Misc


Library of Babel

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}