How do I use Cross-Site Scripting to find the session cookie of a user if I have the source code of the Server?

I am currently studying about Client Side Web Security
and I have this task regarding Cross-Site Scripting. I am stuck for the past two days and don’t know where to start, I would appreciate if someone would be able to provide some tipps and guidance on how to solve/approach the task 🙂

The admin of https://noncense.is.hackthe.space regurarily debunks common misconceptions on his website and is very concerned with the security of his page. He also gives his readers a possibility to report errors within the page. If you encounter any errors, please do not hesitate to report them!
The flag is hidden in the session cookie of the admin.
The admin only accepts URLs that start with https://noncense.is.hackthe.space/ and their firewall prevents any connection to the Internet.

from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
import time, base64, re, json
from database import DBConnection
import logging, os
import redis

PORT = 5000
URL = os.environ['EXTERNAL_URL']
db = DBConnection()

QUEUE = 'help-urls'
rq = redis.Redis(host=os.environ['REDIS_HOST'], decode_responses=True)

def create_admin():
    if db.find_by_name("admin") == None:
        db.insert("admin", os.environ["ADMIN_PW"], os.environ["ADMIN_SESSION"])

def get_session_id(headers) -> (str | None):
    cookies = None if headers["Cookie"] is None else (
        dict(i.split('=', 1) for i in headers["Cookie"].split('; ')))
    return cookies.get("sessionID", None) if cookies else None

def generate_totally_secure_nonce() -> bytes:
    seconds = int(time.time())
    print(f"Generated nonce for {seconds}")
    return base64.b64encode(bytes(str(seconds), "utf-8"))

def validate(txt: str):
    regex = r"^[a-zA-Z0-9_{}]{0,100}$"
    return re.match(regex, txt)

def is_admin(headers):
    # Check if cookies contain the correct value (1010) for "sessionID" cookie
    cookies = None if headers["Cookie"] is None else (
        dict(i.split('=', 1) for i in headers["Cookie"].split('; ')))

return cookies is not None and cookies.get("sessionID", "") == db.find_by_name("admin")["sessionID"]

class SimpleHTTPRequestHandler(BaseHTTPRequestHandler):
def do_GET(self):

    serve_directly = ["/login.html", "/register.html", "/index.html"]
    resource = self.path

    # remove query parameters and fragements from path
    to_truncate = ["?", "#"]
    for c in to_truncate:
        occurrence = resource.find(c)
        if occurrence != -1:
            resource = resource[:occurrence]

    if resource == "/":
        resource = "/index.html"

    # serve the correct file
    if resource.startswith('/users/'):
        user_id = self.path[7:]
        try:
            user = db.find_by_id(user_id)
        except:
            self.serve_file("error.html", 404)
            return

        # Check permissions
        _sessionId = get_session_id(self.headers)
        if not user or not _sessionId or not db.authenticate(user_id, _sessionId):
            self.serve_file("error.html", 404)
            return
        
        # Serve profile page
        self.serve_file("profile.html", 200, {"[USER_PLACEHOLDER]": user["username"], "[DESC_PLACEHOLDER]": user["description"] if user["description"] else "No description"})

    elif resource.startswith('/help.html'):
        queue_size = str(rq.llen(QUEUE))
        self.serve_file('help.html', 200, {"[QUEUE_LOAD_PLACEHOLDER]": queue_size})

    elif resource in serve_directly:
        self.serve_file(resource.replace("/", ""), 200)
    
    elif resource == "/script.js":
        self.serve_file("script.js", 200, content_type="text/javascript")
    
    elif resource == "/style.css":
        self.serve_file("style.css", 200, content_type="text/css")

    elif resource == "/whoAmI":
        cookie = get_session_id(self.headers)
        if not cookie:
            self.send(404, "404 Not Found")
            return
        user = db.find_by_cookie(cookie)
        if not user:
            self.send(404, "404 Not Found")
            return

        self.send(200, json.dumps({"id": str(user["_id"])}))

    else:
        self.serve_file("error.html", 404)

def serve_file(self, file: str, err_code: int, placeholders: dict = dict(), content_type = None):
    nonce = generate_totally_secure_nonce()
    self.send_response(err_code)
    self.send_header("Content-Security-Policy", f"default-src 'self' 'nonce-{nonce.decode('utf-8')}'; style-src-elem 'self' fonts.googleapis.com cdn.jsdelivr.net 'nonce-{nonce.decode('utf-8')}'; img-src http.cat; font-src fonts.gstatic.com")

    if content_type is None:
        self.send_header('Content-type', 'text/html')
    else:
        self.send_header('Content-type', content_type)
    self.end_headers()

    with open("resources/" + file, "rb") as file:
        content = file.read()
        content = content.replace(b"[NONCEPLACEHOLDER]", nonce)
        for key, value in placeholders.items():
            content = content.replace(bytes(key, "utf-8"), bytes(value, "utf-8"))
        self.wfile.write(content)

def do_POST(self):
    content_len = int(self.headers.get('Content-Length'))
    body = self.rfile.read(content_len).decode("utf-8")
    print(f"Received {body=}")

    if self.path.startswith("/users/"):
        user_id = self.path[7:]

        if not user_id:
            self.send(404, "404 Not Found")
            return

        # Validate description if user is not admin
        if not validate(body):
            self.send(422, "422 Unprocessable Entity")
            return
        
        session_cookie = get_session_id(self.headers)
        if not session_cookie:
            self.send(403, "403 Forbidden")
            return
        
        _is_admin = db.is_admin(session_cookie)
        is_owner = db.authenticate(user_id, session_cookie)

        if (_is_admin and is_owner) or 
            (not _is_admin and not is_owner):

            self.send(403, "403 Forbidden")
            return

        db.update_description(user_id, body)

        self.send(200, "200 Ok")

    elif self.path == "/register":

        # Validate body and check if both necessary fields are set
        try:
            user_data = json.loads(body)
        except:
            self.send(422, "422 Unprocessable Entity")
            return

        if (not user_data) or user_data.get("username", "") == "" 
            or user_data.get("password", "") == "" 
            or not validate(user_data['username']) 
            or not validate(user_data['password']):
            
            self.send(422, "422 Unprocessable Entity")
            return

        if db.find_by_name(user_data['username']) is not None:
            self.send(409, "409 Conflict")
            return

        res = db.insert(user_data['username'], user_data['password'])
        user = db.find_by_id(res.inserted_id)
        self.send(200, json.dumps({"id": str(user["_id"]), "username": user["username"]}), user['sessionID'])
    
    elif self.path == "/login":

        # Validate body and check if both necessary fields are set
        try:
            user_data = json.loads(body)
        except:
            self.send(422, "422 Unprocessable Entity")
            return
        
        if (not user_data) or user_data.get("username", "") == "" or user_data.get("password", "") == "":
            self.send(422, "422 Unprocessable Entity")
            return
        
        user_cookie = db.get_session_cookie(user_data['username'], user_data['password'])

        if user_cookie:
            user_id = str(db.find_by_name(user_data['username'])['_id'])
            self.send(200,  json.dumps({"id": user_id}), user_cookie)
        else:
            self.send(401, "401 Unauthorized")

    elif self.path == "/help":

        try:
            user_data = json.loads(body)
        except:
            self.send(422, "422 Unprocessable Entity")
            return
        
        if not user_data.get('url', False) or not user_data['url'].startswith(URL):
            self.send(422, "422 Unprocessable Entity")
            return
        
        try:
            rq.rpush(QUEUE, user_data['url'])
        except Exception as e:
            print(f"Something went wrong: f{e=}")
            self.send(500, "500 Internal Server Error")
            return
        
        self.send(200, "200 Ok")
    else:
        # Send default error response
        self.send(404, "404 Not Found")
        
def send(self, code: int, msg: str, response_cookie: str = None, _json: bool = False):
    self.send_response(code)
    if (_json):
        self.send_header('Content-type', 'application/json')
    else:
        self.send_header('Content-type', 'text/html')
    if response_cookie:
        self.send_header('Set-Cookie', f"sessionID={response_cookie}")
    self.end_headers()
    self.wfile.write(bytes(msg, "utf-8"));


def run(server_class=ThreadingHTTPServer, handler_class=SimpleHTTPRequestHandler, port=PORT):
    server_address = ('', port)
    httpd = server_class(server_address, handler_class)
    print(f'Starting server on port {port}...')
    httpd.serve_forever()


if __name__ == '__main__':
    logging.info("creating admin user...")
    create_admin()
    run()

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật