-
-
Save bburky/58edd7ce00cd4405429269695568fe2c to your computer and use it in GitHub Desktop.
PlaidCTF 2019: A Whaley Good Joke
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import tarfile | |
import json | |
from datetime import datetime | |
import sys | |
import shutil | |
import tempfile | |
from pathlib import Path | |
from io import BytesIO | |
import hashlib | |
# https://stackoverflow.com/a/44873382 | |
def sha256sum(filename): | |
h = hashlib.sha256() | |
b = bytearray(128*1024) | |
mv = memoryview(b) | |
with open(filename, 'rb', buffering=0) as f: | |
for n in iter(lambda : f.readinto(mv), 0): | |
h.update(mv[:n]) | |
return h.hexdigest() | |
image_filename = sys.argv[1] | |
def layer_timestamps(image_dir): | |
for layer_tar in Path(image_dir).glob("*/layer.tar"): | |
with tarfile.open(layer_tar) as layer: | |
max_timestamp = max(info.mtime for info in layer) | |
yield max_timestamp, layer_tar | |
with tempfile.TemporaryDirectory() as tmpdir: | |
with tarfile.open(image_filename, 'r:gz') as image: | |
image.extractall(path=tmpdir) | |
with Path(tmpdir, "manifest.json").open('r') as f: | |
manifest = json.load(f) | |
manifest_layers = manifest[0]["Layers"] = [] | |
config_filename = manifest[0]["Config"] | |
with Path(tmpdir, config_filename).open('r') as f: | |
config = json.load(f) | |
diff_ids = config["rootfs"]["diff_ids"] = [] | |
print("Sorting layers...") | |
layers = sorted(layer_timestamps(tmpdir)) | |
for timestamp, layer_tar in layers: | |
layer_hash = layer_tar.parts[-2] | |
layer_tar = Path(tmpdir, layer_hash, "layer.tar") | |
layer_diffid = sha256sum(layer_tar) | |
manifest_layers.append(f"{layer_hash}/layer.tar") | |
diff_ids.append(f"sha256:{layer_diffid}") | |
print("Rebuilding image...") | |
with tarfile.open(f"{image_filename}-fixed", 'w:gz') as image_fixed: | |
image_fixed.add(Path(tmpdir, "repositories"), arcname="repositories") | |
# Add layer files | |
for image_file in Path(tmpdir).glob("*/*"): | |
# TODO: skip json? | |
image_fixed.add(image_file, arcname=image_file.relative_to(tmpdir)) | |
# print(image_file) | |
manifest_file = BytesIO(json.dumps(manifest).encode("utf-8")) | |
manifest_tarinfo = tarfile.TarInfo("manifest.json") | |
manifest_tarinfo.size = manifest_file.getbuffer().nbytes | |
image_fixed.addfile(manifest_tarinfo, manifest_file) | |
config_file = BytesIO(json.dumps(config).encode("utf-8")) | |
config_tarinfo = tarfile.TarInfo(config_filename) | |
config_tarinfo.size = config_file.getbuffer().nbytes | |
image_fixed.addfile(config_tarinfo, config_file) | |
# Load with: | |
# docker load -i pctf-whales_169aeb74f82dcdceb76e36a6c4c22a89-fixed | |
# Run: | |
# docker run --rm -it pctf-whales:latest ./flag.sh | |
# This soluition has files 12 and 15 missing some reason. | |
# I extracted them manually. | |
# pctf{1_b3t_u_couldnt_c0nt4in3r_ur_l4ught3r} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment