added material

This commit is contained in:
Jeremy Janella
2026-07-26 22:53:03 -04:00
commit 95b1c6bf27
369 changed files with 3468754 additions and 0 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

+183
View File
@@ -0,0 +1,183 @@
{
"white_box": [
{
"num_words": 0,
"evasion_rate": 7.03125,
"evaded": 9,
"total": 128
},
{
"num_words": 5,
"evasion_rate": 41.40625,
"evaded": 53,
"total": 128
},
{
"num_words": 10,
"evasion_rate": 74.21875,
"evaded": 95,
"total": 128
},
{
"num_words": 15,
"evasion_rate": 96.09375,
"evaded": 123,
"total": 128
},
{
"num_words": 20,
"evasion_rate": 100.0,
"evaded": 128,
"total": 128
},
{
"num_words": 25,
"evasion_rate": 100.0,
"evaded": 128,
"total": 128
},
{
"num_words": 30,
"evasion_rate": 100.0,
"evaded": 128,
"total": 128
},
{
"num_words": 35,
"evasion_rate": 100.0,
"evaded": 128,
"total": 128
},
{
"num_words": 40,
"evasion_rate": 100.0,
"evaded": 128,
"total": 128
}
],
"black_box": [],
"top_good_words": [
[
"lor",
50.94243874392973
],
[
"\u00fc",
47.57124794469911
],
[
"...",
45.80542826853246
],
[
"da",
45.69836416734876
],
[
"later",
29.966140437605727
],
[
"doing",
26.220372882905004
],
[
"really",
25.47121937196488
],
[
"ask",
24.722065861024724
],
[
"cos",
23.598335594614515
],
[
"lol",
23.598335594614515
],
[
"said",
23.22375883914445
],
[
"..",
22.795692105601425
],
[
"sure",
21.35087506179409
],
[
"k",
20.78902109332076
],
[
"come",
20.601736303054754
],
[
"morning",
19.852568039913795
],
[
"thing",
19.103414528973666
],
[
"feel",
17.97968426256344
],
[
"oh",
17.230540005274868
],
[
"going",
16.980825074033003
]
],
"word_impacts": [
[
"lor",
7.131785940645545
],
[
"\u00fc",
7.036803994633465
],
[
"...",
6.98438558531918
],
[
"da",
6.981145003801362
],
[
"later",
6.394759474192664
],
[
"doing",
6.206539871713527
],
[
"really",
6.165373493147777
],
[
"ask",
6.122846010746446
],
[
"cos",
6.056288389188433
],
[
"lol",
6.056288389188438
]
]
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+135
View File
@@ -0,0 +1,135 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"id": "33563458-e157-4771-bd54-7676036c1d73",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Base message: 'England v Macedonia - dont miss the goals/team news. Txt ur national team to 87077 eg ENGLAND to 87077 Try:WALES, SCOTLAND 4txt/ú1.20 POBOXox36504W45WQ 16+'\n",
"Budget: 25\n",
"\n",
"Final message: 'England v Macedonia - dont miss the goals/team news. Txt ur national team to 87077 eg ENGLAND to 87077 Try:WALES, SCOTLAND 4txt/ú1.20 POBOXox36504W45WQ 16+ later home morning fine nice lunch meeting happy'\n",
"Words used: 8\n",
"Final classification: ham (spam prob: 0.1077)\n"
]
}
],
"source": [
"import os\n",
"import requests\n",
"import random\n",
"import numpy as np\n",
"from typing import List, Tuple\n",
"\n",
"# Seed for reproducibility\n",
"random.seed(1337)\n",
"np.random.seed(1337)\n",
"\n",
"# Get challenge from server\n",
"host = \"http://154.57.164.78:31757\"\n",
"ch = requests.get(f\"{host}/challenge\", timeout=10).json()\n",
"base, budget = ch[\"base_message\"], int(ch[\"max_added_words\"])\n",
"\n",
"def predict(host, text):\n",
" r = requests.post(f\"{host}/predict\", json={\"text\": text}, timeout=15)\n",
" data = r.json()\n",
" return data[\"label\"], float(data[\"spam_probability\"])\n",
"\n",
"vocab = list(dict.fromkeys([\n",
" # salutations and courtesy\n",
" \"hello\", \"hi\", \"dear\", \"please\", \"thanks\", \"thankyou\", \"regards\", \"sincerely\",\n",
" \"kind\", \"wishes\", \"best\", \"appreciate\", \"welcome\", \"friend\", \"family\",\n",
" # everyday context\n",
" \"meeting\", \"tomorrow\", \"today\", \"later\", \"morning\", \"night\", \"home\", \"work\",\n",
" \"office\", \"schedule\", \"confirm\", \"call\", \"reply\", \"message\", \"note\", \"update\",\n",
" # positive tone\n",
" \"happy\", \"birthday\", \"congratulations\", \"joy\", \"peace\", \"smile\", \"care\",\n",
" \"support\", \"help\", \"good\", \"great\", \"wonderful\", \"awesome\", \"nice\", \"cool\",\n",
" \"fine\", \"okay\",\n",
" # social\n",
" \"lunch\", \"dinner\", \"coffee\", \"weekend\", \"party\", \"invite\", \"visit\", \"enjoy\",\n",
" # misc\n",
" \"true\", \"honest\", \"trust\", \"safe\", \"project\", \"team\"\n",
"]))\n",
"\n",
"def estimate_word_impacts(\n",
" host: str, base_msg: str, words: List[str]\n",
") -> List[Tuple[str, float]]:\n",
" _, base_prob = predict(host, base_msg)\n",
" impacts: List[Tuple[str, float]] = []\n",
" for w in words:\n",
" augmented = f\"{base_msg} {w}\"\n",
" _, new_prob = predict(host, augmented)\n",
" impacts.append((w, base_prob - new_prob))\n",
" impacts.sort(key=lambda x: x[1], reverse=True)\n",
" return impacts\n",
"\n",
"def greedy_compose(\n",
" host: str, base_msg: str, top_words: List[str], budget: int, target_label: str\n",
") -> Tuple[str, int, float]:\n",
" augmented = base_msg\n",
" used = 0\n",
" for w in top_words:\n",
" if used >= budget:\n",
" break\n",
" augmented = f\"{augmented} {w}\"\n",
" used += 1\n",
" label, prob = predict(host, augmented)\n",
" if label == target_label:\n",
" return augmented, used, prob\n",
" label, prob = predict(host, augmented)\n",
" return augmented, used, prob\n",
"\n",
"\n",
"if __name__ == \"__main__\":\n",
" print(f\"Base message: '{base}'\\nBudget: {budget}\")\n",
"\n",
" #Estimate which words help reduce spam probability\n",
" impacts = estimate_word_impacts(host, base, vocab)\n",
" top_words = [w for w, delta in impacts if delta > 0]\n",
"\n",
" #Try to fix the message using greedy approach\n",
" final_msg, used, final_prob = greedy_compose(host, base, top_words, budget, target_label=\"ham\")\n",
" final_label, _ = predict(host, final_msg)\n",
"\n",
" print(f\"\\nFinal message: '{final_msg}'\")\n",
" print(f\"Words used: {used}\")\n",
" print(f\"Final classification: {final_label} (spam prob: {final_prob:.4f})\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "f010b0d4-4ed5-4dbc-b62b-845e6b137b5e",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.6"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
Binary file not shown.
Binary file not shown.
+329
View File
@@ -0,0 +1,329 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 3,
"id": "e5181b56-34a6-4c2e-8045-137f8190ad56",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"[*] Starting white-box phase...\n",
"[*] Downloading model...\n",
"[+] Model loaded: 89972 features\n",
" Attacking review wb_0... Done (6 words)\n",
" Attacking review wb_1... Done (3 words)\n",
" Attacking review wb_2... Done (3 words)\n",
" Attacking review wb_3... Done (4 words)\n",
" Attacking review wb_4... Done (6 words)\n",
" Attacking review wb_5... Done (11 words)\n",
" Attacking review wb_6... Done (5 words)\n",
" Attacking review wb_7... Done (4 words)\n",
" Attacking review wb_8... Done (24 words)\n",
" Attacking review wb_9... Done (7 words)\n",
"[+] White-box phase: 10/10 completed\n",
"[+] White-box phase completed successfully!\n"
]
}
],
"source": [
"import os\n",
"import requests\n",
"import pickle\n",
"import numpy as np\n",
"from typing import List, Dict, Tuple\n",
"\n",
"SEED = 1337\n",
"np.random.seed(SEED)\n",
"\n",
"BASE_URL = \"http://154.57.164.67:30687\"\n",
"\n",
"class WhiteBoxAttacker:\n",
" def __init__(self, base_url: str):\n",
" self.base_url = base_url\n",
" self.model = None\n",
" self.vectorizer = None\n",
" self.feature_names = None\n",
" self.classes = None\n",
"\n",
" def download_model(self):\n",
" print(\"[*] Downloading model...\")\n",
" r = requests.get(f\"{self.base_url}/model/download\")\n",
" r.raise_for_status()\n",
"\n",
" with open(\"/tmp/model.pkl\", \"wb\") as f:\n",
" f.write(r.content)\n",
"\n",
" with open(\"/tmp/model.pkl\", \"rb\") as f:\n",
" bundle = pickle.load(f)\n",
"\n",
" self.model = bundle[\"classifier\"]\n",
" self.vectorizer = bundle[\"vectorizer\"]\n",
" self.feature_names = bundle[\"feature_names\"]\n",
" self.classes = bundle[\"classes\"]\n",
" print(f\"[+] Model loaded: {len(self.feature_names)} features\")\n",
"\n",
" def calculate_word_scores(self, target_class: str) -> List[Tuple[str, float]]:\n",
" target_idx = self.classes.index(target_class)\n",
" other_idx = 1 - target_idx\n",
"\n",
" scores = []\n",
" for i, feature in enumerate(self.feature_names):\n",
" if \" \" in feature:\n",
" continue\n",
" target_prob = np.exp(self.model.feature_log_prob_[target_idx][i])\n",
" other_prob = np.exp(self.model.feature_log_prob_[other_idx][i])\n",
" score = target_prob / (other_prob + 1e-10)\n",
" scores.append((feature, score))\n",
"\n",
" scores.sort(key=lambda x: x[1], reverse=True)\n",
" return scores\n",
"\n",
" def attack_review(self, text: str, target: str, max_words: int) -> Tuple[str, int]:\n",
" word_scores = self.calculate_word_scores(target)\n",
"\n",
" augmented = text\n",
" for num_words in range(1, max_words + 1):\n",
" words_to_add = [w for w, _ in word_scores[:num_words]]\n",
" augmented = text + \" \" + \" \".join(words_to_add)\n",
"\n",
" vec = self.vectorizer.transform([augmented])\n",
" prediction = self.model.predict(vec)[0]\n",
"\n",
" if prediction == target:\n",
" return augmented, num_words\n",
"\n",
" return augmented, max_words\n",
"\n",
" def solve_whitebox(self) -> Dict:\n",
" print(\"\\n[*] Starting white-box phase...\")\n",
"\n",
" r = requests.get(f\"{self.base_url}/challenge/whitebox\")\n",
" r.raise_for_status()\n",
" challenge = r.json()\n",
"\n",
" reviews = challenge[\"reviews\"]\n",
" max_words = challenge[\"max_added_words\"]\n",
"\n",
" self.download_model()\n",
"\n",
" solutions = []\n",
" for review in reviews:\n",
" print(f\" Attacking review {review['id']}...\", end=\" \")\n",
" augmented, words_used = self.attack_review(\n",
" review[\"text\"], review[\"target_sentiment\"], max_words\n",
" )\n",
" solutions.append({\"id\": review[\"id\"], \"augmented_text\": augmented})\n",
" print(f\"Done ({words_used} words)\")\n",
"\n",
" r = requests.post(\n",
" f\"{self.base_url}/submit/whitebox\", json={\"solutions\": solutions}\n",
" )\n",
" r.raise_for_status()\n",
" result = r.json()\n",
"\n",
" if \"results\" in result:\n",
" successes = sum(1 for r in result[\"results\"] if r.get(\"success\", False))\n",
" print(f\"[+] White-box phase: {successes}/10 completed\")\n",
"\n",
" return result\n",
"\n",
"def main():\n",
" wb_attacker = WhiteBoxAttacker(BASE_URL)\n",
" wb_result = wb_attacker.solve_whitebox()\n",
"\n",
" if not wb_result.get(\"phase_complete\", False):\n",
" print(\"[-] Failed to complete white-box phase\")\n",
" return\n",
"\n",
" print(\"[+] White-box phase completed successfully!\")\n",
"\n",
"if __name__ == \"__main__\":\n",
" main()"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "ca580733-0f7d-401b-bd10-a29586b9f4b9",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"[*] Starting black-box phase...\n",
" Attacking review bb_0... Done (22 words, 73 queries total)\n",
" Attacking review bb_1... Done (40 words, 164 queries total)\n",
" Attacking review bb_2... Done (20 words, 235 queries total)\n",
" Attacking review bb_3... Done (17 words, 303 queries total)\n",
" Attacking review bb_4... Done (4 words, 358 queries total)\n",
" Attacking review bb_5... Done (38 words, 447 queries total)\n",
" Attacking review bb_6... Done (40 words, 538 queries total)\n",
" Attacking review bb_7... Done (4 words, 593 queries total)\n",
" Attacking review bb_8... Done (13 words, 657 queries total)\n",
" Attacking review bb_9... Done (6 words, 714 queries total)\n",
"[+] Black-box phase: 10/10 completed\n",
"\n",
"============================================================\n",
"[+] SUCCESS! All challenges completed!\n",
"[+] Flag: HTB{f34tur3_0bfu5c4t10n_m45t3r3d}\n",
"============================================================\n"
]
}
],
"source": [
"import os\n",
"import requests\n",
"import numpy as np\n",
"from typing import List, Dict, Tuple\n",
"\n",
"SEED = 1337\n",
"np.random.seed(SEED)\n",
"\n",
"BASE_URL = \"http://154.57.164.67:30687\"\n",
"\n",
"class BlackBoxAttacker:\n",
" def __init__(self, base_url: str):\n",
" self.base_url = base_url\n",
" self.word_impacts = {}\n",
" self.query_count = 0\n",
"\n",
" def predict(self, text: str) -> Dict:\n",
" self.query_count += 1\n",
" r = requests.post(f\"{self.base_url}/predict\", json={\"text\": text})\n",
" r.raise_for_status()\n",
" return r.json()\n",
"\n",
" def estimate_word_impacts(\n",
" self, base_text: str, vocabulary: List[str]\n",
" ) -> List[Tuple[str, float]]:\n",
" base_pred = self.predict(base_text)\n",
" base_pos_prob = base_pred[\"positive_probability\"]\n",
"\n",
" impacts = []\n",
" for word in vocabulary:\n",
" augmented = base_text + \" \" + word\n",
" pred = self.predict(augmented)\n",
" impact = pred[\"positive_probability\"] - base_pos_prob\n",
" impacts.append((word, impact))\n",
"\n",
" impacts.sort(key=lambda x: x[1], reverse=True)\n",
" return impacts\n",
"\n",
" def attack_review(self, text: str, max_words: int) -> Tuple[str, int]:\n",
" positive_vocabulary = [\n",
" \"excellent\", \"amazing\", \"wonderful\", \"fantastic\", \"brilliant\",\n",
" \"outstanding\", \"superb\", \"magnificent\", \"perfect\", \"exceptional\",\n",
" \"masterpiece\", \"genius\", \"beautiful\", \"stunning\", \"remarkable\",\n",
" \"awesome\", \"incredible\", \"phenomenal\", \"spectacular\", \"marvelous\",\n",
" \"great\", \"good\", \"love\", \"loved\", \"best\", \"favorite\", \"enjoyed\",\n",
" \"recommend\", \"highly\", \"definitely\", \"must\", \"liked\", \"appreciate\",\n",
" \"admire\", \"adore\", \"enjoy\", \"compelling\", \"engaging\", \"captivating\",\n",
" \"mesmerizing\", \"powerful\", \"touching\", \"moving\", \"inspiring\",\n",
" \"uplifting\", \"heartwarming\", \"clever\", \"witty\", \"funny\", \"hilarious\",\n",
" \"entertaining\"\n",
" ]\n",
"\n",
" impacts = self.estimate_word_impacts(text, positive_vocabulary[:50])\n",
"\n",
" augmented = text\n",
" for i, (word, impact) in enumerate(impacts, 1):\n",
" if i > max_words:\n",
" break\n",
"\n",
" augmented = augmented + \" \" + word\n",
" pred = self.predict(augmented)\n",
"\n",
" if pred[\"label\"] == \"positive\":\n",
" return augmented, i\n",
"\n",
" if impacts:\n",
" top_words = [w for w, _ in impacts[:10]]\n",
" words_to_add = []\n",
" while len(words_to_add) < max_words:\n",
" words_to_add.extend(top_words)\n",
" augmented = text + \" \" + \" \".join(words_to_add[:max_words])\n",
"\n",
" return augmented, max_words\n",
"\n",
" def solve_blackbox(self) -> Dict:\n",
" print(\"\\n[*] Starting black-box phase...\")\n",
"\n",
" r = requests.get(f\"{self.base_url}/challenge/blackbox\")\n",
" r.raise_for_status()\n",
" challenge = r.json()\n",
"\n",
" reviews = challenge[\"reviews\"]\n",
" max_words = challenge[\"max_added_words\"]\n",
"\n",
" solutions = []\n",
" for review in reviews:\n",
" print(f\" Attacking review {review['id']}...\", end=\" \")\n",
" augmented, words_used = self.attack_review(review[\"text\"], max_words)\n",
" solutions.append({\"id\": review[\"id\"], \"augmented_text\": augmented})\n",
" print(f\"Done ({words_used} words, {self.query_count} queries total)\")\n",
"\n",
" r = requests.post(\n",
" f\"{self.base_url}/submit/blackbox\", json={\"solutions\": solutions}\n",
" )\n",
" r.raise_for_status()\n",
" result = r.json()\n",
"\n",
" if \"results\" in result:\n",
" successes = sum(1 for r in result[\"results\"] if r.get(\"success\", False))\n",
" print(f\"[+] Black-box phase: {successes}/10 completed\")\n",
"\n",
" return result\n",
"\n",
"def main():\n",
" bb_attacker = BlackBoxAttacker(BASE_URL)\n",
" bb_result = bb_attacker.solve_blackbox()\n",
"\n",
" if bb_result.get(\"flag\"):\n",
" print(\"\\n\" + \"=\" * 60)\n",
" print(\"[+] SUCCESS! All challenges completed!\")\n",
" print(f\"[+] Flag: {bb_result['flag']}\")\n",
" print(\"=\" * 60)\n",
" else:\n",
" print(\"[-] Failed to complete black-box phase\")\n",
"\n",
"if __name__ == \"__main__\":\n",
" main()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "0b9ce2a6-d30d-466c-9e79-e4054b13b4ce",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.6"
}
},
"nbformat": 4,
"nbformat_minor": 5
}