Blind Spot

Contents

Blind Spot#

Helpers#

import base64
import io
import numpy as np
import os
import requests
import time
from dotenv import load_dotenv
from PIL import Image

load_dotenv()
API_KEY = os.environ["API_KEY"]
URL_QUERY = "https://%s.crucible.dreadnode.io/score"
URL_FLAG = "https://crucible.dreadnode.io/api/challenges/%s/submit-flag"
CHALLENGE = "blindspot"

def query(data):
    response = requests.post(
        URL_QUERY % CHALLENGE,
        headers={ "X-API-Key": API_KEY },
        json={ "data": data }
    )
    return response.json()

def submit(flag):
    response = requests.post(
        URL_FLAG % CHALLENGE,
        headers={ "X-API-Key": API_KEY },
        json={ "challenge": CHALLENGE, "flag": flag }
    )
    return False if response.status_code != 200 else response.json().get("correct")

Solution#

We’re given an image of a bird and we need to add enough noise to the image to fool the detection model without changing the image too much. By experimenting with different standard deviations we found that 0.059 was fairly effective although it still requires a couple of attempts to get the flag.

image_original = Image.open("./data/bird.png")
array_original = np.array(image_original).astype(np.float32) / 255

while True:
    array = np.copy(array_original)
    noise = np.random.normal(0.0, 0.059, array.shape)
    array = (np.clip(array + noise, 0.0, 1.0) * 255).astype(np.uint8)
    image = Image.fromarray(array)
    
    buff = io.BytesIO()
    image.save(buff, format="PNG")
    data = base64.b64encode(buff.getvalue()).decode()
    
    response = query(data)
    if "flag" in response:
        print("Flag accepted:", submit(response["flag"]))
        break
    time.sleep(1)
Flag accepted: True