Задание:
Мое внимание привлекает монитор. На него наклеен стикер с надписью B4365F2. Видимо, это какой-то ключ. На экране мигают две точки, соединенные пунктиром, а ниже бегут пакеты сетевого трафика. Наверное, это передача каких-то команд ракете. Но, по всей видимости, передаваемые данные зашифрованы... На компьютере также открыт файл, в котором записаны два IP-адреса (213.170.102.196:4001, 213.170.102.197:4002). Наверняка IP-адреса помогут мне понять схему работы протокола, по которому передаются команды! Да и в отладочной информации, если покопаться, можно будет обнаружить что-нибудь полезное...
Подключившись к адресам из задания понимаем, что используется какой-то протокол связанный с SSL.
Ответ от 213.170.102.196:4001:
Alert! Expected client hello message. Format: 1 byte type NEOSSL_HANDSHAKE 0x16 2 byte version NEOSSL1_VERSION 0x01 3-4 bytes length (excluding header) 5 byte data NEOSSL_CLIENT_HELLO 0x01 ---DEBUG INFO--- Ubuntu Release 10.04 (lucid) Kernel Linux 2.6.32-21-generic Memory 1001.9 MiB Processor Intel(R) Core(TM) i3 CPU Processing time 1998 cycles Processing threads - 1 thread Public-key cryptography algorithm - RSA (with Montgomery multiplication) Symmetric-key cryptography algorithm - AES-128 (zero IV) ------
Ответ 213.170.102.197:4002:
Alert! Expected server hello message. Format: 1 byte type NEOSSL_HANDSHAKE 0x16 2 byte version NEOSSL1_VERSION 0x01 3-4 bytes length (excluding header) 5 byte data NEOSSL_SERVER_HELLO 0x02 6 byte data RSA_WITH_AES_128_CBC 0x01 7-n bytes data Certificate ---DEBUG INFO--- Ubuntu Release 10.04 (lucid) Kernel Linux 2.6.32-21-generic Memory 1001.9 MiB Processor Intel(R) Core(TM) i3 CPU Processing time 1625 cycles Processing threads - 1 thread Public-key cryptography algorithm - RSA (with Montgomery multiplication) Symmetric-key cryptography algorithm - AES-128 (zero IV) ------
Получив формат пакета с ссертификатом от одного сервера и сертификат от другого, приходит идея устроить пересылку сообщений между серверами:
- Устанавливаем два подключения
- Пересылаем сообщения между серверами друг другу, просматривая их
Понимаем, что устанавливается SSL соединение (не совсем классическое, а несколько упрощенное):
- 1-ый сервер выдает сертификат
- 2-ой сервер в ответ на сертификат выдает зашифрованный на открытом ключе первого сервера сеансовый ключ для AES-128-CBC (из отладочной информации понимаем)
- В ответ на это 1 сервер отвечает коротким сообщением об окончании установления соединения
- Пересылается один пакет, зашифрованный уже сеансовым симметричным ключом
Помучавшись с попыткой подменить сертификат, приходим к выводу, что используется атака по времени. Ибо:
- Название намекает
- Намеки в дебажном выводе
- Слишком много намеков в дебажном выводе
Наиболее простым и правильным решением оказывается проведение Тайминг-атаки по мотивам вот этой статьи: http://crypto.stanford.edu/~dabo/papers/ssl-timing.pdf. Ибо Public-key cryptography algorithm - RSA (with Montgomery multiplication).
#!/usr/bin/python from struct import pack from sock import Sock import sys from fractions import gcd from numpy import random from operator import * from time import * #Extended Euclidean algorithm def extended_euclidean(a, b): x = 0 lastx = 1 y = 1 lasty = 0 while b != 0: q = a // b a, b = b, a % b x, lastx = (lastx - q * x, x) y, lasty = (lasty - q * y, y) return (a, lastx, lasty) def inverse(var, module): """ Return b such that b*m mod k = 1, or 0 if no solution """ v = extended_euclidean(var,module) return (v[0]==1)*(v[1] % module) def code(u): buf = '' for i in xrange(0, 16, 1): t = u % (1 << 32) buf += pack('<I', t) u = u >> 32 return buf[::-1] hello1 = '\x16\x01\x00\x01\x01' def decryptTime(u): tries = 3 t = 0 for i in range(0, tries, 1): s = Sock("213.170.102.196:4001", timeout=30) s.send(hello1) cerHello = s.recv(10000) buf = '\x16\x01\x00\x41\x0c' + code(u) s.send(buf) s.read_until('Processing time ') buf = s.read_until(' cycles') s.close() t += int(buf[1:-6]) return (t / tries) Modulus = 0x00d30f0d35084103fdf880a2e23f34b2631cca681eb7651d733cdc09b7c95e68b9b956d37ea3695ea3e6b406c26460a192fc153cf9b688a90282c78dcbee012341 R = 1 << 256 invR = inverse(R, Modulus) treshold = 50000 #this means 50000 cycles from DEBUG output def guess(g0): gOrig = g0 randTries = 1 for i in xrange(0, 252, 1): delta = 0 g1 = 0 for j in xrange(0, randTries, 1): g = gOrig if j > 0: g += random.randint(0, 512) print '#' + str(i) g1 = (1 << (251 - i)) | g ug0 = g * invR % Modulus print 'g : ' + hex(g) print 'g1: ' + hex(g1) ug1 = g1 * invR % Modulus dt0 = decryptTime(ug0) dt1 = decryptTime(ug1) delta += abs(dt1 - dt0) delta = delta / randTries print 'delta: ' + str(delta) if delta < treshold: gOrig = g1 return gOrig def tryWithG0(g0): q = guess(g0) print hex(q) p = Modulus / q if q * p == Modulus: print 'SUCCES' print hex(q) print hex(p) else: print 'FAIL' for b1 in range(0, 8): g0 = 1 << 255 print '======================================= ' + str(b1) g0 = g0 + b1 * (1 << 252) print decryptTime(g0 * invR % Modulus) g0 = (1 << 255) + 6 * (1 << 252) tryWithG0(g0)
Примечение. Используется обертка для сокетов Sock, написанная Hellman (https://github.com/hellman/sock).
Если в функции guess выставить переменную randTries переменную равной >1, то скрипт будет использовать Neighborhood из статьи, но в данном случае это необязательно.
В итоге получаем один из множителей RSA модуля, находим закрытый ключ, расшифровываем сеансовый ключ AES. Далее расшифровываем последнее сообщение. Оно говорит нам, что нужно отправить сообщение вида "XXXXXXX:Connect". В качестве XXXXXXX подставляем код из задания. Все это дело шифруем AES'ом и дописываем заголовок пакета из протокола, используемого в задании:
#!/usr/bin/python import socket import struct from Crypto.Cipher import AES s1 = socket.socket() s1.connect(("213.170.102.196", 4001)) s2 = socket.socket() s2.connect(("213.170.102.197", 4002)) hello1 = '\x16\x01\x00\x01\x01' s1.send(hello1) cerHello = s1.recv(10000) s2.send(cerHello) buf = s2.recv(10000) print '=== recv on cert:' print buf.encode('hex') tmp = buf[-64:] c = int( '0x' + tmp.encode('hex'), 16) d = 0x164e0ae945dc091df7fb303b94ce6ee3c691257bc989e818db9fad6f3cdabb5a6431a9262d6d04558cfc5084dfc2709f743f673396617b9d71de6f8da481eea1L N = 0xd30f0d35084103fdf880a2e23f34b2631cca681eb7651d733cdc09b7c95e68b9b956d37ea3695ea3e6b406c26460a192fc153cf9b688a90282c78dcbee012341L p = pow(c, d, N) p = hex(p)[2:-1] print p if len(p) % 2 == 1: p = '0' + p p = p.decode('hex') key = p[-16:] print len(key) print key.encode('hex') iv = '\x00' * 16 aes = AES.new(key, AES.MODE_CBC, iv) s1.send(buf) buf = s1.recv(10000) s2.send(buf) buf = s2.recv(10000) cmd = aes.decrypt(buf[-112:]) print cmd msg = 'B4365F2:Connect' length = 16 - (len(msg) % 16) msg += chr(length)*length print msg aes = AES.new(key, AES.MODE_CBC, iv) data = '\x17\x01\x00\x10' + aes.encrypt(msg) s2.send(data) aes = AES.new(key, AES.MODE_CBC, iv) flag = s2.recv(10000) flag = aes.decrypt(flag[4:]) print 'FLAG:' print flag s1.close() s2.close()
И вот только после этого получаем ключ:
To obtain the access to the missile control system send a message: "XXXXXXX:Connect". XXXXXXX - ID B4365F2:Connect FLAG: b84395ebd302b3e8943708770d45c4d3
Ключ: b84395ebd302b3e8943708770d45c4d3
Sports brands | UOMO, SCARPE