QShell is running on nc spbctf.ppctf.net 37338
Grab the flag
When a challenge specifies a nc
command it means that we should be making a
TCP connection with that host and port.
So, Lets see what happens when we run the command.
$ nc spbctf.ppctf.net 37338
█████████████████████████████████
█████████████████████████████████
█████████████████████████████████
█████████████████████████████████
████ █ █ █ █ ████
████ █████ █ ██ █ █ █████ ████
████ █ █ ███ █ █ █ █ █ █ ████
████ █ █ █ █████ █ █ █ ████
████ █ █ █ █ █ █ ████
████ █████ █ ███ █ █ █ █████ ████
████ █ █ █ █ █ █ ████
████████████████ █ ██████████████
███████ ██ ██ █ ██ ███ █ ████
███████ █ █ ██ █ ██ █ ████
████ ████ ████ █ █ ██ ████
█████ ████ █ ███ ███ ███████
████ █ █ █ ██ █ ██ █ ███████
████████ ██ █ █ ███ █████ ████
████ ██ ██ ██ ██████ █ ████
█████ █ ██████ █ █ █ ██ ████
████ █ █ ██ ███ █ █ █ ████
████████████ ██ ███ █ ████
████ ███ █ █ █ █ █ ██ ████
████ █████ ████ █ ██ ███ █████
████ █ █ ██ ███ █ █ █████
████ █ █ █ █ ████ █ █ █████
████ █ █ ██ █ █ █ ███ ████
████ █████ ███ ██ ████ ███████
████ █████ ███ ██ ████
█████████████████████████████████
█████████████████████████████████
█████████████████████████████████
█████████████████████████████████
.
We get a QR code which decodes to sh-5.0$
, so it looks like we have a shell
that operates on QR codes delimited by .
characters.
Since the codes are in utf-8 text and all the decoders we could take images, we
need to convert the text into an image.
The white text pixels are Full Block U+2588
unicode runes and the black text
pixels are space characters.
def qr_decode(text):
from pyzbar.pyzbar import decode # QR decoder
from PIL import Image
from itertools import chain
rows = []
for line in text.split('\n'):
if not line or line[0] != WHITE:
continue
row = [c == WHITE for c in line]
# QR decoder wants larger than 1x1 blocks
row = list(chain(*zip(row, row)))
rows.append(row)
rows.append(row)
size = (len(rows[0]), len(rows))
im = Image.new('1', size)
im.putdata(list(chain(*rows)))
decoded = decode(im)[0]
return decoded.data
We will also want to convert strings into QR codes.
def qr_encode(text):
import qrcode
qr = qrcode.QRCode(box_size=1, border=4)
qr.add_data(text)
qr.make(fit=True)
im = qr.make_image().convert('1')
rows = []
row = []
for i, c in enumerate(im.getdata()):
if i != 0 and i % im.width == 0:
rows.append(''.join(row))
row = []
row.append(WHITE if c else BLACK)
return '\n'.join(rows)
Now that we have our encoder and decoder we can assemble it all into a loop to get us an interactive shell that looks like a normal one!
def qshell(host, port):
conn = connect(host, port)
conn.readuntil('.') # skip the first since it is always 'sh-5.0$ '
while 1:
cmd = raw_input('$ ')
cmd = bytearray(qr_encode(cmd), 'utf-8')
try:
conn.sendline(cmd)
conn.sendline('.')
out = conn.readuntil('.')
except EOFError:
return
out = qr_decode(out.decode('utf-8'))
print(out, end='')
Putting everything together with a little bit of preamble.
#!/usr/bin/env python
from __future__ import print_function
from pwn import *
WHITE = b'\xe2\x96\x88'.decode('utf-8')
BLACK = b' '.decode('utf-8')
def qr_decode(...):
...
def qr_encode(...):
...
def qshell(...):
...
qshell('spbctf.ppctf.net', 37338)
Now we get can go find the flag!
root@b1abea01ecf3:/ctf# ./qshell.py
[+] Opening connection to spbctf.ppctf.net on port 37338: Done
$ ls
1.py
2.py
docker-compose.yml
Dockerfile
flag.txt
log.txt
qweqwe.png
rex.txt
runserver.sh
run.sh
$ cat flag.txt
cybrics{QR_IS_MY_LOVE}
$
[*] Closed connection to spbctf.ppctf.net port 37338
root@b1abea01ecf3:/ctf#