копирование сложноформируемого HTTP-запроса или как накрутить голосование

Сейчас трудно найти более-менее популярный сайт, где бы важные для сайта, запросы (голосование, подтверждение перевода денег итд ) формировались через переданные сервером в явном виде данные. Подобные действия со стороны администрации и программистов сайта ясны – они хотят максимально усложнить процесс копирования запроса браузера.
Обычно для усложнения данных запроса на клиентской стороне используеться JavaScript и как правило этот скрипт не так уж легко понять (200-1000 строчек хрензнаеткакнаписанного кода):

  1. сервер посылает гипер-текстовую страницу с вкраплениями JS и исходных данных
  2. JS обрабатывает переданные в явном виде данные и формирует из них данные для верификации запроса
  3. браузер дает запрос серверу с целевыми аргументами и аргументами для верификации запроса
  4. сервер анализирует полученные данные верификации запроса и если они удовлетворяют требованиям, то обрабатывает целевые

Мой способ обойти подобные сложности не претендует на изящность или сверхскорость, однако он рабочий и более-менее универсальный, а самое главное не придеться разбирать JS. Далее я опишу этот способ на примере накрутчика голосования.

Итак, у нас имеется сайт с голосованием, где:

  1. в течении 24-х часов с одного ip-адреса можно проголосовать только 1 раз
  2. данные запроса к серверу содержат кукисы, целевое значение(номер позиции, за которую я проголосовал), данные верификации запроса (формируются посредством 750-строчного JS-кода закодированного всеми возможными base64, а так же какими-то своими способами кодирования и все это разбавлено максимально непонятным стилем программирования).

Ограничение с ip-адресом мы обходим за счет проксиков/tor/итд, собрать сам AJAX/POST-пакет с кукисами и целевыми параметрами мы тоже легко можем, однако как быть с параметрами формируемыми JS.
Первая мысль, конечно, была – разобрать сам JS код, но как показала практика это того не стоит.
Второй вариант – найти/написать самому интерпритатор JS с поддержкой DOM, но писать самому это очень долго, а существующие решения весьма карявые и сильно не дотягивают до интерпритаторов современных браузеров.
Третьей мыслью и был как раз мой способ.

1. Web-сервер

Нам нужно либо написать свой HTTP-сервер, либо воспользоваться уже существующим. Код для формирования страниц там будет очень легкий, поэтому жизнеспособны оба варианта. Я воспользовался чем-то средним между двумя этими вариантами – библиотека-сервер Webrick. Скрипт написан на Ruby.

#!/usr/bin/ruby
require 'webrick'
include WEBrick
require 'net/http'

# глобальный массив браузеров,
# дабы не вызвать подозрений
$user_agents=["Mozilla/5.0 (Windows; U; Windows NT 6.1;"+
  " en-US; rv:1.9.1.5) Gecko/20091102 Firefox/$$v$$",
  "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.17)"+
  " Gecko/2010010604 Ubuntu/9.04 (jaunty) Firefox/$$v$$",
  "Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.1.7)"+
  " Gecko/20091221 MRA 5.5 (build 02842) Firefox/$$v$$",
  "Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.0.7)"+
  " Gecko/20191231 MRA 5.4 (build 02842) Firefox/$$v$$",
  "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1;"+
  " WebMoney Advisor)",
  "Opera/9.80 (Windows NT 5.1; U; MRA 5.5 (build 02842); ru)"+
  " Presto/2.2.15 Version/$$v$$",
  "Opera/9.80 (Windows NT 6.1; U; ru) Presto/2.2.15 Version/$$v$$",
  "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident"+
  "/$$v$$; GTB6.4; InfoPath.2; .NET CLR 1.1.4322)",
  "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/"+
  "532.5 (KHTML, like Gecko) Chrome/$$v$$.249.78 Safari/532.5",
  "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Tr"+
  "ident/4.0; GTB6.4; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30"+
  "729; .NET CLR 3.0.30729)",
  "Mozilla/5.0 (X11; U; Linux i686; en; rv:1.9.0.17) Gecko/2008"+
  "0528 Epiphany/$$v$$ Firefox/3.0",
  "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/"+
  "532.5 (KHTML, like Gecko) Chrome/4.0.249.78 Safari/532.5",
  "Opera/9.64 (Windows NT 6.0; U; ru) Presto/2.1.1",
  "Lynxy/6.6.6dev.8 libwww-FM/3.14159FM",
  "PycURL/7.18.2",
  "Opera/9.51 (Windows NT 6.0; U; en)"]

# хэш замен
$replace={"/konkurs"=>"http://kakoi-nit.oprosnik.ru/konkurs"}

# совершенно не обязательная перегрузка функции
# get из Net::HTTP, увеличивает шансы что
# страница будет загружена, хотя и без нее шансы не малы
class  Net::HTTP
  def my_get(path,headers)
    begin
      return self.get(path,headers)
    rescue TimeoutError
      sleep(1)
      retry
    rescue Errno::ENETUNREACH
      sleep(10)
      retry
    else
      sleep(1)
      retry
    end#begin
  end#def
end#class

# формирует User-agent запроса посредством
# глобального массива $user_agents
def get_user_agent
  return $user_agents[rand($user_agents.size-1)].
    gsub('$$v$$',"#{(rand(10)+1)}.#{(rand(10)+1)}")
end

# формирует заголовок запроса
def get_headers
  headers = {   'User-agent'=> get_user_agent,
    'Accept'=> 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
    'Accept-Language'=> 'ru,en-us;q=0.7,en;q=0.3',
    'Accept-Charset'=> 'UTF-8,*',
    'Keep-Alive'=> '300',
    'Connection'=> 'keep-alive'}
  return headers
end

# чисто webrick'овская примочка,
# создает еще один поток который
# ожидает на ввод 'q\n' чтобы завершить
# работу сервера
th=Thread.new do
  while true do if STDIN.gets.chop=="q" then exit! end end
end

# конфигурируем и запускаем сам сервер webrick
config={}
config.update(:Port => 8080)
server = HTTPServer.new(config)
ruby_dir = File.expand_path('www')
server.mount("www", HTTPServlet::ERBHandler, ruby_dir)

# делаем сервелет для webrick
server.mount_proc('/js-miracle') do |req,resp|

  # получаем страницу голосования с интересуещего нас сайта
  http=Net::HTTP.new('kakoi-nit.oprosnik.ru', 80)
  respp, data = http.my_get("/konkurs/super-golosovanie",get_headers)

  # передаем куки
  resp['Set-Cookie']=respp['set-cookie']

  #ВНИМАНИЕ ЗДЕСЬ ВСЯ ФИШКА
  # заменяем часть строки исходной страницы на нужный нам код
  data.gsub!("href=\"javascript: create_verified(0);\"",
    "href=\"javascript: create_verified(0);\" id=\"jslink\"")
  data.gsub!("konkurs/images/vote.png\" alt=\"\" /></a>",
    "konkurs/images/vote.png\" alt=\"\" /></a><script "+
    "type=\"text/javascript\"> document.getElementById("+
    "'jslink').onclick();</script>")
  #ФИШКА ЗАКОНЧИЛАСЬ

  # меняем адреса ссылок с относительных на kakoi-nit.oprosnik.ru
  # на абсолютные на kakoi-nit.oprosnik.ru посредством хэша замен $replace
  $replace.each {|k,v| data.gsub!(k,v)}

  # передаем страницу
  resp.body=data
end#server

# запускаем сервер
server.start

Теперь разберемся. Во-первых не надо пугаться webrick и Ruby это чисто мой выбор, можно использовать абсолютно любую связку PHP+Apache, PHP+Denver итд вплоть до написания своего маленького однопоточного сервера на C или Delphi. Сервелет это что-то типа странички на PHP или ERB, я выбрал его дабы не заморачиваться и писать меньше кода, однако PHP или его аналог ни в чем ему не уступит.

Как это работает и зачем оно нужно:

  1. вы запускаете сервер и открываете браузер на странице http://127.0.0.1:8080/js-miracle
  2. сервер получив ваш запрос, отправляет запрос на сервер kakoi-nit.oprosnik.ru c целью получить страничку голосования /konkurs/super-golosovanie, иначе говоря заходит по адресу http://kakoi-nit.oprosnik.ru/konkurs/super-golosovanie.
  3. берет полученные от kakoi-nit.oprosnik.ru куки и вкладывает их в ответ вашему браузеру
  4. в секторе про ФИШКУ мы заменяем или добавляем наш JS код т.е. допустим при нажатии на кнопку ‘голосовать’ управление передаеться в JS функцию formirovanie_verified_parameters(), в которой к параметрам формы добавляеться всякая фигня для верификации (заполнение скрытых полей, добавление новых кукисов итд) без которой kakoi-nit.oprosnik.ru воспримит наш следующий запрос как фальшивый. Конечно, мы можем каждый раз вручную нажимать на кнопку ‘голосовать’ но мы же автоматизируем, поэтому мы вставляем сюда код, который при загрузке страницы имитирует нажатие на эту кнопку, причем дальше браузер сам выполнит все как нужно, как будто мы это сделали вручную.
    В данном случае у нас есть картинка konkurs/images/vote.png, которая вложена в тэг ссылки

    1
    2
    
    <a href=”javascript:create_verified()><img
    src=”konkurs/images/vote.png” alt=”” /></a>

    и при загрузке нам нужно на нажать на картинку, чтобы активизировать ссылку, но чтобы это сделать нам сначало нужно как-то идентифицировать ссылку поэтому мы добавляем ей параметр id="jslink". А затем, добавлем сам код нажатия .

  5. меняет ссылки со всех картинок, css-таблиц, js-файлов итд с относительных kakoi-nit.oprosnik.ru на абсолютные http://kakoi-nit.oprosnik.ru/example_page.html. Короче говоря, когда он получит страницу с kakoi-nit.oprosnik.ru большинство ссылок там будут иметь вид /link/path/to/object.js, и если наш браузер получит страницу с таким путем ссылок, то он будет просить этот ресурс у нашего сервера (webrick), а у нас их нет, зато они есть у kakoi-nit.oprosnik.ru, поэтому мы меняем их на http://kakoi-nit.oprosnik.ru/link/path/to/object.js.
  6. заполянем html-тело ответа нашему браузеру в точности такое же как страница http://kakoi-nit.oprosnik.ru/konkurs/super-golosovanie за исключением смены адресов ссылок и изменение/добавление JS-кода.

В итоге в браузере мы получаем точно такую же страницу как http://kakoi-nit.oprosnik.ru/konkurs/super-golosovanie, с теми же самыми куками и параметрами верификации + наш личный JS-код нажатия на кнопку/ссылку, короче код автоматизации процесса.

2. Обход бана по ip

Нам нужно выбрать какой-нить браузер, где можно установить так:

  1. не использовать прокси/socks/tor/итд для 127.0.0.1
  2. использовать прокси/socks/tor для всех остальных

Этим требованиям отлично удовлетворяет FireFox.

Лично я не стал заморачиваться с проксями а решил использовать tor:

  • поднимаем локальный проксик privoxy
  • устанавливаем tor
  • в настройках прокси FF ставим адрес и порты privoxy, чаще всего это бывает так 127.0.0.1:8118.

Далее ставим домашнюю страницу на наш локальный web-сервер (webrick) т.е. http://127.0.0.1:8080/js-miracle

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

3. Автоматизация запуска браузера

Поскольку нам нужно отправлять миллионы таких запросов разумно было бы зациклить запуск и закрытие браузера.
Это можно сделать как угодно, для linux это может быть bash-скрипт, для windows – bat-файл или на худой конец скрипт любого ЯП.
Я выбрал ‘худой конец’ (скрипт написан на Ruby, Linux):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#!/usr/bin/ruby
lim=200
sleep_time=50
def my_sleep (sl)
  for i in 0..sl
   sleep(1)
   print '.'
   STDOUT.flush
  end
end
 
for i in 0..lim do
  puts 'browser start'
  system('firefox http://127.0.0.1:8080/js-miracle &')
  my_sleep sleep_time
  puts "\n kill start"
  system('killall firefox')
end

Замечания и примечания

После запуска сервера и последнего скрипта каждые 50 секунд будет открываться FF автоматически выполняя вашу задачу, процесс будет повторяться 200 раз т.е. будет отправлено 200 запросов или 200 голосов в голосовании будет за меня. Поскольку постоянное мелькание браузера может раздражать пользователям *nix рекомендую заменить firefox на консольный links, и мелькание прекратиться. Пользователям windows не знаю что посоветовать, кроме как сделать окно FF мимнимального размера.

Что касаеться tor и privoxy, они далеко не обязательны, с ними удобнее, однако по скорости они заметно уступят приватным проксям. Для того чтобы сделать все через прокси, нужно будет использовать такие упаковщики трафика как proxychains и widecap итд. Однако так как они не будут разбираться к какому хосту обращаеться браузер и упаковывают весь трафик, их нужно будет либо настроить на то чтобы не применялись прокси для localhost, либо разместить наш сервер на каком-нить бесплатном хостинге или еще где угодно, главное чтобы не в нашей подсети.

Теперь относительно периода открывания браузера. Я взял 50 секунд, иногда этого много, а иногда мало, в зависимости от выбранных нодов тора. Оптимизаторам следует, конечно, выбирать не постоянный период а вычислять прогрузился ли сайт в браузере или нет, и соответсвенно после того как браузер все сделал закрывать его.

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

Выводы и итоги

Этот принцип не отличаеться изящностью и быстродействием, однако он очень универсален, его можно применять далеко не только для опросов. Он хорошо работает для обхода капчи, где верификация капчи проходит через AJAX, парсинга тех сайтов, где админы очень любят все запутать, например списка проксиков, короче он применим везде где вам не нравиться тот или иной JavaScript на странице сайта.
И еще раз обнадежу, весь код приведенный здесь не играет никакого приципиального значения, он целиком и полностью заменяеться аналогичным на PHP, С, Delphi итд.

Статья является плодом бурной фантазии автора и не призывает
ни к каким действиям, противоречащим законодательству. 
Ответственность за использование материала ложиться только 
на вас! Любые совпадения с реальными людьми считаются 
случайными.

2 Comments to “копирование сложноформируемого HTTP-запроса или как накрутить голосование”

  1. Andruxa пишет:

    а можно вас попросить таким образом накрутить голосование я заплачу))))

  2. Павел пишет:

    Могу помочь.
    Обращайтесь superp1987 собака gmail.com

Leave a Reply

(обязательно)

(обязательно)