Description
QShell is running on nc spbctf.ppctf.net 37338
Grab the flag
When we connect on the server, we receive the following question:
$ nc spbctf.ppctf.net 37338
█████████████████████████████████
█████████████████████████████████
█████████████████████████████████
█████████████████████████████████
████ █ █ █ █ ████
████ █████ █ ██ █ █ █████ ████
████ █ █ ███ █ █ █ █ █ █ ████
████ █ █ █ █████ █ █ █ ████
████ █ █ █ █ █ █ ████
████ █████ █ ███ █ █ █ █████ ████
████ █ █ █ █ █ █ ████
████████████████ █ ██████████████
███████ ██ ██ █ ██ ███ █ ████
███████ █ █ ██ █ ██ █ ████
████ ████ ████ █ █ ██ ████
█████ ████ █ ███ ███ ███████
████ █ █ █ ██ █ ██ █ ███████
████████ ██ █ █ ███ █████ ████
████ ██ ██ ██ ██████ █ ████
█████ █ ██████ █ █ █ ██ ████
████ █ █ ██ ███ █ █ █ ████
████████████ ██ ███ █ ████
████ ███ █ █ █ █ █ ██ ████
████ █████ ████ █ ██ ███ █████
████ █ █ ██ ███ █ █ █████
████ █ █ █ █ ████ █ █ █████
████ █ █ ██ █ █ █ ███ ████
████ █████ ███ ██ ████ ███████
████ █████ ███ ██ ████
█████████████████████████████████
█████████████████████████████████
█████████████████████████████████
█████████████████████████████████
.
That server waits our answer. So if you type anything, press Enter, type dot and press Enter again, it answers: list index out of range
. So we know how to answer to server. When you decode this QRCode manually, it answers sh-5.0$
, a prompt shell. Like the description title says (QShell), we have answer to server with another QRCode that decodes some interactive shell command. So diofeher (Diógenes) and me made this code below in Python 3. Enjoy it!
#!/usr/bin/python3
from PIL import Image
import numpy as np
from qrdecode import qrdecode
import pyqrcode
import nclib
def save_into_image(arr, filename, second=False):
if not second:
arr = np.array(arr[:-1])
size = len(arr)
else:
arr = np.array(arr[1:-1])
size = len(arr)
arr = arr.reshape((size, size)).astype('uint8')*255
im = Image.fromarray(arr)
im.save(filename)
def qrcode_to_text(filename):
qr = qrdecode.decode(filename=filename)
return qr
def text_to_qrcode(text):
img = pyqrcode.create(text)
arr = img.text()
resp = arr.replace('0', '\u2588').replace('1', ' ')
return resp
def read_content(text):
text = text.replace(b'\xe2\x96\x88', b'1')
text = text.replace(b' ', b'0')
return text.splitlines()
def parse(content, second=False):
print('Length', len(content.splitlines()), 'x', len(content.splitlines()[0]))
content = read_content(content)
arr = convert_to_array(content)
filename = 'out.png'
save_into_image(arr, filename, second=second)
print('Recv: ', qrcode_to_text(filename))
def convert_to_array(lines):
resp = []
for line in lines:
try:
resp.append([int(c) for c in line.decode()])
except ValueError as e:
pass
return resp
class Client(object):
def __init__(self):
self.conn = nclib.Netcat(('spbctf.ppctf.net', 37338), verbose=False)
def read(self, second=False):
content = self.conn.read_until(b'.')
parse(content, second=second)
def send(self, text):
req = text_to_qrcode(text)
out = str.encode(req) + b'\n.\n'
self.conn.send(out)
def main():
client = Client()
client.read()
client.send('ls\n')
client.read(second=True)
client = Client()
client.read()
client.send('cat flag.txt\n')
client.read(second=True)
main()
Results:
$ python3 qshell.py
Length 35 x 99
Recv: sh-5.0$
Length 64 x 0
Recv: 1.py
2.py
docker-compose.yml
Dockerfile
flag.txt
log.txt
qweqwe.png
rex.txt
runserver.sh
run.sh
Length 35 x 99
Recv: sh-5.0$
Length 40 x 0
Recv: cybrics{QR_IS_MY_LOVE}
Flag: cybrics{QR_IS_MY_LOVE}