Хакерский стритрейсинг. Ломаем бизнес-логику через Race Condition

Содержание статьи

  • Заезд первый. Новичок в гонках забирает свой первый контракт
  • Заезд второй. Смогу ли я участвовать в «Формуле-1»?
  • Круг 1
  • Круг 2
  • Итоги

Сос­тояние гон­ки иног­да поз­воля­ет вме­шать­ся в алго­рит­мы обра­бот­ки дан­ных: от опла­ты кор­зины в интернет‑магази­не до механи­ки перевы­пус­ка API-клю­чей с повыше­нием при­виле­гий. На при­мерах с HTTP/2 и single-packet attack я покажу, как пра­виль­но подоб­ранный момент ата­ки дает воз­можность «выр­вать­ся впе­ред на поворо­те» и бук­валь­но перепи­сать биз­нес‑логику при­ложе­ния.

Это иссле­дова­ние получи­ло пер­вое мес­то на Pentest Award 2025 в катего­рии «Hack the logic». Сорев­нование еже­год­но про­водит­ся ком­пани­ей Awillix.

warning

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

Race Condition (сос­тояние гон­ки) — это уяз­вимость в веб‑при­ложе­ниях, которую отно­сят к груп­пе уяз­вимос­тей биз­нес‑логики. Если ты аппсек, баг­хантер или пен­тестер, то тебе будет полез­но в этом механиз­ме разоб­рать­ся.

Как эта уяз­вимость выг­лядит в реаль­ных веб‑при­ложе­ниях? В голову сра­зу при­ходит такой сце­нарий: у меня есть десять руб­лей, и товар сто­ит десять руб­лей, мож­но одновре­мен­но отпра­вить два зап­роса на его опла­ту, что­бы веб‑при­ложе­ние одновре­мен­но порабо­тало с 10-руб­левым балан­сом, и если оба прой­дут, то получит­ся два товара за десять руб­лей, ито­го — один бес­плат­ный товар. Или, нап­ример, такое: в кино остался пос­ледний билет, а нас двое, мож­но отпра­вить два зап­роса на покуп­ку билета одновре­мен­но, и если все прой­дет как надо, то в отве­те будет два билета. По край­ней мере такие сце­нарии и еще пару похожих мне пред­ложил DeepSeek R1.

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

С помощью такой уяз­вимос­ти мы как бы перес­какива­ем барь­ер нулево­го балан­са и уво­дим перемен­ную в отри­цатель­ные зна­чения (в некото­рых слу­чаях наобо­рот — уве­личи­ваем количес­тво и перес­какива­ем вер­хнюю гра­ницу).

А что, если я ска­жу: это лишь вер­шина айсбер­га и мень­шая часть потен­циала уяз­вимос­ти?

 

Заезд первый. Новичок в гонках забирает свой первый контракт

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

Наш пер­вый заезд будет на трас­се с опла­той кор­зины. Вот как про­исхо­дит опла­та.

  • Поль­зователь добав­ляет в кор­зину или уби­рает отту­да товары на сай­те интернет‑магази­на, тем самым фор­мируя заказ.
  • Поль­зователь отправ­ляет зап­рос на опла­ту кор­зины, и ему в ответ воз­вра­щает­ся ссыл­ка, по которой фрон­тенд перенап­равля­ет его в сто­рону интернет‑эквай­рин­га (при­ем онлайн‑пла­тежей as a service).
  • Магазин бло­киру­ет изме­нение ста­туса кор­зины (допус­тим, Waiting for payment) — ее напол­нение теперь нель­зя изме­нить.
  • Поль­зователь опла­чива­ет кор­зину, и эквай­ринг воз­вра­щает сай­ту информа­цию об успешной опла­те.
  • Получив под­твержде­ние от эквай­рин­га, сайт добав­ляет в лич­ный кабинет поль­зовате­ля офор­млен­ный заказ.
  • Вро­де все хорошо, но давай пос­мотрим на про­цесс с дру­гой сто­роны. Мы здесь можем пов­лиять толь­ко на пер­вый и вто­рой шаги, а имен­но изме­нение сос­тояния кор­зины и отправ­ку кор­зины на опла­ту. Будем счи­тать, что с опла­той на чет­вертом шаге все окей, так как это сто­рон­ний сер­вис.

    Но что, если в нашей гон­ке мы запус­тим одновре­мен­но добав­ление товара в кор­зину и ее опла­ту? Смо­жем ли мы меж­ду вто­рым и треть­им шагом добавить свой товар так, что­бы сос­тояние кор­зины изме­нилось за «мгно­вение» до отправ­ки зап­роса в эквай­ринг? Смо­жет ли веб‑сайт успеть до­бавить в кор­зину товар и одновре­мен­но сде­лать так, что­бы в сум­му, которую он передаст интернет‑эквай­рин­гу, вош­ла сто­имость это­го товара?

    Источник: xakep.ru

    Ответить

    Ваш адрес email не будет опубликован. Обязательные поля помечены *