• XSS.stack #1 – первый литературный журнал от юзеров форума

Статья Что за SSTI: Server-Side Template Injection и автоматизация

grozdniyandy

White-Hat
Premium
Регистрация
11.08.2023
Сообщения
522
Реакции
677
Гарант сделки
2

<%=

Эта статья посвящена 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]: Запуск

Изображение [1]: Запуск

Изображение [2]: Запуск

Изображение [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]: Редактирование типа

Изображение [3]: Редактирование типа


Изображение [4]: Хааацк

Изображение [4]: Хааацк


1694888883891.png

Изображение [5]: Утечка каталога и кода​

Утечка исходного кода и каталогов может помочь в дальнейших атаках. Например, если веб-сайт уязвим для SQL-инъекций, утечка каталога может быть полезна хакеру, чтобы он знал, в какой каталог загружать файл и получать оболочку (Shell). Утечка исходного кода даст хакеру советы по поиску новых уязвимостей или усилению воздействия существующих уязвимостей, которые уже ему известны.

Итак, чтобы устранить проблемы, мы должны сначала обработать данные ввода и этим предотвратить инъекции, отключить debugging, добавить дополнительную проверку электронной почты в серверной части.

1694891334684.png

Изображение [6]: Исправление кода​

Код внутри первого прямоугольника - это функция для проверки электронной почты, второй прямоугольник вызывает эту функцию и, если электронная почта неверна, выводит текст, третий прямоугольник предназначен для предотвращения внедрения с использованием "| h", четвертый прямоугольник просто отключает debugging. Как вы теперь видите, наш код не выполняется:

1694891829463.png

Изображение [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]: Главная страница

Изображение [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]: Хааацк

Изображение [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

Изображение [10]: SSTImap​

ERB используется для встраивания кода Ruby в HTML-документ, поэтому мы можем просто использовать код Ruby для выполнения команд. Я нашел статью об этом: https://www.rubyguides.com/2018/12/ruby-system/. Полезная нагрузка, которую мы собираемся использовать: <%=system("id")%>

Изображение [11]: id

Изображение [11]: id​

После этой лабораторной работы я подумал, что могу просто автоматизировать процесс, чтобы быстрее понять, существует уязвимость или нет. Чтобы это сработало, на сервере должен быть включен режим отладки, так что это снижает шансы, но помогает быстрее понять, существует ли уязвимость, и если да, то мы можем понять, какой шаблонизатор используется.
Полиглот:
Код:
${{<%[%'"}}%\%>

Этот полиглот на самом деле из одной из лабораторий, я протестировал все лаборатории, и он работает в 4 из 7 лабораторий. Я немного отредактировал полиглот, потому что в первой лаборатории он не работал.


1694898719121.png

Изображение [12]: Лаборатория 2/7


Изображение [13]: Лаборатория 2/7

Изображение [13]: Лаборатория 2/7



Изображение [14]: Лаборатория 4/7

Изображение [14]: Лаборатория 4/7



Изображение [15]: Лаборатория 5/7

Изображение [15]: Лаборатория 5/7


Изображение [15]: Лаборатория 5/7

Изображение [16]: Лаборатория 5/7​

Я решил написать простой инструмент, который поможет нам идентифицировать SSTI в больших масштабах. Смысл этого инструмента заключается в замене параметров на полиглот и проверке того, содержит ли ответ ошибки или равен ли статус код 500. Пользователи могут добавлять URL-адреса доменов в файл, а затем использовать команду xargs с помощью этого инструмента и протестировать на наличие SSTI или, возможно, SQL-инъекции, в обоих случаях могут возникнуть ошибки. Я, очевидно, понимаю, что SSTImap более продвинутый, этот инструмент просто попытается определить потенциальные места, где может возникнуть проблема. Представьте, что у вас есть 100 тысяч ссылок и вы отправляете их в SSTIMap, это может занять целую вечность. Я не несу ответственности, если вы получаете вредоносное ПО из скомпилированных версий. Я настоятельно советую вам скомпилировать код самостоятельно.

1694904288028.png

Изображение [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
  • Linux
    • 32:https://www.virustotal.com/gui/file/654c721252f115160e2322ba0f6bbf6040489fa87f6281fc84bcdb6aefa3aaab
    • 64:https://www.virustotal.com/gui/file/0721ee2c00dda0e06b94fb625d7550b52fd72855bb6c7a82cb9af93e62496276
  • 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

Продолжение в комментах
 
Последнее редактирование:

Лаборатория №2

URL: https://portswigger.net/web-securit...side-template-injection-with-a-custom-exploit

Мы должны удалить файл в этой лаборатории. Мы понятия не имеем о шаблонизаторе и используемом синтаксисе, мы постараемся сделать все вручную. Сначала мы должны войти в систему и инпуты. Я вошел в систему и попытался изменить свою информацию, проверяя запросы в Burp Suite, я обнаружил, что при попытке изменить свое имя пользователя значение параметра равно user.name


Изображение [18]: Главная страница

Изображение [18]: Главная страница


Изображение [19]: Редактирование имени

Изображение [19]: Редактирование имени
Это означает, что используется какой-то синтаксис. Чтобы понять это, я попытался воспользоваться нашим полиглотом. Полиглот сработал в параметре "Content-Type" при попытке загрузить аватар. На самом деле это сработало и с некоторыми другими параметрами, но в сообщении об ошибке выходили только каталоги, но когда я ввел polyglot в "Contant-Type", также произошла утечка части кода, который показывает нам, как загружаются файлы. Пожалуйста, обратите внимание, что произошла утечка 2 файловых каталогов, это может пригодиться в будущем для загрузки shell или для чего-то еще.

Изображение [20]: Error

Изображение [20]: Error
После того, как пользователь загружает аватар, он сохраняется в каталоге /tmp, затем путь к файлу и "Content-Type" используются для обновления аватара. Когда мы попытались отредактировать наше имя пользователя, значение параметра было user.name , теперь мы можем использовать user.setAvatar с полным путем и "Content-Type", чтобы заменить наш аватар любым файлом, которое может прочитать система.

Изображение [21]: Хацк

Изображение [21]: Хацк
Я написал комментарий, потому что, когда пользователь пишет комментарий, показываются его имя и аватар. После написания комментария мы должны открыть страницу, на которой был написан коммент, и проверить запросы в Burp Suite, мы увидим наш аватар, и его содержимое является содержимым файла, который мы пытались прочитать.

Изображение [22]: Не Изображение

Изображение [22]: Не Изображение



Изображение [23]: PHP код

Изображение [23]: PHP код
Теперь мы видим PHP-код, который показывает нам больше функций. Суть этой лабораторной работы заключается в удалении файла, есть 3 функции для удаления: rm, delete и gdprDelete. Я не разбираюсь в программировании, и вы можете смело исправлять то, что я пишу. $avatarLink хранит полный путь к аватару пользователя. $user_dir - это путь к каталогу для пользователя. Функция rm принимает имя файла в качестве аргумента и удаляет его с помощью функции unlink(). Функция delete используется для удаления пользователя, после удаления пользователя, если мы пытаемся войти в систему, появляется сообщение об ошибке "Account Delete". gdprDelete вызывает метод rm для удаления обоих аватаров. и он вызывает метод delete, чтобы отключить пользователя.

Изображение [24]: Хаацк

Изображение [24]: Хаацк



Изображение [25]: Ненужный файл

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


Изображение [26]: Хааацк

Изображение [26]: Хааацк​
 
Последнее редактирование:

Как защититься?​

Шаблонизаторы автоматически обходят пользовательский ввод, поэтому технически инъекционных атак не произойдет. Но как они вообще происходят?

Случай 1: https://huntr.dev/bounties/e753bce0-ce82-463b-b344-2f67b39b60ff/
HTML:
#Удалили
<div class="pull-left"><a href="#" class="navbar-link" ng-click="ctrl.menuCollapsed = true" data-ui-sref="edit-current-user" title="click to update account details"><i class="fa fa-user"></i> {{username}}</a></div>
#Поставили
<div class="pull-left"><a href="#" class="navbar-link" ng-click="ctrl.menuCollapsed = true" data-ui-sref="edit-current-user" title="click to update account details"><i class="fa fa-user"></i> <span ng-non-bindable>{{username}}</span></a></div>

Как я понимаю, в данном случае "username" выполняло команды, поэтому разработчик обновил код и использовал <span ng-non-bindable>, который используется для того, чтобы не компилировать содержимое HTML.

Простой пример:
HTML:
<!DOCTYPE html>
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular.min.js"></script>
<body>

<div ng-app="">

<p>Опасно: {{'x'+'s'+'s'+'.'+'i'+'s' }}</p>
<p ng-non-bindable>Сэйффф: {{'x'+'s'+'s'+'.'+'i'+'s' }}</p>

</div>
</body>
</html>

Результат:
HTML:
<div ng-app="" class="ng-scope">

<p class="ng-binding">Опасно: xss.pro</p>
<p ng-non-bindable="">Сэйффф: {{'x'+'s'+'s'+'.'+'i'+'s' }}</p>

</div>


Случай 2: https://huntr.dev/bounties/3ef640e6-9e25-4ecb-8ec1-64311d63fe66/

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

PHP:
            new TwigFilter('filter', [$this, 'filterFilter'], ['needs_environment' => true]),

PHP:
    function filterFilter(Environment $env, $array, $arrow)
    {
        if (is_string($arrow) && Utils::isDangerousFunction($arrow)) {
            throw new RuntimeError('Twig |filter("' . $arrow . '") is not allowed.');
        }

        return \twig_array_filter($env, $array, $arrow);
    }
}

Это 2 исправления, которые были сделаны разработчиком. Приложение использует Twig. $arrow - это вводимые пользователем данные, которые являются "string". Функция filterFilter использует функцию Utils::isDangerousFunction($arrow), чтобы проверить, является ли ввод пользователя опасным или нет.

PHP:
    public static function isDangerousFunction($name): bool
    {
        static $commandExecutionFunctions = [
            'exec',
            'passthru',
            'system',
            'shell_exec',
            'popen',
            'proc_open',
            'pcntl_exec',
        ];
        static $codeExecutionFunctions = [
            'assert',
            'preg_replace',
            'create_function',
            'include',
            'include_once',
            'require',
            'require_once'
        ];
        static $callbackFunctions = [
            'ob_start' => 0,
            'array_diff_uassoc' => -1,
            'array_diff_ukey' => -1,
            'array_filter' => 1,
            'array_intersect_uassoc' => -1,
            'array_intersect_ukey' => -1,
            'array_map' => 0,
            'array_reduce' => 1,
            'array_udiff_assoc' => -1,
            'array_udiff_uassoc' => [-1, -2],
            'array_udiff' => -1,
            'array_uintersect_assoc' => -1,
            'array_uintersect_uassoc' => [-1, -2],
            'array_uintersect' => -1,
            'array_walk_recursive' => 1,
            'array_walk' => 1,
            'assert_options' => 1,
            'uasort' => 1,
            'uksort' => 1,
            'usort' => 1,
            'preg_replace_callback' => 1,
            'spl_autoload_register' => 0,
            'iterator_apply' => 1,
            'call_user_func' => 0,
            'call_user_func_array' => 0,
            'register_shutdown_function' => 0,
            'register_tick_function' => 0,
            'set_error_handler' => 0,
            'set_exception_handler' => 0,
            'session_set_save_handler' => [0, 1, 2, 3, 4, 5],
            'sqlite_create_aggregate' => [2, 3],
            'sqlite_create_function' => 2,
        ];
        static $informationDiscosureFunctions = [
            'phpinfo',
            'posix_mkfifo',
            'posix_getlogin',
            'posix_ttyname',
            'getenv',
            'get_current_user',
            'proc_get_status',
            'get_cfg_var',
            'disk_free_space',
            'disk_total_space',
            'diskfreespace',
            'getcwd',
            'getlastmo',
            'getmygid',
            'getmyinode',
            'getmypid',
            'getmyuid'
        ];
        static $otherFunctions = [
            'extract',
            'parse_str',
            'putenv',
            'ini_set',
            'mail',
            'header',
            'proc_nice',
            'proc_terminate',
            'proc_close',
            'pfsockopen',
            'fsockopen',
            'apache_child_terminate',
            'posix_kill',
            'posix_mkfifo',
            'posix_setpgid',
            'posix_setsid',
            'posix_setuid',
            'unserialize',
            'ini_alter',
            'simplexml_load_file',
            'simplexml_load_string',
            'forward_static_call',
            'forward_static_call_array',
        ];

Функция isDangerousFunction содержит список потенциально опасных функций. Насколько я понимаю, уязвимость не полностью устранена, она просто предотвращает выполнение определенных команд.

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

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

С уважением grozdniyandy
Специально для xss.pro
 
Последнее редактирование:
Скрытый контент для пользователей: grozdniyandy.
 
Функция delete используется для удаления пользователя, после удаления пользователя, если мы пытаемся войти в систему, появляется сообщение об ошибке "Account Delete".
Прошу прощения, там “Account Disabled”, а не “Account Delete”
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх