[CryptoHack] Static Client

 

Alice와 Bob 사이의 대화를 도청했고, Bob과 통신할 기회가 주어졌다고 한다. 어떤 내용을 도청했는지 확인해 보자.

Alice로부터 p, g, A를 받고, Bob으로부터 B를 얻어온다. 그 다음 Alice가 보내는 iv와 encrypted 메세지를 가져온다. 위의 상황은 Alice와 Bob이 공유하는 g^ab mod p를 바탕으로 암호화가 이루어진 것을 확인할 수 있다.

이번 문제에서는 p가 커서 Pohlig-Hellman 알고리즘으로 풀기엔 시간이 굉장히 오래 걸려 힘들다.

그래서 Alice의 응답을 그대로 Bob에게 다시 보내봤더니 Bob이 동일한 B와 함께 새로운 iv와 encrypted 메시지를 보내주었다. 아마도 이를 Alice가 보내줬다고 생각하고 새로운 shared_secret인 g^ab mod p를 계산해서 암호화하는 것 같다.

따라서 Alice의 A를 0x02로 바꿔서 a가 1인 상태, 즉 shared_secret이 g^b mod p = B가 되도록 하고 복호화 해보았다.

~
B=0x8d79b69390f639501d81bdce911ec9defb0e93d421c02958c8c8dd4e245e61ae861ef9d32aa85dfec628d4046c403199297d6e17f0c9555137b5e8555eb941e8dcfd2fe5e68eecffeb66c6b0de91eb8cf2fd0c0f3f47e0c89779276fa7138e138793020c6b8f834be20a16237900c108f23f872a5f693ca3f93c3fd5a853dfd69518eb4bab9ac2a004d3a11fb21307149e8f2e1d8e1d7c85d604aa0bee335eade60f191f74ee165cd4baa067b96385aa89cbc7722e7426522381fc94ebfa8ef0

iv = "3b336eba93b0c91ee24dfdcbe6653dea"
ciphertext = "d430fdfdfec605304f353903b63973f6e50e3af6a90ca1fbffda1ae2814000e901a65609c8c141608660ffbee9dcdfc9c10f834b9a74d1861dbc448be2fc8a0aecac0d7955a35e2103c18ebce86e1705"

print(decrypt_flag(B, iv, ciphertext))

 

decrypt_flag 함수는 기존과 동일하다. 코드 실행 결과는 다음과 같았다.

흠.. 난수 생성하는 게 지겨워졌다고 한다. 이게 뭘 뜻하는 걸까..

계속 고민하다가, 난수를 생성하지 않는다는 것은 Bob은 Alice로부터 받는 정보에 의존한다고 생각했다. 그러니 결국 g도 Alice가 주는 대로 그대로 사용하면서 자신의 개인키 b는 이전에 사용하던 것을 계속 사용한다고 생각했다! (사실 그렇기에 위에서도 Bob은 계속 동일한 B를 보내고 있다.)

Bob이 B를 계산할 때 Alice의 g와 자신의 b를 이용해 g^b mod p를 계산한다는 점을 이용하면, Eve가 메시지를 보낼 때 g를 기존의 g가 아닌 g^a mod p = A로 바꿔서 보낸다면 B = g^ab mod p가 되어 shared_secret을 알아낼 수 있을 것이다.

위와 같이 g는 A로, A는 아무 수나 설정해주었다. 그 다음 Bob이 보내준 B를 shared_secret인 g^ab mod p라고 생각하고, 위의 iv와 encrypted를 이용해 복호화를 진행했다.

from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
import hashlib
import pwn
import json


def is_pkcs7_padded(message):
    padding = message[-message[-1]:]
    return all(padding[i] == len(padding) for i in range(0, len(padding)))


def decrypt_flag(shared_secret: int, iv: str, ciphertext: str):
    # Derive AES key from shared secret
    sha1 = hashlib.sha1()
    sha1.update(str(shared_secret).encode('ascii'))
    key = sha1.digest()[:16]
    # Decrypt flag
    ciphertext = bytes.fromhex(ciphertext)
    iv = bytes.fromhex(iv)
    cipher = AES.new(key, AES.MODE_CBC, iv)
    plaintext = cipher.decrypt(ciphertext)

    if is_pkcs7_padded(plaintext):
        return unpad(plaintext, 16).decode('ascii')
    else:
        return plaintext.decode('ascii')

shared_secret = 0xfa6cbc695ffa73caf25ecb435908a800da4ee3060de5730e940bcd788679c0a5a59498fe67e51399c1eeac1ec6827e0801c4c0de9138fd600ca55ed293ee076f6649a415d4224c0130e45a98698bf02cc8b6c9883b6138c25bb3faf2f629bbdba7fb23d4c41e7467a5b93a6a147dd0272d7e7861e2dc9eedc01143307c34c20709f5b264f48707572c7697f618eb564c6c5f2443bae1cb551ca145d504389ee124e1eb8f2880e5b993560f2bc244fb45b3d90b312da383a113484ba564388a3f
iv = "19e1e539790d753a4159a5b1f2260de9"
ciphertext = "6c119b3f8ccc376ce39daeba9243bef4ab3067717a57c905a9ec44a239daacd3"

print(decrypt_flag(shared_secret, iv, ciphertext))

 

코드 실행결과는 다음과 같다.

flag를 얻어냈다!

🚩 crypto{n07_3ph3m3r4l_3n0u6h}

 

댓글 달기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다

위로 스크롤