История похожа очень на взлом Егора, за исключением того что это не совсем рэйс, вернее совсем не race condition в чистом его виде. Как оно будет полностью не знаю, я больше практик, чем теоретик. Назовем его «conditional race condition» — хоть и масло масленое, но суть отражает верно.
Как-то вечером, домашние уснули, по ящику одна муть, наши опять проигрывают делать было особенно нечего, на опенсорс решил на сегодня забить, решил чего-нибудь сломать. А что ломать (когда Егор уже все сломал), как не банк какой-нибудь или казино (эго, необходимость иногда почувствовать себя крутым парнем, все дела в общем). Это было одно из первых онлайн-казино, которое мне тогда приглянулось в поиске.
Не секрет, что экономят на программистах, тестировщиках и т.д. все или почти все. Я делаю временами аудиты, да и по роду деятельности такого иногда насмотришься, что волосы дыбом. Но тут-то казино! С возможностью вывода (выигранных) вечнозеленых и т.д. Т.е. контора должна вроде соответствовать…
Завел себе аккаунт, и поехали…
Собственно взлом
Как оказалось — здесь тоже сэкономили изрядно.
Сначала решил набросить себе немного «виртуальных» денег. Виртуальная валюта там не выводится (чисто поиграть — потренироваться). Можно было через paypal (10ct = 10V$), можно раз в день через капчу (20V$).
При беглом просмотре страницы «покупки» (загрузив ее несколько раз) обнаружил там токен, привязанный ко времени (заметен инкремент по модулю 180), отправляющийся с капчей после нажатия «Order». Вероятно в базу для моего аккаунта писался еще и datetime времени «покупки» (чтоб значит только раз в сутки), но нам оно сейчас без надобности.
Я хотел сначала попробовать чистый race (я не настолько глуп чтобы поверить про 3-и минуты, ну или 1.5 минуты если используют формулу со смещением), но у меня были сомнения что нет даже нескольких миллисекунд, т.е. с высокой долей вероятности этот токен скорее всего тоже помечался как использованный в DB, чтобы значит совсем «до завтра» (кстати так оно и оказалось впоследствии).
В результате, решил начать пробовать сразу со своего «условного рэйс». Предположим, что токен пишется в базу int-ом (типа unixtime — т.е. целым числом), ведь они исходят из того, что следующий токен выдадут только через 3 минуты (хотя обычно оно все-таки с каким либо смещением, чтобы даже на границе срок действия его уже истек). Т.е. думаю имеем что-то вида:
create table user_order (usrid int, token bigint, lasttoken bigint, lastorder datetime, ...)
Тут немного техники: я не люблю штуки вида Greasemonkey и ко, хоть и юзаю иногда. Но не люблю (мало что ли таких как Егор;). Много можно сделать и из dev консоли firefox-а, но так по мелочи. Я так тоже довольно редко «работаю».
У меня есть собственный (ну почти) плагин, разворачивающий «полноценный» интерпретор тикля (tcl) с api к javascript текущего окна. Ну типа greasemonkey, только на тикле. Удобно жуть.
В общем, тикль-джиэсный скрипт для «взлома» выглядел следующим образом:
set tok [js form.ordertoken.value]
set i 0
set cntr 0
time {
## чтобы не плодить формы - делаем максимум пять штук:
elm duplicate -overwrite form[expr $i % 5] form
## делаем токен "float" и сабмитим форму в таргет (0-4) ...
js {
var f = form[expr $i % 5];
f.target = '_tmp_win_[expr $i % 5]';
f.ordertoken.value = f.ordertoken.value + '.' + '[format %05d [incr cntr]]';
f.submit();
}
## отработать события, контекст свич и задержка...
update; after 5
incr i
} 10
Т.е. для каждой новой сдублированной формы делаем значение ordertoken в виде числа с плавающей точкой.
Т.е. имеем следуещее в javascript:
...
var f = form0;
f.target = '_tmp_win_0';
f.ordertoken.value = f.ordertoken.value + '.' + '00001';
f.submit();
...
var f = form1;
f.target = '_tmp_win_1';
f.ordertoken.value = f.ordertoken.value + '.' + '00002';
f.submit();
...
Догадливый читатель уже наверное понял что происходит.
Следующий SQL-statement будет легально выполнен (если имеем автоконвертирование и режет без ошибки переполнения), а условие будет положительное (т.к. сравнение будет производится во float).
UPDATE user_order set lasttoken = 1432254060.00007, lastorder = now(), vmoney = vmoney + 20
WHERE token = 1432254060.00007 AND lasttoken != 1432254060.00007 AND ...
Что там они проверяли, affected rows или просто if begin… end в транзакции, и SQL ли это вообще, я не в курсе но в очередной раз исполнив скрипт я стал таки «виртуальным» миллионером!
Ну то есть
time casino-virt-order 50000
.
Как вы думаете как долго сайт продержался с реальным платежом?! День (да и то потому что уже баиньки хотелось очень).
Там конечно не было time casino-real-order 50000
да и думаю, что такое они бы заметили на раз два. Ну какой-то же мониторинг средств (читерства и т.д.) должен все-таки быть. Хоть и с десятью тысячами клиентов. Но 50 по 20 я таки исполнил разок (т.е. заплатив всего 20 вечнорастущих).
Справедливости ради, надо сказать, что я естественно закрыл этот аккаунт без вывода средств.
Мораль
Ну тут вроде и обсуждать нечего.
Единственное, что могу добавить — чистый race condition там не работал, я проверял (второй параллельный вызов выдавал «уже использован»). Но судя по «профессионализму» ребят — это была скорее защита от дурака (типа F5 после реквеста и т.д.).
Интересен другой момент, когда токен устаревал (+ 180) оно уже не работало по причине проверки уже даты последнего «платежа» типа lastorder < now() + '1 day'
. Но почему-то не с тем же самым токеном, т.е. думаю что болячка та не одна была.
И да, капча видимо была привязана таким же образом к токену + чего-то еще в форме. Или для нее работал «race», оно мне без надобности было искать.
Кстати все остальное, от SQL-Injection до разных трюков с известными мне эксплойтами на той платформе, выглядели довольно солидно, но как-то все-таки полупрофессионально что ли, т. е. придраться все же было к чему (ну некоторые вещи не делаются так уже лет дцать как).
«Разборки» со мной — злодейским хакером
Даже рассказывать не хочу.
Я, по своему обыкновению, сперва выложил им только результаты «эксплойта» — т.е. вот аккаунт, на нем виртуальный мильён денег. Аккаунт создан позавчера, ну и намек — мол расскажу как, после доната.
Про взлом с реальными деньгами я сначала вообще умолчал (другой аккаунт — другой донат ;). Я не беден, но любая работа должна быть оплачена. Естественно «покаялся», ну т.е. «чисто из спортивного интереса» и «естественно никогда (зуб даю) не буду применять».
Результат:
- реальная попытка сделать из меня злостного вскрывателя казинов;
- через некоторое время уже просьбы сказать «как» — т.е. о чудо, они даже по accesslog не нашли!
- после совсем откровенного намека «работа должна быть оплачена», попытка сделать меня шантажистом (я уже друга адвоката думал подключать)
- в результате вежливо послал их подальше, снова обязавшись не использовать во вред и игнорируя в дальнейшем все попытки тупого «прессинга»
Что смешно, после закрытия аккаунта уже с реальными деньгами (предварительно вывел только свои 20 евро) я в течении некоторого времени еще получал от них письма, мол «заберите деньги»… Хотел сперва им ответить — потратьте на благотворительность, но они все же не мои. Так и лежат они вероятно там…
Люди, не экономьте все же на профи… Мы, профи, стоим тех денег, которые нам платят.
This entry passed through the Full-Text RSS service - if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.
Этот комментарий был удален автором.
ОтветитьУдалить