diff --git a/web-security/level-9/.config b/web-security/level-9/.config
deleted file mode 100644
index ec63514..0000000
--- a/web-security/level-9/.config
+++ /dev/null
@@ -1 +0,0 @@
-9
diff --git a/web-security/level-9/DESCRIPTION.md b/web-security/level-9/DESCRIPTION.md
new file mode 100644
index 0000000..0fc0b60
--- /dev/null
+++ b/web-security/level-9/DESCRIPTION.md
@@ -0,0 +1,5 @@
+Like with SQL injection and command injection, sometimes your XSS occurs in the middle of some non-optimal context.
+In SQL, you have dealt with injecting into the middle of quotes.
+In XSS, you often inject into, for example, a textarea, as in this challenge.
+Normally, text in a textarea is just, well, text that'll show up in a textbox on the page.
+Can you bust of this context and `alert("PWNED")`?
diff --git a/web-security/level-9/run b/web-security/level-9/run
deleted file mode 120000
index 84ba55b..0000000
--- a/web-security/level-9/run
+++ /dev/null
@@ -1 +0,0 @@
-../run
\ No newline at end of file
diff --git a/web-security/level-9/server b/web-security/level-9/server
new file mode 100755
index 0000000..394c0a0
--- /dev/null
+++ b/web-security/level-9/server
@@ -0,0 +1,22 @@
+#!/opt/pwn.college/python
+
+import flask
+import os
+
+app = flask.Flask(__name__)
+
+@app.route("/", methods=["GET"])
+def challenge_get():
+ return f"""
+
+ pwnmsg ephemeral message service
+ The message:
+
+
+ """
+
+app.secret_key = os.urandom(8)
+app.run("challenge.localhost", 8080 if os.geteuid() else 80)
diff --git a/web-security/level-9/victim b/web-security/level-9/victim
new file mode 100755
index 0000000..a676fe4
--- /dev/null
+++ b/web-security/level-9/victim
@@ -0,0 +1,68 @@
+#!/opt/pwn.college/python
+
+import contextlib
+import urllib
+import sys
+import os
+
+from selenium import webdriver
+from selenium.webdriver.firefox.options import Options as FirefoxOptions
+from selenium.webdriver.firefox.service import Service as FirefoxService
+from selenium.webdriver.common.by import By
+from selenium.webdriver.support.wait import WebDriverWait
+from selenium.webdriver.support import expected_conditions as EC
+from selenium.common.exceptions import TimeoutException, WebDriverException
+
+os.environ["PATH"] = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
+
+@contextlib.contextmanager
+def run_browser():
+ options = FirefoxOptions()
+ options.add_argument("--headless")
+
+ # workaround for ubuntu
+ if os.path.exists("/snap/bin/geckodriver"):
+ service = FirefoxService(executable_path="/snap/bin/geckodriver", log_path="/dev/null")
+ else:
+ service = FirefoxService(log_path="/dev/null")
+ driver = webdriver.Firefox(service=service, options=options)
+
+ try:
+ yield driver
+ finally:
+ driver.quit()
+
+if len(sys.argv) <= 1:
+ print(f"Usage: {sys.argv[0]} URL")
+ sys.exit(1)
+
+url = sys.argv[1]
+url_arg_parsed = urllib.parse.urlparse(url)
+try:
+ assert url_arg_parsed.hostname == "challenge.localhost", "hostname should be 'challenge.localhost'"
+ assert url_arg_parsed.port in {None, 80, 8080}, "port should be 80 or 8080"
+except AssertionError as e:
+ print(f"Invalid URL: {e}")
+ sys.exit(2)
+
+print("Visiting the URL!")
+with run_browser() as browser:
+ try:
+ browser.get(url)
+ print("URL loaded...")
+ WebDriverWait(browser, 1).until(EC.alert_is_present())
+ except TimeoutException:
+ print("Failure: JavaScript alert did not trigger...")
+ sys.exit(3)
+ except WebDriverException as e:
+ if "can%E2%80%99t%20establish%20a%20connection" in str(e):
+ print("Connection error! Is the service running?")
+ else:
+ print(f"Failure: {e}...")
+ sys.exit(4)
+ else:
+ if url_arg_parsed.port is None or url_arg_parsed.port == 80:
+ print("Alert triggered! Your flag:")
+ print(open("/flag").read())
+ else:
+ print("Alert triggered! Now do it on the real service (port 80)!")
diff --git a/web-security/module.yml b/web-security/module.yml
index f9b9cc7..821fd2d 100644
--- a/web-security/module.yml
+++ b/web-security/module.yml
@@ -38,7 +38,6 @@ challenges:
name: XSS 3
- id: level-9
name: XSS 4
- description: Exploit a cross site scripting vulnerability with more complicated context
- id: level-10
name: XSS 5
description: Exploit a cross site scripting vulnerability to cause a user action