company_banner

Железо проекта: как мы строили комнату с хакерским квестом


    Пару недель назад мы провели онлайн-квест для хакеров: построили комнату, которую заполнили умными устройствами и запустили из нее YouTube-трансляцию. Игроки могли управлять IoT-девайсами с сайта игры; целью было найти запрятанное в комнате оружие (мощную лазерную указку), хакнуть его и устроить в комнате короткое замыкание.

    Чтобы добавить остросюжетности, мы поставили в комнате шредер, в который загрузили 200 000 рублей: шредер съедал по купюре в час. Выиграв игру, можно было остановить шредер и забрать все оставшиеся деньги.

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


    Было очень много запросов показать момент уборки комнаты — показываем, как мы ее разбираем

    Архитектура железа: управление комнатой


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

    Вспоминая старый анекдот «The S in IoT stands for Security» («Буква S в аббревиатуре IoT обозначает Security») мы приняли решение, что в этот этот раз игроки по сценарию игры взаимодействуют только с фронтендом и бэкендом сайта, но не получают возможности добраться непосредственно к железу.

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

    Перед началом проектирования у нас сформулировались несколько принципов управления игровыми устройствами, которые стали базой конструкции:

    Не использовать беспроводные решения


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

    Не использовать какие-то специальные устройства от умного дома


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

    Кроме того, нужно было придумать устройства, по которым будет явно видно, что именно игроки меняют его состояние: включили/выключили или проставили конкретный свет на буквах СОКОЛ.

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

    Выбор собрать все самим упрощал отладку, масштабируемость, однако, требовал большей аккуратности при монтаже.

    Все реле и арудино не должно быть видно в кадре


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


    В итоге все спрятали под столом, а камеру установили так, чтобы ниже стола ничего не было видно. Это была наша «слепая зона» для подползания инженера

    С точки зрения аппаратной реализации это устройство управляло 6 элементами:

    1. Несколько настольных ламп, они имеют состояние вкл/выкл и управляются игроками
    2. Буквы на стене, они могут менять свой цвет по команде игроков
    3. Вентиляторы, которые крутятся и открывают флипчарт при нагрузке на сервер
    4. Лазер, который управляется через ШИМ
    5. Шредер который сжирал деньги по расписанию
    6. Дым-машина, которая срабатывала перед каждым выстрелом лазера


    Тестируем дым-машину вместе с лазером

    Позже добавился ещё сценический свет, стоявший за кадром и управлявшийся ровно как светильники из пункта 1. Сценический свет срабатывал в двух случаях: подсвечивал лазер при подаче на него питания и подсвечивал гирю перед тем, как лазер запускался в боевом режиме.

    Что из себя представляло это умное устройство




    У нас получилось фактически одно умное устройство: оно получало от бэкенда состояние каждой своей части и меняло его соответствующей командой.

    Предполагалось, что на компьютере будет крутиться простой скрипт, который получает json с состоянием устройств и пересылает его на подключенную по usb ардуинку. В последствии этот компьютер заменили на расберри, она подключалась к бекэнду из-за нат.

    К портам подключались:

    • 16 обычных реле (именно они издавали то щелканье, которое было слышно на видео. В основном мы выбрали их из-за этого звука)
    • 4 твердотельных реле для управления каналов с ШИМ, например вентиляторов,
    • отдельный ШИМ выход для лазера
    • вывод, формирующий сигнал на светодиодную ленту

    Вот пример json-команды, которая приходила к реле от сервера

    {"power":false,"speed":0,"period":null,"deviceIdentifier":"FAN"}

    А это пример функции, с помощью которой команда попадала на арудино

    
    def callback(ch, method, properties, body):    
        request = json.loads(body.decode("utf-8"))    
        print(request, end="\n")     
        send_to_serial(body)
    

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


    Кнопка-мониторинг движения гири

    При этом сигнале должны были загореться дымовые шашки, сделанные из шариков для пинг-понга. Мы вложили 4 дымовухи прямо в корпус сервера и подвели к ним нихромовую нить, которая должна была раскалиться и сработать как запал.


    Корпус с дымовыми шашками и китайской гирляндой



    Ардуино


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

    Первое — при получении нового запроса, запрос парсился с помощью библиотеки ArduinoJson. Далее каждому управляемому устройству сопоставлялись несколько его свойств:

    • состояние питания «включен» или «выключен» (вернулся в стандартное состояние)
    • время в милисекундах, на которое устройство включено (при обработке JSON это время прибавлялось к текщему, и сохранялся момент когда уже пора выключать, то есть приводить состояние к стандартному)
    • у вентиляторов и PWM выходов задавалась глубина ШИМ, которая определяла скорость вращения
    • для светодиодной ленты передавались значения цвета, и с какого и по какой пискель этот цвет применить. Таким образом любой из 587 светодиодов можно было зажечь своим цветом. Но, чтобы надпись смотрелась на камере равномерно, цвет корректировался так, чтобы яркость ближних букв была меньше чем у более далеких. Для этого использовался ешё один параметр.

    Последнее время задавалось при получении соответствующего параметра в JSON, однако его можно было и не передавать, тогда значение устанавливалось в 0 и обнуления не происходило.

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

    Лазерная указка — тот самый Мегатрон 3000




    Это обычный лазерный модуль для резки и маркировки LSMVR450-3000MF 3000мВт 450нм с ручной фокусировкой.

    Буквы Сокол


    Сделаны очень просто — мы просто скопировали буквы с логотипа, вырезали их из картона, а потом обклеили led-лентой. При это пришлось спаивать куски ленты между собой, по 4 контакта на каждом шве, но результат того стоил. Наш бекендер Паша показал чудеса умелости, сделав это меньше чем за несколько часов.


    Первые тесты iot-устройства и допиливание


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

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

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

    При запуске с тестовым токеном мощность регулируемая через шим составляла менее 10% и веревку не повреждала даже при длительной экспозиции.

    Для боевого режима лазер расфокусировали примерно до пятна диаметром 10 мм и он уверенно пережигал веревку с грузом, с расстояния около метра.


    Так лазер срабатывал отлично на тестах

    Когда мы уже начали тестировать все прямо в комнате на подвешенной гире, оказалось, что надежно закрепить лазер не так-то просто. Затем, что когда веревка горит — она плавится, растягивается и смещается из под первоначального фокуса.


    А вот так он уже не работал: веревка смещалась

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

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


    Нить, которая в итоге пережигала веревку за кадром

    Таким образом появилась третья задача которую решала ардуинка — отработать последовательности, связанные с исполнением этих команд.

    Также мы решили отдать raspberry, которая раньше просто пересылала ad-hoc JSON получаемые с бекэнда, м необходимость вести отсчет денег на телевизоре и запускать шредер. Первоначально предполагалось что этим займется бекэнд и на сайте будет виден текущий баланс, а на телевизоре мы будем показывать комментарии с ютуба, как дополнительный интерактивный элемент, подсказывающий зрителям, что события в комнате происходят в реальном времени.

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

    Raspberry мы завязали на текущее время: каждый полный час запускался шредер. Картинка на телевизор выдавалась с помощю распберри, которая в тот момент уже получала с сервера запросы и пересылала их на исполнение в ардуинку. Картинки с денежными показателями рисовались с помощью вызова консольной утилиты fim примерно вот так

    image = subprocess.Popen(["fim", "-q", "-r", "1920×1080", fim_str]), где fim_str

    И формировалась исходя из нужной суммы или времени.

    Картинки мы сгенерировали заранее: просто взяли готовое видео с таймером и экспортировали 200 картинок.

    Вот такая механика была запрограммирована в квесте. К моменту, как запустился финальный отсчет, мы все выехали на площадку, вооружились огнетушителями и сели ждать пожар (который вовсю пылал только в дискорде)

    Как сделать трансляцию, которая работает неделю: выбор камеры


    Для квеста нам нужна была непрерывная трансляция на ютубе в течение 7 дней — именно столько мы закладывали как максимальную продолжительность игры. Было две вещи, которые нам могли помешать:

    1. Перегрев камеры от непрерывной работы
    2. Обрыв интернета

    Камера должна была отдавать картинку как минимум Full HD, чтобы играть и наблюдать за комнатой было комфортно.

    Изначально мы смотрели в сторону веб-камер, которые выпускают для стримеров. Мы резали бюджет, поэтому покупать камеру не хотелось, а в аренду, как оказалось, их не дают. В этот же момент мы чудом нашли лежащую у меня дома камеру Xbox Kinect, поставили в комнате и запустили тестовую трансляцию на неделю.

    Камера справлялась нормально и не перегревалась, но Илья почти сразу заметил, что в ней не хватает настроек, в частности нельзя выставить экспозицию.

    Илья стремился приблизить вид трансляции к стандартам кино-видео производства: передавать динамично меняющуюся световую сцену с яркими источниками света, затемнённым фоном и предметами в кадре. При этом хотелось сохранить проработку изображения как в светах так и в тенях, с минимальным цифровым шумом.

    Поэтому, хоть кинект и показал себя надежным при тестах и ему не требовалась плата видеозахвата (еще одна точка отказа), от него мы решили отказаться. После трёх дней тестов разных камер, Илья выбрал Sony FDR-AX53 — небольшой надежный камкордер, бюджетный в аренде, но при этом обладающий достаточной надежностью и изобразительными характеристиками.

    Мы арендовали камеру, включили ее на неделю в связке с платой видеозахвата и поняли, что с ней можем рассчитывать на непрерывную трансляцию в течение всего квеста.

    Делаем кино: постановка сцены и света


    Работа над освещением требовала определенного изящества, нам требовалось минимальными средствами выстроить световую партитуру:

    1. Подсветка предметов, когда их находят игроки (лазер, гиря), а также постоянный свет на шредер. Здесь использовались dedolight 150 — надежные и компактные осветительные киноприборы с низковольтными галогенными лампами, позволяющие акцентно сфокусировать луч на конкретном предмете, не задевая фон и остальные предметы.

    2. Практический игровой свет — настольная лампа, торшер, звезда, гирлянда. Весь практический свет был гармонично распределён в кадре, чтоб освещать свою область изображения, внутри стояли led лампы с цветовой температурой 3200К, лампа в торшере была закрыта красным фолиевым фильтром Rosco, для создания необычного цветового акцента-подсказки.


    Я у мамы инженер или запуск завтра

    Как мы резервировали интернет и электричество


    К вопросу отказоустойчивости подошли почти как в дата-центре: решили не отступать от основных принципов и зарезервировали по привычной схеме N+1.

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

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

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

    Поэтому мы взяли бесперебойник ippon innova g2 3000, который резервировал бы все игровые устройства: суммарная потребляемая мощность нашей системы была в районе 300 Ватт. Его хватило бы на 75 минут, вполне достаточно для наших целей.

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

    Благодарности


    • Всей команде RUVDS, которая придумывала и реализовывала игру.
    • Отдельно админам RUVDS, за то, что следили за работой серваков, нагрузка была приемлемой и все работало штатно в обычном режиме.
    • Лучшему боссу ntsaplin за то, что в ответ на звонок «есть идея: мы возьмем сервер, на него поставим аквариум, а над ним подвесим гирю, бум, бах, все залило водой, короткое замыкание, пожар!» он всегда уверенно говорит «делайте!»
    • Спасибо Tilda Publishing за то, что они подарили нам бизнес-аккаунт на год, когда мы рассказали о проекте.
    • Илье Серову S_ILya за то, что он присоединился и стал сопродюсером проекта, готовым полночи ползать, приклеивая светодиодную ленту, искать технические решения и сделать все, чтобы у нас получилось настоящее кино.
    • zhovner за то, что всегда был готов спасти ситуацию, когда другие разводили руками, борщик, моральную поддержку и разговоры до утра.
    • samat за то, что связал нас с лучшим пентестером страны, который проконсультировал нас и помог с задачками.
    • daniemilk за крутой видеопродакшен всех роликов.
    • delfphe за твердую руку и готовность работать до последнего.
    • Ну Dodo Pizza Engineering за почти всегда теплую пиццу.

    И самая большая благодарность — игрокам за все эмоции, которые мы пережили, пока вы двое суток штурмовали квест без сна и даже отложив работу.

    Остальные статьи про квест с уничтожением сервера


    RUVDS.com
    VDS/VPS-хостинг. Скидка 10% по коду HABR

    Комментарии 33

      +1
      Могли-бы оставить как комнату-музей:)
        0
        По договору аренды мы должны были освободить ее и оставить чистой и пустой :)
        0

        Жутко интересно, что же это было за помещение? Ведь требовалось ещё короткое замыкание делать и обслуживать его. Хотя судя по видео это квартира.

          +2
          Это Хакспейс Нейрон.

          Мы долго искали ангары, посуточные квартиры и гаражи, которые не жалко, но как всегда в итоге нашлось через знакомых
            +2

            Ребята из RuVDS прекрасные, но второй раз мы бы не выдержали наверное :)

              0

              Класс, очень круто

            +1

            Гирлянда была отвлекающим манёвром? В дискорде мигание приняли за модуляцию, морзянку какую-нибудь.

              +1
              Да! Мы ее вставили, чтобы повторить мигание на корпусе обычного старого системника. Собственно поэтому было так забавно наблюдать, как пытались найти в ней морзянку)
              0
              Отлично, когда следующий квест? :)
                0
                Ближе к зиме. Когда кстати лучше, в выходные или будни?
                  +2

                  Выходные! Легче погрузиться с головой, работа не страдает.

                    +1

                    30 декабря, в качестве подарка на Новый Год.

                  +1
                  Выходит, лазер стоял в основном для красоты?
                    +1
                    Получилось, что так, хотя тестировали и выбирали так, чтобы пережигал нашу веревку.
                    +3
                    Работа со светом на квесте была очень крутой!
                    +1
                    Сколько в сумме времени заняла подготовка, если каждую камеру тестировали по неделе?
                      +1

                      Примерно 4 недели

                      +1

                      Так бесперебойник в итоге пригодился? Не было особо одаренных взломщиков, которые снаружи рубильник в подъезде дёрнули?

                        0

                        Нет:) нас слава богу так и не нашли. Но рубильник мы сами дёргали, когда проверяли ИБП.

                        +2

                        Там 220? Выглядит жутковато :)


                        картинка

                        +1

                        А кто этот, лучший пентестер страны, если не секрет?

                          0
                          Омар Ганиев
                          +1
                          какой бюджет квеста?
                            0
                            К сожалению, это под NDA
                            +1
                            Мне казалось системник — бутафория, только корпус. Если в нём всё равно была начинка, почему не стали запускать сайт именно на нём?
                            Исключение возможности взломать iot устройства в квесте для itшников — это скорее минус.
                              0
                              Для надежности. Изначально конечно собирались прямо там крутить сайт, потом решили сделать надежнее и проще
                              +1

                              А потом спрашивают, чем ардуина плоха. Да тем, что ее любители начинают засовывать ее в любой проект, не думая головой, надо, не надо, есть решения лучше, нет решений лучше…
                              В итоге ради задачи "GPIO с компа" берётся контроллер, добавляется куча библиотек, JSON-парсер, все это обвешивается релюшками и самодельной логикой, и получается франкенштейн.
                              Хотя хватило бы FTDI GPIO с библиотекой на питоне, или, если хочется по-взрослому, контроллера типа Wirenboard, у которого внутри линукс, и там непринужденно пишется любая логика, которая управляет любыми датчиками и реле.


                              По опыту работы в квестах, разработчики железок очень не любят нормальные контроллеры — потому что после перевода на эти контроллеры логики, квест почему-то перестаёт ломаться в части электроники совсем, и им начинают платить не за "приезжай, почини, срочно", а только за добавление новых функций, что очень сильно ломает их бюджет.

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

                                Ну и ремонт попроще.

                                В итоге у нас получилось 21 gpio на выходы, 1 на вход и ещё выход на светодиодную ленту. Подключенных библиотек было 3 — ArduinoJson, FastLED и avr/wdt.
                                  0
                                  Вот именно из стремления «попроще» и вырастают монстры:
                                  1)Пересылаются данные — значит UART. UART это вряд ли RS232<->UART-TTL, скорее всего это USB-UART, который не то, чтобы стабильный (а китайские микросхемы совсем не стабильные). Когда он отвалится — никто не знает, может через час, может через сутки. Детектировать это сложно, что-то делать еще сложнее — непонятно, где проблема, и если проблема на стороне контроллера, как его ребутать-то, если он же и GPIO реализует. Второе устройство добавить сложно — нумерацией устройств занимается система, и линукс-то будет это делать как попало, если ему специально что-то не указать, а в винде вообще все плохо.
                                  Еще из-за реализации Arduino bootloader любое открытие порта ведет к перезагрузке контроллера.
                                  И таких вот тонкостей, которые могут выстрелить в непонятный момент — тонна.

                                  2)Собственный протокол — это велосипеды в области идентификации сущностей: есть ли соглашение по поводу передачи данных на исполнительные устройства и соглашение по поводу названия устройств?
                                  Велосипеды по разбору протокола: например, что служит терминатором JSON-строки? /n? Время посылки? Что будет, если потеряется произвольный символ? (это очень частая ситуация в случае помех, например)
                                  Непонятно, что делать с подтверждением посылки и проверкой ее на корректность, с проверкой что команда исполнена.

                                  Хотя можно взять WB, у которого связь с внешним миром Ethernet/TCP/MQTT, что сразу снимает добрую часть всех этих проблем, начиная от потери пакетов и заканчивая соглашениями о наименовании. Плюс, отлаженная низкоуровневая логика, которая гарантирует, что при получении такого пакета щелкнет вот это реле. Плюс, нормальные контакты, а не месиво проводков.

                                  Т.е. я верю, что у вас все работало в этот раз нормально. Или лечилось втыканием-вытыканием «ардуинки». Но такой подход все равно ведет к тому, что вероятность сломать следующий проект очень сильно повышается. Когда объект существует в единственном экземпляре, и на него не жалко потратить лишние 10к, стоит все-таки для управления входами/выходами по определенной логике взять промышленный контроллер вместо обучающего набора по разработке под МК для детей.
                                    0
                                    В нашем случае монстр если и получился, то только по хитросплетению проводов. Фактически те сущности которые отрабатывались на бекэнде и стали управляемыми объектами в микроконтроллере. Чтобы систему не замучали бесконечными запросами мы поставили таймаут на переключение со стороны сервера.
                                    Чтобы избежать перезагрузок ардуинки использовался USB-UART на микросхеме cp2102, который был подключен к UART1 микроконтроллера. Проверялось отвалился ли он очень просто — обновление состояния загрузки процессора, и соответственно оборотов вентилятора приходило по шедуллеру раз в секунду. Ну и конечно на контроллере был настроен ватчдог.
                                      0
                                      Ну, как знаете, я не ж. и не у вас работаю ¯\_(ツ)_/¯
                                      Что смог, посоветовал.

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

                              Самое читаемое