
At the distant approaches and immediately before the elections, the authors of Novaya Gazeta warned of potential vulnerability of remote electronic voting (DEG). On the day of elections at the electronic election commission, strange events took place, which was told by our readers - Ilya Sukhorukov, Anna Lobonok and Nikolai Kolosov. We tried to obtain intelligible explanations from the CEC, the Department of Information Technology (DIT) of Moscow and the Artem Kostyrko , who is responsible for electronic voting in Moscow, but from personal conversation, Artem Kostyko and Ella Pamfilova dodged, and in the written communication we did not receive intelligible answers.
Statistical analysis of the physicist of Maxim Gongalsky showed that, most likely, the main mechanism of falsifications that ensured the victory of pro -government candidates was to “twist” the votes of the opposition through a parting, and estimated the number of “twisted” at 250,000 votes. The report of the DEG technical group did not refute such a version.
The programmer Peter Zhizhin in his article on the portal for programmers, which he popularly set out to our readers in an interview with Yulia Latinina, established the existence of a “secret blockchain”. This eliminates the verification of the results of the public blockchain published by the Moscow. Pyotr Zhizhin then could not give an answer: how could stuffing in the system? And now he has such an answer.
If very short:
First, votes for pro -government candidates from “not people” could fit into the public blockchain. And after the end of the vote, the “Himmeric” lines could fit into the “private blockchain”,
In which the field corresponding to the voter would be taken from living people from other lines of a private blockchain, and a field corresponding to a vote for any candidate-taken from a “not man”, ballot for power from a public blockchain.
In addition, it was found that the code published by Moscow did not correspond to the one that was launched in the elections: for the elections they increased the time during which the partition was available. It also turned out that during the program the program was recorded not provided for by the law and the procedure for the DEG of a simple table with voter data, information about which is absent in the documentation for DEG.
Finally, in addition to all the listed holes, Peter experimentally discovered a whole “window” through which, if there is a key of the organizer of the elections to the blockchain, you can introduce any Beliberd, and the blockchain will not choke.
We are the first to publish the results of further research by Peter and his colleagues of the DEG program code.
-Peter, after the publication of your article on Habre and your interview in Novaya Gazeta, you continued to explore how the electronic vote is arranged and found something interesting that you did not talk about in the previous interview. What did you manage to find?
- During the time that passed with the publication of my article on Habri and the interview of “New”, I and many other people in the chat of programmers who are analyzing remote voting, studied the source code. The answers to those questions that were not three weeks ago became clear to us: how we have a vote count, how we have a break -in and how to technically fake the elections in this system, if you want.
- We did not manage to achieve from Artem Kostyko a clear answer to the question of what the secret “second blockchain” is, in which the senior is recorded. Can you describe what you managed to understand about this second blockchain?
Yes. After I published an article on Habr, they shared documents with me from the technical group on electronic voting and part of the documentation of the Moscow Dit, we looked at the contents of the secret blockchain for test voting and realized that this system was arranged as follows. When the voter votes, he writes a voice into a public blockchain, and writes a special such number in a closed blockchain, which is one and the same for all his votes for the first, second and all subsequent distortions.
- called group_id?
- Yes, Group_id is written to the base, that is, the group identifier (ballots from one voter), and the real vote time is written - when the ballot reception server received a voice. And the same hash of the voice that could be preserved is written if you used the instructions from the “voice”* (the authorities called the organization an ino -agent) . That is, we have a hash of voting, the real time of the voice and ID of the Bulletins group from this voter. After voting, all ballots from the same group are grouped, and the last voice is selected from them.
- Let us clarify for our readers that the hash has a parameter that is unique for this voting. He binds records in a public blockchain and in a private blockchain, right?
- Yes. The hash allows us to say for this voice in a public blockchain according to the closed blockchain, when this voice was really received and which group of settlements it belongs to. That is, it allows you to connect these two blockchains with each other.
Example transactions with test voting
The public warhead is written with the Hash transaction B8823CB709B0AC45A6DED89A16D7383838ADDB7F2E93899C4D363636363ADEEC0C1 and the next contents:
{"Voting_id": "4113E78A5AD798E91E387F43D9AD0908934D08CA2B107CFDCEB9CA546B6DB3", "DISTRICT_ID": 1, 1, 1, 1,
"Encrypted_choice: {" Encrypted_message ":" AA4401F1A105F9E251E54F623762BD4994986C6C63 "," Nonce ":
"8FAE4904A3229F82C74FD02CDED9FF337EC7A7245211B4A",
"Public_key": "37F8CBF25B70316B2B4746957A1DBD785D72B35893939391653FCDBD34722"}}}}}}}
A transaction with the following contents is written in a private warhead:
{"Voting_id": "4113E78A5AD798E91E387F43D9AD0908934D08CA2B107CFDCEB9CA546B6DB3", "Store_TX_HASH":
"B8823CB709B0AC45A6DED89A16D7383838ADDB7F2E93899C4D363ADEEC0C1", "ENCRYPTED_GROUP_ID":
"Acjhkj0NWVIEEGFGFV52TKHXGYIK7DBOHOSSEMHJ/U2YRQIKIBEXALBXQBVOE+HXEM+
XSSSSXRLBTCILTN7073JLXOVZX7LVSVWWWQWUVUVUVUVUV2QPTZZZGJEM/0A8GTCCOFYGHYZFV
JMOC4BRopTSILRU3RUUZ0HBPP/T9HWNX4+ACGABNMYTFKZ5FMS9LSAQTX8QVZXZDXSIX/XIZFFQ4IARCHTRYYUK+
l8fiegimsaatrhjgepdob/PMT9G+MTBPFMYBSOQMBIFQRWXTK1JN5PXIQOJHFXOO2enSDUR9DG+C4VQER2GOI3 "," TS ":" 1627659588000 "}
You can set a mutually unambiguous correspondence through Store_TX_HASH in the contents of the transaction of the BS2 and the hash of the transaction with the voice in the warhead.
- Is the Group_ID identifier, that is, the identifier common to all the votes of this voter?
- No, it is not recorded.
-But is something that would find out to us that this voter of the legitimate?
- No, it is not recorded.
- Fine. So, we have a second blockchain in which Group_id is recorded, which has been encrypted, right?
- Yes. Group_ID in open form during voting is not written in a closed blockchain, a random number is added to this Group_ID and the current time is added. In addition to the time, which is additionally written in open form. And this three numbers are encrypted so that for the same voter this encrypted text would be different every time. This is done so that it is impossible to understand before the end of the vote, what votes belong to the same person. The Group_ID is encrypted with a certain key - not the one that is divided into 7 parts.
- Who owns the encryption and decryption key for Group_ ID?
-He, apparently, is recorded on the server in some text file on the server. It is not clear who can look at him.
According to the source code, the encryption key lies in the PHP environment variable under the name Crypt_Secret.
Link to source code.
The value of this variable is indicated in the configuration file. We have no examples of how the configuration could be made.
- And who has the server?
- Our vote is held by the child of Moscow, therefore, apparently, in a child.
- Let's talk again: both the clarification key of Group_id, and the decoding key of Group_ID is stored in the same legal entity, right?
- That's it, yes. The same key that is in the hands of the same organization is used - the child of Moscow.
-You said that no parameters are written to the public blockchain that would determine that this voice belongs to some specific voter and that this voter is a legitimate, right?
- Yes, everything is so.
-How, in this case, the software, which makes a public blockchain, checks that the messages who came from the outside world do not belong to some kind of Prokhinda who wants to deceive us, but a legitimate voter?
-There is a separate server in front of the blockchain, which is authorized by the user, that is, it receives the user's name, password, authorization by SMS conducts some kind of protection-and this is the protection that we have no jacket in our voice. However, if you have access directly to this blockchain so that you can write data directly bypassing this server there, you can ignore all these requirements so that your voice comes from a real user with a real SMS.
- That is, on the outside we cannot climb into it, because we have a filter in the form of mos.ru. But suppose that now I am an attacker who attacks this system from the inside who imitates the coming to it messages, as it were, from an external user. What do I need to hack? Who will allow me or will not allow me to record this message in the blockchain and by what principle will it allow or not allow?
- In order for you to throw the ballot into this ballot of electronic voting, you sign the ballot with your digital signature, and the voting organizer must allow you to throw the ballot into the urn, signed by your digital signature. And if you are an external person who even has direct access to the blockchain, but does not have access to the keys that allow you to write transactions in the blockchain on behalf of the election organizers, then you cannot throw the ballot into this urn. But if you are the organizer of the election, you can do it. The same key, for example, signed messages from the election organizers-reports that voting was created, that some voters are registered, the issuance of ballots is signed by this key, and the completion of voting is also with the same key. If you have access to this key, you can do all this.
- Let's emphasize once again for our readers that this key is not identical to the key with which the voices are deciphered, which is divided into seven parts, right?
- Yes, right.
- And that this is not the key to encrypting Group_id?
- Right.
- So, this is the third key that we are talking about. And when did you manage to find out?
- I read the source code, this, in principle, was already clear right away. But I wanted to conduct an experiment. I took the source code that was published in Moscow, and launched this public blockchain, to which we had access and could look at Observer.mos.ru. I made the following scheme: I created some kind of test vote that I wanted to hold, created a vote with two candidates, Vasya and Petya. Then I registered the zero voters for this vote, gave out zero ballots, and after that I threw 100 ballots into the urn. I emphasize once again that we have been registered zero voters, zero ballots were issued, but there were 100 votes in the urn. And the most amazing thing: since this system cannot take into account the distillations, there is such a hole in it that allows you to bring an arbitrary result, and through this hole I give the result: I threw 100 votes behind Vasya, and the result failed - 146 million votes for Petya and zero votes behind Vasya, behind which I threw it.
The source code of the program that does this (with the instructions for launch).
- Explain what the hole is? The fact that you threw the ballots, you have already mocked this blockchain. You could further simply, like an honest thief, to smack what you threw. But somewhere you hung a hole somewhere, what did this hole consist of?
-This hole lies in the fact that those 100 votes from the point of view of a public blockchain are all real voices, but from the point of view of how the system is arranged in general, some of these 100 votes can be real, some of these 100 votes can be distorted. Therefore, another separate hole was made in this public blockchain, which was supposed to be used as follows: we have the voices of these public blockchain are compared with those groups of voters who are recorded in a closed, secret blockchain, and a closed blockchain sums up, and then these results are copied from a closed blockchain to a public one. And then it will be too sticky, apparently, if our vote is over, but there will be no results there.
- Wait, you still did not have 146 million votes in the closed blockchain, right?
- Yes, yes.
-That is, do I understand correctly that after the closed blockchain counted something, there is a stage that is carried out by handles and a living person?
-With pens, yes, or it can be some kind of program, launched manually or automatically. But, judging by what was happening, the calculation was stopped and automatically did not summarize. Either something broke, or something else. In my experiment, I write down the desired result with my hands.
- With pens, the data that seemed to be obtained from the second, closed blockchain.
- Yes.
- And at the same time you told everyone that since our relations are gentlemen, we should believe you, right?
- Something like that, yes.
- And there is no more way to check that * o * in a closed blockchain, we do not have, so? **
- 146 million votes would be completely sticky, yes. How to check? We have a gentleman's relationship. The closed blockchain counted.
- And when you conducted this experience, relatively recently, right?
- Yes, I did it relatively recently.
- Do you think at all that the head of the public headquarters on observation of the election Alexei Venediktov should you give the award for detection of a hole?
- In this system, I assume that I have absolute access to it. I am the election organizer in this system. But if I am an external person, if you use the logic of Venediktov, the logic of Moscow, then nothing can be hacked from outside. If you are an insider, if you have access ...
-In the usual elections, I never encountered that someone would organize someone besides the election commission. Because if an outsider is filled, then he will only lead everything. He needs to assist the election commission in order to fake voter lists.
So, do I finally understand that in order to carry and/or direct amending the results with handles (and two different ways), you just need to have access to the key of voting organizers?
- Yes. And access to the Node of the blockchain straight, so that directly, bypassing all the servers to write there.
- Explain why, with such a stuffing, there will be no problem with public services? Do I understand correctly that if the attacker in this way will make notes, he makes an entry in which there is no information about the voter, right?
- Yes. This is done to protect the secret of voting.
- Therefore, a public blockchain cannot track that the record appeared not with MOS.ru, but from the ceiling?
- There is no record in the blockchain to check the authenticity of the voter. It is assumed that it is checked outside the blockchain. He is public, and if something likes to write there, then you can break the secret of voting.
- Please tell me in a hash transaction (which, recall, unites both a public and non -public blockchain), is it not written in it in any hidden way Voter_id, Sudir_id, Group_id?
- No, nothing is written.
- And where does the hash come from, explain its origin?
- The hash is formed from the contents of the voice directly. And there is also a signature of the voter, but the signature here is so strange-it is a new one, as if you signed it all the time differently on each new ballot.
- Do I understand correctly that there is no way to check his legitimacy on the signature of the voter?
- In a public blockchain - no.
-Does this hash somehow incorporate the hashs of previous transactions or is it strictly connected only with this transaction?
- Strictly connected only with this transaction, strictly only with this voice.
- Do I understand correctly that the blockchain actually takes place, but it is rushed not to a hesh of voting, but by other hashs?
That is, this base is “stitched” with additional hashs through the way the book of voters is stitched with thread. Thanks to which nothing can be “thrown away” from the blockchain. But these are other Heshi, not the hash that connects the public and non -public blockchain.
- Yes. But in principle, there is nothing unusual in this.
-So, we realized that, having the key to the organizer of the vote, you can enter any information about what was voted for someone, not to indicate who was voted in a public blockchain. And thereby we go around the need to log in to public services, create fake voters, track which of the voters does not vote, or break their accounts, right?
- Yes. And if you bring a paper counterpart, this can be compared with the way I came to the polling station, having previously printed the ballots on the printer, and would throw this independent pack.
- That is, ballots that are not taken into account either when they receive them with the election commission or when issuing voters, - we just brought from the printing house.
- Yes.
— В таком случае мы в обычной жизни попали бы на то, что у нас не сошлось бы количество бюллетеней в урне и количество голосующих избирателей: было бы в урне больше бюллетеней, чем избирателей по книгам, и тогда бы урну пришлось аннулировать.
Та же самая проверка должна быть встроена и в систему ДЭГ, с которой мы имеем дело, потому что она записывает факт выдачи бюллетеней. Если предположить, что злоумышленник, атакующий систему, атаковал ее так, как ты предлагаешь, то получается какая-то глупость: у него будет голосов больше, чем выдано бюллетеней. Как ты это объясняешь, то есть как ты с этим справишься в качестве злоумышленника?
— Во-первых, я хочу сказать, что, по публичным данным, именно это и произошло, на что движение «Голос» обратило внимание сразу же после подведения итогов.
Если мы зайдем прямо сейчас на observer.mos.ru, то увидим, что голосов в системе больше, чем выдано бюллетеней.
Так что у нас действительно так и произошло. Объяснение здесь, откуда тут взялись бюллетени, лежит в алгоритме переголосований, потому что какие-то из этих бюллетеней были первые, какие-то вторые, какие-то третьи, какие-то последние. И нам нужно выкинуть все эти бюллетени, которые были переголосованы потом каким-то другим бюллетенем. В моей предлагаемой схеме взлома мы накидали туда голосов, но потом, для того чтобы подвести «хорошие» итоги, нам нужно какие-то выкинуть. Для этого есть удобный механизм в виде второго блокчейна, который позволяет нам сказать, что вброшенные бюллетени относятся к некоему идентификатору группы бюллетеней.
— Напомню нашим читателям, что идентификатор группы бюллетеней одинаковый у всех бюллетеней, которые поступили от данного избирателя.
- Yes. И мы можем по ходу голосования писать в публичный блокчейн голоса, которые за провластного кандидата, а в закрытый блокчейн ничего не писать до поры до времени. Когда у нас закончилось голосование, опубликован ключ расшифрования, мы расшифровываем все голоса и смотрим, какие из них за оппозицию. Про вброшенные голоса мы говорим: вот у нас есть голоса, мы запомнили их хэши. После голосования мы внесем эти хэши и в тайный блокчейн. При этом запись мы сделаем в виде химеры: мы возьмем хэш вброшенного бюллетеня (за власть) и group_id бюллетеня за оппозицию . Таким образом, мы «перетрем» ненастоящим бюллетенем, который мы кинули в систему, настоящий бюллетень реального избирателя.

— Давай еще раз проговорим: когда мы вбрасывали, мы вбрасывали их как бы безымянными. Поэтому не записывали их во второй блокчейн.
Как же нам удалось их потом вставить вот в этот второй блокчейн? Мы же много раз повторили, что блокчейн устроен как прошитый и запечатанный документ, из которого нельзя выдрать или вставить лист, потому что каждая следующая транзакция несет в себе следы предыдущей. Почему же с потайным блокчейном это не работает?
— Во-первых, из-за того, что этот блокчейн сам по себе приватный, никто его никогда не видел. Если мы его перепишем заново с нуля, все равно никто ничего не заметит, вы не видели, как он составлялся, поэтому вы не увидите, что мы его подменили.
— В отличие от публичного блокчейна, который хотя бы раз в полчаса выгружался на observer.
- Yes. Во-вторых, можно, например, выключить подсчет голосов между тем моментом, когда мы опубликовали ключи и все (или часть) расшифровали, и моментом, когда надо подводить итоги. Если у нас, например, все не расшифровалось, но ключ уже опубликован, мы останавливаем подсчет голосов, останавливаем все эти блокчейны, расшифровываем голоса и смотрим, какие нам из них не нравятся, и дописываем их в этот закрытый блокчейн так, чтобы выкинуть те голоса, которые нас не устраивают.
— Итак, повторим, как мы сделали химеру: этруски взяли голову змеи и приделали к хвосту льва, а мы взяли хэши от голосований, которые были за оппозицию, нашли в закрытом блокчейне, какой group_id соответствует данному хэшу, потом взяли этот group_id, вставили в новую строчку закрытого блокчейна и хэш заменили на хэш от вброшенного голоса от ноунейма, правильно?
Пример изготовления химеры
Пример транзакции из приватного блокчейна с тестового голосования с записанным зашифрованным group_id:
{"voting_id":"6a2bd471332d3dc0c3d25bb170b4ba18a8ffdd1b09cb6a6a36304d7272da96f9","store_tx_hash":
"1791e2b22570a54a44a662a42c4f6e92074177f7ac7d2732f5a3f322b9fac132","encrypted_group_id":
"DPVz0ezcVoq3jCuepPPShfEqSGeOrDrs3H9P1za1uydq6MimiKrEJGi8xQ2zqr95Ws+
usKa/XLxp2WEShbbcNzpjAhI3ZjcXS0nW5HfjrylRDgTeNp1Rdpgg/tcJobCoJhX+
dTSBwEZRjHVhaVemTASKqDMxGCNHrGW1EzbjExp7AVhk4DwbTwZ+
s/chdm+
Mt10W6bzylfAb5xlq/a8xgRCtPTbNbI9Ce3PoOU2RHF7yWkl1SEIlm2lFSfISaoOTptm5QwwzjUb/
GJnqbM9Elm62gD+d2iubw0ZAtIcZ3x+ISPBU0yB4qkDTT/okAwev","ts":"1627535034000"}
Чтобы переголосовать настоящий голос, мы смотрим в БЧ-2 и видим неприятную транзакцию:
{"voting_id":"ID","store_tx_hash":"<хэш за «нехорошего» кандидата>","encrypted_group_id":"<зашифрованный ID группы реального избирателя>","ts":"<20:00 18 сентября>"}
У нас есть ненастоящий, вброшенный в 13.00 19 сентября голос за «хорошего» кандидата. Чтобы переголосовать настоящий голос нашим вброшенным, мы пишем следующую транзакцию в БЧ-2:
{"voting_id":"ID","store_tx_hash":"<хэш фейкового голоса за 'хорошего' кандидата>","encrypted_group_id":"<зашифрованный ID группы реального избирателя>","ts":"<13:00 19 сентября>"}
Несмотря на то, что в зашифрованный ID группы пишется реальное время голоса, БЧ-2 при подсчете берет время из открытого источника — поля ts, где время не зашифрованное. Поэтому можно подставить тот же самый шифротекст, не расшифровывая encrypted_group_id.
После этого продолжаем подсчет в штатном режиме, система уже не знает, что мы подменили реальный голос фейковым.
Все так, да. И добавили в запись время, что этот голос пришел позже, чем тот голос, который мы выкинули.
— И дальше мы можем честно посчитать приватный блокчейн, после того как мы в него вкинули голоса, и приватный блокчейн нам скажет, что люди голосовали за оппозицию, а меньше чем через день раздумали , верно?
- Yes. Такая вот система получилась дырявая.
— Какие еще интересные дырки или странности в этой системе удалось тебе увидеть?
— Мы нашли, что помимо блокчейна-1 (публичного) и блокчейна-2 (тайного) в коде системы ДЭГ предусмотрено ведение некоей «обычной» базы данных. Когда сообщение с голосом приходит в систему, помимо того, чтобы записать его в блокчейн-1 и (часть данных) в блокчейн-2, он еще попадает в отдельную таблицу под названием p_ballot — считай, это просто табличка в Excel. Зачем это делается, из исходного кода абсолютно непонятно. Туда просто пишутся данные, никак не используются.
Таблица p_ballot
Ссылка на код .
Функция persistBallot вызывается сразу же после получения бюллетеня вот тут .
Более того, в этой таблице все бюллетени пронумерованы по порядку их добавления в систему. При добавлении в таблицу бюллетеню автоматически назначается порядковый номер (поле ID): 1, 2, 3, 4 и т.д.
Это видно исходя из того, как эта таблица создается при запуске голосования .
Нумерация бюллетеней прямо запрещена законом.
— Это была странность номер один?
— А теперь странность номер два. Тот сервис, который шифрует идентификаторы группы избирателей, чтобы они зашифрованными попали в блокчейн-2, имеет внутри себя логи. Логи — это специальный текстовый файл, который создается по ходу работы программы, для того чтобы программист понимал, что с ней происходит, что она делает, или мог понимать, где какие ошибки могут возникнуть. Так вот, в нашем случае в этот текстовый файл пишется содержимое следующего рода. На каждый запрос к этому серверу что-то зашифровать он пишет сначала сообщение: зашифровываю вот такой-то текст. Дальше пишет опять в этот же лог: зашифровал этот текст следующим образом. Таким образом, если у вас неправильно настроено логирование в этом сервисе, у вас все пишется в этот лог, а по умолчанию именно так у меня и произошло, то все шифрование теряет абсолютно смысл, потому что вы читаете этот текстовый файл и видите нешифрованный и шифрованный текст одновременно.
Пример лога сервиса шифрования
[2021-10-09 13:38:49] production.INFO: Получение запроса на шифрование сообщения {"action":"crypt_request","request":{"data":"test"}}
[2021-10-09 13:38:49] production.INFO: Ответ с телом зашифрованного сообщения: {"action":"crypt_response","response":{"result":"J18pQE9c0K/xzeNS3gtJUi/AnjNIhUJKAuPrSZs1S5YYAr9E5FqQnPNtxZL93EE+OX7lQY+pf8JDHTL2nn98VA=="}}
[2021-10-09 13:38:50] production.INFO: Request served: /api/encryption/crypt?data=test {"action":"request_served","method":"GET","uri":"/api/encryption/crypt?data=test","duration":308.49,"version":8,"requestIp":"127.0.0.1","code":null}
— Напоминает анекдот про Штирлица и парашютные стропы.
- Something like that, yes. Странность номер три заключается в том, что идентификатор группы избирателей создается на основе идентификатора в mos.ru. Таким образом, если у нас есть доступ к сайту mos.ru и доступ к всему списку избирателей, мы можем из содержимого закрытого блокчейна или этой странной «таблицы в экселе» понять, кто как голосовал, каждый из двух миллионов человек.
Как это может нарушить анонимность
За создание group_id избирателя (также известный в системе в том числе под названием mdmCypher) отвечает вот этот участок кода .
Код делает следующее:
- Считает $ssoIdHmac = hash_hmac('stribog512', $sudirId, $hmacSecret)
hmacSectet — соль для хэширования из переменной окружения (аналогично ключу шифрования для groupId)
sudirId — ID избирателя в системе СУДИР (система управления доступом к информационным ресурсам г. Москвы), считайте ID избирателя в mos.ru.
- Обращается к сервису componentX для получения по ssoIdHmac соответствующую группу бюллетеней. Получает зашифрованный groupId избирателя.
Шифруется он в методе receiveGid .
Сам groupId получается из «подсистемы «Реестр участников голосования», или еще он называется MDM (Master Data Management). Исходного кода этой части у нас уже нет.
Делается это следующим запросом .
Опять обращу внимание, что в логи пишется ssoIdHmac и groupId избирателя.
Чтобы нарушить тайну голосования надо сделать следующее:
sudirId сопоставить с персональными данными избирателя.
Для sudirId всех 2 млн человек посчитать ssoIdHmac.
Запросом в MDM получить groupId всех ssoIdHmac.
Посмотреть в содержимое «закрытого блокчейна», либо в неправильно настроенные логи, либо в таблицу p_ballot
Там найти хэши со всеми голосами данных groupId в публичном блокчейне.
Посмотреть в публичном блокчейне, за кого был отдан голос. С шага один у нас есть персональные данные этого избирателя.
— Дмитрий Нестеров многократно указывал в своих выступлениях на то, что электронное голосование чисто теоретически не может совместить две вещи: проверку легитимности и анонимность. Either one or the other. Правильно ли я понимаю, что ровно это мы и видим сейчас с двумя блокчейнами? Публичный блокчейн не может проверить легитимность, но при этом соблюдает вашу анонимность, а приватный блокчейн нарушает вашу анонимность (потому что в создании group_id используется идентификатор избирателя с mos.ru), но при этом как бы знает о том, легитимный вы избиратель или нет.
- Something like that, yes.
— Были ли еще сюрпризы в исходном коде?
— Наконец, мы выяснили, что исходный код, который был опубликован, отличается от того, который реально использовался. Сначала заметили, что отличается та часть кода, которая исполняется в браузере пользователя. Дальше мы обнаружили, что в опубликованном коде переголосовывать можно только в текущие сутки, а не через 24 часа после первого голоса (как было на реальных выборах). Я не думаю, что исходный код очень сильно изменялся, но все равно некрасиво со стороны ДИТ.
Подмена кода
Файл election.js из реального голосования можно найти по ссылке . Можете сами убедиться, что он отличается от файла в репозитории .
Наконец, в исходном коде действительно записана логика , что переголосовывать можно только в течение текущих суток.
— И наконец, возвращаясь к тому ключу, с помощью которого в блокчейн можно писать все что угодно, в обход mos.ru или Госуслуг. Есть ли у тебя понимание, исходя из анализа исходного кода и твоих экспериментов, в каких формах мог существовать этот ключ?
— Я напомню, что сейчас мы говорим о ключе подписи организаторов выборов. Это электронно-цифровая подпись, которой организатор выборов подписывает свои сообщения, что это именно он создает голосование, именно он регистрирует избирателей, именно он выдает бюллетень, именно он подводит итоги. Когда я понял значимость этого ключа, у меня сразу возник вопрос: а кто имел доступ к этому ключу и как он формировался?
И для меня было большим расстройством увидеть, что в тестовом голосовании по вопросу общественного транспорта, по вопросу прививок, обязательной вакцинации от коронавируса использовался тот же самый ключ, который использовался на выборах в Госдуму. Это значит, что между 30 июля и 17–19 сентября непонятно какие люди, непонятно на каком основании могли смотреть на этот ключ, могли не смотреть на этот ключ, и это очень расстраивает — то, что этот ключ не пересоздавался для каждого голосования заново, меня очень пугает. Это навевает мысли о плохих практиках программирования в ДИТ Москвы. Во-первых, когда секретные ключи просто переиспользуются, это уже нарушение правил информационной безопасности. Во-вторых, я опасаюсь, что этот ключ мог быть просто записан в текстовый файл, и к нему непонятно какие программисты могли иметь доступ, в непонятно какое время (у нас удалены были конфигурационные файлы из исходного кода, и я не могу это подтвердить или опровергнуть).
Благодарность Петра Жижина за помощь в анализе исходного кода: чату программистов, которые анализировали ДЭГ, и, в частности, Борису Тавадову, и программисту под псевдонимом SinX.