반응형
제 웹사이트를 위한 쿠키를 얻을 수 있지만 flag를 읽는 데 도움이 되지 않습니다... 제 생각에는 말이죠.
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}
분석
check_admin함수에서는 cookie와 iv를 입력받는다.
AES_CBC를 가지고 복호화하는 과정을 거치는데, 복호화하고 패딩을 제거한 문자열에서
;로 구분했을 때, admin=True라는 문장이 있으면 flag를 준다.
그럼 get_cookie부분은 어떨까. admin=False와 cookie의 만료 시간을 적고 byte로 바꾼다.
바꾼 문자열을 AES_CBC로 암호화하여 돌려준다.
admin=False라는 내용은 한 블록 내에 들어간다.
우리가 입력받는건 cookie와 iv인데, cookie암호화 과정이 예측되도록 그대로 준다 쳐도 iv를 잘 바꾸면 복호화 결과를 admin=True가 나오도록 할 수는 없을까
풀이
아니 뭐야 iv를 주잖아;; 계속 고민했는데
iv와 원문을 알고 있으므로 iv를 입력하는 부분에 iv ^ 원문 ^ admin=true 이런 값을 넣으면 된다.
복호화 이후에 iv와 xor을 하게 되는데 위와 같이 입력하면 iv ^ 원문이 xor에 의해 날아가고 admin = true 만 남을 것이기 때문이다.
import requests
from pwn import *
url = 'https://aes.cryptohack.org/flipping_cookie/'
def check_admin(cookie, iv):
furl = url + f'check_admin/{cookie}/{iv}/'
r = requests.get(furl)
js = r.json()
try :
print(js['flag'])
except:
print(js['error'])
def get_cookie():
furl = url + 'get_cookie/'
r = requests.get(furl)
js = r.json()
return bytes.fromhex(js['cookie'])
cookie = get_cookie()
iv = cookie[: 16]
ciphertext = cookie[16 :]
plain16 = b'admin=False;expi'
shot = b'admin=True;;;;;;'
payload = xor(xor(iv, plain16), shot)
check_admin(ciphertext.hex(), payload.hex())
이걸 코드로 구현하면 된다.
반응형