Matthew, спасибо за ответы.
Продолжаю тему по XSS...
Был найден еще один очень интересный случай: можно выполнить произвольный JavaScript код, но данную XSS непонятно, можно ли вообще эксплуатировать.
Что имеем:
Есть форма заполнения комментария, это форма обрабатывает HTML-код, то есть у меня хорошо выполнялся код
<iframe onload=alert()></iframe> или
<img src='#' onerror=alert() />, и после этого на странице с комментом была Stored XSS (или пассивная, как кому удобнее), но проблема в том, что этот коммент заносится не в БД на сервере, а в сессию, доступ к которой осуществляется через один параметр в cookie у пользователя, и хранится это сообщение/комментарий (с кодом) там в течении сессии, то есть там в той системе юзеры для себя комментируют/делают себе пометки.
Я стал разбираться, можно ли как-то сформировать ссылку, пройдя по которой пользователь оставит коммент с JS-кодом и соответственно выполнится этот код, но очередной барьер заключался в том, что при нажатии кнопки по добавлению коммента данные формы из поля для текста коммента отправляются не посредством обычного
POST запроса и вообще не через атрибут
action, а через аттрибут
onclick на кнопке, там вызывается JS функция:
Цитата:
<input type="button" onclick="note_save('rent', 'flat', 12081370);" value="Сохранить">
|
Ссылки на страницу дать, к сожалению, не могу из-за правил форума/темы, но приведу листинг кода этой функции:
Цитата:
function note_save(deal_type, offer_type, oid) {
var text,
existed = false;
text = $.trim($('#note_comment_' + deal_type + '_' + offer_type + '_' + oid).val());
existed = $('#note_span_' + deal_type + '_' + offer_type + '_' + oid).length > 0 ? true : false;
function renderComment() { //функция поста коммента
$('#note_' + deal_type + '_' + offer_type + '_' + oid).empty();
$("#note_" + deal_type + '_' + offer_type + '_' + oid).append(text ? '<span style="background:#D2DBDA;"><b>Ваш комментарий:</b></span> <span id=note_span_' + deal_type + '_' + offer_type + '_' + oid + '>' + text + '</span>' : '');
$("#note_" + deal_type + '_' + offer_type + '_' + oid).show();
$("#note_a_" + deal_type + '_' + offer_type + '_' + oid).show();
$("#note_text_" + deal_type + '_' + offer_type + '_' + oid).hide();
$("#note_text_" + deal_type + '_' + offer_type + '_' + oid).empty();
}
function sendRequest() { //функция формирования и отправки ajax-запроса
var url = "/js/note.php";
request.open("POST", url, true);
request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
request.send("mode=" + (text ? 'save' : 'delete') +
"&deal_type=" + escape(deal_type) +
"&offer_type=" + escape(offer_type) +
"&oid=" + escape(oid) +
"&text=" + escape(encodeURIComponent(text)));
}
if (text || existed) {
sendRequest(); //тут делается ajax-запрос на добавление коммента в сессию
renderComment(); //пост коммента через JavaScript, конкрентно с помощью jQuery (естественно, без обновления страницы)
}
}
|
Три функции
show(),
hide() и
empty() – это, как многие догадались, функции jQuery.
Тут мы видимо, что эта функция формирует Ajax запрос методом POST, в котором передает параметры, куки, один из которых играет ключевую роль (ниже опишу) и наш коммент.
Итак
заголовки запроса:
Цитата:
Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Encoding gzip, deflate
Accept-Language ru-RU,ru;q=0.8,en-US;q=0.5,en;q=0.3
Cache-Control no-cache
Connection keep-alive
Content-Length 123
Content-Type application/x-www-form-urlencoded; charset=UTF-8
Cookie h_p=881a75edd1d32c20f3dee5a94452f1c3; complaint=622d9f9dea075b994d3c2f60867a5db3; first=1417367988; __utma=63792317.339146785.1417367991.1417371990.14 17384115.3; __utmz=63792317.1417367991.1.1.utmcsr=(direct)|utm ccn=(direct)|utmcmd=(none); PHPSESSID=7apd9n3llr0njrk366gbah0lb3; __utmb=63792317.4.9.1417384164174; __utmc=63792317; _ym_visorc_67132=w
Host www.cian.ru
Pragma no-cache
Referer http://www.cian.ru/cat.php?deal_type=1&obl_id=1&city[0]=1
User-Agent Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:33.0) Gecko/20100101 Firefox/33.0
|
Параметры (тело запроса):
Цитата:
mode=save&deal_type=rent&offer_type=flat&oid=12081 370&text=%253Ciframe%2520onload%253Dalert%28%29%253E%253C%2 52Fiframe%253E
|
Жирным выделены в запросе - это куки, по которому потом из сессии вытягивается коммент, а в параметрах жирным выделен, собственно, сам коммент, закодированный.
Это все сведения, которые нарыл, и от которых надо отталкиваться.
В принципе можно написать PHP или JS-скрипт, который отправляет Ajax-запрос, как это делается в той функции
note_save(), устанавливает там текст коммента, свое значение
complaint для кук, и после этого перенаправляет на нужную страницу с комментом.
Но потом проблема будет в том, что это, установленное скриптом, значение
complaint на сервере, не совпадет со значением из кук юзера, которого перенаправили, ведь сайт ему когда-то присвоил свое значения или сайт установит новое значение, которое так же не будет совпадать с нашим.
НО это сайт будет присваивать свое значение, если мы просто перенаправим пользователя,
А ЕСЛИ мы это сделаем через GET-запрос, где в параметре Cookie отправим свое значение
complaint (как будто от пользователя из кук), то получается, что мы как бы обойдем стороной старые куки юзера (если они есть) или в случае их отсутствия скажем сайту, что они типа есть (ведь в запросе их указали).
Поэтому чисто теоретически, если не будет конфликта с некоторыми другими параметрами куки типа идентификаторов сессий (но этого не должно быть, я проверял, они не влияют на запросы), то это может сработать. Я пока только выдвинул гипотезу, но не тестировал ее, написал вопрос, может быть чего-то не учел, забыл или недопонял, поэтому если кому-то будет интересно, то может прочитать и, возможно, найдет какой-то недочет в данной схеме, пока я еще не попробовал ее в действии.