{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# We're just importing some stuff to make sure the challenges and helper code works.\n# Feel free to import anything else you need (or solve in a different language), but if you overwrite these, provided code may not work.\n\nimport pandas as pd\nimport numpy as np\nimport os\nimport requests\nfrom IPython.display import Image as Ima\nfrom IPython.display import clear_output, display\nfrom PIL import Image as Im\nfrom torch.utils.data import Dataset, DataLoader\nimport torch\nimport joblib\nimport matplotlib.pyplot as plt\nimport json\nimport base64\nimport shutil\nimport warnings\nwarnings.filterwarnings(\"ignore\")\n\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-11T20:02:32.7267Z","iopub.execute_input":"2022-09-11T20:02:32.727355Z","iopub.status.idle":"2022-09-11T20:02:34.951786Z","shell.execute_reply.started":"2022-09-11T20:02:32.727265Z","shell.execute_reply":"2022-09-11T20:02:34.950409Z"},"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-11T20:02:34.954209Z","iopub.execute_input":"2022-09-11T20:02:34.955305Z","iopub.status.idle":"2022-09-11T20:02:34.969927Z","shell.execute_reply.started":"2022-09-11T20:02:34.955242Z","shell.execute_reply":"2022-09-11T20:02:34.968239Z"},"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":"# **Basically a visual solution: extract the tokens, plot them in different embedding spaces, follow the path and get the flag.**","metadata":{}},{"cell_type":"code","source":"from matplotlib import offsetbox\nfrom sklearn.preprocessing import MinMaxScaler, LabelEncoder\n\ndm1 = np.load('../input/ai-village-ctf/wifi/Embedded_characters.npz')\n\ntokens = '!!\"\"##$$%%&&\\'\\'(())**++,,--..//00112233445566778899::;;<<==>>??@@AABBCCDDEEFFGGHHIIJJKKLLMMNNOOPPQQRRSSTTUUVVWWXXYYZZ[[\\\\\\\\]]^^__``aabbccddeeffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~'\n\ny = np.empty(shape=(188, 1), dtype='object')\nfor idx, ch in enumerate(tokens):\n    y[idx] = ch\n\nds = pd.DataFrame(dm1['embeddings'])\n\nX = ds.iloc[:, :-1]\nlbe = LabelEncoder()\ny_tr = lbe.fit_transform(y)\n\nds['target'] = y_tr","metadata":{"execution":{"iopub.status.busy":"2022-09-11T20:03:16.758392Z","iopub.execute_input":"2022-09-11T20:03:16.758817Z","iopub.status.idle":"2022-09-11T20:03:17.240292Z","shell.execute_reply.started":"2022-09-11T20:03:16.75878Z","shell.execute_reply":"2022-09-11T20:03:17.238912Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from sklearn.decomposition import TruncatedSVD\nfrom sklearn.discriminant_analysis import LinearDiscriminantAnalysis\nfrom sklearn.ensemble import RandomTreesEmbedding\nfrom sklearn.manifold import (\n    Isomap,\n    LocallyLinearEmbedding,\n    MDS,\n    SpectralEmbedding,\n    TSNE,\n)\n\nfrom sklearn.neighbors import NeighborhoodComponentsAnalysis\nfrom sklearn.pipeline import make_pipeline\nfrom sklearn.random_projection import SparseRandomProjection\n\nn_neighbors = 30\n\nembeddings = {\n    \"Random projection embedding\": SparseRandomProjection(\n        n_components=2, random_state=42\n    ),\n    \"Truncated SVD embedding\": TruncatedSVD(n_components=2),\n    \"Linear Discriminant Analysis embedding\": LinearDiscriminantAnalysis(\n        n_components=2\n    ),\n    \"Isomap embedding\": Isomap(n_neighbors=n_neighbors, n_components=2),\n    \"Standard LLE embedding\": LocallyLinearEmbedding(\n        n_neighbors=n_neighbors, n_components=2, method=\"standard\"\n    ),\n    \"t-SNE embeedding\": TSNE(\n        n_components=2,\n        init=\"pca\",\n        learning_rate=\"auto\",\n        n_iter=500,\n        n_iter_without_progress=150,\n        n_jobs=2,\n        random_state=0,\n    )\n}","metadata":{"execution":{"iopub.status.busy":"2022-09-11T20:04:28.251952Z","iopub.execute_input":"2022-09-11T20:04:28.252396Z","iopub.status.idle":"2022-09-11T20:04:28.598049Z","shell.execute_reply.started":"2022-09-11T20:04:28.252364Z","shell.execute_reply":"2022-09-11T20:04:28.596886Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from time import time\n\nprojections, timing = {}, {}\nfor name, transformer in embeddings.items():\n\n    print(f\"Computing {name}...\")\n    start_time = time()\n    projections[name] = pd.DataFrame(transformer.fit_transform(X, y_tr))\n    timing[name] = time() - start_time","metadata":{"execution":{"iopub.status.busy":"2022-09-11T20:04:30.125667Z","iopub.execute_input":"2022-09-11T20:04:30.126067Z","iopub.status.idle":"2022-09-11T20:04:31.376235Z","shell.execute_reply.started":"2022-09-11T20:04:30.126035Z","shell.execute_reply":"2022-09-11T20:04:31.375332Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def plot_embedding(X, title):\n    _, ax = plt.subplots()\n    X = pd.DataFrame(MinMaxScaler().fit_transform(X))\n\n    for digit in np.unique(y_tr):\n        idx = ds['target'] == digit\n\n        ax.scatter(\n            x=X.loc[idx, 0],\n            y=X.loc[idx, 1],\n            marker=f\"${digit}$\",\n            s=60,\n            # color=plt.cm.Dark2(digit),\n            alpha=0.425,\n            zorder=2,\n        )\n\n    ax.set_title(title)\n    ax.axis(\"off\")\n\nplt.rcParams[\"figure.figsize\"] = (20, 16)\nfor name in timing:\n    title = f\"{name} (time {timing[name]:.3f}s)\"\n    plot_embedding(projections[name], title)","metadata":{"execution":{"iopub.status.busy":"2022-09-11T20:04:40.172621Z","iopub.execute_input":"2022-09-11T20:04:40.173042Z","iopub.status.idle":"2022-09-11T20:04:57.683271Z","shell.execute_reply.started":"2022-09-11T20:04:40.17301Z","shell.execute_reply":"2022-09-11T20:04:57.681937Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"labels = [93,92,91,90,63,62,61,60,59,58,31,30,29,28,27,26,25,\n          14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,\n          57,56,55,54,53,52,51,50,49,48,47,46,45,44,43,42,41,40,39,38,37,36,35,34,33,32,\n          89,88,87,86,85,84,83,82,81,80,79,78,77,76,75,74,73,72,71,70,69,68,67,66,65,64,\n          24,23,22,21,20,19,18,17,16,15,\n          93,91,63,62,61,60,59,58,\n          31,30,29,28,27,26,25,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,\n          57,56,55,54,53,50,\n          48,47,46,44,42,41,40,39,34,33,\n          89,88,87,86,85,84,83,82,81,80,79,78,77,76,75,74,73,72,71,70,69,68,67,66,65,64,\n          24,23,22,21,20,19,18,17,16,15,\n          92,35,36,45,49,52,51,90,38,32,43,37]\n\nans = ''.join(lbe.inverse_transform(labels))\nans[::-1]","metadata":{"execution":{"iopub.status.busy":"2022-09-11T20:05:28.145324Z","iopub.execute_input":"2022-09-11T20:05:28.145792Z","iopub.status.idle":"2022-09-11T20:05:28.165Z","shell.execute_reply.started":"2022-09-11T20:05:28.145753Z","shell.execute_reply":"2022-09-11T20:05:28.163762Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Submission Helper\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-11T20:08:41.53993Z","iopub.execute_input":"2022-09-11T20:08:41.540384Z","iopub.status.idle":"2022-09-11T20:08:41.805863Z","shell.execute_reply.started":"2022-09-11T20:08:41.540347Z","shell.execute_reply":"2022-09-11T20:08:41.804373Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"add_flag(\"wifi\", \"Y3A0FNN6NT63E7Y4EM83XHQT95RP75ZNFXHY41MXHVD9E5BTB752ZTR7FMK3WTL6X7MG40KTJCTI2DM}HJMZ0CG9SCL8C5K9DRK6DVDP4ZC{ASN58T5K3K1KYU3SU10O\")","metadata":{"execution":{"iopub.status.busy":"2022-09-11T20:08:43.247711Z","iopub.execute_input":"2022-09-11T20:08:43.248958Z","iopub.status.idle":"2022-09-11T20:08:43.272662Z","shell.execute_reply.started":"2022-09-11T20:08:43.248912Z","shell.execute_reply":"2022-09-11T20:08:43.27133Z"},"trusted":true},"execution_count":null,"outputs":[]}]}