from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
KEY = ?
FLAG = ?
@chal.route('/ecb_oracle/encrypt/<plaintext>/')
def encrypt(plaintext):
plaintext = bytes.fromhex(plaintext)
padded = pad(plaintext + FLAG.encode(), 16)
cipher = AES.new(KEY, AES.MODE_ECB)
try:
encrypted = cipher.encrypt(padded)
except ValueError as e:
return {"error": str(e)}
return {"ciphertext": encrypted.hex()}
flag도 key도 모름… plain은 넣을 수 있음
16바이트로 padding
음… 문제 감을 못잡겠어서 라이트업 참고했다…
해당 사이트에서 푸는 거였다
패딩은 16 단위이다. 왼쪽은 \x61을 15번 채우면 flag에서 한 글자를 가져올 수 있다.
오른쪽에서 브루트포스처럼 a부터 넣어서 같은 output을 출력하는 한 글자를 찾으면 그 값이 flag의 첫글자이다.
이후에는 \x61 14번 + 찾은 글자 + 찾을 flag 한 글자로 반복한다.
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
import time
import requests
#ciphertext를 받아온다.
def get_cipher(plaintext):
chellenge_site = 'https://aes.cryptohack.org/ecb_oracle/encrypt/' + plaintext.hex() + '/'
r = requests.get(chellenge_site)
ciphertext = r.json()
return bytes.fromhex(ciphertext['ciphertext'])
flag=b''
#range 범위 설정에 대해서는 후술...
for i in range(0, 32):
plaintext = b'\x61' * (31 - i) #\x61을 31-i만큼 채운다
ciphertext = get_cipher(plaintext)[:32] #보내고 ascii 하나씩 대입해서 비교
plaintext += flag #찾아둔 flag들 더해야 함
print("try %d" % (i+1))
#ascii 브루트포스 for문
for j in range(33, 127):
plaintext = plaintext[:31]
plaintext += j.to_bytes(1, byteorder='big')
wr_ci = get_cipher(plaintext)[:32]
#같다면
if (wr_ci == ciphertext):
flag += j.to_bytes(1, byteorder='big')
print(flag)
break
time.sleep(1)
길이는 어떻게 알았냐 하면…
61을 1번 넣고, 2번 넣고… 하다보면 7번의 61을 넣었을 떄 갑자기 cipher가 길어진다. -> 블록이 추가됐다는 뜻
7+x=32
x=25이다.