О чем речьЗмеи приветствуют нас и присылают нам сразу 3 артефакта:
На SOC FORUM во время квеста Solar 4RAYS мы предложили вам взломать коммуникации змеев и узнать их секрет.
Сегодня делимся с вами ответом на задание по форензике. Ответы по пентесту были выше.
dsa.pub, send2zmiy.py и zmiy. dsa.pub — публичный ключ DSA. А из send2zmiy.py мы можем понять, что змеи получают результат проверки подписи и наше сообщение последовательно. Теперь рассмотрим
zmiy. Он содержит в себе уязвимость переполнения буфера для сообщений змеям:__isoc99_scanf("%d", &is_good_sign);
fflush(stdin);
__isoc99_scanf("%s", v8);
v4 = strcmp(FromPlanet, "Zmesk") == 0;
if ( !is_good_sign )
{
v1 = rand();
printf("%s%d\n", s[v1 % 3], v6);
fflush(_bss_start);
}
if ( is_good_sign == 1 && !v4 )
{
v2 = rand();
puts(s[v2 % 2 + 3]);
fflush(_bss_start);
}
if ( is_good_sign == 1 && v4 )
{
puts("Ty odin is nas {}");
fflush(_bss_start);
}
return 0LL;Из функции
zmiy_answer видно, что змеи проверяют два флага. Первый, как мы поняли из send2zmiy.py, относится к подписи, а второй — проверка строчки с планетой участника. И если оба флага верны, то змеи принимают нас как сородича репликой: Ty odin is nas {}.Проэксплуатируем уязвимость переполнения буфера строчкой:
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaZmesk. Из zmiy также видим, что змеев волнует какая-то проблема с подписью. А что это вообще за подпись? Для этого откроем страничку «Википедии» о DSA — по названию данного нам ключа — и узнаем, что подпись состоит из пары r, s, которые вычиcляются с использованием параметра k.
Выбор случайного числа k∈(0,q)
Вычисление r=(g^k mod p) mod q
Вычисление s = k^(−1)*(H(m)+xr) mod q
Подписью является пара (r,s) oбщей длины 2NНиже на странице видим, что есть описание уязвимости, связанное с повторением k: повторение параметра k для двух сообщений ведет к простому взлому системы.
Снова обратим внимание на сообщения змеев и увидим, что в каждом сообщении они высылают нам
Ty ne odin is nasKKKKKKkkkk54533 — какое-то число 54533. Проверим гипотезу, что змеи переиспользуют k. Действительно, после нескольких сообщений замечаем, что подпись у одних и тех же сообщений не меняется.
Для взлома подписи змеев необходимо решить уравнение r^(-1)(sk-H(m)) = x mod q или воспользоваться одним из готовых решений на github. Это даст нам секретную константу x приватного ключа змеев.
Дальше нужно только подписать наше сообщение.
Скрипт решения:
from Crypto.PublicKey import DSA
from Crypto.Hash import SHA1
from Crypto.Signature import *
from Crypto.Util.number import inverse
from Crypto.Math.Numbers import Integer
from binascii import unhexlify, hexlify
def calculate_x(public_key, k, r, s, h):
q = public_key._key["q"]
r_inv = r.inverse(q)
x = r_inv * (s*k - h) % q
return x
public_key_file = 'dsa.pub'
message = "Mi est Zmiy s planeti Zmesk".encode("utf-8")
hash_hex = SHA1.new(message)
signature_hex = unhexlify("5dee4c2f57a24000558f13ec20937ea95d287fb15492d9d3805c4bd758b8d859571913d213626a65")
k = 54533
with open(public_key_file, 'rb') as f:
public_key = DSA.import_key(f.read())
h = Integer.from_bytes(hash_hex.digest())
r_s_length = len(signature_hex) // 2
r = Integer.from_bytes(signature_hex[:r_s_length])
s = Integer.from_bytes(signature_hex[r_s_length:])
x_value = calculate_x(public_key, k, r, s, h)
public_key._key["x"] = x_value
print(f"The calculated parameter x is: {x_value}")
dss = DSS.new(public_key, 'fips-186-3')
print("Verification Zmiy meassage ", not dss.verify(hash_hex, signature_hex))
# LETS HACK ZMIY
message = b"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaZmesk"
m_hash = SHA1.new(message)
sign = dss.sign(m_hash)
print("Verification our message ", not dss.verify(m_hash, sign)) # library returns false when signature is ok \_0_/
print(f"{message.decode("utf-8")}:{hexlify(m_hash.digest()).decode("utf-8")}:{hexlify(sign).decode("utf-8")}")