Атака на Мистера Твиттера

21 Травня 2009

Стаття публікувалась в 4-тому випуску журнала "Хакер" за 2009 рік. Самі скріпти вже викладалися окремо мною на сайті - шукайте їх в розділі "Python". І маленький анонс: "5-тий випуск Хакера вже в продажі і в ньому стаття про "Автоматизованний взлом сайтів"


Недавно мне попался на глаза пост на хабре с располагающим названием "Коммерческий инструмент для спама в твиттере - TweetTornado". Я заглянул на официальный сайт (tweettornado.com) этого чуда-юда и чуть не упал со стула. Он же стоит целых 100 долларов!

Разумеется, написать аналог TweetTornado можно за один день без всяческого напряжения. Позволь мне поделится своим опытом создания подобного чуда! Сегодня мы увидим, как злые хакеры создают рабочий инструмент для спама в твиттере. Он будет представлять собой 4 скрипта:

  • для отсылки одиночного сообщения;
  • бота для имитации активности аккаунта;
  • для добавления друзей;
  • для удаления "не друзей".

Ну что же, приступим.

Twitter

Для начала – немного теории для олдскульных зомби, которые до этого момента ничего не знали о микроблоггинге. Если ты не из их числа – перескакивай к следующему абзацу. Итак, Twitter (twitter.com) - это микроблогинговый сервис, максимальный размер сообщения в котором не должен содержать не более 140 символов. Суть его проста: у тебя есть лента сообщений, в которой отображаются записи, сделанные тобою и  твоими друзьями (или на языке твиттера - following). У всех людей, следящих за твоим блогом (followers), будут появляться твои сообщения.

Твиттер родился в 2006 году, но популярность стал набирать где-то в начале 2007. Сейчас в нем около 5 миллионов пользователей. С одной стороны вроде бы и маловато (по сравнению с социальными сетями), но учитывая неплохую положительную динамику в плане роста твиттера и тот факт, что одно отправленное сообщение тут же будет приходить всем зафололвленным пользователям - "реклама" в твиттере будет иметь очень радужные перспективы. Сразу оговорюсь, мы не будем работать с русскоговорящей аудиторией твиттера, в связи с тем что ее представляют в основном компьютерные специалисты, хорошо понимающие "рекламную" работу, предпочтя ей злых буржуинов - в штатах твиттер уже выбрался в массы, к "домохозяйкам".

Подготовка рабочего места

Скрипты мы будем писать на Python, а для роботы с ним в Windows (в Linux он есть в большинстве дистрибутивов по умолчанию) нужно установить интерпретатор версии 2.5 и библиотеку pyCurl. Все это дело ты сможешь найти на нашем диске. Для экспериментов со скриптами рекомендую заранее зарегистрировать новый аккаунт на твиттере вручную, этот этап автоматизировать мы не будем в связи с наличием хорошей капчи. Но много аккаунтов и не нужно, для спама хватит и одного.

Твиттер API

Twitter всегда был приветлив к рекламным агентам. Его авторы создали очень простое API, позволяющее одним POST или GET запросом производить любые действия над твиттером. Все эти запросы отлично описаны в документации (apiwiki.twitter.com). Для каждого действия приводится:

  • URL запроса;
  • формат ответа который вернет сервер;
  • метод запроса (POST или GET);
  • параметры и их описание;
  • пример запроса.

Некоторые примеры описания действий, взятые из документации, ты сможешь увидеть на врезках. Кстати, когда будешь производить действия, требующие авторизации, помни,   что  в запросе нужно посылать логин и пароль с помощью HTTP Basic Authentication.

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

Теперь немного отвлечемся от API твиттера и научимся посылать запросы с помощью Python.

Python и cURL

В случае возникновения необходимости выполнения HTTP-запросов я всегда выбираю мощный, универсальный инструмент, который работает во многих языках программирования. Зовут его cURL. Для его использования подключим библиотеку pycURL:

import pycurl

Чтобы принять данные после запроса и сохранить их, библиотека pycURL требует указать функцию, которая будет принимать данные. Можно, конечно и самим написать ее, но лучше воспользуемся модулем для работы со строками StringIO. В объекте StringIO есть метод write, идеально для этой цели подходящий. Подключим модуль и объявим объект такими строчками:

import StringIO data = StringIO.StringIO()

Теперь можно объявить объект pycURL и настроить параметры, например, для осуществления Get запроса главной странички xakep.ru. Полученный результат выведем на экран:

curl = pycurl.Curl() #устанавливаем параметры запроса curl.setopt(pycurl.URL, 'xakep.ru') curl.setopt(pycurl.WRITEFUNCTION, data.write) #исполним запрос curl.perform() #освободим память curl.close() #получим результат и выведем на экран print data.getvalue()

Далее, манипулируя методом setopt, мы по желанию сможем изменять наши запросы. Например, если добавить нижеуказанный код, то запрос будет осуществлен через socks с IP 192.168.1.1 размещенным на 2222 порту.

curl.setopt(pycurl.PROXYTYPE,pycurl.PROXYTYPE_SOCKS5) curl.setopt(pycurl.HTTPPROXYTUNNEL,1) curl.setopt(pycurl.PROXY, '192.168.1.1:2222')

Постинг сообщений

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

import pycurl, StringIO data = StringIO.StringIO() curl = pycurl.Curl() curl.setopt(pycurl.URL,  'http://twitter.com/statuses/update.xml') curl.setopt(pycurl.WRITEFUNCTION, data.write) curl.setopt(pycurl.USERPWD,'spiritua:password') curl.setopt(pycurl.POSTFIELDS,'status=TEXT') curl.setopt(pycurl.POST,1) curl.perform() curl.close() print data.getvalue()

В нем, как видно, нечего сложного нет, главное - не забыть "spiritua:password" заменить на свой логин и пароль. А вместо "TEXT", соответственно, написать нужное сообщение.

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

import sys

и изменим наш "TEXT" на sys.argv[1]

Вызывать скрипт мы теперь будем так:

sender.py "I love XAKEP"

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

Имитация активности

Чтобы пользователи тебя добавили в друзья и долго не удаляли, нужно имитировать активность, вести себя как обычный твиттерянин, лишь иногда публикуя рекламные посты. А не слишком ли тяжело будет придумывать сообщения? Может, проще подсмотреть их у соседа? Сделаем хитро - выберем проявляющего сетевую активность человека и утащим его посты к себе. После написания подобного скриптика для автопостинга, его можно поставить на cron (программа для запуска заданий по расписанию) с ежечасным вызовом. Для реализации этой задачи научимся читать посты юзеров. В твиттер API указано, что нужно использовать GET-запрос следующего вида - http://twitter.com/statuses/user_timeline/spiritua.xml. Здесь вместо 'spiritua' мы вставим имя выбранного донора сообщений. По расширению xml становится понятно, в каком формате придет результат :). Для дальнейшего парсинга xml можно использовать библиотеки, но в нашем случае от этого усложнения помогут избавиться регулярные выражения. Если мы посмотрим на структуру xml-ответа, то увидим, что сообщения всегда находятся между тегами <text>. Исходя из этого, заюзаем следующую регулярку:

 <text>(.*)</text>.

Для использования регулярных выражений в Python подключим модуль с названием re и используем его метод findall который возвратит массив. Получим следующее:

import re rez = re.findall("<text>(.*)</text>",data)

Алгоритм скрипта активности будет такой:

  • берем в донора самое последнее сообщение;
  • проверяем, есть ли это сообщение среди наших, если нет - публикуем.

Думаю, теперь ты и сам сможешь его написать, а если нет - смотри на врезке или нашем диске.

Теперь у нас есть два анонсированных в начале статьи скрипта. Но осталось еще два, которые связаны с ростом рекламной сети, - то есть, расширением списка друзей.

Твиттерянин, где ты?

Для поиска друзей я знаю 3 способа, которые нужно использовать в зависимости от желаемого результата:

1. Поиск по имени
2. Поиск по списку друзей
3. Случайный выбор

Поиск по имени почти не интересен, я не знаю, где он был бы в нашей деятельности полезен. Поиск по списку друзей - наиболее продвинут и совершенно незаменим в случае, если нужно искать людей определенного круга. Например, мы хотим продавать маечки с нарисованной Бритни Спирс. Ясное дело, что для этого нужно найти ее твиттер и достать список тех, кто его читает. Разумеется, на первых порах такой основательный таргетинг мы рассматривать не будем, поэтому в рамках статьи мы рассмотрим третий вариант - случайный выбор. Для этого лезем в API и видим, что послав Get-запрос на URL http://twitter.com/statuses/public_timeline.xml мы получим 20 последних сообщений вместе с данными о авторах. Кстати, третий вариант удобен еще и тем что используя его, мы получим лишь активных пользователей. Имя в ответе от твиттера будет находиться между тегами <screen_name>, поэтому для последующего парсинга результата подойдет регулярка <screen_name>(.*)</screen_name>.

Теперь, получив список из 20-ти пользователей, нужно попросить их добавить нас в друзья. Недаром существует такая наука наука как психология, а она говорит, что если добавить пользователя к себе в друзья, то он с большой вероятностью добавит нас и будет читать наши сообщения :).

Опять обратимся к API, в котором указано, что для добавления в друзья необходимо послать Post запрос на URL http://twitter.com/friendships/create/spirit.xml, где вместо spirit придется вставить имя нужного аккаунта.

Переводя все это на Python получим основные строчки для добавления в друзья (остальное можно подсмотреть на диске):

curl.setopt(pycurl.URL, 'http://twitter.com/friendships/create/'+name+'.xml') curl.setopt(pycurl.USERPWD,'spiritua:passwd') curl.setopt(pycurl.POST,1)

Теперь берем и соединяем "поиск 20-ти случайных юзеров" и "добавление в друзья". В результате получаем суперовый скрипт, который опять же ставим на Cron с определенным интервалом, и наблюдаем, как бодро и молодцевато (так говорят у нас в милиции) растет рекламная сеть (блин, не зря мне показалось подозрительной его фотография в погонах – прим. Лозовского) ;).

"Редиска" - плохой человек

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

Для получения этих списков нужно послать запросы на URL:

  • http://twitter.com/statuses/friends.xml
  • http://twitter.com/statuses/followers.xml

В результате получим следующий код:

#настроим cURL на получение списка друзей curl.setopt(pycurl.URL, 'http://twitter.com/statuses/friends.xml') curl.setopt(pycurl.USERPWD,'spiritua:passwd') curl.setopt(pycurl.WRITEFUNCTION, data.write) #запустим запрос curl.perform() #сохраним результаты в переменную friends friends = data.getvalue() #очистим буфер для следующего запроса data.truncate(0) #получим список людей которые читают нас curl.setopt(pycurl.URL,  'http://twitter.com/statuses/followers.xml') curl.perform() followers = data.getvalue()

В переменных friends, followers будет храниться результат в формате xml, полученный от твиттера. Обработав их уже знакомой нам регуляркой на поиск тегов <screen_name>, получим массивы:

friends = re.findall("<screen_name>(.*)</screen_name>",friends) followers = re.findall("<screen_name>(.*)</screen_name>",followers)

А теперь можно приступать к удалению, посылая запросы на URL http://twitter.com/friendships/destroy/spirit.xml. В результате должен получиться примерно следующий код (полный исходник рекомендуется курить с нашего диска):

#подключим библиотеку time для команды sleep import time curl.setopt(pycurl.POST, 1) #цикл по всему списку друзей for friend in friends: #проверка - читает ли друг нас if friend not in followers: #если не читает - то для нас он не друг curl.setopt(pycurl.URL, 'http://twitter.com/friendships/destroy/'+friend+'.xml') curl.perform() #ждем 2 секунды time.sleep(2)

В путь

Вроде бы, мы рассмотрели основные тезисы создания рекламной сети в твиттере. Напоследок я предлагаю тебе ознакомиться с примером из частной практики одного злого хакера. Итак, после регистрации аккаунта он устанавливает фотографию и заполняет все поля в профиле. Далее он настраивает крон на запуск имитации активности где-то с периодичностью в 3 часа. Ждет неделю. Затем - добавляет в крон запись, позволяющую раз в 3 дня запускать скрипт сначала на очистку от "редисок", а затем - на приглашение 100 новых юзеров. Он не забывает об аккаунте до тех пор, пока у него не насобирается где-то 2000 фаловеров. На этом он останавливает скрипты роста, оставляя лишь имитацию активности. Приблизительно раз в неделю размещается рекламное объявление. 

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

 
 
 
Роман Хоменко aka PresidentUA
mail/jabber: spirt40@gmail.com