Задание:
Мое внимание привлекает монитор. На него наклеен стикер с надписью 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