https://app.hackthebox.com/challenges/119

Description

Let’s see if you’re a QuickR soldier as you pretend to be

Exploitation

#!/usr/bin/env python3
from pyzbar.wrapper import ZBarSymbol
from pyzbar.pyzbar import decode
from pwn import remote
from PIL import Image
import struct, sys

def parse_ip_port(arg):
    return arg.split(':')[0], int(arg.split(':')[1])

if __name__ == '__main__':
    if len(sys.argv) != 2: sys.exit(f"Usage: python {sys.argv[0]} <ip:port>")
    ip, port = parse_ip_port(sys.argv[1])
    io = remote(ip, port)
    input_str = io.recvuntil(b'string:').decode('utf-8')
    qr_code = input_str[548:]
    qr_code_binary = qr_code.replace(' ', '')
    qr_code_binary = qr_code_binary.replace('\x1B[7m', '1,').replace('\x1B[0m', '')
    qr_code_binary = qr_code_binary.replace('\x1B[41m', '0,')
    qr_code_binary = qr_code_binary[0:qr_code_binary.index('\t\n')].replace('\t', '')
    qr_code_binary = qr_code_binary + ('0,' * 51) + '\n'
    qr_code_binary = qr_code_binary[:-2]
    visual = qr_code_binary.replace(',', '').replace('0', '\x1b[30;47m██\x1b[0m').replace('1', '\x1b[37;40m██\x1b[0m')
    print(visual)
    rows = qr_code_binary.count('\n')
    qr_code_binary_arr = qr_code_binary.replace('\n', '').split(',')
    size = 51, rows
    arr_size = len(qr_code_binary_arr)
    data = struct.pack('B' * arr_size, *[int(pixel) * 255 for pixel in qr_code_binary_arr])
    img = Image.frombytes('L', size, data)
    img.save('img.png')
    img.close()
    im = Image.open("img.png")
    qr_out = decode(im, symbols=[ZBarSymbol.QRCODE])
    if qr_out:
        qr_data = qr_out[0].data.decode("utf-8").replace('=', '').replace('x', '*')
        print(f"QR Data: {qr_data}")
        qr_result = str(eval(qr_data)).encode('utf-8')
        print(f"QR Result: {qr_result.decode('utf-8')}")
        io.sendline(qr_result)
    else:
        print("No QR code found in the image.")
    response = io.recvall().replace(b" \x1b[1m\x1b[92m",b"\x1b[1m\x1b[92m").decode('utf-8')
    print(response)

Summary

QuickR: reduce the custom rules to a scriptable check and use the smallest reliable path to the flag.