В 2015 году поднялась большая шумиха, когда по всему миру на различных узлах были обнаружены одинаковые SSH-отпечатки. Далее шума дело не пошло, но осадок остался. Попробуем разобраться, в чем основная опасность таких «дублей». Большая часть собранных данных актуальна для 2015 года.
Что такое отпечаток
SSH-отпечаток — это число, которое вычисляется от открытого ключа, который хранится по пути /etc/ssh в файле с разрешением pub. Когда вы впервые подключаетесь к узлу, вам предлагается его аутентифицировать. И в качестве валидатора выступает строка вида 56:ca:17:72:0b:d4:3c:fd:5e:23:fb:7b:9e:9a:c8:42
— MD5-сумма от открытого ключа.
The authenticity of host '192.168.100.124 (192.168.100.124)' can't be established. RSA key fingerprint is 56:ca:17:72:0b:d4:3c:fd:5e:23:fb:7b:9e:9a:c8:42. Are you sure you want to continue connecting (yes/no)?
Если вы впервые подключаетесь к узлу, то увидеть такое сообщение естественно. Но если вы уже аутентифицировали этот узел и подключались к нему прежде, то стоит задуматься: «Почему произошло изменение отпечатка?». Возможно, вы переустанавливали целевую систему или сгенерировали новый ключ? А может, вы подключаетесь совсем не к той машине, к которой собирались?..
Как считается отпечаток
Итак, SSH-отпечаток — это хеш-сумма. В нашем случае это MD5-сумма от открытой части RSA-ключа.
Открытая часть ключа:
root@ubuntu:/etc/ssh# cat /etc/ssh/ssh_host_rsa_key.pub
ssh-rsa
AAAAB3NzaC1yc2EAAAADAQABAAABAQCrID5HFOZiQlq6DDUCsLOG5xJFOMbxtqPTtgL0BfEyRVQ1AGD9kwSWnAU7bm/uFmfkfG5ff/8S02PKaQo26sYIWi8/NyOGMyLNnCLpMJkJ+CT12qrqpD+3Q749DpVzBBbCUaYiDNg7RbKxbbnSZUe9k69P4FE0itS4MQDFAnD0XY78aQuxNpIQUexTIP0b4QuIaShV0c6FXmpHHqr85uZ9t1cTdLtl3Kphv3yu6Z+bkGBd+c80pdV+islTUGa+YJse0rvi/qP8AU67KNXscAc4UDe1yaMG5Y3eUshvt3OTCXliYQKw3NIw/KzXbbY6s/sB49LAvDOal4FK6ZAA+HUP root@ubuntu
Декодируем строку AAAAB....A+HUP
из base64 и подсчитаем MD5-сумму получившейся строки:
root@ubuntu:/etc/ssh# awk '{print $2}' ssh_host_rsa_key.pub | base64 -d | md5sum
56ca17720bd43cfd5e23fb7b9e9ac842
Мы получили исходный отпечаток.
В трафике ключ передается так:
Вместо RSA могут использоваться и другие ключи, например ECDSA, ED25519. При помощи утилиты ssh-keyscan мы можем получить открытую часть ключа SSH сервера целевой машины.
root@ubuntu:/etc/ssh# ssh-keyscan -t ED25519 192.168.100.124
# 192.168.100.124 SSH-2.0-OpenSSH_6.6.1p1 Ubuntu-2ubuntu2.6
192.168.100.124 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIF8GXOsOnWBf1NY6Px6upViTXX0ZOw9txOEjwxMORafZ
root@ubuntu:/etc/ssh# ssh-keyscan -t RSA 192.168.100.124
# 192.168.100.124 SSH-2.0-OpenSSH_6.6.1p1 Ubuntu-2ubuntu2.6
192.168.100.124 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCrID5HFOZiQlq6DDUCsLOG5xJFOMbxtqPTtgL0BfEyRVQ1AGD9kwSWnAU7bm/uFmfkfG5ff/8S02PKaQo26sYIWi8/NyOGMyLNnCLpMJkJ+CT12qrqpD+3Q749DpVzBBbCUaYiDNg7RbKxbbnSZUe9k69P4FE0itS4MQDFAnD0XY78aQuxNpIQUexTIP0b4QuIaShV0c6FXmpHHqr85uZ9t1cTdLtl3Kphv3yu6Z+bkGBd+c80pdV+islTUGa+YJse0rvi/qP8AU67KNXscAc4UDe1yaMG5Y3eUshvt3OTCXliYQKw3NIw/KzXbbY6s/sB49LAvDOal4FK6ZAA+HUP
Также мы можем видеть баннер, который сообщает нам версию сервера, номер протокола и версию ОС: # 192.168.100.124 SSH-2.0-OpenSSH_6.6.1p1 Ubuntu-2ubuntu2.6
.
Поиск одинаковых отпечатков. Сравнение поисков
Сервис shodan.io уже собрал всю необходимую нам статистику. Shodan предлагает искать отпечатки так:
import shodan
api = shodan.Shodan(YOUR_API_KEY)
# Get the top 1,000 duplicated SSH fingerprints
results = api.count('port:22', facets=[('ssh.fingerprint', 1000)])
for facet in results['facets']['ssh.fingerprint']:
print '%s --> %s' % (facet['value'], facet['count'])
Во время анализа отпечатков сервис вел себя нестабильно. Долгое время отсутствовала возможность фильтрации фасетов по стране. Не работала конструкция вида api.count('port:22 country:RU', facets=[('ssh.fingerprint', 20)])
. Как следствие, приходилось делать выборку через facets для конкретного отпечатка по топ-странам api.count('e2:40:24:40:b8:87:4e:41:1f:d4:68:69:67:b2:22:5d', facets=[('country', 20)])
.
Сравните результаты вывода:
fa = api.count('e2:40:24:40:b8:87:4e:41:1f:d4:68:69:67:b2:22:5d', facets=[('country', 20)])
for i in range(len(fa['facets']['country'])):
if fa['facets']['country'][i]['value']=='RU': print fa['facets']['country'][i]
{u'count': 60433, u'value': u'RU'}
И
api.count('port:22 country:RU', facets=[('ssh.fingerprint', 10)])['facets']['ssh.fingerprint'][0]
{u'count': 52929, u'value': u'e2:40:24:40:b8:87:4e:41:1f:d4:68:69:67:b2:22:5d'}
Заметная разница в 14%.
Скорее всего, она обусловлено тем, что сервис активно искал баннеры и заносил их в базу, но индексация базы происходила с задержкой.
Также можно искать отпечатки в лоб:
results = api.search('e2:40:24:40:b8:87:4e:41:1f:d4:68:69:67:b2:22:5d')
results['total']
Есть ограничение выборки в 100 записей на страницу, но можно выбирать результаты по страницам:
api.search('e2:40:24:40:b8:87:4e:41:1f:d4:68:69:67:b2:22:5d', page=2)
Интересно посмотреть на статистику распределения ключей по странам.
fp30 = {}
for i in api.count('port:22', facets=[('ssh.fingerprint', 30)])['facets']['ssh.fingerprint']:
fp={}
fp['count'] = i['count']
fp['country']= api.count(i['value'], facets=[('country', 100)])['facets']['country']
fp30[i['value']]=fp
print fp30
Сравним значения разных годов:
Топ-10 — 2015:
dc:14:de:8e:d7:c1:15:43:23:82:25:81:d2:59:e8:c0, 321014 32:f9:38:a2:39:d0:c5:f5:ba:bd:b7:75:2b:00:f6:ab, 245499 d0:db:8a:cb:74:c8:37:e4:9e:71:fc:7a:eb:d6:40:81, 161471 34:47:0f:e9:1a:c2:eb:56:eb:cc:58:59:3a:02:80:b6, 149775 df:17:d6:57:7a:37:00:7a:87:5e:4e:ed:2f:a3:d5:dd, 105345 81:96:a6:8c:3a:75:f3:be:84:5e:cc:99:a7:ab:3e:d9, 97778 7c:a8:25:21:13:a2:eb:00:a6:c1:76:ca:6b:48:6e:bf, 93686 c2:77:c8:c5:72:17:e2:5b:4f:a2:4e:e3:04:0c:35:c9, 88393 1c:1e:29:43:d2:0c:c1:75:40:05:30:03:d4:02:d7:9b, 87218 03:56:e6:52:ee:d2:da:f0:73:b5:df:3d:09:08:54:b7, 64379
Топ-2016:
e7:86:c7:22:b3:08:af:c7:11:fb:a5:ff:9a:ae:38:e4, 343048 34:47:0f:e9:1a:c2:eb:56:eb:cc:58:59:3a:02:80:b6, 138495 dc:14:de:8e:d7:c1:15:43:23:82:25:81:d2:59:e8:c0, 109869 32:f9:38:a2:39:d0:c5:f5:ba:bd:b7:75:2b:00:f6:ab, 46451 62:5e:b9:fd:3a:70:eb:37:99:e9:12:e3:d9:3f:4e:6c, 41578 d0:db:8a:cb:74:c8:37:e4:9e:71:fc:7a:eb:d6:40:81, 39126 7c:a8:25:21:13:a2:eb:00:a6:c1:76:ca:6b:48:6e:bf, 38816 8b:75:88:08:41:78:11:5b:49:68:11:42:64:12:6d:49, 34203 1c:1e:29:43:d2:0c:c1:75:40:05:30:03:d4:02:d7:9b, 32621 03:56:e6:52:ee:d2:da:f0:73:b5:df:3d:09:08:54:b7, 29249 c2:77:c8:c5:72:17:e2:5b:4f:a2:4e:e3:04:0c:35:c9, 28736 59:af:97:23:de:61:51:5a:43:16:c3:6c:47:5c:11:ee, 25110 7c:3e:bc:b9:4b:0d:29:91:ed:bd:6e:4c:6b:60:49:14, 22367
Как видим, некоторые отпечатки стали встречаться реже, а какие-то, наоборот, чаще.
Карта отпечатков
Далее выведем на экран ключи и их статистику. Статистику собираем по 30 самым частым странам. Она содержит название страны в формате iso alpha2 (2-буквенное обозначение) и долю совпадений в общем числе нахождений отпечатка.
for i in fp30:
print i, fp30[i]['count']
sum = fp30[i]['count']
for j in fp30[i]['country']:
if 100*j['count']/sum > 0: print '%s: %s' % (j['value'], 100.0*j['count']/sum)
Да, 146% процентов может получиться из-за того, что данные в базе неполностью индексированы.
За 2015 год:
dc:14:de:8e:d7:c1:15:43:23:82:25:81:d2:59:e8:c0 332493
ES: 90.0605953479
TW: 3.56833133558
US: 2.1252561631
http://chartsbin.com/view/32232
32:f9:38:a2:39:d0:c5:f5:ba:bd:b7:75:2b:00:f6:ab 254856
CN: 54.5263608791
TW: 41.3041225361
DO: 1.22736474116
US: 1.18763860965
d0:db:8a:cb:74:c8:37:e4:9e:71:fc:7a:eb:d6:40:81 162800
US: 54.9035226422
JP: 45.0382223913
34:47:0f:e9:1a:c2:eb:56:eb:cc:58:59:3a:02:80:b6 151027
DE: 69.7611572028
US: 27.9946735249
ES: 1.41647682396
df:17:d6:57:7a:37:00:7a:87:5e:4e:ed:2f:a3:d5:dd 108057
CN: 99.7404030473
81:96:a6:8c:3a:75:f3:be:84:5e:cc:99:a7:ab:3e:d9 101156
TW: 100.0
8b:75:88:08:41:78:11:5b:49:68:11:42:64:12:6d:49 75760
PL: 100.0
57:94:42:63:a1:91:0b:58:a6:33:cb:db:fe:b5:83:38 39167
IN: 38.2145131455
AU: 9.01840676835
US: 8.73335961428
TR: 6.34381538648
AE: 4.14531340025
ZA: 3.3538526852
SA: 3.15977802711
MX: 3.0384813658
GB: 2.80498529278
FR: 2.56542438669
IR: 2.5199381387
IT: 2.3440579798
TH: 2.32889589714
DE: 2.31676623101
BR: 2.19243715317
MY: 1.98623282894
NG: 1.47678685144
KE: 1.46465718531
TW: 1.14625344937
chartsbin.com/view/32196
За 2016 год:
e7:86:c7:22:b3:08:af:c7:11:fb:a5:ff:9a:ae:38:e4 343048
US: 99.9988339824
34:47:0f:e9:1a:c2:eb:56:eb:cc:58:59:3a:02:80:b6 138495
DE: 54.827972129
US: 42.5546048594
GB: 1.33795443879
ES: 1.27946857287
dc:14:de:8e:d7:c1:15:43:23:82:25:81:d2:59:e8:c0 109869
ES: 88.2241578607
TW: 4.07485277922
US: 3.3376111551
DK: 1.1104133104
VC: 1.0594435191
32:f9:38:a2:39:d0:c5:f5:ba:bd:b7:75:2b:00:f6:ab 46451
CN: 49.5188478181
TW: 44.5932272717
DO: 1.59738218768
US: 1.22494671805
62:5e:b9:fd:3a:70:eb:37:99:e9:12:e3:d9:3f:4e:6c 41578
US: 84.3907835875
SG: 9.02881331473
NL: 6.58521333397
Можно заметить, что есть отпечатки, которые встречаются только в одной стране или почти только в одной (90%).
Например:
81:96:a6:8c:3a:75:f3:be:84:5e:cc:99:a7:ab:3e:d9 TW: 100.0% 8b:75:88:08:41:78:11:5b:49:68:11:42:64:12:6d:49 PL: 100.0% df:17:d6:57:7a:37:00:7a:87:5e:4e:ed:2f:a3:d5:dd CN: 99.7404030473% 59:af:97:23:de:61:51:5a:43:16:c3:6c:47:5c:11:ee US: 99.9953928728% c2:52:47:0f:8b:82:b9:3c:74:ee:64:b5:35:f4:c5:c3 MY: 99.7626425793%
Возьмем, например, Польшу:
8b:75:88:08:41:78:11:5b:49:68:11:42:64:12:6d:49 PL: 100.0%
Статистика по баннерам, в которых присутствует отпечаток:
[('SSH-2.0-OpenSSH_5.9p1 Debian-8netart1rn', 37188), ('SSH-2.0-OpenSSH_6.2p2 Ubuntu-7netart1rn', 10390), ('SSH-2.0-OpenSSH_6.6.1p1 Ubuntu-15netart2nKey type: ssh-rsanKey: AAAAB3NzaC1yc2EAAAADAQABAAABAQCnt2+LOdS1Gy/47UXMfHDYQERQQR5M4/CYsfT7IE3FYQ/mnwJO6rLKLcUo+q4U+0iIH6uBSXG5HNa4569rg2eWH5lUiJHEL1pPIA9wKKZ+MpMoE9nkr1xaXxVK5nqO1gUfaYCo+VYre2CJDe3HIJlUht3PITdxmQTwnL/tJHHBkR8xrgEpjF+9FjFKwdE7ZCNObqvhK0nPio/318DyUiRK/JaIqggL0K9KzoGytq7uKSkECFMYCDTqPmdDerCEiT+C5Lxy6ZOdp4yTyxjOM7Ensr0C/ePzPvT8rCLayz3GzBnEwZ4QKlOxbZHl/48LxtWlY/vROkiLTuU3kcpFqvo0Uc/3nFingerprint: 8b:75:88:08:41:78:11:5b:49:68:11:42:64:12:6d:49', 3421), ('SSH-2.0-OpenSSH_6.6.1p1 Ubuntu-15netart2nKey type: ssh-rsanKey: AAAAB3NzaC1yc2EAAAADAQABAAABAQCnt2+L', 3421), ('SSH-2.0-OpenSSH_6.6.1p1 Ubuntu-15netart2rn', 2)]
Судя по торговой марке NetArt, это, скорее всего, nazwa.pl — польский
Статистика для отпечатка dc:14:de:8e:d7:c1:15:43:23:82:25:81:d2:59:e8:c0
показана в исходной статье. Это предустановленный ключ SSH-сервера Dropbear v0.46. Очень старый уязвимый SSH-сервер. Количество устройств с этим ключом до сих пор очень велико.
Статистика по России за 2015 год:
e2:40:24:40:b8:87:4e:41:1f:d4:68:69:67:b2:22:5d 50107 {'Dropbear sshd_0.46': 50107}
-------------------------------------
OJSC Rostelecom 49794
OJSC Rostelecom, Vladimir branch 160
OJSC RTComm.RU 46
OJSC Bashinformsvyaz 32
CJSC ER-Telecom Holding 11
1c:1e:29:43:d2:0c:c1:75:40:05:30:03:d4:02:d7:9b 26286 {'Dropbear sshd_0.52': 26286}
-------------------------------------
OJSC Rostelecom 19596
OJSC Bashinformsvyaz 1025
MTS OJSC 1024
CJSC Teleset-Service 645
VimpelCom 340
2d:7b:35:e5:33:66:d5:ee:0d:58:19:cb:ae:e7:90:ea 24036 {'Dropbear sshd_0.53.1': 23413, 'Dropbear sshd_0.28': 623}
-------------------------------------
National Cable Networks 14860
OJSC Rostelecom 8179
VimpelCom 214
Net By Net Holding LLC 101
CJSC ER-Telecom Holding 94
f5:50:8d:ca:f7:5a:07:41:08:81:65:2e:b3:a4:d6:48 14065 {'Dropbear sshd_2011.54': 14065}
-------------------------------------
Net By Net Holding LLC 13923
OJSC Central telegraph 73
Optilink Ltd 29
Web Plus ZAO 23
Iskratelecom CJSC 10
Выводы
Как видим, с 2015 года ситуация кардинально не поменялась. Повторяющиеся отпечатки встречались раньше и встречаются сейчас. Какие-то из них стали встречаться реже, какие-то чаще. Обновилось ПО — и некоторые ключи пропали, а некоторые появились.
Так чем опасны «дубли»? Допустим, злоумышленник скомпрометировал ключ, и теперь он знает соответствующий данному открытому ключу закрытый ключ. Вендорам оборудования и хостерам этот ключ уже известен, так как они причастны к его выпуску. В этом случае можно провести MitM-атаку, например ARP Spoofingили DNS Spoofing. Злоумышленник подменяет исходный сервер своим и ждет соединения, при этом жертва не получает сообщения о недоверенном сервере. Таким образом злоумышленник в состоянии узнать пароль жертвы.
Потенциальные жертвы подобной атаки — все пользователи предустановленного ПО. Например, готовых сборок, таких как Bitnami и TurnKey. Казалось бы, достаточно просто сменить пароль… но не все так просто. Не все меняют предустановленные пароли, что же говорить о выпуске новых ключей?
Как мы видим, от подобных действий могут пострадать сотни тысяч пользователей по всему миру. При этом в случае авторизации по ключам этого не произойдет.
Будьте внимательны, вовремя обновляйте ПО.
Автор: Артур Гарипов, Positive Technologies
Автор: Positive Technologies