{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# We're just importing some stuff to make sure the challenges and helper code works.\n# Feel free to import anything else you need (or solve in a different language), but if you overwrite these, provided code may not work.\n\nimport pandas as pd\nimport numpy as np\nimport os\nimport requests\nfrom IPython.display import Image as Ima\nfrom IPython.display import clear_output, display\nfrom PIL import Image as Im\nfrom PIL import Image\nfrom PIL import ImageOps\nfrom torch.utils.data import Dataset, DataLoader\nimport torch\nimport joblib\nimport matplotlib.pyplot as plt\nimport json\nimport base64\nimport shutil\nimport warnings\nwarnings.filterwarnings(\"ignore\")\n\nimport tensorflow as tf\ntf.compat.v1.disable_eager_execution()\nfrom keras.applications.mobilenet import preprocess_input\nfrom keras.models import load_model\nfrom keras.preprocessing.image import img_to_array, array_to_img\nfrom PIL import Image, ImageOps\nfrom imagehash import phash\nimport numpy as np\nfrom keras import backend as K\nfrom tensorflow.keras.applications import MobileNet\n\ndir_name = \"/kaggle/input/ai-village-ctf\"","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2022-09-11T23:52:11.654117Z","iopub.execute_input":"2022-09-11T23:52:11.655230Z","iopub.status.idle":"2022-09-11T23:52:20.985590Z","shell.execute_reply.started":"2022-09-11T23:52:11.655105Z","shell.execute_reply":"2022-09-11T23:52:20.983415Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# HOTTERDOG (id: hotterdog) -- 400 Points\n\n### Scenario\n\nChester submitted himself in the \"most creative hotdog\" contest. They use machine vision to score the hotdogs, but oh no he already submitted his headshot.\n\n### Objective\n\nHelp Chester classify as a hotdog, but it has to look like Chester to a human. Modify his picture to fool a classifier.","metadata":{}},{"cell_type":"code","source":"Ima(filename=f'{dir_name}/hotdog/chester.png')","metadata":{"execution":{"iopub.status.busy":"2022-09-11T23:52:20.988336Z","iopub.execute_input":"2022-09-11T23:52:20.989021Z","iopub.status.idle":"2022-09-11T23:52:21.042576Z","shell.execute_reply.started":"2022-09-11T23:52:20.988976Z","shell.execute_reply":"2022-09-11T23:52:21.041631Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"IMAGE_DIMS = (224, 224)\n# from https://tcode2k16.github.io/blog/posts/picoctf-2018-writeup/general-skills/#solution-20 :\n\n# I'm pretty sure I borrowed this function from somewhere, but cannot remember\n# the source to cite them properly.\ndef hash_hamming_distance(h1, h2):\n    s1 = str(h1)\n    s2 = str(h2)\n    return sum(map(lambda x: 0 if x[0] == x[1] else 1, zip(s1, s2)))\n\n\ndef is_similar_img(path1, path2):\n    image1 = Image.open(path1)\n    image2 = Image.open(path2)\n\n    dist = hash_hamming_distance(phash(image1), phash(image2))\n    return dist <= 1\n\n\ndef prepare_image(image, target=IMAGE_DIMS):\n    # if the image mode is not RGB, convert it\n    if image.mode != \"RGB\":\n        image = image.convert(\"RGB\")\n\n    # resize the input image and preprocess it\n    image = image.resize(target)\n    image = img_to_array(image)\n    image = np.expand_dims(image, axis=0)\n    \n    image = preprocess_input(image)\n    # return the processed image\n    return image\n\n\ndef create_img(img_path, img_res_path, model, target_str, target_idx, des_conf=0.95):\n    original_image = Image.open(img_path).resize(IMAGE_DIMS)\n    original_image = prepare_image(original_image)\n\n    model_input_layer = model.layers[0].input\n    model_output_layer = model.layers[-1].output\n\n    max_change_above = original_image + 0.01\n    max_change_below = original_image - 0.01\n\n    # Create a copy of the input image to hack on\n    hacked_image = np.copy(original_image)\n    \n    # How much to update the hacked image in each iteration\n    learning_rate = 0.01\n\n    # Define the cost function.\n    # Our 'cost' will be the likelihood out image is the target class according to the pre-trained model\n    cost_function = model_output_layer[0, target_idx]\n\n    # We'll ask Keras to calculate the gradient based on the input image and the currently predicted class\n    # In this case, referring to \"model_input_layer\" will give us back image we are hacking.\n    \n    # this supported only in TF1 gradient_function = K.gradients(cost_function, model_input_layer)[0]\n    gradient_function = K.gradients(cost_function, model_input_layer)[0]\n    #with tf.GradientTape() as gtape:\n    #    gradient_function = gtape.gradient(cost_function, model_input_layer)[0]\n    \n    # Create a Keras function that we can call to calculate the current cost and gradient\n    grab_cost_and_gradients_from_model = K.function([model_input_layer, K.learning_phase()], [cost_function, gradient_function])\n\n    cost = 0.0\n\n    # In a loop, keep adjusting the hacked image slightly so that it tricks the model more and more\n    # until it gets to at least 80% confidence (here 99%)\n    # original code and comment: https://medium.com/@ageitgey/machine-learning-is-fun-part-8-how-to-intentionally-trick-neural-networks-b55da32b7196\n    while cost < 0.99:\n        # Check how close the image is to our target class and grab the gradients we\n        # can use to push it one more step in that direction.\n        # Note: It's really important to pass in '0' for the Keras learning mode here!\n        # Keras layers behave differently in prediction vs. train modes!\n        cost, gradients = grab_cost_and_gradients_from_model([hacked_image, 0])\n\n        # Move the hacked image one step further towards fooling the model\n        # print gradients\n        hacked_image += np.sign(gradients) * learning_rate\n\n        # Ensure that the image doesn't ever change too much to either look funny or to become an invalid image\n        hacked_image = np.clip(hacked_image, max_change_below, max_change_above)\n        hacked_image = np.clip(hacked_image, -1.0, 1.0)\n\n        #print(\"Model's predicted likelihood that the image is a tree frog: {:.8}%\".format(cost * 100))\n        print(\"Model's predicted likelihood that the image is a {}: {:.8}%\".format(target_str, cost * 100))\n\n    hacked_image = hacked_image.reshape((224,224,3))\n    img = array_to_img(hacked_image)\n    img.save(img_res_path)","metadata":{"execution":{"iopub.status.busy":"2022-09-11T23:52:21.043869Z","iopub.execute_input":"2022-09-11T23:52:21.044404Z","iopub.status.idle":"2022-09-11T23:52:21.059835Z","shell.execute_reply.started":"2022-09-11T23:52:21.044367Z","shell.execute_reply":"2022-09-11T23:52:21.058554Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"IMAGE_DIMS = (224, 224)\n# ImageNet classes: https://gist.github.com/yrevar/942d3a0ac09ec9e5eb3a\nHOTDOG_IDX = 934\nHOTDOG_STR = 'hotdog'\n\nimg_true_path = f'{dir_name}/hotdog/chester.png'\nimg_fake_path = './chester_hotdog.png'\nmodel = MobileNet()\n\ncreate_img(img_true_path, img_fake_path, model, HOTDOG_STR, HOTDOG_IDX)\nassert is_similar_img(img_true_path, img_fake_path)","metadata":{"execution":{"iopub.status.busy":"2022-09-11T23:52:21.062567Z","iopub.execute_input":"2022-09-11T23:52:21.063687Z","iopub.status.idle":"2022-09-11T23:52:29.443612Z","shell.execute_reply.started":"2022-09-11T23:52:21.063614Z","shell.execute_reply":"2022-09-11T23:52:29.442494Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"Image.open(f'{dir_name}/hotdog/chester.png')","metadata":{"execution":{"iopub.status.busy":"2022-09-11T23:52:29.445182Z","iopub.execute_input":"2022-09-11T23:52:29.445604Z","iopub.status.idle":"2022-09-11T23:52:29.947763Z","shell.execute_reply.started":"2022-09-11T23:52:29.445577Z","shell.execute_reply":"2022-09-11T23:52:29.946425Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#print(np.array(Image.open(f'{dir_name}/hotdog/chester.png')).shape)\nImage.open('./chester_hotdog.png').resize((1200, 900))","metadata":{"execution":{"iopub.status.busy":"2022-09-11T23:52:29.949160Z","iopub.execute_input":"2022-09-11T23:52:29.949421Z","iopub.status.idle":"2022-09-11T23:52:30.520412Z","shell.execute_reply.started":"2022-09-11T23:52:29.949397Z","shell.execute_reply":"2022-09-11T23:52:30.519348Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Submission Helper\n\nIMAGE_DIMS = (224, 224)\n\n#img = Im.open(f\"{dir_name}/hotterdog/chester.png\")\nimg = Im.open(img_fake_path)\nimg = img.resize(IMAGE_DIMS)\nimg_bytes = img.tobytes()\nb64_img_bytes = base64.urlsafe_b64encode(img_bytes)\n\ntry:\n    r = requests.post(\"https://hotterdog.fly.dev/score\", data=json.dumps({\"input\": b64_img_bytes.decode()}))\n    print(r.text)\nexcept requests.exceptions.ConnectionError:\n    print(\"Connection problems. Contact the CTF organizers.\")","metadata":{"execution":{"iopub.status.busy":"2022-09-11T23:52:30.522145Z","iopub.execute_input":"2022-09-11T23:52:30.522522Z","iopub.status.idle":"2022-09-11T23:52:31.382552Z","shell.execute_reply.started":"2022-09-11T23:52:30.522494Z","shell.execute_reply":"2022-09-11T23:52:31.380940Z"},"trusted":true},"execution_count":null,"outputs":[]}]}