Solution de OliverSwift pour QR Code

misc

29 janvier 2025

Utilitaires sous Linux

On installe les paquets qui vont nous servir pour décoder les différentes “encapsulation” de la charge envoyée.

Sur distributions basées sur Debian/Ubuntu (mais les paquets similaires existent pour les autres distributions) :

  • coreutils : commande base64, pour le décodage Base 64. Et printf en ligne de commande.
  • gzip : commande gzip, pour la décompression Zlib
  • zbar-tools : zbarimg pour décoder les QRCodes.
  • mawk : awk, pour filtrage intelligent de la sortie de zbarimg.

Il y a de grandes chances que base64, printf, gzip et awk soient déjà présents.

Zbarimg est un utilitaire puissant pour exploiter les QRCodes. Il repose sur ImageMagick pour supporter un grand nombre de format d’images (entre autres).

Shell de décodage et calcul

#!/bin/bash
exec 2>/dev/null
base64 -i -d | cat <(printf "\x1f\x8b\x08\x00\x00\x00\x00\x00") - | gzip -qdc | zbarimg -q - | awk -F : '{ t = t+$2} END { print t}'
  • base64: Il prend une charge base64 et la décode en binaire.
  • cat + printf: Afin que gzip puisse décoder une charge zlib on préfixe la charge avec le magic des fichiers GZIP (astuce ici).
  • gzip: décompresse la charge
  • zbarimg: décode tous les QRCodes présents dans l’image et fournit ligne par ligne les contenus
  • awk: filtre les lignes pour récupérer le texte du qrcode (au format QR-Code:nnnnnnnnn) et en profite pour faire la somme.

Python d’interfaçage

On écrit un shell python utilisant ‘pwn’ pour dialoguer avec le docker (localhost:4000) et le shell de décodage.

from pwn import *

#context.log_level = "DEBUG"  # or INFO, WARNING, ERROR

# Connect to docker application via TCP socket
r = remote("localhost", 4000)

# Wait for "Are you ready? [Y/N]" and prompt >>
r.recvuntil(b">> ")

# Reply Yes
r.sendline(b"Y")

# Get the base64 payload
b64 = r.recvuntil(b'\n')

# Start decoding shell
c = process("./flag.sh")

# Send payload to decoding shell
c.sendline(b64)

# Close decoding shell input to trigger it
c.shutdown()

# Wait for sum
resp = c.recvuntil(b'\n')

# Wait to 'What is you answer?' and prompt >>
r.recvuntil(b">> ")

# Send sum
r.sendline(resp)

# Wait for replay
flag = r.recv()

# Show reply, hopefully the flag
print(flag.decode())

Final

On exécute le script python:

$ python3 flag.py
[+] Opening connection to localhost on port 4000: Done
[+] Starting local process './flag.sh': pid 22771
Congrats! Here is your flag: ECSC{e076963c132ec49bce13d47ea864324326d4cefa}

[*] Process './flag.sh' stopped with exit code 0 (pid 22771)
[*] Closed connection to localhost port 4000

On obtient notre flag en récompense.