In the previous article, I analyzed CVE-2022-35914, in this article, I will analyze the bypass authentication vulnerability through SQL injection with the code CVE-2022-35947.
Analysis CVE-2022-35947
According to the description of this vulnerability at https://github.com/glpi-project/glpi/security/advisories/GHSA-7p3q-cffg-c8xh , it is known that an attacker can take advantage of the vulnerability to login to an account. of any user with an API token when Enable login with external token
is enabled (it is enabled by default). Also here we know that the faulty glpi version is < 10.0.3 and is fixed in version 10.0.3.
Diff patch
From the information above, we proceed to diff versions 10.0.2 and 10.0.3 to find the source of the vulnerability. Commit bug fix here: https://github.com/glpi-project/glpi/commit/564309d2c1180d5ba1615f4bbaf6623df81b4962
glpi fixes the SQLi bug by ensuring that the token passed to the getFromDBbyToken
function is a string. if not string will give an error immediately.
Analysis
Let’s find out why glpi fixes such a bug. Jump into the getFromDBbyToken
function in src/User.php
Here there are 2 jobs we have to do. The first is to find the taint flow from source to this function, the second is to find the taint flow from this function to the sink. about sink or source, you can read my old posts again. To find this taint fow you can use ide like PhpStorm
, in this article I use VSCode
to trace and debug by echo
or var_dump
the variables I’m interested in.
Train flow from source to function getFromDBbyToken
At the getFromDBbyToken function, right-click and select Go to References
to list all the places where this function is used.
Here appear 2 places to call getFromDBbyToken
in the file Auth.php
and Session.php
. Re-reading the description of the vulnerability, we know this is a bypass authentication vulnerability, so there’s a high chance that what we’re interested in will be in Auth.php
. Jump into getAlternateAuthSystemsUserLogin
function in the Auth.php
file. This function will handle different logins based on $authtype
passed in. If $authtype=self::API
then the function will call getFromDBbyToken
.
At line 610, the parameter passed to getFromDBbyToken
taken from the variable $_REQUEST['user_token']
is completely controllable. However, we do not know how to jump into this case, our first job does not stop here. Continue the reverse trace from the getAlternateAuthSystemsUserLogin
function.
This function will be called in the login
function. This function will perform the login of the user. The login request will look like this:
Observe the code from line 750-754
1 2 3 4 5 6 | <span class="token keyword">if</span> <span class="token punctuation">(</span> <span class="token operator">!</span> <span class="token variable">$noauto</span> <span class="token operator">&&</span> <span class="token punctuation">(</span> <span class="token variable">$authtype</span> <span class="token operator">=</span> <span class="token keyword static-context">self</span> <span class="token operator">::</span> <span class="token function">checkAlternateAuthSystems</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> <span class="token variable">$this</span> <span class="token operator">-></span> <span class="token function">getAlternateAuthSystemsUserLogin</span> <span class="token punctuation">(</span> <span class="token variable">$authtype</span> <span class="token punctuation">)</span> <span class="token operator">&&</span> <span class="token operator">!</span> <span class="token keyword">empty</span> <span class="token punctuation">(</span> <span class="token variable">$this</span> <span class="token operator">-></span> <span class="token property">user</span> <span class="token operator">-></span> <span class="token property">fields</span> <span class="token punctuation">[</span> <span class="token string single-quoted-string">'name'</span> <span class="token punctuation">]</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> |
if $noauto=false
and self::checkAlternateAuthSystems()
return values other than false then getAlternateAuthSystemsUserLogin
will be called with the $authtype
parameter being the return value of self::checkAlternateAuthSystems()
. Jump into self::checkAlternateAuthSystems()
.
At line 1324, if the request contains a noAUTO
parameter, the function will return false immediately. So when we send login request, we need to remove this parameter. Next observe the code line 1360, if user_token
parameter exists in the request, the function will return self::API
. This is exactly what we need.
In a nutshell, the tain from source to the getFromDBbyToken function looks like this:
login(no noAUTO
parameter and user_token
parameter)
=> getAlternateAuthSystemsUserLogin($authtype)
=>getFromDBbyToken($_REQUEST[‘user_token’], ‘api_token’)
Taint flow from getFromDBbyToken function to sink
Our next job will have to find taint from getFromDBbyToken to sink.
The getFromDBbyToken
function takes a user_token
parameter and passes it to the getFromDBByCrit
function
1 2 | <span class="token keyword">return</span> <span class="token variable">$this</span> <span class="token operator">-></span> <span class="token function">getFromDBByCrit</span> <span class="token punctuation">(</span> <span class="token punctuation">[</span> <span class="token variable">$this</span> <span class="token operator">-></span> <span class="token function">getTable</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">.</span> <span class="token string double-quoted-string">". <span class="token interpolation"><span class="token variable">$field</span></span> "</span> <span class="token operator">=></span> <span class="token variable">$token</span> <span class="token punctuation">]</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> |
Before going to the getFromDBByCrit
function we need to note one thing. Version 10.0.3 only accepts getFromDBbyToken
function as a string input, so perhaps if the input is a data type other than string it will cause an error. Here we aim for the array data type. I will explain why below.
Jump into the getFromDBByCrit
function.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">getFromDBByCrit</span> <span class="token punctuation">(</span> <span class="token keyword type-hint">array</span> <span class="token variable">$crit</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">var_dump</span> <span class="token punctuation">(</span> <span class="token variable">$crit</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">die</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">global</span> <span class="token variable">$DB</span> <span class="token punctuation">;</span> <span class="token variable">$crit</span> <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token string single-quoted-string">'SELECT'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'id'</span> <span class="token punctuation">,</span> <span class="token string single-quoted-string">'FROM'</span> <span class="token operator">=></span> <span class="token variable">$this</span> <span class="token operator">-></span> <span class="token function">getTable</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> <span class="token string single-quoted-string">'WHERE'</span> <span class="token operator">=></span> <span class="token variable">$crit</span> <span class="token punctuation">]</span> <span class="token punctuation">;</span> <span class="token variable">$iter</span> <span class="token operator">=</span> <span class="token variable">$DB</span> <span class="token operator">-></span> <span class="token function">request</span> <span class="token punctuation">(</span> <span class="token variable">$crit</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> <span class="token function">count</span> <span class="token punctuation">(</span> <span class="token variable">$iter</span> <span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token number">1</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token variable">$row</span> <span class="token operator">=</span> <span class="token variable">$iter</span> <span class="token operator">-></span> <span class="token function">current</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token variable">$this</span> <span class="token operator">-></span> <span class="token function">getFromDB</span> <span class="token punctuation">(</span> <span class="token variable">$row</span> <span class="token punctuation">[</span> <span class="token string single-quoted-string">'id'</span> <span class="token punctuation">]</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> <span class="token function">count</span> <span class="token punctuation">(</span> <span class="token variable">$iter</span> <span class="token punctuation">)</span> <span class="token operator">></span> <span class="token number">1</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">trigger_error</span> <span class="token punctuation">(</span> <span class="token function">sprintf</span> <span class="token punctuation">(</span> <span class="token string single-quoted-string">'getFromDBByCrit expects to get one result, %1$s found in query "%2$s".'</span> <span class="token punctuation">,</span> <span class="token function">count</span> <span class="token punctuation">(</span> <span class="token variable">$iter</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> <span class="token variable">$iter</span> <span class="token operator">-></span> <span class="token function">getSql</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> <span class="token constant">E_USER_WARNING</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token constant boolean">false</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> |
Here we have to observe the value of the variables passed, I use var_dump
to observe the variable $crit
.
With user_token=1
, $crit
is currently an array with the key glpi_users.api_token
and the value of type 1
string. Next, the $crit
variable is overwritten back into an array where the key WHERE
value is the value. initial value of the variable $crit
Next $crit
will be passed to the function $DB->request($crit);
. Jump into this function.
1 2 3 4 5 6 7 | <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">request</span> <span class="token punctuation">(</span> <span class="token variable">$tableorsql</span> <span class="token punctuation">,</span> <span class="token variable">$crit</span> <span class="token operator">=</span> <span class="token string double-quoted-string">""</span> <span class="token punctuation">,</span> <span class="token variable">$debug</span> <span class="token operator">=</span> <span class="token constant boolean">false</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token variable">$iterator</span> <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">DBmysqlIterator</span> <span class="token punctuation">(</span> <span class="token variable">$this</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token variable">$iterator</span> <span class="token operator">-></span> <span class="token function">execute</span> <span class="token punctuation">(</span> <span class="token variable">$tableorsql</span> <span class="token punctuation">,</span> <span class="token variable">$crit</span> <span class="token punctuation">,</span> <span class="token variable">$debug</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token variable">$iterator</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> |
This function calls execute($tableorsql, $crit, $debug)
1 2 3 4 5 6 7 8 9 | <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">execute</span> <span class="token punctuation">(</span> <span class="token variable">$table</span> <span class="token punctuation">,</span> <span class="token variable">$crit</span> <span class="token operator">=</span> <span class="token string double-quoted-string">""</span> <span class="token punctuation">,</span> <span class="token variable">$debug</span> <span class="token operator">=</span> <span class="token constant boolean">false</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token variable">$this</span> <span class="token operator">-></span> <span class="token function">buildQuery</span> <span class="token punctuation">(</span> <span class="token variable">$table</span> <span class="token punctuation">,</span> <span class="token variable">$crit</span> <span class="token punctuation">,</span> <span class="token variable">$debug</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token variable">$this</span> <span class="token operator">-></span> <span class="token property">res</span> <span class="token operator">=</span> <span class="token punctuation">(</span> <span class="token variable">$this</span> <span class="token operator">-></span> <span class="token property">conn</span> <span class="token operator">?</span> <span class="token variable">$this</span> <span class="token operator">-></span> <span class="token property">conn</span> <span class="token operator">-></span> <span class="token function">query</span> <span class="token punctuation">(</span> <span class="token variable">$this</span> <span class="token operator">-></span> <span class="token property">sql</span> <span class="token punctuation">)</span> <span class="token punctuation">:</span> <span class="token class-name return-type">false</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token variable">$this</span> <span class="token operator">-></span> <span class="token property">count</span> <span class="token operator">=</span> <span class="token variable">$this</span> <span class="token operator">-></span> <span class="token property">res</span> <span class="token keyword">instanceof</span> <span class="token class-name class-name-fully-qualified"> mysqli_result</span> <span class="token operator">?</span> <span class="token variable">$this</span> <span class="token operator">-></span> <span class="token property">conn</span> <span class="token operator">-></span> <span class="token function">numrows</span> <span class="token punctuation">(</span> <span class="token variable">$this</span> <span class="token operator">-></span> <span class="token property">res</span> <span class="token punctuation">)</span> <span class="token punctuation">:</span> <span class="token number">0</span> <span class="token punctuation">;</span> <span class="token variable">$this</span> <span class="token operator">-></span> <span class="token function">setPosition</span> <span class="token punctuation">(</span> <span class="token number">0</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token variable">$this</span> <span class="token punctuation">;</span> |
Here, the query will be built using the buildQuery($table, $crit, $debug)
function and then executed with $this->res = ($this->conn ? $this->conn->query($this->sql) : false);
Go into the buildQuery
function. Note, the $table
parameter is $crit
I described above, and currently $table
is an array
.
Reading the code logic, at line 146, the $table
variable will be set to glpi_users
. Next at line 203, since the $crit
array contains a key of WHERE
, $where
variable will be set to an array with the key glpi_users.api_token
and the value 1
At line 311, the sql
variable containing the query will be concatenated as follows.
1 2 | <span class="token variable">$this</span> <span class="token operator">-></span> <span class="token property">sql</span> <span class="token operator">.=</span> <span class="token string double-quoted-string">" WHERE "</span> <span class="token operator">.</span> <span class="token variable">$this</span> <span class="token operator">-></span> <span class="token function">analyseCrit</span> <span class="token punctuation">(</span> <span class="token variable">$where</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> |
jump into the function analyseCrit
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">analyseCrit</span> <span class="token punctuation">(</span> <span class="token variable">$crit</span> <span class="token punctuation">,</span> <span class="token variable">$bool</span> <span class="token operator">=</span> <span class="token string double-quoted-string">"AND"</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> <span class="token operator">!</span> <span class="token function">is_array</span> <span class="token punctuation">(</span> <span class="token variable">$crit</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">//if ($_SESSION['glpi_use_mode'] == Session::DEBUG_MODE) {</span> <span class="token comment">// trigger_error("Deprecated usage of SQL in DB/request (criteria)", E_USER_DEPRECATED);</span> <span class="token comment">//}</span> <span class="token keyword">return</span> <span class="token variable">$crit</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token variable">$ret</span> <span class="token operator">=</span> <span class="token string double-quoted-string">""</span> <span class="token punctuation">;</span> <span class="token keyword">foreach</span> <span class="token punctuation">(</span> <span class="token variable">$crit</span> <span class="token keyword">as</span> <span class="token variable">$name</span> <span class="token operator">=></span> <span class="token variable">$value</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> <span class="token operator">!</span> <span class="token keyword">empty</span> <span class="token punctuation">(</span> <span class="token variable">$ret</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token variable">$ret</span> <span class="token operator">.=</span> <span class="token string double-quoted-string">" <span class="token interpolation"><span class="token variable">$bool</span></span> "</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> <span class="token function">is_numeric</span> <span class="token punctuation">(</span> <span class="token variable">$name</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// no key and direct expression</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> <span class="token variable">$value</span> <span class="token keyword">instanceof</span> <span class="token class-name">QueryExpression</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token variable">$ret</span> <span class="token operator">.=</span> <span class="token variable">$value</span> <span class="token operator">-></span> <span class="token function">getValue</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> <span class="token variable">$value</span> <span class="token keyword">instanceof</span> <span class="token class-name">QuerySubQuery</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token variable">$ret</span> <span class="token operator">.=</span> <span class="token variable">$value</span> <span class="token operator">-></span> <span class="token function">getQuery</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> <span class="token comment">// No Key case => recurse.</span> <span class="token variable">$ret</span> <span class="token operator">.=</span> <span class="token string double-quoted-string">"("</span> <span class="token operator">.</span> <span class="token variable">$this</span> <span class="token operator">-></span> <span class="token function">analyseCrit</span> <span class="token punctuation">(</span> <span class="token variable">$value</span> <span class="token punctuation">)</span> <span class="token operator">.</span> <span class="token string double-quoted-string">")"</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> <span class="token punctuation">(</span> <span class="token variable">$name</span> <span class="token operator">===</span> <span class="token string double-quoted-string">"OR"</span> <span class="token punctuation">)</span> <span class="token operator">||</span> <span class="token punctuation">(</span> <span class="token variable">$name</span> <span class="token operator">===</span> <span class="token string double-quoted-string">"AND"</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// Binary logical operator</span> <span class="token variable">$ret</span> <span class="token operator">.=</span> <span class="token string double-quoted-string">"("</span> <span class="token operator">.</span> <span class="token variable">$this</span> <span class="token operator">-></span> <span class="token function">analyseCrit</span> <span class="token punctuation">(</span> <span class="token variable">$value</span> <span class="token punctuation">,</span> <span class="token variable">$name</span> <span class="token punctuation">)</span> <span class="token operator">.</span> <span class="token string double-quoted-string">")"</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> <span class="token variable">$name</span> <span class="token operator">===</span> <span class="token string double-quoted-string">"NOT"</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// Uninary logicial operator</span> <span class="token variable">$ret</span> <span class="token operator">.=</span> <span class="token string double-quoted-string">" NOT ("</span> <span class="token operator">.</span> <span class="token variable">$this</span> <span class="token operator">-></span> <span class="token function">analyseCrit</span> <span class="token punctuation">(</span> <span class="token variable">$value</span> <span class="token punctuation">)</span> <span class="token operator">.</span> <span class="token string double-quoted-string">")"</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> <span class="token variable">$name</span> <span class="token operator">===</span> <span class="token string double-quoted-string">"FKEY"</span> <span class="token operator">||</span> <span class="token variable">$name</span> <span class="token operator">===</span> <span class="token string single-quoted-string">'ON'</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// Foreign Key condition</span> <span class="token variable">$ret</span> <span class="token operator">.=</span> <span class="token variable">$this</span> <span class="token operator">-></span> <span class="token function">analyseFkey</span> <span class="token punctuation">(</span> <span class="token variable">$value</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> <span class="token variable">$name</span> <span class="token operator">===</span> <span class="token string single-quoted-string">'RAW'</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token variable">$key</span> <span class="token operator">=</span> <span class="token function">key</span> <span class="token punctuation">(</span> <span class="token variable">$value</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token variable">$value</span> <span class="token operator">=</span> <span class="token function">current</span> <span class="token punctuation">(</span> <span class="token variable">$value</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token variable">$ret</span> <span class="token operator">.=</span> <span class="token string single-quoted-string">'(('</span> <span class="token operator">.</span> <span class="token variable">$key</span> <span class="token operator">.</span> <span class="token string single-quoted-string">') '</span> <span class="token operator">.</span> <span class="token variable">$this</span> <span class="token operator">-></span> <span class="token function">analyseCriterion</span> <span class="token punctuation">(</span> <span class="token variable">$value</span> <span class="token punctuation">)</span> <span class="token operator">.</span> <span class="token string single-quoted-string">')'</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> <span class="token variable">$ret</span> <span class="token operator">.=</span> <span class="token class-name static-context">DBmysql</span> <span class="token operator">::</span> <span class="token function">quoteName</span> <span class="token punctuation">(</span> <span class="token variable">$name</span> <span class="token punctuation">)</span> <span class="token operator">.</span> <span class="token string single-quoted-string">' '</span> <span class="token operator">.</span> <span class="token variable">$this</span> <span class="token operator">-></span> <span class="token function">analyseCriterion</span> <span class="token punctuation">(</span> <span class="token variable">$value</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token variable">$ret</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> |
In this function, our $name
variable currently has the value glpi_users.api_token
So we’ll jump to line 557
1 2 | <span class="token variable">$ret</span> <span class="token operator">.=</span> <span class="token class-name static-context">DBmysql</span> <span class="token operator">::</span> <span class="token function">quoteName</span> <span class="token punctuation">(</span> <span class="token variable">$name</span> <span class="token punctuation">)</span> <span class="token operator">.</span> <span class="token string single-quoted-string">' '</span> <span class="token operator">.</span> <span class="token variable">$this</span> <span class="token operator">-></span> <span class="token function">analyseCriterion</span> <span class="token punctuation">(</span> <span class="token variable">$value</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> |
go into the function analyseCriterion
. Note, the $value
parameter is currently the user_token
value we passed in.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | <span class="token keyword">private</span> <span class="token keyword">function</span> <span class="token function-definition function">analyseCriterion</span> <span class="token punctuation">(</span> <span class="token variable">$value</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token variable">$criterion</span> <span class="token operator">=</span> <span class="token constant">null</span> <span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> <span class="token function">is_null</span> <span class="token punctuation">(</span> <span class="token variable">$value</span> <span class="token punctuation">)</span> <span class="token operator">||</span> <span class="token punctuation">(</span> <span class="token function">is_string</span> <span class="token punctuation">(</span> <span class="token variable">$value</span> <span class="token punctuation">)</span> <span class="token operator">&&</span> <span class="token function">strtolower</span> <span class="token punctuation">(</span> <span class="token variable">$value</span> <span class="token punctuation">)</span> <span class="token operator">===</span> <span class="token string single-quoted-string">'null'</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// NULL condition</span> <span class="token variable">$criterion</span> <span class="token operator">=</span> <span class="token string single-quoted-string">'IS NULL'</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> <span class="token function">is_array</span> <span class="token punctuation">(</span> <span class="token variable">$value</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> <span class="token function">count</span> <span class="token punctuation">(</span> <span class="token variable">$value</span> <span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token number">2</span> <span class="token operator">&&</span> <span class="token keyword">isset</span> <span class="token punctuation">(</span> <span class="token variable">$value</span> <span class="token punctuation">[</span> <span class="token number">0</span> <span class="token punctuation">]</span> <span class="token punctuation">)</span> <span class="token operator">&&</span> <span class="token variable">$this</span> <span class="token operator">-></span> <span class="token function">isOperator</span> <span class="token punctuation">(</span> <span class="token variable">$value</span> <span class="token punctuation">[</span> <span class="token number">0</span> <span class="token punctuation">]</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token variable">$comparison</span> <span class="token operator">=</span> <span class="token variable">$value</span> <span class="token punctuation">[</span> <span class="token number">0</span> <span class="token punctuation">]</span> <span class="token punctuation">;</span> <span class="token variable">$criterion_value</span> <span class="token operator">=</span> <span class="token variable">$value</span> <span class="token punctuation">[</span> <span class="token number">1</span> <span class="token punctuation">]</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> <span class="token operator">!</span> <span class="token function">count</span> <span class="token punctuation">(</span> <span class="token variable">$value</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name class-name-fully-qualified"> RuntimeException</span> <span class="token punctuation">(</span> <span class="token string single-quoted-string">'Empty IN are not allowed'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">// Array of Values</span> <span class="token keyword">return</span> <span class="token string double-quoted-string">"IN ("</span> <span class="token operator">.</span> <span class="token variable">$this</span> <span class="token operator">-></span> <span class="token function">analyseCriterionValue</span> <span class="token punctuation">(</span> <span class="token variable">$value</span> <span class="token punctuation">)</span> <span class="token operator">.</span> <span class="token string double-quoted-string">")"</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> <span class="token variable">$comparison</span> <span class="token operator">=</span> <span class="token punctuation">(</span> <span class="token variable">$value</span> <span class="token keyword">instanceof</span> <span class="token class-name class-name-fully-qualified"> AbstractQuery</span> <span class="token operator">?</span> <span class="token string single-quoted-string">'IN'</span> <span class="token punctuation">:</span> <span class="token string single-quoted-string">'='</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token variable">$criterion_value</span> <span class="token operator">=</span> <span class="token variable">$value</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token variable">$criterion</span> <span class="token operator">=</span> <span class="token string double-quoted-string">" <span class="token interpolation"><span class="token variable">$comparison</span></span> "</span> <span class="token operator">.</span> <span class="token variable">$this</span> <span class="token operator">-></span> <span class="token function">getCriterionValue</span> <span class="token punctuation">(</span> <span class="token variable">$criterion_value</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token variable">$criterion</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> |
At line 582. If value is an array consisting of 2 elements, the first word is one of the operators in the list, then $comparison = $value[0];
and the value after operator will be $value[1]
.
The function will then return a concatenated string from those two elements
1 2 | <span class="token variable">$criterion</span> <span class="token operator">=</span> <span class="token string double-quoted-string">" <span class="token interpolation"><span class="token variable">$comparison</span></span> "</span> <span class="token operator">.</span> <span class="token variable">$this</span> <span class="token operator">-></span> <span class="token function">getCriterionValue</span> <span class="token punctuation">(</span> <span class="token variable">$criterion_value</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> |
This is the sink we are looking for. Let me explain a little more. If the user_token
value is a 2-element array. Where the first element is LIKE
, and the second element is %a%
, the query after string concatenation will be ... WHERE glpi_users.api_token LIKE %a%
At this point, we were able to bypass the authen successfully. If the user creates an API token with the character a
, the above query will return that user => we login to that user account.
In summary, our chain from source to sink will look like this:
=> login(no noAUTO
parameter and user_token[]=['LIKE','%a%']
parameter)
=> getAlternateAuthSystemsUserLogin($authtype)
=> getFromDBbyToken($_REQUEST[‘user_token’], ‘api_token’)
=> getFromDBByCrit([$this->getTable() . “.$field” => $token])
=> $DB->request($crit)
=> execute($tableorsql, $crit, $debug)
=> buildQuery($table, $crit, $debug)
=> analyzeCrit($crit, $bool = “AND”)
=> analyzeCriterion($value)