Атаки на JavaScript. Часть 2
Life-Hack [Жизнь-Взлом]/ХакингВ DVWA поднимите уровень безопасности до medium.
Между прочим, даже до вникания в особенности работы страницы, обратите внимание, что «детский» метод с сохранением страницы и изменением формы по-прежнему работает!
Но приступим к отладке, поскольку далеко не все случаи такие простые: например, форма отправки может вообще отсутствовать в исходном коде и создаваться на лету средствами JavaScript.
Посмотрим в исходный код страницы, JavaScript был вынесен в отдельный файл:
<script src="../../vulnerabilities/javascript/source/medium.js"></script>
Содержимое этого файла такое:
function do_something(e){for(var t="",n=e.length-1;n>=0;n--)t+=e[n];return t}setTimeout(function(){do_elsesomething("XX")},300);function do_elsesomething(e){document.getElementById("token").value=do_something(e+document.getElementById("phrase").value+"XX")}
Чтобы сделать код JavaScript читаемым я воспользуюсь инструментом JStillery.
Скачиваем интересующий файл:
wget http://localhost/dvwa/vulnerabilities/javascript/source/medium.js
Запускаем деобфускацию:
./jstillery_cli.js medium.js
Получено:
function do_something(e)
/*Scope Closed:true*/
{
for (var t = '', n = e.length - 1; n >= 0; n--)
t += e[n];
return t;
}
setTimeout(function ()
/* Called:undefined | Scope Closed:false| writes:false*/
{
do_elsesomething('XX');
}, 300);
function do_elsesomething(e)
/*Scope Closed:false | writes:true*/
{
document.getElementById('token').value = do_something(e + document.getElementById('phrase').value + 'XX');
}

Если присмотреться к исходной строке, то можно увидеть, что код не обфусцирован, а сжат. В любом случае, теперь стало намного понятнее.
Из трёх функций фактически используется только последняя, а остальные, видимо, добавлены чтобы нас запутать.
Начинаем отладку кода, чтобы заменить значение переменной для получения нужного нам токена.
В веб-браузере вновь переходим в Инструменты разработчика (F12), находим файл medium.js. Чтобы привести сжатый JavaScript в понятный вид нажмите кнопку { }:

Анализ кода подсказывает, что стоит обратить внимание на функцию:
function do_elsesomething(e) {
document.getElementById("token").value = do_something(e + document.getElementById("phrase").value + "XX")
}
Ставим точку прерывания там. Поскольку в одной строке выполняется сразу несколько операций, выбираем последнюю позицию для точки прерывания:

Перезагружаем страницу.

Видим, что переменной e присвоено значение «XX». Нажимаем F9 для перехода к следующему шагу.
Как видно, я был неправ говоря, что первые две функции добавлены только чтобы нас запутать — готовится вызов первой функции и в качестве параметра ей будет передано «XXChangeMeXX». Видимо, это и есть начало вычисления токена.

Я присвоил параметру e значение «success», но получил ошибку о неверном токене. По аналогии с передаваемым значением («XXChangeMeXX»), назначем e строку «XXsuccessXX».

Затем нажимаем F8 для продолжения выполнения кода JavaScript без отладки и прерываний.
Вводим на странице слово «success»:

И отправляем:

Как можно увидеть, всё прошло сработало.
4. Отладка обфусцированного кода JavaScript
В DVWA поднимите уровень безопасности до High.
JavaScript код вновь вынесен в файл high.js, посмотрим на него:

Код обфусцирован, я попробовал применить JStillery, но принципиально ничего не изменилось — код остался полностью нечитаем.
Самый лучший результат показал JavaScript онлайн деобфускатор deobfuscatejavascript.com, адрес этого сервиса: http://deobfuscatejavascript.com/
После деобфускации получился большой фрагмент JavaScript кода.

В конце кода есть следующие функции:
function do_something(e) {
for (var t = "", n = e.length - 1; n >= 0; n--) t += e[n];
return t
}
function token_part_3(t, y = "ZZ") {
document.getElementById("token").value = sha256(document.getElementById("token").value + y)
}
function token_part_2(e = "YY") {
document.getElementById("token").value = sha256(e + document.getElementById("token").value)
}
function token_part_1(a, b) {
document.getElementById("token").value = do_something(document.getElementById("phrase").value)
}
document.getElementById("phrase").value = "";
setTimeout(function() {
token_part_2("XX")
}, 300);
document.getElementById("send").addEventListener("click", token_part_3);
token_part_1("ABCD", 44);
Обратите внимание на строку:
document.getElementById("token").value = do_something(document.getElementById("phrase").value)
В ней считывается значение поле phrase. У меня подозрение, что огромный код до этих функций не выполняет ничего нужного и размещён просто чтобы запутать нас. Но в любом случае, хотим ли мы делать отладку всего кода либо только указанного фрагмента, главный вопрос — как именно в файл http://localhost/dvwa/vulnerabilities/javascript/source/high.js вставить наш деобфусцированный код? Если не ответить на этот вопрос, то отладка обфусцированного кода может стать невозможной, так как предыдущий бессмысленный код может выполнять миллионы операций прежде чем управление перейдёт к действительно функциональному фрагменту.
Выход из этой ситуации есть — причём функция изменения файлов на лету и сохранение этих изменений даже после перезагрузки страницы есть прямо в Инструментах разработчика браузера.
Вставляем деобфусцированный код, ставим точку прерывания:

Добавляем эту страницу в «Save for overrides» как это описано в статье по ссылке выше и перезагружаем страницу.
Пожалуй, не буду разбирать этот пример до конца — будет это будет домашним заданием.
Заключение
На практике встречаются очень сложные для анализа варианты использования JavaScript, комбинирующие динамическое построение DOM структуры страницы, динамическое назначение событий, обфускацию кода, использование громоздких фреймворков и т. д. Но в целом исходить нужно из того, что защиты на стороне пользователя, в том числе с использованием JavaScript априори являются ненадёжными.
JavaScript может использоваться, например, для верификации данных в форме, но только для удобства пользователя, чтобы сообщить ему, что пропущено какое-то обязательное поле или введена информация в неверном формате. Но на стороне сервера всё обязательно должно перепроверяться так, как будто бы на стороне пользователя не было никаких проверок. Нужно исходить из того, что с пользовательской стороны может прийти что угодно.