Исследование образа VM

$ qemu-img convert -O raw ra-wrt-x86-disk1.vmdk rev-clean.raw

$ sudo kpartx -a rev-clean.raw

Disk: /dev/loop1 Size: 52.5 MiB, 55050240 bytes, 107520 sectors Label: dos, identifier: 0x00000000 Device Boot Start End Sectors Size Id Type >> /dev/loop1p1 * 512 8703 8192 4M 83 Linux /dev/loop1p2 9216 107519 98304 48M 83 Linux

Скрытый текст 2014-04-10+18:34:34.0000000000 ./lib/firmware/rtl_nic/rtl8105e-1.fw 2014-04-10+18:34:34.0000000000 ./lib/firmware/rtl_nic/rtl8106e-1.fw 2014-04-10+18:34:34.0000000000 ./lib/firmware/rtl_nic/rtl8106e-2.fw 2014-04-10+18:34:34.0000000000 ./lib/firmware/rtl_nic/rtl8168d-1.fw … 2014-09-16+23:45:16.0000000000 ./lib/netifd/netifd-proto.sh 2014-09-16+23:45:16.0000000000 ./lib/netifd/netifd-wireless.sh 2014-09-16+23:45:16.0000000000 ./lib/netifd/utils.sh 2014-09-21+14:46:54.0000000000 ./bin/ipcalc.sh … 2015-10-23+12:04:49.0000000000 ./bin/revizor_postboot 2015-10-23+12:04:49.0000000000 ./bin/revizor_postupdate 2015-10-23+12:04:49.0000000000 ./dev 2015-10-23+12:04:49.0000000000 ./dev/console 2015-10-23+12:04:49.0000000000 ./etc/agent_id 2015-10-23+12:04:49.0000000000 ./etc/config/dropbear 2015-10-23+12:04:49.0000000000 ./etc/dropbear/dropbear_dss_host_key 2015-10-23+12:04:49.0000000000 ./etc/dropbear/dropbear_rsa_host_key 2015-10-23+12:04:49.0000000000 ./etc/opkg.conf 2015-10-23+12:04:49.0000000000 ./etc/shadow 2015-10-23+12:04:49.0000000000 ./etc/shells 2015-10-23+12:04:49.0000000000 ./etc/ssl 2015-10-23+12:04:49.0000000000 ./etc/ssl/certs 2015-10-23+12:04:49.0000000000 ./etc/ssl/certs/revizor_opkg.crt 2015-10-23+12:04:49.0000000000 ./root 2015-10-23+12:04:49.0000000000 ./root/.ssh 2015-10-23+12:04:49.0000000000 ./root/.ssh/id_rsa 2015-10-23+14:49:17.0000000000 ./etc/crontabs 2015-10-23+14:49:17.0000000000 ./etc/crontabs/root 2015-10-23+14:49:17.0000000000 ./etc/revizor_server 2015-10-29+14:27:19.0000000000 ./bin/revizor_boot 2015-10-29+14:27:19.0000000000 ./etc/config/network 2015-10-29+14:27:19.0000000000 ./etc/netfallback.conf 2015-10-29+14:27:19.0000000000 ./etc/rc.local 2015-11-03+15:43:21.0000000000 ./etc/init.d/dropbear 2015-11-03+15:43:21.0000000000 ./usr/lib/opkg/info/dropbear.conffiles 2015-11-03+15:43:21.0000000000 ./usr/lib/opkg/info/dropbear.control 2015-11-03+15:43:21.0000000000 ./usr/sbin/dropbear 2015-11-03+17:05:22.0000000000 ./bin/admin/admsrv 2015-11-03+17:05:22.0000000000 ./bin/revizor_logger 2015-11-03+17:05:22.0000000000 ./bin/revizor_preboot 2015-11-03+17:05:22.0000000000 ./etc/passwd 2015-11-09+17:10:52.0000000000 ./bin 2015-11-09+17:10:52.0000000000 ./bin/admin/admcli 2015-11-09+17:10:52.0000000000 ./bin/revizor_updater 2015-11-09+17:10:52.0000000000 ./etc/config 2015-11-09+17:10:52.0000000000 ./etc/config/system 2015-11-09+17:10:52.0000000000 ./etc/dropbear 2015-11-09+17:10:52.0000000000 ./etc/dropbear/authorized_keys 2015-11-09+17:10:52.0000000000 ./etc/inittab 2015-11-13+12:06:31.0000000000 ./bin/admin/netfallback 2015-11-16+15:31:23.0000000000 ./bin/admin 2015-11-16+15:31:23.0000000000 ./bin/admin/pwd-sh 2016-02-09+11:09:52.0000000000 ./etc 2016-02-09+11:09:52.0000000000 ./etc/revizor_firmware_version 2016-02-09+11:09:53.0000000000 ./bin/ash 2016-02-09+11:09:53.0000000000 ./bin/cat 2016-02-09+11:09:53.0000000000 ./bin/chgrp …

# Put your custom commands here that should be executed once # the system init finished. By default this file does nothing. /bin/admin/admsrv & /bin/admin/netfallback & /bin/revizor_boot & exit 0

Скрытый текст #!/bin/sh sleep 2 chmod a+rw /etc/opkg.conf chmod a+rw /etc/netfallback.conf ADMIN_PORT=2222 ADMIN_TIMEOUT=120 read ADMIN_PWD </etc/agent_id if [ ! -z ADMIN_PWD ]; then ADMIN_PWD=`echo $ADMIN_PWD | tail -c +2 | md5sum | head -c 12` if [ ! -z ADMIN_PWD ]; then echo "admin password: $ADMIN_PWD" | revizor_logger echo -e "$ADMIN_PWD

$ADMIN_PWD" | passwd admin fi fi /usr/sbin/dropbear -F -p 0.0.0.0:$ADMIN_PORT -n -K 30 -I 300 & PID=$! sleep $ADMIN_TIMEOUT kill -9 $PID

Скрытый текст #!/bin/sh if [ ! -f /rom/etc/opkg.conf ]; then read REVIZOR_SERVER </etc/revizor_server if [ -z "$REVIZOR_SERVER" ]; then REVIZOR_SERVER="revizor.mfisoft.ru" fi mkdir -p /rom/etc OPKG_CFG=`cat /etc/opkg.conf | grep -v '^src revizor '` echo "$OPKG_CFG" > /rom/etc/opkg.conf echo "src revizor https://$REVIZOR_SERVER/updates/openwrt-x86/common" >> /rom/etc/opkg.conf cp -f /rom/etc/opkg.conf /etc/opkg.conf fi rm -f /usr/lib/opkg/lock /bin/revizor_preboot sleep 2 /bin/revizor_updater -f /rom/etc/opkg.conf /etc/init.d/cron start /bin/revizor_postboot

Файлы /bin/revizor_preboot и /bin/revizor_postboot пусты. Файлыпусты.

system reboot system resetfs system update log info ifconfig route arp ping nslookup traceroute net proxy clear net proxy set net fallback

Скрытый текст Certificate: Data: Version: 3 (0x2) Serial Number: 12303214825491704792 (0xaabdccb2d4c0abd8) Signature Algorithm: sha256WithRSAEncryption Issuer: C=RU, ST=Russia, O=MFISOFT Validity Not Before: Oct 21 10:21:46 2015 GMT Not After : Aug 5 10:21:46 2289 GMT Subject: C=RU, ST=Russia, O=MFISOFT Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (1024 bit) Modulus: 00:cc:ed:e0:84:c4:7b:4e:49:2d:11:86:41:0f:f8: 51:97:42:91:76:34:38:96:e0:9e:a4:3c:7b:30:f6: 15:b2:1e:03:0e:12:46:96:f9:57:a1:db:2d:63:8a: dc:01:2e:e7:10:56:8d:c3:d5:de:5a:bb:d7:75:e3: 6b:e3:d5:6a:04:4d:f4:65:81:05:07:d7:d0:a8:29: ab:9d:83:81:00:04:73:27:39:db:d3:c8:ba:d3:78: 41:84:d9:8b:62:21:00:51:fc:78:06:ce:f7:db:e6: 5b:fd:d7:b6:2b:0f:72:9e:63:d8:06:f1:dd:2d:c5: 17:f1:a9:b8:d3:5e:ad:6c:d5 Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Subject Key Identifier: F6:F9:BB:39:1B:20:4F:B4:11:B5:CE:EA:C2:F5:95:DB:24:DB:49:53 X509v3 Authority Key Identifier: keyid:F6:F9:BB:39:1B:20:4F:B4:11:B5:CE:EA:C2:F5:95:DB:24:DB:49:53 X509v3 Basic Constraints: CA:TRUE Signature Algorithm: sha256WithRSAEncryption 16:31:a0:2f:01:1b:06:a3:31:d3:d2:50:38:b4:c2:57:ec:6d: a0:25:5e:e0:35:68:92:dd:38:fc:1a:ef:88:2d:e8:b9:1b:d7: f5:ef:97:14:75:ef:65:1c:f9:ae:61:43:05:49:74:08:8a:d5: 19:01:e3:63:ff:69:57:34:74:9e:b8:7d:6d:5b:2a:66:59:a6: 9d:b4:a3:3f:41:91:30:26:1f:0e:3a:24:2b:36:0e:68:f8:e8: 44:f5:5a:18:ea:5e:48:8e:a9:8f:03:25:87:ba:60:9c:93:ac: cb:43:b7:ee:6d:6c:85:88:77:40:a7:b4:a8:c9:ce:d0:29:6d: 78:0a -----BEGIN CERTIFICATE----- MIICMDCCAZmgAwIBAgIJAKq9zLLUwKvYMA0GCSqGSIb3DQEBCwUAMDAxCzAJBgNV BAYTAlJVMQ8wDQYDVQQIDAZSdXNzaWExEDAOBgNVBAoMB01GSVNPRlQwIBcNMTUx MDIxMTAyMTQ2WhgPMjI4OTA4MDUxMDIxNDZaMDAxCzAJBgNVBAYTAlJVMQ8wDQYD VQQIDAZSdXNzaWExEDAOBgNVBAoMB01GSVNPRlQwgZ8wDQYJKoZIhvcNAQEBBQAD gY0AMIGJAoGBAMzt4ITEe05JLRGGQQ/4UZdCkXY0OJbgnqQ8ezD2FbIeAw4SRpb5 V6HbLWOK3AEu5xBWjcPV3lq713Xja+PVagRN9GWBBQfX0Kgpq52DgQAEcyc529PI utN4QYTZi2IhAFH8eAbO99vmW/3XtisPcp5j2Abx3S3FF/GpuNNerWzVAgMBAAGj UDBOMB0GA1UdDgQWBBT2+bs5GyBPtBG1zurC9ZXbJNtJUzAfBgNVHSMEGDAWgBT2 +bs5GyBPtBG1zurC9ZXbJNtJUzAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUA A4GBABYxoC8BGwajMdPSUDi0wlfsbaAlXuA1aJLdOPwa74gt6Lkb1/XvlxR172Uc +a5hQwVJdAiK1RkB42P/aVc0dJ64fW1bKmZZpp20oz9BkTAmHw46JCs2Dmj46ET1 WhjqXkiOqY8DJYe6YJyTrMtDt+5tbIWId0CntKjJztApbXgK -----END CERTIFICATE-----

ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCAxFzEe20FUIegQ8p25S/b1SIhVi0XTWZtLDF7FLpMsoxi+JhgzoVEwmCIpoQ9c5Flid0jiqKCVhnm8GRe+qjkxibAOa8WlfiQ16eapqA0Dd6laFW4RzTTiinebPRlLJBsj8xGhrvf4lsKXng5+ZDWXnrz7pICbh62U7MYNEpOuy9x4P4285Xq9ccIuCrCAS8rZ4TdFdzeM+270asIQB/vsQ2joJ1vNn3WzdISmRepknR4eTo6H881vHAiWVTpGioXssvOGyLYfqn0rqVECC9/tknV0hQJP+iYU3mov4+JYvRVa+5m1DLD0Nj0QWKFXl79VNxstwyOt6RDvQrhlxNB root@revizor-agent

Обновляемся!

Package: revizor Version: 1.2.2-34720 Depends: libc, libstdcpp, libpthread, libpcre, libopenssl Section: utils Architecture: x86 MD5Sum: 0afc31c21b785690ca38a89d24d749ed Size: 322098 Filename: revizor_1.2.2-34720_x86.ipk Source: package/revizor Description: revizor agent

Выполнение HTTP/HTTPS GET/POST-запросов по определенному URL

Выполнение запросов по определенному URL с заданным IP-адресом (без разрешения доменного имени через DNS)

Выполнение нестандартных запросов для обхода DPI: добавление точки в конец домена, двойной слеш в начале URL, экранирование URL

Определение факта блокировки сайта путем поиска совпадений регулярного выражения в теле и заголовках ответа сервера

Отправка ICMP-запросов к определенному хосту

Запуск traceroute до определенного хоста

Создание SSH-туннеля до сервера Ревизора для предоставления Socks5-прокси

Отправка журнала из syslog на сервер разработчика

Перезагрузка устройства

Развлекаемся!

POST /rpclens HTTP/1.1 Host: n01.rfc-revizor.ru Connection: close Content-Length: 176 {"method":"SetMyParams","params":{"version":"WRT-1.2.2.34720","traf":{"duration":3600,"bytes_in":24055,"bytes_out":32636}},"id":"DICK-BUTT-I386---1AE822EF40","session_id":1488}

Server: nginx Date: Mon, 01 Apr 2016 12:34:56 GMT Content-Type: text/html Transfer-Encoding: chunked Connection: keep-alive X-Powered-By: PHP/5.2.6 X-Frame-Options: SAMEORIGIN X-Content-Type-Options: nosniff {"jsonrpc":"2.0","result":{"status":"done"},"id":"DICK-BUTT-I386---1AE822EF40"}

Скрытый текст {"method":"GetMyTasks","params":"","id":"DICK-BUTT-I386---1AE822EF40","session_id":1488}

{"jsonrpc":"2.0","result":{"tasks":[{"id_task":"493629","id_task_meta":null,"type":"check","priority":"1","checklist":"own","checklist_count":"2","params":"{\"checklist\":{\"group_id\":1,\"records\":{\"records_type\":2},\"requests\":{\"get\":1,\"post\":0,\"use_dns\":1,\"check_escaped\":0,\"add_slashes\":0,\"add_dot\":0,\"randomize\":0,\"report_success\":0,\"max_redirects\":5,\"use_dns_only\":1,\"all_resolved_ips\":0},\"screenshots\":{\"fail_screenshots\":1,\"skip_if_protocol_exist\":0,\"skip_if_exists_hours\":null,\"skip_if_over\":null,\"only_200\":1,\"skip_3xx\":null}}}","status":"CREATED","completion":null,"result":null,"pass":null,"fail":null,"passed_items":null,"failed_items":null,"id_creator":"WWW-ANUS-PYOS","id_lens":"DICK-BUTT-I386---1AE822EF40","ts_create":"1461299321","ts_start":null,"ts_stop":null}],"params":{"DnsThreadsMax":20,"MAXfailedChecklistDownloadCount":100,"MAXfailedReportUploadCount":25,"whiteCheckMinInterval":60000,"connectTimeout":10000,"soTimeout":10000,"maxTotalConnections":50,"maxHttpsConnections":20,"maxContentSize":3000},"ts":1461299347,"zip":1,"tests":[{"id":1,"statusCode":"200","header":null,"headerRegexp":null,"contentRegexp":"\u0437\u0430\u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u043d","content":null},{"id":9,"statusCode":"200","header":null,"headerRegexp":null,"contentRegexp":"\u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d","content":null},{"id":2661,"statusCode":"409","header":null,"headerRegexp":null,"contentRegexp":".*","content":null},{"id":2919,"statusCode":"404","header":null,"headerRegexp":null,"contentRegexp":".*","content":null},{"id":2922,"statusCode":"403","header":null,"headerRegexp":null,"contentRegexp":".*","content":null},{"id":2923,"statusCode":"451","header":null,"headerRegexp":null,"contentRegexp":".*","content":null},{"id":2924,"statusCode":"500","header":null,"headerRegexp":null,"contentRegexp":".*","content":null},{"id":2925,"statusCode":"502","header":null,"headerRegexp":null,"contentRegexp":".*","content":null},{"id":2926,"statusCode":"503","header":null,"headerRegexp":null,"contentRegexp":".*","content":null},{"id":2932,"statusCode":"307","header":null,"headerRegexp":null,"contentRegexp":".*","content":null},{"id":2936,"statusCode":"301","header":null,"headerRegexp":null,"contentRegexp":".*","content":null},{"id":2967,"statusCode":"302","header":null,"headerRegexp":null,"contentRegexp":".*","content":null},{"id":2968,"statusCode":"302","header":"Location","headerRegexp":"62.33.207.195","contentRegexp":null,"content":null},{"id":3228,"statusCode":"404","header":"Connection","headerRegexp":"close","contentRegexp":null,"content":null},{"id":3580,"statusCode":"307","header":"Location","headerRegexp":".*","contentRegexp":null,"content":null}]},"id":"DICK-BUTT-I386---1AE822EF40"}

"method":"GetMyTasks","params":"","id":"DICK-BUTT-I386---1AE822EF40","session_id":1488} {"jsonrpc":"2.0","result":{"tasks":[{"id_task":"148411","id_task_meta":null,"type":"service","priority":"1","checklist":null,"checklist_count":"0","params":"{\"format\":1,\"command\":\"tunnel_on\",\"param1\":64123,\"param2\":60000}","status":"RUNNING","completion":"0","result":null,"pass":"0","fail":"0","passed_items":null,"failed_items":null,"id_creator":"N01-KONA-CHAN","id_lens":"DICK-BUTT-I386---1AE822EF40","ts_create":"1460000000","ts_start":"1460000000","ts_stop":null}],"params":{"DnsThreadsMax":20,"MAXfailedChecklistDownloadCount":100,"MAXfailedReportUploadCount":25,"whiteCheckMinInterval":60000,"connectTimeout":10000,"soTimeout":10000,"maxTotalConnections":50,"maxHttpsConnections":20,"maxContentSize":3000},"ts":1460000000,"zip":1,"tests":null},"id":"DICK-BUTT-I386---1AE822EF40"}

/usr/bin/ssh -y -y -K 30 -N -T -R 0.0.0.0:6412:127.0.0.1:1080 -p 22 -i /root/.ssh/id_rsa

Прошу прощения у пострадавшего провайдера, у которого внезапно открылись все заблокированные сайты, да еще и из Чехии!

Вместо заключения

Бонус



Скриншоты вот такой вот страницы сейчас наблюдают в Роскомнадзоре по всем заблокированным URL.

Ревизор — программно±аппаратный комплекс для мониторинга доступа к сайтам из реестра со стороны провайдеров — берет свое начало в октябре 2015 года, когда компания «МФИ Софт», та же компания, что сделала СОРМы, выиграла тендер на разработку ПО за 84 миллиона рублей. Согласно условиям тендера, разработчик должен был предоставить работоспособное ПО под Windows и Linux и 700 аппаратных «Агентов» в срок до 14.12.2015, всего через 2.5 месяца, и, похоже, все было готово даже на пару недель раньше дедлайна. Провайдерам в добровольно-принудительном порядке уже в начале декабря предлагалось установить один из трех вариантов Ревизора: в виде образа виртуальной машины VMWare, основанной на OpenWRT 14.07, в виде программы-сервиса под Windows, либо же в виде железного «Агента», который представлял из себя маршрутизатор TP-Link MR3020 с установленным на него OpenWRT и необходимым ПО. Многие провайдеры отказывались от установки комплекса из-за того, что он не сертифицирован, а использоваться будет только им во вред, а другим устройств просто не досталось, и им пришлось установить софтовую версию.Итак, у меня в руках последняя версия VMWare-образа и exe-файла Ревизора. Давайте же посмотрим, что внутри!Первым делом, образ я переконвертировал в RAW, чтобы иметь возможность просто подмонтировать его, не запуская в вирутальной машине. Для этого есть замечательная утилита в составе qemu, qemu-img, которая умеет конвертировать все популярные форматы образов виртуальных машин между собой:Подмонтировать файл образа нам поможет прекрасная программа kpartx из пакета multipath-tools, которая умеет анализировать образ и делать все автоматически, иначе нам бы пришлось монтировать каждый раздел вручную, указывая его смещение, что очень неудобно:Нас встречают два раздела с файловыми системами ext2 и ext4:Первый раздел — загрузочный, монтируется в /boot. На нем находится Grub2 и ядро. Ничего интересного.Второй раздел представляет из себя файловую систему OpenWRT. Каким образом нам найти отличия от штатной сборки OpenWRT? Элементарно — по дате изменения файлов!Можем проследить процесс создания образа: первые файлы появились 23 октября, затем файлов докидывали в течение ноября, и, похоже, 16 ноября появился готовый базовый образ, который обновили и кастомизировали 9 февраля.Процесс загрузки скриптов, относящихся к Ревизору, сделан небрежно — они просто добавлены вменяет пароль пользователя admin путем хеширования первой строки файла, который уникальный для каждой виртуальной машины и устройства (вида DICK-BUTT-I386), без первого символа, алгоритмом MD5, и обрезает полученный хеш до 12 символов, который и будет паролем. В самом же файлезащита от дурака — 28 переносов строк, которые не влезут в стандартный терминал размером 80×24. Вероятно, предполагается, что кто-то не знает про Shift+PgUp/PgDown. Этот же скрипт запускает SSH-сервер (dropbear) на порту 2222, доступный извне, на 2 минуты после старта.В скриптепроисходит непотребство — если через 5 секунд после загрузки Ревизор не получил IP-адрес от DHCP-сервера, он устанавливает статический адрес 192.168.0.254, и далее в цикле каждые 30 секунд пытается понять, не появился ли DHCP-сервер и не выдал ли он нам IP-адрес.Отвечающий за загрузку ПО скриптдобавляет собственный репозиторий в файл пакетного менеджера, запускает процесс обновления и стартует cron, в котором настроена проверка обновлений каждые 15 минут. Другие репозитории отсутствуют.Скрипт, который используется в качестве логин-шелла (прописан вдля tty1 и ttyS0), использует крайне необычную технику входа — запуск SSH-клиента на localhost. Дело в том, что OpenWRT используется преимущественно в домашних роутерах, у которых нет ни экрана, ни легкого доступа к параллельному порту, поэтому пароль на доступ просто не нужен. В случае Ревизора это бы означало, что любой может получить root-доступ, просто нажав Enter для активации консоли в виртуальной машине. Как правило, для осуществления логина используют программы вроде getty, вы их видели в любом дистрибутиве, именно getty спрашивает и проверяет логин и пароль. Здесь же, по какой-то причине, разработчики не стали устанавливать getty, а просто подключались к самому себе через SSH, ведь SSH-сервер запросит аутентификацию. Поначалу я думал, что сделано это не просто так, что таким образом захотели хитро отключить вход из-под пользователя root, но нет, SSH-сервер настроен самым обычным образом.Шеллом для пользователя admin задан скрипт, который позволяет выполнять следующие команды:Пакеты из репозитория подписываются ключом «МФИ Софт», подпись проверяется средствами opkg:Вход по SSH открыт пользователю, обладающему следующим ключом:Но где же сам Ревизор?Файлов самого ПО в прошивке нет, они поставляются пакетом из репозитория. Загрузим список пакетов с сайта:Как видим, репозиторий содержит один пакет «revizor»:Скачаем же его!Файл формата IPK представляет из себя архив .tar.gz со структурой DEB-пакета. Собран он неким abelyak.Внутри пакета имеется несколько скриптов и два исполняемых ELF-файла:. Первый совсем простой, на данный момент, насколько я понимаю, не используется, и служит для получения публичного ключа из приватного, чтобы использовать его в качестве идентификатора ноды. Файл ключа, который передается в качестве параметра этой утилите, отсутствует, и идентификатор ноды генерируется каждый раз разный.Перейдем к главному Ревизору — файлу. Он написан на C++, динамически слинкован, использует libevent и его OpenSSL-обертку, и обладает нижеперечисленными функциями:Программа поддерживает IPv6 и работу через прокси.Общение с сервером Lens, как его называют сами разработчики, происходит по протоколу JSON-RPC, для чего используется URL n01.rfc-revizor.ru/rpclens . Lens отправляет клиенту «задания», которые он должен выполнить. Каждое задание имеет идентификатор, тип, различные опции и параметры. Для проверки заблокированности веб-сайтов сервер передает клиенту белый список адресов, который на данный момент состоит из сайтов ya.ru, google.ru, cbr.ru, gov.ru, hotlog.ru, kremlin.ru, onf.ru, ria.ru, rostelecom.ru, kp.ru, и случайные URL из реестра запрещенных сайтов. Проверка выполняется путем поиска совпадений по регулярным выражениям в теле и заголовке ответа от веб-сайта. Если какие-то ссылки, которые не должны были открыться, не проходят проверки по регулярным выражениям, сервер отсылает запрос на предоставление SSH-туннеля до Socks5-прокси, который поднимается самим, чтобы самостоятельно загрузить страницу с помощью curl, проанализировать ее, и сделать скриншот с помощью wkhtmltoimage.Помимо заданий, сервер также может корректировать настройки Ревизора, например, изменять таймаут подключения и ожидания ответа, ограничивать количество одновременных подключений, устанавливать размер пула потоков для DNS-резолвера.Хоть общение с API и происходит по протоколу HTTPS, а у сервера имеется сертификат, выданный GeoTrust, Ревизор не выполняет проверку подлинности сертификата, а это значит, что ничто не помешает нам выполнить атаку типа «человек посередине», чтобы прослушивать и модифицировать проходящий трафик. По всей видимости, на сертификаты просто не хватило места в аппаратном решении: в TP-Link MR3020 памяти всего 4 МБ, а образ для x86 не стали переделывать.Запускаем mitmproxy!Общение с сервером начинается с команды, в которой клиент передает версию ПО, свой идентификатор агента и случайные 4 цифры в качестве идентификатора сессии.Далее происходит вызов, в ответ на который сервер возвращает какое-то задание для клиента. Вот пример настроек для проверки сайтов:Как мы можем видеть, Ревизор будет определять страницы-заглушки по наличию слов «заблокирован» и «ограничен», будет искать IP-адрес заглушки провайдера ТТК 62.33.207.195 в заголовке, а также проверять статус, отдаваемый веб-сервером.Чтобы установить SSH-туннель с клиентом, сервер посылает командус портом и количеством миллисекунд, после которого его следует завершить, в качестве параметров к команде:После этого система запускает SSH-клиент Dropbear, который часто используют во встраиваемых системах, путем совершения вызовов fork() и execv(), со следующими параметрами:Два параметраотключают проверку ключа SSH-сервера (зачем?),отключают выполнение команд, авключает режим проброса порта от сервера клиенту, т.е. открывает на стороне сервера заданный порт (64123) и перенаправляет запросы с него на порт 1080 клиента, на прослушивание которого настроен Socks5-сервер.Конечно же, первым деломбыла заменена на, однако на все исходящие соединения возвращался ICMP Administratively Prohibited.Если подумать, никто нам не запрещает указать несколько портов для проброса. Почему бы не воспользоваться этим моментом, и не пробросить на себя чуточку больше портов, скажем, диапазон с 1024 до 65535? К сожалению, одно соединение может пробросить около 1000 портов. Не знаю, чем вызвано это ограничение, быть может, виноваты настройки ulimit, а может и OpenSSH. Итак, Socks5-сервер запущен, 65 SSH-соединений установлено, и мы принимаем первое подключение на порт прокси!Что же произошло? Проверяющий сервер отправляет какому-то действующему Ревизору командус портом, не проверяя, используется ли он уже кем-то в системе, Ревизор подключается к серверу, но пробросить порт не может, так как мы заняли его раньше. Сервер подключается к нашему Socks5-серверу и открывает сайты, думая, что открывает их через проверяемого провайдера, у которого стоит Ревизор.Делать API по HTTPS, но отключать проверку TLS- и SSH-сертификатов? Использовать роутеры с 4 МБ ROM стоимостью 1500₽ в розницу? Держать сервер с Debian Oldstable без обновлений безопасности? За 84 миллиона такое можно себе позволить.Быть может, Роскомнадзор затеял этот проект из-за зависти к Blockcheck ? Кто знает…