https://habrahabr.ru/post/282005/- Информационная безопасность
- Python
Каждая девочка мечтает стать принцессой, быть самой красивой, самой умной и обязательно встретить принца. Множество маркетологов и PR-акул обогатили свои компании, играя на этих простых девичьих мечтах. Сферу IT, мужскую и брутальную, это явление тоже не обошло стороной. Известная компания запустила
громкий конкурс на звание титула IT-принцессы. Всех, кто слышал и кому интересно, как оно было, приглашаю под кат.
В конкурсе было заявлено 3 этапа. Я расскажу про первый.
1. Регистрация участниц и голосование за приз зрительских симпатий
Чтобы принять участие в конкурсе достаточно выбрать миленькую фоточку и… и всё. Порог вхождения для участия — нулевой. Приз зрительских симпатия в виде корзинки косметики получает леди, набравшая больше всего лайков. Привлекать живой трафик и засорять социалки бесконечными репостами — это не удел принцесс, так что запускаем Burp и смотрим, как оно все устроено.
На странице для голосования (/itprincess/gallery/) отражается 6 участниц и дальше при прокрутке с каждым ajax-запросом загружается еще по 6. Голосование осуществляется post-запросом c ID нужной участницы, но он не фиксированный и генерируется для каждой новой пользовательской сессии.
Примеры запроса на страницы для голосования:
GET /itprincess/gallery/ HTTP/1.1
Host: it.mail.ru
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:43.0) Gecko/20100101 Firefox/43.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Cookie: csrftoken=t4XRJ4J4EJYLqzVhL22pzHvPynzKkhMz; sessionid=jxtr3fljir54b9qn2liyl71tohr6n5ff;
Connection: keep-alive
По факту, в поле Cookie указано больше параметров, но они не имеют никакого значения для голосования, я их убрала.
Пример отправки лайка:
POST /itprincess/gallery/2 HTTP/1.1
Host: it.mail.ru
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:43.0) Gecko/20100101 Firefox/43.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequest
Referer: https://it.mail.ru/itprincess/gallery/
Content-Length: 52
Cookie: csrftoken=u7lS6UIww7Eppq9HVD66iS7i4ss6SO04; sessionid=sln1o1pivi5sl7mgezdqa8p6us59jhek
Connection: keep-alive
csrfmiddlewaretoken=u7lS6UIww7Eppq9HVD66iS7i4ss6SO04
Что ж, пишем лайк-машину. Все, что нужно — это отправлять запросы, парсить html-страницы с ответом сервера и искать мой ID. Для парсинга использовался фреймворк BeautifulSoup. Потом я подумала, что лайк-машину быстро спалят и нужно на каждом запросе менять User-Agent и IP-адрес. Тут я, конечно, сильно заморочилась, хотя по факту организаторы и не думали отслеживать накрутку лайков.
Функция def get_ua() проходит по файлику со списком user-agent (там порядка 300 значений) и выбирает 1 рандомно. Для того, чтобы организовать работу с Тором, понадобилось 2 библиотеки: requesocks — позволяет работать библиотеке request через socks-прокси и stem — позволяет контролировать смену ноды (на каждый новый запрос — новый ip-шник).
Мой скрипт (я написала его за 2 часа, и, безусловно, тут можно много оптимизировать и украшательствовать):
# -*- coding: UTF-8 -*-
import sys
import urllib2
import requests
import requesocks as requests
import time
import random
from random import randint
#for tor sent signal
from stem import Signal
from stem.control import Controller
#for parsing html
from BeautifulSoup import BeautifulSoup
url = 'https://it.mail.ru/itprincess/gallery/'
proxy = {
'http': 'socks5://127.0.0.1:9050',
'https': 'socks5://127.0.0.1:9050',
}
while 1:
def get_ua():
f = open('ualist.txt', 'rb')
agents = f.readlines()
return random.choice(agents).strip()
ua=get_ua()
headers_get = {
'User-agent': ua,
'Referer':'https://it.mail.ru/itprincess/gallery/'
}
headers_post = {
'User-agent': ua,
'Referer':'https://it.mail.ru/itprincess/gallery/',
'X-Requested-With': 'XMLHttpRequest',
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
}
r = requests.get(url, headers=headers_get, proxies=proxy, verify=False)
#с POST-запросом требуется передача csrf-токена, поэтому сразу зафиксируем его
data = 'csrfmiddlewaretoken='+r.cookies['csrftoken']
#получаем содержимое ответа сервера на запрос
soup = BeautifulSoup(r.content)
#единственная уникальная информация, которая есть для каждой участницы - это ответ на вопрос, что для нее значит сфера IT - по этой строчке и будем искать
my_title = soup.find(title=u"строка обо мне")
if my_title:
# получаем id для меня
id=my_title.parent.get('id')
print id
url_post = "https://it.mail.ru/itprincess/gallery/"+str(id)
s = requests.post(url_post, headers=headers_post, cookies=r.cookies, data=data, proxies=proxy, verify=False)
continue
else :
print 1
# с помощью Контроллера, запущенного на 9051 порту посылаем тору сигнал о смене ноды
# кстати, сам скрипт нужно запускать от root, потому как иначе stem выбрасывает exception
with Controller.from_port(port = 9051) as controller:
controller.authenticate("16:872******************")
controller.signal(Signal.NEWNYM)
time.sleep(5)
Чтобы запустить Контроллер необходимо установить параметр ControlPort в /etc/tor/torrc файле:
ControlPort 9051
## If you enable the controlport, be sure to enable one of these
## authentication methods, to prevent attackers from accessing it.
HashedControlPassword 16:872*************
А затем перезапустить Тор:
/etc/init.d/tor restart
После закрытия голосования 1-го этапа возможность ставить лайки через веб-морду пропала, но мой скрипт спокойно продолжал работать и накручивать. По-моему, они это заметили и закрыли только через 2 дня.
На втором этапе конкурса условия слегка изменились, но баги остались те же.
2. Голосование зарегистрированных участников
Веб-приложение для конкурса написано на Python/Django, и тут встретилась его типичная фича — при регистрации пользователь автоматически авторизуется, т.е. без необходимости подтверждения почты. Это значит, что по сути можно отправить любые регистрационные данные (Имя/Фамилия пользователя, почта и пароль) и сразу перейти к голосованию. Данные регистрации отправляются через multipart/form-data и как заполнять эти данные через python легко гуглится.
Кстати, на случай, если бы конкурс был сделан по уму и разработчики предусмотрели необходимость подтверждения почты перед голосованием, для сервиса временной почты Guerilla Mail есть отличный
python-клиент, да и вообще у них
открытый API, так что реализация может быть на чем угодно.
Почему я не продолжила парсить и лайкать? В отличие от первого этапа, на интерфейс не выводилось количество набранных лайков. А такой развод уже точно не для принцесс.