{"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":"# AI Village Capture the Flag🚩 @ DEFCON \n\n## All but Secret Sloth and Crop2 [LB 0.842] Solution \n\n\n### Description \nHelp Henry 👾Hacker👾 get to Homecoming during DEFCON30 -- Brought to you by the AI Village! In this series of challenges, you'll be interacting with various machine learning🤖 security challenges.\n\nThis Competition was a rather unique challenge for Kaggle, in just a month 668 people joined the competition and faced a lot of puzzles🧩.\n\nPeople learned a lot, some learned new aspects of machine learning and data science they didn't know before, others learned new libraries to solve adversarial attacks atuomatically, others enjoyed discussing on discord, others discussing on kaggle discussions.\n\nI for one learned how many models are easy to fool, for example I learned about [adversarial-robustness-toolbox\n](https://github.com/Trusted-AI/adversarial-robustness-toolbox) that has many attacks, both black⬛ and white box⬜. Using a white box⬜ attack was easier than I ever thought, with around 10-15 lines of code you can make an image from being a dog🐶 to being and hotdog🌭 to the neurons of a neural network.\n\nThe goal in each challenge was solving a problem to receive a flag🚩 composed of 256 characters. Those flags🚩 were used to check if a participant solved a specific challenge.\nEvery challenge could be attempted as many times as you want but the flags🚩 could be submitted up to 50 times per day.","metadata":{}},{"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.\nduring_challenge_period=False\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 torch.utils.data import Dataset, DataLoader\nimport torch\nimport joblib\nimport matplotlib.pyplot as plt\nimport json\nimport base64\nimport shutil\nimport warnings\nwarnings.filterwarnings(\"ignore\")\ndir_name = \"/kaggle/input/ai-village-ctf\"\n","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2022-09-17T15:31:09.488804Z","iopub.execute_input":"2022-09-17T15:31:09.489195Z","iopub.status.idle":"2022-09-17T15:31:09.497841Z","shell.execute_reply.started":"2022-09-17T15:31:09.489163Z","shell.execute_reply":"2022-09-17T15:31:09.496171Z"},"jupyter":{"source_hidden":true},"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-17T15:31:09.499799Z","iopub.execute_input":"2022-09-17T15:31:09.500328Z","iopub.status.idle":"2022-09-17T15:31:09.510028Z","shell.execute_reply.started":"2022-09-17T15:31:09.500295Z","shell.execute_reply":"2022-09-17T15:31:09.508366Z"},"jupyter":{"source_hidden":true},"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.\n\n## Solution\nMy first attempt at this challenge was trying adding random noise to the image but after several attempts I didn't succed so I changed the approach and added also random rotations to the image and this allowed me to find my flag for hotdog.\n\nThe code to generate the same exact image I used is in this [notebook](https://www.kaggle.com/code/pietromaldini1/hotdog-not-elegant)","metadata":{}},{"cell_type":"code","source":"Ima(filename=f'../input/temporary2/hotdog.png')","metadata":{"execution":{"iopub.status.busy":"2022-09-17T15:31:09.512379Z","iopub.execute_input":"2022-09-17T15:31:09.513413Z","iopub.status.idle":"2022-09-17T15:31:09.527163Z","shell.execute_reply.started":"2022-09-17T15:31:09.513257Z","shell.execute_reply":"2022-09-17T15:31:09.526366Z"},"jupyter":{"source_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Submission Helper\n\nIMAGE_DIMS = (224, 224)\n\nimg = Im.open(f\"../input/temporary2/hotdog.png\")\nimg = img.resize(IMAGE_DIMS)\nimg_bytes = img.tobytes()\nb64_img_bytes = base64.urlsafe_b64encode(img_bytes)\nif during_challenge_period:\n    try:\n        r = requests.post(\"https://hotdog.fly.dev/score\", data=json.dumps({\"input\": b64_img_bytes.decode()}))\n        print(r.text)\n    except requests.exceptions.ConnectionError:\n        print(\"Connection problems. Contact the CTF organizers.\")\n\n    add_flag(\"hotdog\",r.text.split(\"message\\\": \\\"\")[1].split(\"\\\"\")[0])\nelse:\n    print(\"Challenge Ended.\\nLast flag obtained 'LAO67NWH5UP1YW}WEPVSJ24VF325OGHKH5EOAZOI6LG5HSCYWIUHJP3RD6V5Z1RS0CV8HNKX9WZQY6AMY0YEFO7M7MJWY15CIE5ATMH1HQD8GHNLJRDA7HPY1HJ{TAKE'\")","metadata":{"execution":{"iopub.status.busy":"2022-09-17T15:31:09.528416Z","iopub.execute_input":"2022-09-17T15:31:09.529534Z","iopub.status.idle":"2022-09-17T15:31:09.541417Z","shell.execute_reply.started":"2022-09-17T15:31:09.529484Z","shell.execute_reply":"2022-09-17T15:31:09.540566Z"},"jupyter":{"source_hidden":true},"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":"I organized my code to generate the solutions to Math 1-2-3 and WIFI in this [noteboook](https://www.kaggle.com/code/pietromaldini1/math-challenges)","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":"markdown","source":"# Solution\n\nTo solve this challenge I opened the files and performed knee-elbow analysis to find the correct number of cluster for the data provided in the file `clusters1.npy`. ","metadata":{}},{"cell_type":"code","source":"# Submission Helper\nif during_challenge_period:\n    try:\n        r = requests.post(\"http://flags.fly.dev:5000/score\", json=json.dumps({\"challenge_id\": \"math_1\", \"submission\": \"523\"}))\n        print(r.text)\n    except requests.exceptions.ConnectionError:\n        print(\"Connection problems. Contact the CTF organizers.\")\n    add_flag(\"math_1\", r.text.split(\"The flag is \")[1].replace(\".\",\"\"))\nelse:\n    flag=\"LBBGWLSH9TRFKCQ6L8JQYTDCTIY{9ZGE01MG97X6HTCLJT1Y5PWL39WTVTE2L1IS}SEKGX2CTB505X31IM20BVFG5GMWSC3K01APJ0HHO6RJ3ONFQYBT9RIOAR0UM3MV\"\n    print(f\"Challenge Ended.\\nLast flag obtained:\\n'{flag}'\")","metadata":{"execution":{"iopub.status.busy":"2022-09-17T15:31:09.543347Z","iopub.execute_input":"2022-09-17T15:31:09.544643Z","iopub.status.idle":"2022-09-17T15:31:09.551152Z","shell.execute_reply.started":"2022-09-17T15:31:09.544607Z","shell.execute_reply":"2022-09-17T15:31:09.550420Z"},"jupyter":{"source_hidden":true},"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":"markdown","source":"# Solution\nI used sklearn [PCA ](https://scikit-learn.org/stable/modules/generated/sklearn.decomposition.PCA.html) to find the dimensionality of the data for the 3 files. ","metadata":{}},{"cell_type":"code","source":"if during_challenge_period:\n    try:\n        r = requests.post(\"http://flags.fly.dev:5000/score\", json=json.dumps({\"challenge_id\": \"math_2\", \"submission\": \"354\"}))\n        print(r.text)\n    except requests.exceptions.ConnectionError:\n        print(\"Connection problems. Contact the CTF organizers.\")\n    add_flag(\"math_2\", r.text.split(\"The flag is \")[1].replace(\".\",\"\"))\nelse:\n    flag=\"LV9PNYGGXZUD9QFO7JE16KW29L}EBI1FKE030NJ5WQTDVXBSJ3ZE9DMTA63M1RRZAE2QTFBKG3FC5AX6Y4VJO9N63P6H24L3AAZTLB0MLW0DOKRB2{JRE0O8AWJ5JTK1\"\n    print(f\"Challenge Ended.\\nLast flag obtained:\\n'{flag}'\")","metadata":{"execution":{"iopub.status.busy":"2022-09-17T15:31:09.553929Z","iopub.execute_input":"2022-09-17T15:31:09.554253Z","iopub.status.idle":"2022-09-17T15:31:09.568448Z","shell.execute_reply.started":"2022-09-17T15:31:09.554200Z","shell.execute_reply":"2022-09-17T15:31:09.567048Z"},"jupyter":{"source_hidden":true},"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":"markdown","source":"# Solution\nThis challenge was practically the same as Math Challenge 2. This allowed reusing the same code to solve it.","metadata":{}},{"cell_type":"code","source":"if during_challenge_period:\n    try:\n        r = requests.post(\"http://flags.fly.dev:5000/score\", json=json.dumps({\"challenge_id\": \"math_3\", \"submission\": f\"474\"}))\n        print(r.text)\n    except requests.exceptions.ConnectionError:\n        print(\"Connection problems. Contact the CTF organizers.\")\n    add_flag(\"math_3\", r.text.split(\"The flag is \")[1].replace(\".\",\"\"))\nelse:\n    flag=\"83DPLDFAUH0HZ791UQXWA8OOT}{YV8CLA0MK3URS0LLMQKBAU4IBDN23DOU4HTYA7K4939GB1LK_IFM9IM7IAGHIDKH3PSMA3MVWFPGF2JZKOG379PTCJTOU0VTMPTO9\"\n    print(f\"Challenge Ended.\\nLast flag obtained:\\n'{flag}'\")","metadata":{"execution":{"iopub.status.busy":"2022-09-17T15:31:09.570103Z","iopub.execute_input":"2022-09-17T15:31:09.570555Z","iopub.status.idle":"2022-09-17T15:31:09.579653Z","shell.execute_reply.started":"2022-09-17T15:31:09.570522Z","shell.execute_reply":"2022-09-17T15:31:09.578714Z"},"jupyter":{"source_hidden":true},"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":"markdown","source":"# Solution \n\nThis challenge is a combination of the math challenges seen before. In this case we had to first identify the clusters and then find the dimensionality of data inside each cluster. \n\nFirst I performed a knee-elbow analysis to find the number of clusters for the data (5), after that I used PCA for each of the clusters to find its dimensionality.","metadata":{}},{"cell_type":"code","source":"if during_challenge_period:\n    try:\n        r = requests.post(\"http://flags.fly.dev:5000/score\", json=json.dumps({\"challenge_id\": \"math_4\", \"submission\": \"54312\"}))\n        print(r.text)\n    except requests.exceptions.ConnectionError:\n        print(\"Connection problems. Contact the CTF organizers.\")\n    add_flag(\"math_4\", r.text.split(\"The flag is \")[1].replace(\".\",\"\"))\nelse:\n    flag=\"GEQ6S3GA0MLJUEOMJU6BXFMPEZL5L7WS0M8}9HPKYXSFI4P5PSPTN5IIKJC37DBRU2IBFTRI3PAKZCI2NTHVQL7RX3NHFJRSZD6{MIIZP2SA76Z5TLMY590YAPBS1AKG\"\n    print(f\"Challenge Ended.\\nLast flag obtained:\\n'{flag}'\")","metadata":{"execution":{"iopub.status.busy":"2022-09-17T15:31:09.582398Z","iopub.execute_input":"2022-09-17T15:31:09.582914Z","iopub.status.idle":"2022-09-17T15:31:09.592778Z","shell.execute_reply.started":"2022-09-17T15:31:09.582877Z","shell.execute_reply":"2022-09-17T15:31:09.590762Z"},"jupyter":{"source_hidden":true},"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":"markdown","source":"# Solution\n\nThis challenge was quite interesting, it is not far from the Math challenges but required understanding how to retrieve data from a high dimensional space, my first idea was using PCA.\n\nAfter that I stopped going forward as I didn't know what to do with the newly found 2D data. After some days I thought that 2D data is quite easy to visualize and I should try it. To my surprise the data points were placed on a spiral, a pattern too precise to be by chance.\nAfter unrolling the spiral the flag revealed itself.","metadata":{}},{"cell_type":"code","source":"# Submission Helper\nif during_challenge_period:\n    try:\n        r = requests.post(\"http://flags.fly.dev:5000/score\", json=json.dumps({\"challenge_id\": \"wifi\", \"submission\": \"FLAG{TURNED}\"}))\n        print(r.text)\n    except requests.exceptions.ConnectionError:\n        print(\"Connection problems. Contact the CTF organizers.\")\n    add_flag(\"wifi\", r.text.split(\"The flag is \")[1].replace(\".\",\"\"))\nelse:\n    flag=\"3KOIRP80NY8RE4B9N0ZS2DMM2ERZ26QFTNXOX4QBX0D6UBYT0VGY4G4AFWQM2DLYUVTGR4J34WJ6E25}EU3PJCSFZG7YCW4DJUUZNUFXWEM{A3XH1PLISBUZVO2RUGEV\"\n    print(f\"Challenge Ended.\\nLast flag obtained:\\n'{flag}'\")","metadata":{"execution":{"iopub.status.busy":"2022-09-17T15:31:09.594371Z","iopub.execute_input":"2022-09-17T15:31:09.595305Z","iopub.status.idle":"2022-09-17T15:31:09.609591Z","shell.execute_reply.started":"2022-09-17T15:31:09.595267Z","shell.execute_reply":"2022-09-17T15:31:09.608080Z"},"jupyter":{"source_hidden":true},"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":"markdown","source":"# Solution\nI attempted a lot of attacks to solve this challenge, I tried reducing the amount of noise, I tried combining the image of Chester with one of an hotdog and taking the average for each pixel. Nothing seemed to work. After long time trying and failing, I moved on to the next challenges.\n\nWhile trying to solve Theft and Salt I noticed many similarities in the output classes, so I tried using tf.keras.applications.mobilenet.MobileNet that is the model architecture used in Theft and Salt. I noticed that the class predictions were the same for the challenge and the model pretrained on imagenet.\n\nOnce I discovered this I tried using adversarial robustness toolkit to attack the network and in less than a minute I had this perfect Chester to our eyes and hotdog to MobileNet.\n\nI had already solved Theft and Salt by the time I solved hotterdog, but I tried anyway to use the same code to attempt again the two challenges and I succeded.\n\nThe code to generate the adversarial images for Hotterdog, Theft and Salt are available in this [notebook](https://www.kaggle.com/code/pietromaldini1/this-is-an-art-attack)","metadata":{}},{"cell_type":"code","source":"Ima(filename=f'../input/temporary/hotterdog.png')","metadata":{"execution":{"iopub.status.busy":"2022-09-17T15:31:09.611301Z","iopub.execute_input":"2022-09-17T15:31:09.611944Z","iopub.status.idle":"2022-09-17T15:31:09.623404Z","shell.execute_reply.started":"2022-09-17T15:31:09.611901Z","shell.execute_reply":"2022-09-17T15:31:09.622383Z"},"jupyter":{"source_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Submission Helper\n\nIMAGE_DIMS = (224, 224)\n\nimg = Im.open(f\"../input/temporary/hotterdog.png\")\nimg = img.resize(IMAGE_DIMS)\nimg_bytes = img.tobytes()\nb64_img_bytes = base64.urlsafe_b64encode(img_bytes)\nif during_challenge_period:\n    try:\n        r = requests.post(\"https://hotterdog.fly.dev/score\", data=json.dumps({\"input\": b64_img_bytes.decode()}))\n        print(r.text)\n    except requests.exceptions.ConnectionError:\n        print(\"Connection problems. Contact the CTF organizers.\")\n\n    add_flag(\"hotterdog\",r.text.split(\"message\\\": \\\"\")[1].split(\"\\\"\")[0])\nelse:\n    flag=\"MPW7FFOZEW6U8SN3OWRGPTUJH3Z0DDSGG{YYXZFTTOG0DUYPMN0DGT1TA3DWCVL7}VHI6KQOZ2H9BTG2NXA7GZAXQMGMAPUWG7PBTYMOOPNOL2PWJTTVYNKOXW3E0AF5\"\n    print(f\"Challenge Ended.\\nLast flag obtained:\\n'{flag}'\")","metadata":{"execution":{"iopub.status.busy":"2022-09-17T15:31:09.625307Z","iopub.execute_input":"2022-09-17T15:31:09.626046Z","iopub.status.idle":"2022-09-17T15:31:09.639710Z","shell.execute_reply.started":"2022-09-17T15:31:09.626008Z","shell.execute_reply":"2022-09-17T15:31:09.637985Z"},"jupyter":{"source_hidden":true},"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":"markdown","source":"# Solution\nIn this challenge I got a bit lucky.\n\nI tried adding random noise to the image. The first noise that I added returned me a flag.","metadata":{}},{"cell_type":"code","source":"if during_challenge_period:\n    with open(\"../input/temporary2/f.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.\")\n    add_flag(\"honorstudent\", r.text.split(\"yourself! \")[1])\nelse:\n    flag=\"Q4S8FEUPS4N1DI99KYW9P3Y24CXPHGPNOBO3CU26U6WG}XC9AU4OULZJA2OP6KAITPJL7RJ32HEEKPSFYWKQRLQP6Z{49D27H6IPCR97FR22TTGW0019L4X64LKQQKLV\"\n    print(f\"Challenge Ended.\\nLast flag obtained:\\n'{flag}'\")","metadata":{"execution":{"iopub.status.busy":"2022-09-17T15:31:09.642706Z","iopub.execute_input":"2022-09-17T15:31:09.643667Z","iopub.status.idle":"2022-09-17T15:31:09.651248Z","shell.execute_reply.started":"2022-09-17T15:31:09.643626Z","shell.execute_reply":"2022-09-17T15:31:09.650034Z"},"jupyter":{"source_hidden":true},"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":"markdown","source":"# Solution\nThis challenge was quite interesting, I didn't understand well the setting until after I solved it and there was some messages that cleared the scenario to me.\n\nMy first attempt was tampering the best students in the class so that Henry could appear better to the model, this approach didn't work. \nAfter that I tried working mainly on Henry while changing a bit other students. Once I reduced the demerits value I noticed an increase of Henry score. \n\nThis gave me an idea, going with negative demerits and absences.\nThis returned me a flag. \n\nLater I tried going further and in this [notebook](https://www.kaggle.com/code/pietromaldini1/it-is-results-that-matter-or-is-it) I show how I made Henry the best student in human history with a score of 1269/100.","metadata":{}},{"cell_type":"code","source":"# Submission Helper\nif during_challenge_period:\n    with open(f\"../input/temporary2/math.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.\")\n    add_flag(\"bad_to_good\", r.text.split(\"student! \")[1])\n    \nelse:\n    flag=\"wtWpKFCRhJPFVONHnAI0DBR7N1043CFI20FF8ITRP_ED2XWWG4QHC5HtUQPXYEJ_AVH946YeUKIY9BaN7FB8}bDLCXISQLFGoFJWO5LWKGR683_QP8SVC1d14{WFXDST\"\n    print(f\"Challenge Ended.\\nLast flag obtained:\\n'{flag}'\")","metadata":{"execution":{"iopub.status.busy":"2022-09-17T15:31:09.652383Z","iopub.execute_input":"2022-09-17T15:31:09.652818Z","iopub.status.idle":"2022-09-17T15:31:09.669848Z","shell.execute_reply.started":"2022-09-17T15:31:09.652788Z","shell.execute_reply":"2022-09-17T15:31:09.668738Z"},"jupyter":{"source_hidden":true},"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":"markdown","source":"# Solution \n\nThis challenge was quite difficult. The model had a strange 6 way output that gave out quite quickly that the flag was a 6 characters long string, but how to get those character was the difficult part. I tried many ways to attack the challenge, from drawing letters on paint to using emnist. \n\nI wanted to solve this as much automatically as I could but in the end I solved it, many automatic solutions allowed me to find strings like `DIFCON`, `DYCOM`, `D35C0M`. In the end by considering the conference name the flag was easily guessable. It was `D3FC0N`.\n\nThe code for the most automatic way to find a base string is in this [notebook](https://www.kaggle.com/code/pietromaldini1/inference/notebook) (hopefully i'll eventually automate it without inserting prior knowledge of the correct flag).","metadata":{}},{"cell_type":"code","source":"# To try and get the flag\nif during_challenge_period:\n    try:\n        r = requests.post(\"http://flags.fly.dev:5000/score\", json=json.dumps({\"challenge_id\": \"inference\", \"submission\": \"FLAG{D3FC0N}\"}))\n        print(r.text)\n    except requests.exceptions.ConnectionError:\n        print(\"Connection problems. Contact the CTF organizers.\")\n    add_flag(\"inference\", r.text.split(\"The flag is \")[1][:-1])\nelse:\n    flag=\"S46NEMFP3SRY0OOAF06CSCRS5LKNVMDJNFCH8Y6UOZ3B53EBKKBDINRWXB1RTGVIF90CDB4D70Y89ML1BZ6IFFAUNUCBR}G4K6QM12TYRLCN{U7FJH98YZ1RFEBCGRVS\"\n    print(f\"Challenge Ended.\\nLast flag obtained:\\n'{flag}'\")\n    ","metadata":{"execution":{"iopub.status.busy":"2022-09-17T15:31:09.671495Z","iopub.execute_input":"2022-09-17T15:31:09.672098Z","iopub.status.idle":"2022-09-17T15:31:09.682702Z","shell.execute_reply.started":"2022-09-17T15:31:09.672057Z","shell.execute_reply":"2022-09-17T15:31:09.681280Z"},"jupyter":{"source_hidden":true},"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":"markdown","source":"# Solution\n\nI solved this challenge in a 2 step approach, first finding a Henry like set of pitches and than iteratively improving the set by changing a pitch at a time taking the best improvement in a 8x8 grid from the current pitch position.\n\nThe code to generate the set of pitches I used can be found in this [notebook](https://www.kaggle.com/code/pietromaldini1/baseball-iterative-solution).","metadata":{}},{"cell_type":"code","source":"# Submission Helper\n\nimport json\nif during_challenge_period:\n    with open(\"../input/temporary2/throws.json\") as f:\n        test=json.load(f)\n\n    try:\n        r = requests.post(\"https://bball.fly.dev/score\", json=test)\n        print(r.text)\n    except requests.exceptions.ConnectionError:\n        print(\"Connection problems. Contact the CTF organizers.\")\n    add_flag(\"baseball\", r.text.split(\"Bring the heat! \")[1].split(\"\\\"\")[0])\nelse:\n    flag=\"INH6WEWFIPJN8WH31FWRC9PQ0GZIRIJ3ANAA6EQ59BJ{AOX0ZIAUHZ7MCL1J4V46G1W82J1SS4SG}SO6DK6X7N2X4CRRXGDJLZ6R0S34COK61JPGERPGGP14FARU1J4V\"\n    print(f\"Challenge Ended.\\nLast flag obtained:\\n'{flag}'\")\n    ","metadata":{"execution":{"iopub.status.busy":"2022-09-17T15:31:09.684718Z","iopub.execute_input":"2022-09-17T15:31:09.685167Z","iopub.status.idle":"2022-09-17T15:31:09.696926Z","shell.execute_reply.started":"2022-09-17T15:31:09.685126Z","shell.execute_reply":"2022-09-17T15:31:09.695541Z"},"jupyter":{"source_hidden":true},"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":"markdown","source":"# Solution \nThis challenge for me was the second hardest among the ones that I solved. I have really little experience about WAF and exploits outside XSS. My first attempts were some XSS payloads but I got nowhere. So I went to github to find some data for WAF exploits.\n\nWhile trying out the various payloads to understand what kind of exploit was required I ended up finding an exploit for this WAF inside one [dataset](https://github.com/grananqvist/Machine-Learning-Web-Application-Firewall-and-Dataset).\n\nThe [notebook](https://www.kaggle.com/code/pietromaldini1/waf-solve-by-mistake) with my code is nothing special but I leave a link for completeness.","metadata":{}},{"cell_type":"code","source":"# Submission Helper\n\nimport base64\nif during_challenge_period:\n    input =  base64.b64encode(b\"env x='() { :;}; apt-get update && apt-get install --only-upgrade bash' bash -c \\\"Oops.\\\"\").decode()\n    data = json.dumps(\n        {\"input\": input}\n    )\n\n    try:\n        r = requests.post(\"https://waf.fly.dev/score\", data=data)\n        print(r.text)\n    except requests.exceptions.ConnectionError:\n        print(\"Connection problems. Contact the CTF organizers.\")\n    add_flag(\"waf\", r.text.split(\"message\\\": \\\"\")[1].split(\"\\\"}\")[0])  \nelse:\n    flag=\"LYY6M846DSUFRFTMY0ZDX8BQSZ5A0Z781B97MY6R0D4ZXL6QMIK362CALXLCP{PW5YBNZIGEYSYJZ5NACZKO30819UF0RLKOG0A}JAISNLKNTJZRPQ0UZLUUA14ZOYU7\"\n    print(f\"Challenge Ended.\\nLast flag obtained:\\n'{flag}'\")\n    ","metadata":{"execution":{"iopub.status.busy":"2022-09-17T15:31:09.698476Z","iopub.execute_input":"2022-09-17T15:31:09.698759Z","iopub.status.idle":"2022-09-17T15:31:09.712500Z","shell.execute_reply.started":"2022-09-17T15:31:09.698732Z","shell.execute_reply":"2022-09-17T15:31:09.711368Z"},"jupyter":{"source_hidden":true},"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\n","metadata":{}},{"cell_type":"markdown","source":"```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","metadata":{}},{"cell_type":"markdown","source":"### Objective\n\nThe password is your flag, as usual it is in the format `FLAG{something}`","metadata":{}},{"cell_type":"markdown","source":"# Solution\n\nGiven a RNN and a string. We have to find what came after in the saved password file.\n\nWe can start from feeding the initial string to the network and saving the internal state of the LSTM together with its output.\nFrom the output we obtain the next character in the password fild.\n\nAfter that we can keep feeding back the new character and the internal state of the LSTM to find a new internal state and character until the flag is complete.","metadata":{}},{"cell_type":"code","source":"import 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(\"../input/ai-village-ctf/leakage/pretrained_model.pt\"))\nchr(torch.argmax(model(featurize(\"xXx_SkynetKilla_xXx\"))))\n","metadata":{"execution":{"iopub.status.busy":"2022-09-17T15:31:09.713920Z","iopub.execute_input":"2022-09-17T15:31:09.714294Z","iopub.status.idle":"2022-09-17T15:31:09.741365Z","shell.execute_reply.started":"2022-09-17T15:31:09.714268Z","shell.execute_reply":"2022-09-17T15:31:09.739776Z"},"jupyter":{"source_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"username=featurize(\"xXx_SkynetKilla_xXx\")\nh = model.E(username)\nh,m = model.LSTM(h)\nres=\"\"\nfor i in range(50):\n    char=chr(torch.argmax(model.predict(h[:,-1,:])))\n    #print(char)\n    res+=char\n    if char==\"}\":\n        print(res)\n        break\n    h = model.E(torch.Tensor([[int(ord(char))]]).long())\n    h,m=model.LSTM(h,m)","metadata":{"execution":{"iopub.status.busy":"2022-09-17T15:31:09.745133Z","iopub.execute_input":"2022-09-17T15:31:09.745747Z","iopub.status.idle":"2022-09-17T15:31:09.768785Z","shell.execute_reply.started":"2022-09-17T15:31:09.745708Z","shell.execute_reply":"2022-09-17T15:31:09.767801Z"},"jupyter":{"source_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Submission Helper\nif during_challenge_period:\n    try:\n        r = requests.post(\"http://flags.fly.dev:5000/score\", json=json.dumps({\"challenge_id\": \"leakage\", \"submission\": res[1:]}))\n        print(r.text)\n    except requests.exceptions.ConnectionError:\n        print(\"Connection problems. Contact the CTF organizers.\")\n    add_flag(\"leakage\", r.text.split(\"The flag is \")[1].replace(\".\",\"\"))\nelse:\n    flag=\"Ta3IsB4DXXrL34n6DH5oHTKHNTM7SG5WCA84DRGABOK2PCD0BVU2<TLZ1M4UUPBAD3GREKX}X5FNNT1Gc41F{0DYB5MW3CV3LKJ43XT<MGT0FR9N8FLM7UK6UNJK4TL2\"\n    print(f\"Challenge Ended.\\nLast flag obtained:\\n'{flag}'\")","metadata":{"execution":{"iopub.status.busy":"2022-09-17T15:31:09.770164Z","iopub.execute_input":"2022-09-17T15:31:09.770776Z","iopub.status.idle":"2022-09-17T15:31:09.778044Z","shell.execute_reply.started":"2022-09-17T15:31:09.770738Z","shell.execute_reply":"2022-09-17T15:31:09.777042Z"},"jupyter":{"source_hidden":true},"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":"markdown","source":"# Solution\nThe flag was the name of the file that can be accessed easily by just reading `model.name`. ","metadata":{}},{"cell_type":"code","source":"if during_challenge_period:\n    import tensorflow as tf\n    new_model = tf.keras.models.load_model('../input/ai-village-ctf/forensics/forensics.h5')\n    flag=new_model.name.replace(\"(\",\"{\").replace(\")\",\"}\")\n\n    try:\n        r = requests.post(\"http://flags.fly.dev:5000/score\", json=json.dumps({\"challenge_id\": \"forensics\", \"submission\": flag}))\n        print(r.text)\n    except requests.exceptions.ConnectionError:\n        print(\"Connection problems. Contact the CTF organizers.\")\n        \n    add_flag(\"forensics\", r.text.split(\"The flag is \")[1].replace(\".\",\"\"))\nelse:\n    flag=\"P9ZPH49O20RXYYUFWLAFXUJ5VGCY37DPQ}KQWYVFHAJX2N46QY473BRINX9II5GDF2SA7RB1YH1O2BSLYU8WSF7B1T9X6VTBX5KQ7QK59GYHA{ZCW_VYMC02RSSSM057\"\n    print(f\"Challenge Ended.\\nLast flag obtained:\\n'{flag}'\")","metadata":{"execution":{"iopub.status.busy":"2022-09-17T15:31:09.779935Z","iopub.execute_input":"2022-09-17T15:31:09.780554Z","iopub.status.idle":"2022-09-17T15:31:09.795879Z","shell.execute_reply.started":"2022-09-17T15:31:09.780506Z","shell.execute_reply":"2022-09-17T15:31:09.794402Z"},"jupyter":{"source_hidden":true},"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":"markdown","source":"# Solution \n\nMy first solution for this problem is quite inelegant and is split in 2 notebooks so currently I haven't published it. \n\nThe challenge checked the provided image for both distance between the image and the provided starting image and confidence. For what i saw the distance (d) should be <=4 and the confidence >=0.8.\n\nIt was a composition of two attacks, first I used adversarial robustness toolkit to perform a hopskipjump blackbox attack from an image with the average of the pixels of the turtle and of the owl images provided by the organizers. This attacked aimed at reducing the distance of the image with the correct class (loggerhead) to a specific image ( starting owl image). This allowed me to have an image close enough to be accepted by the network but without enough confidence.\n\nMy second attack was an iterative noise addition to the image, I added random noises and checked if the added noise improved the condifence, if it did I kept the noise otherwise I dropped it. This allowed me to find an image to get a flag in 2 days.\n\nFor a more elegant solution check my notebook linked in Hotterdog section.","metadata":{}},{"cell_type":"code","source":"Ima(filename=f'../input/temporary/eagle-turtle.png')","metadata":{"execution":{"iopub.status.busy":"2022-09-17T15:31:09.798725Z","iopub.execute_input":"2022-09-17T15:31:09.799572Z","iopub.status.idle":"2022-09-17T15:31:09.821235Z","shell.execute_reply.started":"2022-09-17T15:31:09.799532Z","shell.execute_reply":"2022-09-17T15:31:09.820009Z"},"jupyter":{"source_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Submission Helper\n\nif during_challenge_period:\n    IMAGE_DIMS = (224, 224)\n    img = Im.open(\"../input/temporary/eagle-turtle.png\")\n    img = img.resize(IMAGE_DIMS)\n    img_bytes = img.tobytes()\n\n    b64_img_bytes = base64.urlsafe_b64encode(img_bytes)\n\n    data = {\n        \"input\": b64_img_bytes.decode()\n    }\n\n    try:\n        r = requests.post(\"https://theft.fly.dev/score\", data=json.dumps(data))\n        print(r.text)\n    except requests.exceptions.ConnectionError:\n        print(\"Connection problems. Contact the CTF organizers.\")\n    add_flag(\"theft\", r.text.split(\"message\\\": \\\"\")[1][:-2])    \nelse:\n    flag=\"RQ0FTLV59CHK04ZK1PHJD}NZNSO?JL3WTNHYZX5VHI1G2NMTU0LXCFK0NA4D1W3LDQWGEYB4UUM{ZFV0NB0XB6RYFFCSCU9G7TDNELTGDNB93VA0DL30WF43FQO80PH7\"\n    print(f\"Challenge Ended.\\nLast flag obtained:\\n'{flag}'\")","metadata":{"execution":{"iopub.status.busy":"2022-09-17T15:31:09.822600Z","iopub.execute_input":"2022-09-17T15:31:09.823583Z","iopub.status.idle":"2022-09-17T15:31:09.832987Z","shell.execute_reply.started":"2022-09-17T15:31:09.823543Z","shell.execute_reply":"2022-09-17T15:31:09.831721Z"},"jupyter":{"source_hidden":true},"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":"markdown","source":"# Solution \n\nMy first solution to this challenge was very similar to the one I used for Theft, but it required two hop skip jump attacks as the kernel on kaggle lasts only 12 hours and they weren't enough to get a good enough image for the subsequent iterative noise improvement attack.","metadata":{}},{"cell_type":"code","source":"Ima(filename=f'../input/temporary/salt-solution.png')","metadata":{"execution":{"iopub.status.busy":"2022-09-17T15:31:09.834305Z","iopub.execute_input":"2022-09-17T15:31:09.835082Z","iopub.status.idle":"2022-09-17T15:31:09.849137Z","shell.execute_reply.started":"2022-09-17T15:31:09.835050Z","shell.execute_reply":"2022-09-17T15:31:09.848452Z"},"jupyter":{"source_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Submission Helper\nif during_challenge_period:\n    IMAGE_DIMS = (224, 224)\n\n    img = Im.open(f\"../input/temporary/salt-solution.png\")\n    img = img.resize(IMAGE_DIMS)\n    img_bytes = img.tobytes()\n    b64_img_bytes = base64.urlsafe_b64encode(img_bytes)\n\n    data = {\n        \"input\": b64_img_bytes.decode()\n    }\n\n    try:\n        r = requests.post(\"https://salt.fly.dev/score\", data=json.dumps(data))\n        print(r.text)\n    except requests.exceptions.ConnectionError:\n        print(\"Connection problems. Contact the CTF organizers.\")\n    add_flag(\"salt\", r.text.split(\"message\\\": \\\"\")[1][:-2])\nelse:\n    flag=\"3CELXJS593A4T1L9S3XT6ML8UN<RZ1SKLQQGVWPG3B{LHGKONADTSUZ7C135H7IQ}GLW4MJCAF7Z7LXHBF9GGLFTEZLJ61T65BK3K0WULTIQP6T1QOS065FTXI1SV12O\"\n    print(f\"Challenge Ended.\\nLast flag obtained:\\n'{flag}'\")","metadata":{"execution":{"iopub.status.busy":"2022-09-17T15:31:09.850283Z","iopub.execute_input":"2022-09-17T15:31:09.850986Z","iopub.status.idle":"2022-09-17T15:31:09.858210Z","shell.execute_reply.started":"2022-09-17T15:31:09.850953Z","shell.execute_reply":"2022-09-17T15:31:09.857253Z"},"jupyter":{"source_hidden":true},"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":"markdown","source":"# Solution\n\nThe test.csv provided contained some suspicious text, and really suspicious sets of rows containing only SECRETKEY and BLANK tokens. \n\nThe latter appeared also in some rows together with text. By removing the two rows where BLANK appears together with text we get our flag.","metadata":{}},{"cell_type":"code","source":"# Submission Helper\nif during_challenge_period:\n    data = json.dumps(\n        {\n            \"line1\": 336,\n            \"line2\": 492\n        }\n    )\n    try:\n        r = requests.post(\"https://token.fly.dev/score\", data=data)\n        print(r.text)\n    except requests.exceptions.ConnectionError:\n        print(\"Connection problems. Contact the CTF organizers.\")\n    add_flag(\"token\",r.text.split(\"message\\\": \\\"\")[1].split(\"\\\"}\")[0])    \nelse:\n    flag=\"R62CW38QRKNRY{EROTTKN68OLVSWE5JRWPGUFG4L0ZBAU8H913533V4}CD10ARXVBFKRK64VN71R4MOLAUYQFMLMM0BPAR8D8SL4OGVZFU1INEBH1DJ9K3ROYB3R1WW6\"\n    print(f\"Challenge Ended.\\nLast flag obtained:\\n'{flag}'\")","metadata":{"execution":{"iopub.status.busy":"2022-09-17T15:31:09.859521Z","iopub.execute_input":"2022-09-17T15:31:09.859761Z","iopub.status.idle":"2022-09-17T15:31:09.877917Z","shell.execute_reply.started":"2022-09-17T15:31:09.859738Z","shell.execute_reply":"2022-09-17T15:31:09.877150Z"},"jupyter":{"source_hidden":true},"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":"markdown","source":"# Solution\n\nThis challenge took me some time, at the beginning I tried using the provided sample and iteratively improving it but this resulted in scores too high to reach the required score.\n\nAfter that I analysed X_comp and crop/sample_image.png that made me understand that the network was trained on images. \n\nThe images were grids of 3x3 squares with a circle inside. The whole image could be characterized using 18 rgb values so 54 floats.\n\nAfter this discovery the solution was an easy iterative noise improvement I used practically everywhere in the competition.\n\nThe code to find the solution I submitted can be found in this [notebook](https://www.kaggle.com/code/pietromaldini1/crop-1).","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-17T15:31:09.878878Z","iopub.execute_input":"2022-09-17T15:31:09.879435Z","iopub.status.idle":"2022-09-17T15:31:10.032321Z","shell.execute_reply.started":"2022-09-17T15:31:09.879404Z","shell.execute_reply":"2022-09-17T15:31:10.031388Z"},"jupyter":{"source_hidden":true},"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):\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    if debug:\n        print({\"idx\":idx})\n        plt.imshow(actual_square)\n        plt.show()\n    sse = ((actual-(expected*10).astype(int))**2).sum()\n    redness = (actual_square[:,:,0][actual_square[:,:,0]>230]**2).sum()+1\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-17T15:31:10.034516Z","iopub.execute_input":"2022-09-17T15:31:10.035068Z","iopub.status.idle":"2022-09-17T15:31:10.054109Z","shell.execute_reply.started":"2022-09-17T15:31:10.035035Z","shell.execute_reply":"2022-09-17T15:31:10.053233Z"},"jupyter":{"source_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"if during_challenge_period:\n    with open(\"../input/crop-dataset/crop1.txt\") as f:\n        s=f.read()\n    try:\n        r = requests.post(\"https://crop1.fly.dev/score\", data=s)\n        print(r.text)\n    except requests.exceptions.ConnectionError:\n        print(\"Connection problems. Contact the CTF organizers.\")\n    add_flag(\"crop1\", r.text.split(\"champion. \")[1].split(\"\\\",\")[0])\nelse:\n    flag=\"5TWX7TCE{JUNCGOn}6XK085DXOnK1TWU04T4AC7eXWOTYC30AgHJ28IN22KTL8CN7IA8BUhRU04A4RURLHUZ7rPaI8LRKTEZJESZ4822VP0FTAGag1843JYGGE9P2O3U\"\n    print(f\"Challenge Ended.\\nLast flag obtained:\\n'{flag}'\")","metadata":{"execution":{"iopub.status.busy":"2022-09-17T15:31:10.057295Z","iopub.execute_input":"2022-09-17T15:31:10.058131Z","iopub.status.idle":"2022-09-17T15:31:10.072264Z","shell.execute_reply.started":"2022-09-17T15:31:10.058098Z","shell.execute_reply":"2022-09-17T15:31:10.071157Z"},"jupyter":{"source_hidden":true},"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":"markdown","source":"# Solution \n\nMy first attempts to this challenge were trying to modify the whole image at once using adversarial robustness toolkit. The library required float32 numpy arrays that were too big for the ram on kaggle.\n\nAfter that I tryed changing a frame at the time.\nThis attempt didn't yield significant results.\n\nMy last attempt was considering a slice of the whole video ndarray.\nI found the portion of the video containing the face and created a boolean mask.\n\nIn around 10 minutes I had a flag.\n\nThe code to generate the video I submitted can be found in this [notebook](https://www.kaggle.com/code/pietromaldini1/deepfake).\n\n\n","metadata":{}},{"cell_type":"code","source":"import time\nif during_challenge_period:\n    failed=True\n    for i in range(15):\n        if not failed:\n            break\n        time.sleep(15)\n        try:\n            with open(f\"../input/temporary2/target.mp4\", \"rb\") as f:\n                data = f.read()\n            b64_data = base64.urlsafe_b64encode(data).decode()\n            in_data = json.dumps({\"input\": b64_data})\n            r = requests.post(\"https://deepfake.fly.dev/score\", data=in_data)\n            temp=r.text.split(\"message\\\": \\\"\")[1].split(\"\\\"}\")[0]\n            print(temp)\n            failed=False\n        except:\n            try:\n                print(r)\n            except:\n                print(\"failed\")\n    add_flag(\"deepfake\", temp)\nelse:\n    flag=\"1AGRICZ3OVLDBODTGC5FM58AYI3N5CXOSA6UZ0GMGXDZQ341ER89FJEIQ2AZ6Z36Q0ZUTPL5M65LS}LOTBLOULN06YR6Z12NK4REXFELBBE98NDC1R{I4D7SERQGL8H7\"\n    print(f\"Challenge Ended.\\nLast flag obtained:\\n'{flag}'\")","metadata":{"execution":{"iopub.status.busy":"2022-09-17T15:31:10.073615Z","iopub.execute_input":"2022-09-17T15:31:10.073954Z","iopub.status.idle":"2022-09-17T15:31:10.093027Z","shell.execute_reply.started":"2022-09-17T15:31:10.073920Z","shell.execute_reply":"2022-09-17T15:31:10.091540Z"},"jupyter":{"source_hidden":true},"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":"markdown","source":"# Solution\n\nI first tried creating several models from LGBMClassifiers to DecisionTreeClassifiers to train on the train data and predict which doors to open. This yielded horrible results. \n\nNow I know that maybe I should have started from easier models.\n\nMy solution was visualizing the train data to understand differences between humans and murderbots.\nI noticed that murderbot never used more than 4 units of water nor had more than 15 movement events.\nI created a condition combining these two considerations. The cell indexes with readings following any of these 2 conditions returned a flag.\n\nIf you are interested in the few visualizations I tried or want to suggest me other visualization to see even better how to solve this challenge leave me a comment here or in my [notebook](https://www.kaggle.com/code/pietromaldini1/murderbots-by-easy-eda) with my solution to this challenge.","metadata":{}},{"cell_type":"code","source":"X=pd.read_json(\"../input/ai-village-ctf/murderbots/train_data.json\")\ny=pd.read_json(\"../input/ai-village-ctf/murderbots/train_labels.json\")\nX_test=pd.read_json(\"../input/ai-village-ctf/murderbots/test_data.json\")","metadata":{"execution":{"iopub.status.busy":"2022-09-17T15:31:10.094427Z","iopub.execute_input":"2022-09-17T15:31:10.094784Z","iopub.status.idle":"2022-09-17T15:31:10.125022Z","shell.execute_reply.started":"2022-09-17T15:31:10.094754Z","shell.execute_reply":"2022-09-17T15:31:10.123736Z"},"jupyter":{"source_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"temp=X_test[((X_test[\"water_usage\"]>4)|(X_test[\"movement_events\"]>15))].index\nres=\"\".join(\"1\"if v in temp else \"0\" for v in range(50))","metadata":{"execution":{"iopub.status.busy":"2022-09-17T15:31:10.126929Z","iopub.execute_input":"2022-09-17T15:31:10.127534Z","iopub.status.idle":"2022-09-17T15:31:10.133146Z","shell.execute_reply.started":"2022-09-17T15:31:10.127499Z","shell.execute_reply":"2022-09-17T15:31:10.132262Z"},"jupyter":{"source_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Submission Helper\nif during_challenge_period:\n    f = res #'00001000001000101000000000000011000000101000010000' # length == 50\n    try:\n        r = requests.post(\"http://murderbot.fly.dev:5000/score\", json=json.dumps({\"submission\": f, 'challenge_id':'murderbots'}))\n        print(r.text)\n    except requests.exceptions.ConnectionError:\n        print(\"Connection problems. Contact the CTF organizers.\")\n    add_flag(\"murderbots\", r.text.split(\"The flag is \")[1])\nelse:\n    flag=\"JSAR4bJDF4NM}8DOY05eMoVMUtEGVDaVu2I3Ot5Ur5LAL{JK7DF53XEOsHALQ49R97C06FRdtB5WIRADo2A6CE6d8U2WIZeO8R4L4VNNNC3F0BMF09W2YI9QN1YRZMR3\"\n    print(f\"Challenge Ended.\\nLast flag obtained:\\n'{flag}'\")","metadata":{"execution":{"iopub.status.busy":"2022-09-17T15:31:10.134673Z","iopub.execute_input":"2022-09-17T15:31:10.135453Z","iopub.status.idle":"2022-09-17T15:31:10.147167Z","shell.execute_reply.started":"2022-09-17T15:31:10.135427Z","shell.execute_reply":"2022-09-17T15:31:10.146249Z"},"jupyter":{"source_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Thank you \n\nThis competition was really fun and allowed many people to gather and learn new skills. Even some grandmasters on kaggle had to try new things that they never tried before, so everyone had something to learn here.\n\nFor me it was interesting how sometimes I created overcomplicated solutions that took from 1 to 2 days to compute an adversarial image and later I found out ways to have the same results within seconds (not considering tensorflow import time 😂).\n\nI'm looking forward for the next edition of this CTF. \nWith or without teaming. I think anyway it will be even better than this one.\n\nI hope the community that was created by this challenge will be active and maybe this challenge may allow someone to find they next team mate for another CTF or another Kaggle Competition.\n\nAnd now, Thank you again for reading up to here. See you in a future challenge. ","metadata":{}}]}