I encrypted the flag with RSA, it is now very secure!
Flag 每個字元都被 RSA 加密了。請找出 flag。
由於每個字元是分開加密的,明文會是 0~127 之間的數字,所以只要檢查 0~127 哪一個數字加密後等於密文就好。
# from output.txt
n = ...
e = ...
encrypted = ...
flag = ''
for encrypted_char in encrypted:
for plaintext_char in range(128):
if pow(plaintext_char, e, n) == encrypted_char:
flag += chr(plaintext_char)
print(flag)
If my encryption code is very complex (and slow), then no one will be able to break it!
有一個看起來非常複雜的加密演算法 encrypt(plaintext, key, rounds)
,並且有兩個用一樣的 key
與 rounds
加密的結果。其中一個明文已知,另一個是 flag。
加密流程為用 key
算出 derived
,然後把 derived
用某種方法和明文 xor,是一種(很爛的) stream cipher。因為是使用 xor,所以加密和解密的操作是一樣的。
雖然 key_derive
裡面的過程比較複雜,但可以發現同個 key
被用了兩次,所以兩次得到的 derived
結果會一樣。因此其實不需要知道 key
是什麼或是 key_derive
裡面在幹嘛,只要得到加密時用的 derived
就可以解密。
我們發現 derived
是長度 16 的 bytes,而且從
for i in range(len(plaintext)):
ciphertext[i] ^= derived[(i ^ (i >> 4)) % 16]
可以知道 derived
就是 ciphertext[0:16]
xor plaintext[0:16]
。利用題目提供的 test plaintext/ciphertext 可以得到 derived
解密。
# from output.txt
test_crypt = bytes.fromhex(...)
flag_crypt = bytes.fromhex(...)
test_plain = b'this is a test plaintext'
derived = bytearray(16)
for i in range(16):
derived[i] = test_plain[i] ^ test_crypt[i]
flag = bytearray(flag_crypt)
for i in range(len(flag)):
flag[i] ^= derived[(i ^ (i >> 4)) % 16]
print(flag.decode())
I heard that SHA-1 or similar functions are vulnerable to LEA, so I revised my hash algorithm. Can you make a fake signature?
服務有兩種功能:
message
,獲得 sign(message)
也就是 hash(secret + nonce + message)
的值,但 message
只能是八位數字nonce
和 sign('GIVE ME THE FLAG!!')
,獲得 flagHash 的實作是用 byte 陣列
的值,其中
如果知道
反之也可以得到
重複這個流程,就能對於任意字串
如果令 s = secret + nonce
,那我們可以從 sign(b'12345678') = hash(s + b'12345678')
推得 hash(s)
然後再推得 hash(s + b'GIVE ME THE FLAG!!') = sign(b'GIVE ME THE FLAG!!')
:
hash_value = sign(b'12345678')
for char in reversed(b'12345678'):
hash_value = (hash_value - char) * pow(b, -1, p) % p
for char in b'GIVE ME THE FLAG!!':
hash_value = (hash_value * b + char) % p
# hash_value == sign(b'GIVE ME THE FLAG!!')
所以得到
我們知道 secret
與 nonce
長度,並且第 nonce
會等於 str(i).encode() * 8
。因此,當 sign(m)
的值是 secret
、ord('0') + i
。把他展開可以得到
如果第 0 次、第 1 次 sign 一樣的
令
因為
如果第 2 次 sign 的是
而
如果第 3 次 sign 一樣的
若 b'GIVE ME THE FLAG!!'
的 signature 來拿 flag。可能有其他更簡單的方法拿
import pwn
io = pwn.remote('localhost', '33334')
def sign_password(password):
io.sendlineafter(b'> ', b'1')
io.sendlineafter(b'Password? ', password)
signature = bytes.fromhex(io.recvline().decode())
_nonce, hash = signature[:8], signature[8:]
return int.from_bytes(hash, 'big')
def verify_password(password, signature):
io.sendlineafter(b'> ', b'2')
io.sendlineafter(b'Password? ', password)
io.sendlineafter(b'Signature? ', signature.hex().encode())
return io.recvline().decode()
h0 = sign_password(b'00000000')
h1 = sign_password(b'00000000')
h2 = sign_password(b'00000010')
h3 = sign_password(b'00000010')
# r = b^8 + b^9 + ... + b^15
# h1 - h0 = r (mod p)
# h2 - h1 = r + b (mod p)
# h3 - h2 = r (mod p)
if h1 - h0 > 0 and h3 - h2 < 0:
r = h1 - h0
negr = h3 - h2
elif h1 - h0 < 0 and h3 - h2 > 0:
negr = h1 - h0
r = h3 - h2
else:
print('solve fail')
exit(1)
p = r - negr
b = ((h2 - h1) - r) % p
# make h4 = sign('GIVE ME THE FLAG!!')
h4 = h3
for char in reversed(b'00000010'):
h4 = (h4 - char) * pow(b, -1, p) % p
for char in b'GIVE ME THE FLAG!!':
h4 = (h4 * b + char) % p
h4 = h4.to_bytes(64, 'big')
nonce = b'3' * 8
flag = verify_password(b'GIVE ME THE FLAG!!', nonce + h4)
print(flag)