Bean Counter

문제

나는 PyCrypto의 카운터 모드를 내가 원하는 것을 하기 위해 고심했고, 그래서 나는 ECB 모드에서 직접 CTR모드로 바꾸었다. 내 카운터는 암호 분석가들을 따돌리기 위해 위아래로 움직일 수 있다! 그들이 내 사진을 읽을 가능성은 없다.

풀이

더보기
from Crypto.Cipher import AES


KEY = ?


class StepUpCounter(object):
    def __init__(self, value=os.urandom(16), step_up=False):
        self.value = value.hex()
        self.step = 1
        self.stup = step_up

    def increment(self):
        if self.stup:
            self.newIV = hex(int(self.value, 16) + self.step)
        else:
            self.newIV = hex(int(self.value, 16) - self.stup)
        self.value = self.newIV[2:len(self.newIV)]
        return bytes.fromhex(self.value.zfill(32))

    def __repr__(self):
        self.increment()
        return self.value



@chal.route('/bean_counter/encrypt/')
def encrypt():
    cipher = AES.new(KEY, AES.MODE_ECB)
    ctr = StepUpCounter()

    out = []
    with open("challenge_files/bean_flag.png", 'rb') as f:
        block = f.read(16)
        while block:
            keystream = cipher.encrypt(ctr.increment())
            xored = [a^b for a, b in zip(block, keystream)]
            out.append(bytes(xored).hex())
            block = f.read(16)

    return {"encrypted": ''.join(out)}

먼저 encrypt함수에서 ecb모드를 사용하고,ctr을 통해 StepUpCounter객체를 생성한다.

StepUpCounter에선

value변수에 임의의 16진수, 16바이트값을 주고,

step_up은 False를 가져, CTR을 증가 시키진 않는다.

 

그리고 bean_flag.png 이미파일을 열고 block변수에 16바이트씩 읽는다.

ctr.increment()로 ecb암호화 하고, keystream과 block을 xor한다.

 

 16바이트 블록마다 xor 결과로 출력되는 값이다.

 

 

 ctr모드는 1씩 증가하는 카운터를 암호화하여  '키스트림'을만든다.

그리고 평문블록과 xor연산을한다.

그리고 이 복호화과정도 암호화블럭과 ctr과 xor하기 때문에

유사하다.

 

https://stackoverflow.com/questions/54845745/not-able-to-read-ihdr-chunk-of-a-png-file

현재 블럭을 16바이트씩 나누기 때문에 암호블럭 16바이트,

그래서 키스트림값 16바이트이다.

 

png값의 16바이트는 PNG 시그니처+IHDR 길이+ 청크 타입이기 때문에

첫 평문블럭은 89504e470d0a1a0a0000000d49484452이다.

그럼 키스트림은 1번째 평문 블럭 ^ 암호문 블럭이고,

현재 ctr모드지만 ctr을 증가시키지 않기 때문에

from pwn import xor
import requests

r= requests.get('http://aes.cryptohack.org/bean_counter/encrypt/')
encrypted=bytes.fromhex(r.json()['encrypted'])
png_header = bytes.fromhex('89504e470d0a1a0a0000000d49484452')

key = xor(png_header, encrypted[:16])
flag = xor(key, encrypted) 

with open('flag.png', 'wb') as save:
    save.write(flag)

 플래그값이 사진파일을 통해 나왔다.

플래그값은 crypto{hex_bytes_beans}이다.

 

복사했습니다!