В 2021 году Центризбирком РФ обфусцировал статистические данные выборов на своем сайте. Несколько дней назад я сделал и выложил в комментариях к новости на хабре деобфускатор, чтобы помочь исследователям обнаружить статистические аномалии в результатах. Сегодня взял день отпуска, написать этот пост и поделиться очищенными данными в формате sqlite по федеральному избирательному округу, которыми поделился @illusionofchaosв посте Получаем данные результатов выборов с сайта Центризбиркома РФ
Под катом я предлагаю еще раз посмотреть, какими техническими методами затрудняли анализ программисты сайта ЦИК-а. Новых идей там нет, решения примитивные , даже обидно что кто-то за них квартиру получил[*]. Вся работа по написанию деобфускатора заняла меньше рабочего дня (точнее вечера + полночи). Основная цель этой статьи не в описании методов, а дополнительный анонс деобфускатора для исследователей. Обсуждать решение применить методики запутывания на государственном сайте куда интереснее, но этим бессмысленно заниматься в интернете.
Итак, они реализовали четыре метода:
Лишние элементы
На место в DOM, где дожно находиться просто число с результатам добавляют дополнительные элементы, которые отрисовываются где-то за пределами окна браузера.
Единственный интересный момент тут это то, что иногда примешиваются синтаксически неверные правила css у элементов с верными данными. Самый интересный пример, что я видел, это font-size: 0am
. Видимо расчёт, что люди будут использовать регулярные выражения для считывания этих правил. В деобфускаторе используется честный парсер CSS и поэтому он не восприимчив к таким трюкам.
JavaScript DOM modification
Страница с результатами с сервера приходит еще более грязная, чем есть в DOM, которые видим в Developer Tools. Дополнительная мелкая подножка есть в JavaScript.
Там определены три функции, которые либо переставляют ячейки местами в таблице, либо убирают один символ, либо просто ставят результат в ячейку.
У меня есть некоторые сомнения в компетентности людей, которые это делали. Им вроде бы известно, что бывают типы данных отличные от строчек, но при этом функция isq_dns
принимает в параметры два целочисленных значения, по которым потом идёт обращение в массив. И совершенно не ясно, зачем ей так старательно передают в аргументы строчки.
В деобфускаторе я это обошёл просто реализовав эти функции на C#.
CSS ::after
Для некоторых элементов контент записывается в CSS стиле.
Парсим CSS и меняем значение элемента с такими стилями — скучно.
Игры со шрифтами
Самым интересным для меня была игра со шрифтами.
На скриншоте видно, что Ь
отрисовывается как цифра 2.
Если открыть этот шрифт в Windows Font Viewer то будет отображаться полная ерунда. Что же тут произошло?
ЦИК нагенерировал 100 шрифтов (узнал это из данных от @illusionofchaos) в которых по только им известному правилу изменили правила, по которым отображаются коды символов в глифы, которые определены внутри шрифта и определяют то, как графема будет отрисована.
В Open Font это определяется в таблице cmap. Эта таблица используется для того, чтобы можно было переиспользовать глифы для разных букв. Например, латинская A
может иметь такие же правила отрисовки, как и русская А
.
Эту таблицу ЦИК и заменил в каждом из сгенерированных шрифтов по (предположительно) случайным правилам. Это перемешивание не сложно обратить. У каждого глифа есть правила, по которым он отрисовывается. Если один раз применить OCR или вручную разметить символы, и сравнивая эти правила рисования можно однозначно сказать, какая это графема. Но к моей большой радости, нашлось более простое и изящное решение. На сайте был доступен оригинальный шрифт :)
Поскольку таблица глифов осталась в том же порядке, что и была до перемешивания, то, имея на руках оригинальный шрифт, можно обратить это перемешивание. В оригинальном шрифте мы можем найти индекс в таблице глифов для любой интересующей нас буквы и использовать этот индекс для понимания того, что изображено на глифе. Строго говоря, это не всегда возможно, но поскольку для перемешивания были выбраны только цифры, то это отображение биективно.
Заключение
Я проверил и оптимизировал деобфускатор. Он работает примерно полчаса на ноутбуке на данных по федеральному округу, которые предоставил illusionofchaos на GitHub . Эти же данные, прогнанные через деобфускатор, можно тоже скачать на GitHub
Сейчас сделал проект Schwabra, для переброса этих данных в sqlite.
Я очень бегло проверил валидность данных, общая сумма по УИК-ам выглядит похожей. Данные в sqlite формате тоже там же
Краткая проверка правдоподобности
Данные из sqlite
SELECT num, title, SUM(value)
FROM station
JOIN result ON station.id = result.StationId
WHERE name LIKE '%УИК%'
GROUP BY num
ORDER BY num;
SELECT num, title, value
FROM station
JOIN result ON station.id = StationId
WHERE name = 'ЦИК России'
ORDER BY num
1 |
Число избирателей, внесенных в список избирателей на момент окончания голосования |
108171434 |
2 |
Число избирательных бюллетеней, полученных участковой избирательной комиссией |
98614022 |
3 |
Число избирательных бюллетеней, выданных избирателям, проголосовавшим досрочно |
199064 |
4 |
Число избирательных бюллетеней, выданных в помещении для голосования в день голосования |
47386185 |
5 |
Число избирательных бюллетеней, выданных вне помещения для голосования в день голосования |
8081206 |
6 |
Число погашенных избирательных бюллетеней |
42946873 |
7 |
Число избирательных бюллетеней, содержащихся в переносных ящиках для голосования |
8272698 |
8 |
Число избирательных бюллетеней, содержащихся в стационарных ящиках для голосования |
47243246 |
9 |
Число недействительных избирательных бюллетеней |
1167957 |
10 |
Число действительных избирательных бюллетеней |
54347987 |
11 |
Число утраченных избирательных бюллетеней |
1201 |
12 |
Число избирательных бюллетеней, не учтенных при получении |
507 |
13 |
1. Политическая партия "КОММУНИСТИЧЕСКАЯ ПАРТИЯ РОССИЙСКОЙ ФЕДЕРАЦИИ" |
10558234 |
14 |
2. Политическая партия "Российская экологическая партия "ЗЕЛЁНЫЕ" |
500671 |
15 |
3. Политическая партия ЛДПР – Либерально-демократическая партия России |
4185051 |
16 |
4. Политическая партия "НОВЫЕ ЛЮДИ" |
2946703 |
17 |
5. Всероссийская политическая партия "ЕДИНАЯ РОССИЯ" |
27626893 |
18 |
6. Партия СПРАВЕДЛИВАЯ РОССИЯ – ЗА ПРАВДУ |
4139640 |
19 |
7. Политическая партия "Российская объединенная демократическая партия "ЯБЛОКО" |
744065 |
20 |
8. Всероссийская политическая партия "ПАРТИЯ РОСТА" |
286598 |
21 |
9. Политическая партия РОССИЙСКАЯ ПАРТИЯ СВОБОДЫ И СПРАВЕДЛИВОСТИ |
425677 |
22 |
10. Политическая партия КОММУНИСТИЧЕСКАЯ ПАРТИЯ КОММУНИСТЫ РОССИИ |
707968 |
23 |
11. Политическая партия "Гражданская Платформа" |
85716 |
24 |
12. Политическая партия ЗЕЛЕНАЯ АЛЬТЕРНАТИВА |
349820 |
25 |
13. ВСЕРОССИЙСКАЯ ПОЛИТИЧЕСКАЯ ПАРТИЯ "РОДИНА" |
426359 |
26 |
14. ПАРТИЯ ПЕНСИОНЕРОВ |
1364592 |
Сам деобфускатор https://github.com/ulex/izbirkom21
Комментарии (73)
Wesha
23.09.2021 03:58+30Мораль истории: не давайте программистам интересные задачи. А то они уйдут в неё с головой, а когда вынырнут - окажется, что они электронное правительство заодно написали, и бюрократов увольнять можно.
Gengenid
23.09.2021 06:10+13Я до сих пор понять не могу, почему они просто не сделали цифры картинками. Все их ухищрения в любом случае с помощью OCR можно обойти, но можно и по другому (как оказалось), а картинку только с OCR.
SnakeSolid
23.09.2021 07:32+30А мне непонятно зачем вообще было делать обфускацию. Для снижения нагрузки на сайт - просто выложите все данные в открытом виде, банально в csv. Тот, кому нужны данные, не будет парсить сайт, а просто скачает этот файл. Даже с идеальной обфускацией, не позволяющей парсить сайт и копировать текст, всегда можно вручную переписать данные.
Gorthauer87
23.09.2021 07:54+65Наверное чтобы их не ловили за руку прямо сразу, когда эмоции наиболее сильные, а где нибудь попозже.
vesper-bot
23.09.2021 08:01+33Для того, чтобы когда данные таки получили в деобфусцированном виде, кое-чьи жопы уже пригрелись на местах и нельзя было бы их нормальным образом сковырнуть.
GooG2e
23.09.2021 11:59+7Я не помню сколько по закону, но вроде через 10 дней результаты выборов уже нельзя обжаловать т.е. это тупо временная задержка, чтобы в законном порядке схватить уже было нельзя то бишь скорее всего там есть какие-то фантастические вещи, за которые реально можно схватить - как в электронном голосовании, где тупо цифры не сходятся.
Собственно поэтому электронку и будут 5 дней пересчитывать.
Hlad
23.09.2021 12:54+5Раньше выкладывали прямо сразу. До сих пор помню на сайте ЦИК таблицу с результатом «107% избирателей за Единую Россию» в одном из районов Мордовии.
KapasMordorov
23.09.2021 13:36Выборы 2007 года. Сейчас уже прямых ссылок нет, только в интервью косвенные остались.
Атяшевский район.
Ole
24.09.2021 11:11Это знаковый район. Там теперь массово производят недорогие колбасные изделия для сети магазинов Магнит в очень больших объемах.
Druj
23.09.2021 16:00Исходя из того что предоставлять людям чистые данные не планировалось, было ожидаемо что будет очень много желающих попарсить эти самые данные с сайта. Не могу оценить количество таких желающих, но предположу что их будет больше тысячи в первую пару дней. Разумеется не каждый будет делать себе дамп страничек с прода предпочтя работу напрямую с сервером. А так, добавляя обуфускацию(на мой взгляд довольно неплохую), вы сразу шлете лесом подавляющую часть таких людей оставляя свою ЦА, т.е. тех кто просто посмотрит(прости WAI) результаты по паре округов.
P.S. Рассуждать почему было решено не предоставлять чистые данные не буду.
aulitin Автор
23.09.2021 10:38+6я очень старательно избегал подсказок в тексте поста, а вы так. Да, есть куча способов усложнить это и картинка не самый страшный.
Old_Chroft
23.09.2021 21:25Распознавание картинок одинаково работает как с картинкой вставленной в HTML, так и со скриншотами. Разница только в векторе решения задачи, соответственно заинтересовались бы просто другие группы программистов.
aulitin Автор
23.09.2021 23:06+1Да, согласен, что любую обфускацию можно обойти. Если бы они сделали ее сложнее, это бы заинтересовало бы еще больше людей, как мне кажется (меня так точно)
streloc84
24.09.2021 10:14+1Я до сих пор не могу понять зачем они сделали выборы????
SantaCluster
27.09.2021 17:49партии к выборам получили деньги
плюс денег заработали другие причастные.
сейчас на волне успеха можно придумать хоть каждый месяц "выборы" устраивать. с заранее заданным результатом отчего бы и нет? ;)
MaxxDamage
23.09.2021 08:47Роскомпозор уже старается вовсю - Хабр нормально не доступен, через Тор работает
Darkwing4
23.09.2021 11:49+1Аналогично, хабр открывается нормально только через TOR. Есть инфа у кого-то почему так?
MaxxDamage
23.09.2021 11:56У меня не работает через МТС проводной, ругается на DNS. Назначил в свойствах подключения гугловский DNS - заработало. Видимо что-то накосячили на некоторых российских DNS-серверах. Мегафон мобильный, Дом.ру проводной - работает.
gremlin244
23.09.2021 17:25Аналогично, МТС мобильный. Поменял DNS, все заработало. Без понятия что они там делают, но что-то очень странное и неприятное.
wataru
23.09.2021 12:38+4У меня из европы вчера и сегодня проблемы с хабром и QnA. Отваливается при работе с DNS. Похоже какие-то проблемы с доменным именем/ DNS сервером хабра.
T_Cirkla
23.09.2021 22:40У меня вчера вечером и сегодня ночью не работал. А днём был доступен без всяких обходов.
quillon45
23.09.2021 11:49Мегафон, смартфон: в процессе регистрации вотпрямщас через WebView ссылка для подтверждения не открывалась, скопипастил в Vivaldi – всё открылось без проблем. Вот и пойми, где проблема.
vamal
23.09.2021 12:14+4Это не РКН. Это что-то с DNSSec на хабровской зоне. Вчера где-то после 20:00 по МСК отвалилось.
Предположительно, проблема с knot на 178.248.233.33.Popadanec
23.09.2021 18:46Аналогично чпда тупил и разные другие сайты, даже в ru зоне. При этом ютуб/спидтест работали нормально. Йота. А при работе через любой VPN, всё грузилось нормально.
Сейчас вроде починили
scorp_nv
23.09.2021 10:14Да даже с обфускацией есть участки "здорового человека". Был удивлён, слегка пошастав по результатам:
euroUK
23.09.2021 11:08+1Готов поспорить, что там были коибы
symbix
23.09.2021 12:04+2Можно подумать, коибы мешают тупо нарисовать протокол.
Вот о чем готов поспорить — что были наблюдатели.scorp_nv
23.09.2021 12:37Видимо очень активные наблюдатели с правом совещательного голоса, это тоже сразу подумал. Жаль таких было мало.
symbix
23.09.2021 18:48ПСГ это отлично (сам был ПСГ на этих выборах), но и у наблюдателя достаточно прав и возможностей: если не отступать перед попытками комиссии незаконно ограничить права наблюдателей и требовать буквального соблюдения всех норм 67-ФЗ как в плане прав наблюдателей, так и касаемо процедур проведения голосования и подсчета голосов, фальсифицировать становится крайне затруднительно.
AdmAlexus
23.09.2021 15:09А можно поподробнее, как при использовании КОИБа "нарисовать" протокол.
Интересует техническая сторона реализации (если только это не "тупо засовывать в него бюллетени").
tyomitch
23.09.2021 18:35+3Техническая сторона: объявить ручной пересчёт, вписать в протокол любые нужные цифры.
Подробнее: regnum.ru/news/polit/2720503.htmlAdmAlexus
23.09.2021 20:33+3Ну да, в этом случае остается надеяться только на наблюдателей.
Хотя, на моей памяти, около 30 раз присутствовал на ручных пересчетах во многих участках с КОИБами, и везде данные полностью совпадали с тем, что КОИБ посчитал (ну и в "ГАС Выборы", естественно, грузились именно эти данные).
AdmAlexus
24.09.2021 08:12Кстати, вспомнил, у нас как раз в 2019 году тоже был поголовный ручной пересчет на всех участках с КОИБ (в целях перепроверки).
Видимо это было указание ЦИКа или ИКСРФа.
Но делали мы это сразу на всех участках с КОИБами и сразу после завершения процедуры голосования и формирования протокола с КОИБа.
Через 2 недели делать пересчет - это "немного" странно.
symbix
23.09.2021 19:03+1Можно объявить ручной подсчет, а можно при отсутствии наблюдения и прямо в коиб напихать
dimirsen
23.09.2021 23:55+1Недавно на Эхе была программа с Дмитрием Орешкиным, не помню точно, на прошлой недели или на позапрошлой. Поо коибы он так сказал. Известен формат документа о результате голосования, который выдает коиб (не знаю, у него своё печатающее устройство или он подключен к принтеру). Вот тут и будет точка атаки. Допустим, коиб в нужный момент не сможет напечатать свои данные, а из принтера выйдет заготовленный похожий документ. Если взять самый наглый сценарий: коиб без картриджа с тонером или подключен к принтеру, который на самом деле стоит в глухом чулане. А тот принтер, который стоит с ним рядом, в нужный момент напечатает заготовку с 60% голосов Единогласной России.
symbix
24.09.2021 00:45+2О, я, когда, прийдя на участок, увидел, что принтер, подключенный к КОИБу, умеет печатать по Wi-Fi, причем даже без особой настройки — по кнопочке WPS, несколько напрягся. При печати протокола следил за сообщениями на экране КОИБа в оба глаза :)
То, что все подключено как полагается, мониторил регулярно, да.
Впрочем, по здравому размышлению, это слишком тонкая шутка для нашего цика. :) Там председатель с секретарем с электронным рабочим блокнотом-то с трудом справлялись, откуда у них такие скиллы (особенно чтобы я не заметил).
AdmAlexus
24.09.2021 07:52+1И КОИБ-2010 и КОИБ-2017 подключаются к отдельному принтеру.
Принтер печатает не только итоговый протокол, но и кучу другой информации, поэтому кмк вариант "напечатать в нужный момент 60% за нужную партию" можно отклонить. Печатаемую информацию (исходные данные и т.п.), опять таки, обязательно нужно брать и сверять наблюдателям и членам с ПСГ.
symbix
27.09.2021 05:08Еще КОИБ должен зачитывать робоголосом результаты, и если он этого не сделал, это повод объявить ручной пересчет. На участке, где я наблюдал, этого не произошло, коиб молчал как рыба в воде. Но там и "здравствуйте-спасибо" все 3 дня глючили, наблюдал я все три дня внимательно, итоги голосования по участку правдоподобные (в пользу КПРФ и кандидата от УмГ с заметным отрывом), так что я возражать против подведения итогов не стал.
AdmAlexus
27.09.2021 06:44Если КОИБ был 2010 (за другие сказать не могу, потому что не работал с ними), то вероятнее всего член комиссии, который работал с КОИБом просто нажал "Нет" на запрос "Зачитать результаты голосования по выборам N"?"
symbix
27.09.2021 06:50Вполне возможно. Она там еще долго не могла понять, как протокол напечатать, звонила в техподдержку, может, натыкала куда-то не туда.
Понабрали по объявлению :)
gerbflagoff
23.09.2021 10:34У меня хабр перестал открываться. Tele2.
Зашёл через антизапрет для openvpn.
alexshy
23.09.2021 12:13Надо ЦИК и РКН наживку поближе к носу закинуть, пост поактивнее пошарить. (Может быть, сам Хабр его в Твиттер и других соцсетях промотнет (с другой стороны, ему оно надо? :)) ).
dimka11
23.09.2021 13:07Какие решения используются для профессиональной, а не примитивной защиты от парсинга?
Day2
23.09.2021 13:17Можно вообще на другом уровне абстракции проблему решить. С помощью тестилки графических интерфейсов с возможностью OCR. Давно не занимался этим, а когда занимался была популярна Sikuli.
С таким подходом им не поможет даже изменение алгоритма обфускации.
FrankSinatra
23.09.2021 13:38+2Я дико извиняюсь, но зачем?
Есть https://observer.mos.ru/all/
Если выбрать последние данные, там есть дамп БД для развлечений.
Весит около 3гб. Развлекайтесь.
Bonio
23.09.2021 13:47+3Там только по электронному голосованию.
FrankSinatra
23.09.2021 14:12-9Коллективное бессознательное уже решало данную проблему ранее. Я смотрю на это как на некий троллинг со стороны ЦИК. Все сошли с ума и пишут деобсфукаторы, чтобы получить данные, которые и так можно на листик переписать.
https://habr.com/ru/news/t/578832/comments/#comment_23499710
ifap
23.09.2021 16:05+9Основными принципами обеспечения доступа к информации о деятельности государственных органов и органов местного самоуправления являются:
1) открытость и доступность информации о деятельности государственных органов и органов местного самоуправления, за исключением случаев, предусмотренных федеральным законом;
2) достоверность информации о деятельности государственных органов и органов местного самоуправления и своевременность ее предоставления;
3) свобода поиска, получения, передачи и распространения информации о деятельности государственных органов и органов местного самоуправления любым законным способом;
4) соблюдение прав граждан на неприкосновенность частной жизни, личную и семейную тайну, защиту их чести и деловой репутации, права организаций на защиту их деловой репутации при предоставлении информации о деятельности государственных органов и органов местного самоуправления.
Источник: www.consultant.ru/document/cons_doc_LAW_84602/e37570367fd60171931916b5227191dd934c379c
Прокуратуру что ли на них натравить…Ritan
23.09.2021 18:36+4Вы ещё конституцию попытайтесь процитировать. Даже федеральные законы - почти экстремизм
herwind
23.09.2021 16:11+3Спасибо вам за ваш труд. По сводной таблице и ОИК накидал простенький отчетик в Power BI. https://bit.ly/2Z8KkTh
vasilykomyagin
23.09.2021 23:59Интересно, что капча такая простая. Может, на той стороне технари за правое дело, просто они в плену?
Naves
24.09.2021 02:37Ага, шепотом:
Теория заговора
На самом деле все результаты в таблицах, которые мы видим, они вообще из фейковой БД, в которой проценты сгенерировали заранее с учетом всех правил статистики и нормализаций, чтобы никакие Шпилькины не подкопались. Разработчики сайта ЦИКа узнали об этом, и такой обфускацией передают нам послание канарейки, что верить этим данным нельзя совсем. А перед начальством они отчитались, что это новая передовая защита от Отак.
Cossack13
24.09.2021 10:15Мне кажется, или проще не исходники исследовать, а распарсить скриншоты?
aulitin Автор
24.09.2021 10:28Это зависит. Создание скриншота и распознование его более ресурсоемкая операция. Навскидку это тяжело будет будет сделать в разумные сроки на одном компьютере. И для этого надо будет придумать что-нибудь с инфраструктурой. Мне проще было уйти от этого и сделать все локально, кому-то может проще кластер поднять или в лямбду какую-нибудь положить.
herwind
26.09.2021 22:04+4@aulitin на основе ваших данных по УИК доработал отчет в Power BI. Добавил регионы и визуализации, которые помогут анализировать данные.
Ссылка на отчет https://bit.ly/2Z8KkTh
D_dMer
12.10.2021 09:31Что значит "общая сумма по УИК-ам выглядит похожей"
говорите прямо на мухлевали или нет?
А то как доли процентов не сходится истерика, и безапелляционное заключение, что обман. Давайте на чистоту, что получилось, вывод какой?
symbix
Ну всё, теперь квартиру отберут!
ZhilkinSerg
Нет, конечно — от «атаки» же защитились.