Note to fellow-HTBers: Only write-ups of retired HTB machines or challenges are allowed.

## Machine info ¶

QuickR [by hfz]
Let’s see if you’re a QuickR soldier as you pretend to be
Difficulty: Medium (40 points)
Release: 16 April 2020

## Recon ¶

Browsing or cURL’ing the endpoint, we get a QR code in our terminal.

``````\$ curl docker.hackthebox.eu:32169

___               _          __       _______
.'   `.            (_)        [  |  _  |_   __ \
/  .-.  \  __   _   __   .---.  | | / ]   | |__) |
| |   | | [  | | | [  | / /'`\] | '' <    |  __ /
\  `-'  \_ | \_/ |, | | | \__.  | |`\ \  _| |  \ \_
`.___.\__|'.__.'_/[___]'.___.'[__|  \_]|____| |___|

[*] Hello there! Let's see if you are an QuickR soldier, you got only 3 seconds!

<Prints QR code>

[+] It's important to realise that this is, in a real sense, an illusion: you simply need the true machine value.
[!] Decoded string: [-] Wrong!
``````

There’s also the notion of something being Wrong and having a 3 second limit.

Scanning this QR code with a smartphone, we get an equation:
`48.530023014695644 - 58.8774162315505 / 214.69427403011673 =`

So we can assume the challenge requires us to perform the following steps:

2. extract QR code
3. decode QR code
4. calculate equation
6. retrieve flag

## Tackling the challenge ¶

We definitely need to automate this whole challenge, since we can’t manually retrieve the QR code, scan it with a smartphone, solve the equation and return the solution.

### Capture the QR code ¶

The hardest part of this challenge was finding a way to convert the QR code in the terminal to one that we can scan via a script.
I first looked into a solution to screengrab the terminal, but didn’t immediately find a solution that worked for me.
Next tactic was to read the output and build an image in a kind of search and replace way.

Note that `^[` is actually a control character `Ctrl` + `Esc` followed by a square bracket.
Typing this in a console might not work because the terminal captures the control command.
I guess it might also work using `\e` or `\033` instead, but I haven’t tried.

``````def qrimg(lines ,filename):
font = ImageFont.truetype('DejaVuSansMono.ttf')
img=Image.new("1", (102,102), 1)
draw = ImageDraw.Draw(img)
y = 0
for line in lines:
line = line.decode("utf-8", "backslashreplace")
line = re.sub(r"^[ \t]*","", line)
line = re.sub(r"\[41m  \[0m","*", line)
line = re.sub(r"\[7m  \[0m","-", line)

x = 0
for c in line:
if c == "*":
draw.point((x, y), 0)
#draw.point((x, y+1), 0) # drawing 2x2 pixels
#draw.point((x+1, y), 0) # drawing 2x2 pixels
#draw.point((x+1, y+1), 0) # drawing 2x2 pixels
#elif c == "-":
#    draw.point((x, y), 1) # Adding white pixel is not needed
x+=1
#x+=2 # drawing 2x2 pixels
y += 1
#y += 2 # drawing 2x2 pixels
draw = ImageDraw.Draw(img)
img.save(filename)
#print("x: {}  y: {}".format(x, y))

print("[+] Wrote QR code image to {}".format(filename))
``````

### Scan the QR code ¶

Scanning the QR code from an image is easier, since there are Python modules readily available for this.

``````def qrdecode(filename):
result = ""

qr = qrtools.QR()
if qr.decode(filename):
#conn.send(qr.data)
result = qr.data

print("[+] QR Code decodes to: '{}'".format(result))
return result
``````

### Solving the equation ¶

Easy peasy

``````def solve(equation):
equation = re.sub("x", "*", equation)
equation = re.sub("=", "", equation)
equation = re.sub(r"^[ \t]*", "", equation) # trim whitespace, might not be necessary
equation = re.sub(r"[ \t]*\$", "", equation)) # trim whitespace, might not be necessary
print("[+] Cleaned equation: '{}'".format(equation))

result = eval(equation)
print("[+] Equation results to: '{}'".format(result))

return result
``````

Finally we send our answer back using the same socket and retrieve the flag.

Make sure you end your output with a newline.
This almost got me pulling my hair out.

``````conn.sendline("{}".format(result))
print("[+] Send '{}' to {}:{}".format(result, hostname, port))

``````

## Solution ¶

Combining all of this together and running our final script, we get:

``````\$ ./QuickR.py
[+] Opening connection to docker.hackthebox.eu on port 31607: Done
[+] Wrote QR code text to quickr.txt
[+] Wrote QR code image to quickr.png
[+] QR Code decodes to: '74.22252072924252 - 5.833454784680273 / 379.68114191784696 = '
[+] Cleaned equation: '74.22252072924252 - 5.833454784680273 / 379.68114191784696'
[+] Equation results to: '74.20715664043048'
[+] Send '74.20715664043048' to docker.hackthebox.eu:31607
[+] Receiving all data: Done (263B)
[*] Closed connection to docker.hackthebox.eu port 31607

[+] It's important to realise that this is, in a real sense, an illusion: you simply need the true machine value.
[!] Decoded string: [+] Congratulations! Here is your flag: HTB{@lriGh7_1_tH1nK_y0u`r3_QuickR_s0ldi3r}
``````

And this is the full script:

``````#!/usr/bin/env python3

### Solution for QuickR by hfz on HackTheBox.eu

import re
import PIL
from PIL import ImageFont
from PIL import Image
from PIL import ImageDraw
from pwn import *
import qrtools

def qrtxt(lines, filename):
with open(filename,"w") as f:
for line in input:
line = line.decode("utf-8", "backslashreplace")
f.write("{}\n".format(line))
print("[+] Wrote QR code text to {}".format(filename))

def qrimg(lines ,filename):
font = ImageFont.truetype('DejaVuSansMono.ttf')
img=Image.new("1", (102,102), 1)
draw = ImageDraw.Draw(img)
y = 0
for line in lines:
line = line.decode("utf-8", "backslashreplace")
line = re.sub(r"^[ \t]*","", line)
line = re.sub(r"\\[41m  \\[0m","*", line)
line = re.sub(r"\\[7m  \\[0m","-", line)

x = 0
for c in line:
if c == "*":
draw.point((x, y), 0)
#draw.point((x, y+1), 0) # drawing 2*2 pixels
#draw.point((x+1, y), 0) # drawing 2*2 pixels
#draw.point((x+1, y+1), 0) # drawing 2*2 pixels
#elif c == "-":
#    draw.point((x, y), 1) # Adding white pixel is not needed
x+=1
#x+=2 # drawing 2*2 pixels
y += 1
#y += 2 # drawing 2*2 pixels
draw = ImageDraw.Draw(img)
img.save(filename)
#print("x: {}  y: {}".format(x, y))

print("[+] Wrote QR code image to {}".format(filename))

def qrdecode(filename):
result = ""

qr = qrtools.QR()
if qr.decode(filename):
#conn.send(qr.data)
result = qr.data

print("[+] QR Code decodes to: '{}'".format(result))
return result

def solve(equation):
equation = re.sub("x", "*", equation)
equation = re.sub("=", "", equation)
equation = re.sub(r"^[ \t]*", "", equation)
equation = re.sub(r"[ \t]*\$", "", equation)
print("[+] Cleaned equation: '{}'".format(equation))

result = eval(equation)
print("[+] Equation results to: '{}'".format(result))

return result

def output(lines):
for line in lines:
# line = line.decode("utf-8", "backslashreplace")
print("{}".format(chr(line)), end = '')

hostname = 'docker.hackthebox.eu'
port = 31607

conn = remote(hostname, port)
conn.recvuntil("you got only 3 seconds!")
conn.recvlines(3)
input = conn.recvlines(51)

qrimage = "quickr.png"
qrtext = "quickr.txt"
qrtxt(input, qrtext)
qrimg(input, qrimage)
equation = qrdecode(qrimage)
result = solve(equation)

conn.sendline("{}".format(result))
print("[+] Send '{}' to {}:{}".format(result, hostname, port))