
💡 내 웹사이트에 대한 쿠키를 얻을 수 있지만 플래그를 읽는 데 도움이 되지는 않습니다… 제 생각에는.
음. 설명이 딱히 도움이 되는 것 같진 않다. 코드를 직접 보자.
from Crypto.Cipher import AES
import os
from Crypto.Util.Padding import pad, unpad
from datetime import datetime, timedelta
KEY = ?
FLAG = ?
@chal.route('/flipping_cookie/check_admin/<cookie>/<iv>/')
def check_admin(cookie, iv):
cookie = bytes.fromhex(cookie)
iv = bytes.fromhex(iv)
try:
cipher = AES.new(KEY, AES.MODE_CBC, iv)
decrypted = cipher.decrypt(cookie)
unpadded = unpad(decrypted, 16)
except ValueError as e:
return {"error": str(e)}
if b"admin=True" in unpadded.split(b";"):
return {"flag": FLAG}
else:
return {"error": "Only admin can read the flag"}
@chal.route('/flipping_cookie/get_cookie/')
def get_cookie():
expires_at = (datetime.today() + timedelta(days=1)).strftime("%s")
cookie = f"admin=False;expiry={expires_at}".encode()
iv = os.urandom(16)
padded = pad(cookie, 16)
cipher = AES.new(KEY, AES.MODE_CBC, iv)
encrypted = cipher.encrypt(padded)
ciphertext = iv.hex() + encrypted.hex()
return {"cookie": ciphertext}
먼저 get_cookie 부분을 살펴보자. 현재 시간을 이용하여 expires_at을 만들고, ‘admin=False;expire=’과 합쳐서 cookie로 만든다. 그 다음 패딩을 넣어주고 CBC로 암호화한 다음 iv와 붙여서 cookie로 보여준다.
check_admin 부분도 보자. cookie와 iv를 입력받아서 쿠키를 CBC로 복호화하고 패딩을 지워준다. 만약 복구한 cookie 안에 ‘admin=True’가 있다면 FLAG를 보여준다!
이 문제를 해결하기 위해서는 CBC의 구조에 대해 다시 생각해봐야 한다.
CBC Flipping이라고 구글링했더니 위와 같이 CBC 모드에서의 bit flipping attack이라는 것을 알게 되었다.(제목이 힌트였나..!) 간단히 설명하면, iv에서 원하는 위치 비트를 조작하여 복호화 시에 나오는 평문 값도 조작 가능하다는 것이다!
이번 문제에 적용하면, cookie에서 admin=False로 되어있는 것을 복호화 시에 admin=True;로, 즉 False → True가 되게끔 iv를 조작해주면 될 것 같다.

왼쪽은 admin=True;, 오른쪽은 admin=False의 hex 값이다. 둘의 xor한 값을 구해준 뒤,

이를 원래의 iv와 xor하여 조작된 iv를 만들어낸다.

CHECK_ADMIN에 입력해주면 복호화시에 admin=TRUE;;~로 인식하기에 조건을 만족하여 flag를 보여주게 된다!

🚩 flag: crypto{4u7h3n71c4710n_15_3553n714l}
