Back
Featured image of post Hack The Box - [Crypto] - Android-in-the-Middle

Hack The Box - [Crypto] - Android-in-the-Middle

[Crypto] - Android-in-the-Middle

해당 문제는 소켓통신을 하는 Docker 서버와 서버를 동작시키는 코드가 주어졌다.

서버 코드도 제공을 했는데 해당 코드를 다운로드 하여 열어보면 아래와 같았다.

from Crypto.Cipher import AES
from Crypto.Util.number import long_to_bytes
import hashlib
import random
import socketserver
import signal

FLAG = "HTB{--REDACTED--}"
DEBUG_MSG = "DEBUG MSG - "
p = 0x509efab16c5e2772fa00fc180766b6e62c09bdbd65637793c70b6094f6a7bb8189172685d2bddf87564fe2a6bc596ce28867fd7bbc300fd241b8e3348df6a0b076a0b438824517e0a87c38946fa69511f4201505fca11bc08f257e7a4bb009b4f16b34b3c15ec63c55a9dac306f4daa6f4e8b31ae700eba47766d0d907e2b9633a957f19398151111a879563cbe719ddb4a4078dd4ba42ebbf15203d75a4ed3dcd126cb86937222d2ee8bddc973df44435f3f9335f062b7b68c3da300e88bf1013847af1203402a3147b6f7ddab422d29d56fc7dcb8ad7297b04ccc52f7bc5fdd90bf9e36d01902e0e16aa4c387294c1605c6859b40dad12ae28fdfd3250a2e9
g = 2

class Handler(socketserver.BaseRequestHandler):
    def handle(self):
        signal.alarm(0)
        main(self.request)

class ReusableTCPServer(socketserver.ForkingMixIn, socketserver.TCPServer):
    pass

def sendMessage(s, msg):
    s.send(msg.encode())

def recieveMessage(s, msg):
    sendMessage(s, msg)
    return s.recv(4096).decode().strip()

def decrypt(encrypted, shared_secret):
    key = hashlib.md5(long_to_bytes(shared_secret)).digest()
    cipher = AES.new(key, AES.MODE_ECB)
    message = cipher.decrypt(encrypted)
    return message

def main(s):
    sendMessage(s, DEBUG_MSG + "Generating The Global DH Parameters\n")
    sendMessage(s, DEBUG_MSG + f"g = {g}, p = {p}\n")
    sendMessage(s, DEBUG_MSG + "Calculation Complete\n\n")

    sendMessage(s, DEBUG_MSG + "Generating The Public Key of CPU...\n")
    c = random.randrange(2, p - 1)
    C = pow(g, c, p)
    sendMessage(s, DEBUG_MSG + "Calculation Complete\n")
    sendMessage(s, DEBUG_MSG + "Public Key is: ???\n\n")

    M = recieveMessage(s, "Enter The Public Key of The Memory: ")

    try:
        M = int(M)
    except:
        sendMessage(s, DEBUG_MSG + "Unexpected Error Occured\n")
        exit()

    sendMessage(s, "\n" + DEBUG_MSG + "The CPU Calculates The Shared Secret\n")
    shared_secret = pow(M, c, p)
    sendMessage(s, DEBUG_MSG + "Calculation Complete\n\n")

    encrypted_sequence = recieveMessage(
        s, "Enter The Encrypted Initialization Sequence: ")

    try:
        encrypted_sequence = bytes.fromhex(encrypted_sequence)
        assert len(encrypted_sequence) % 16 == 0
    except:
        sendMessage(s, DEBUG_MSG + "Unexpected Error Occured\n")
        exit()

    sequence = decrypt(encrypted_sequence, shared_secret)

    if sequence == b"Initialization Sequence - Code 0":
        sendMessage(s, "\n" + DEBUG_MSG +
                    "Reseting The Protocol With The New Shared Key\n")
        sendMessage(s, DEBUG_MSG + f"{FLAG}")
    else:
        exit()


if __name__ == '__main__':
    socketserver.TCPServer.allow_reuse_address = True
    server = ReusableTCPServer(("0.0.0.0", 1337), Handler)
    server.serve_forever()

처음에 해석이 잘 되지 않아 불필요한 코드를 제거하였고, 아래와 같이 정리 했다.

from Crypto.Cipher import AES
from Crypto.Util.number import long_to_bytes
import hashlib
import random
import socketserver
import signal

p = 0x509efab16c5e2772fa00fc180766b6e62c09bdbd65637793c70b6094f6a7bb8189172685d2bddf87564fe2a6bc596ce28867fd7bbc300fd241b8e3348df6a0b076a0b438824517e0a87c38946fa69511f4201505fca11bc08f257e7a4bb009b4f16b34b3c15ec63c55a9dac306f4daa6f4e8b31ae700eba47766d0d907e2b9633a957f19398151111a879563cbe719ddb4a4078dd4ba42ebbf15203d75a4ed3dcd126cb86937222d2ee8bddc973df44435f3f9335f062b7b68c3da300e88bf1013847af1203402a3147b6f7ddab422d29d56fc7dcb8ad7297b04ccc52f7bc5fdd90bf9e36d01902e0e16aa4c387294c1605c6859b40dad12ae28fdfd3250a2e9
g = 2

c = random.randrange(2, p - 1)
C = pow(g, c, p)

M = ‘’ # 뭔가를 입력받음

M = int(M)
shared_secret = pow(M, c, p)

encrypted_sequence = '' # 뭔가 입력받음
encrypted_sequence = bytes.fromhex(encrypted_sequence)

key = hashlib.md5(long_to_bytes(shared_secret)).digest()
cipher = AES.new(key, AES.MODE_ECB)
message = cipher.decrypt(encrypted_sequence)

코드를 해석해보면 아래의 흐름으로 코드가 실행 되고 있다는 것을 알 수 있었다.

  1. 고정된 값을 통해 난수생성
  2. M을 입력받아 생성한 난수와 pow() 연산을 통해 난수 생성
  3. 생성한 난수를 md5 digest 값을 생성하여 키 값으로 저장
  4. 해당 키값과 입력받는 encrypted_sequence 를 AES ECB로 object를 생성
  5. object를 decrypt하여 키값(b’Initialization Sequence - Code 0’)과 비교하여 동일하면 FLAG출력

이러한 흐름으로 봤을떄 md5 digest값으로 생성한 키 값만 고정시키고 해당 키로 AES ECB encrypt 할 경우 FLAG를 얻을 수 있을 것이라고 생각이 들었다.

이를 위해 M에 0을 입력하여 키 값을 고정시켰고, 아래와 같은 키값을 생성할 수 있었다.

key: b'\x93\xb8\x85\xad\xfe\r\xa0\x89\xcd\xf64\x90O\xd5\x9fq'

해당 키를 가지고 AES ECB로 인코드하는 코드를 만들었고, 해당 코드로 키 값을 생성을 하면 아래와 같은 키 값을 생성 할 수 있었다

b'1af761314a07bf79f31aeb53bc9e1335e1749e1142b326d82a3c29ac37a042bf' 

인크립션 코드는 아래 참조

from Crypto.Cipher import AES
import binascii

key = b'\x93\xb8\x85\xad\xfe\r\xa0\x89\xcd\xf64\x90O\xd5\x9fq'
msg = (b'Initialization Sequence - Code 0')

cipher = AES.new(key, AES.MODE_ECB)
msg_en = cipher.encrypt(msg)

print(binascii.hexlify(msg_en))

최종적으로 nc로 해당 서버에 붙어 구한 M값과 encryption코드를 입력하면 FLAG 나오는 것을 확인할 수 있었다.

comments powered by Disqus