Description

Category: Crypto

Source: VolgaCTF 2019 Qualifier

Points: 200

Author: Jisoon Park(js00n.park)

Description:

Pull the flag...if you can.

nc blind.q.2019.volgactf.ru 7070

server.py

Write-up

서버 코드와 접속할 수 있는 URL이 주어진다.

class RSA:
    def __init__(self, e, d, n):
        self.e = e
        self.d = d
        self.n = n

    def sign(self, message):
        message = int(message.encode('hex'), 16)
        return pow(message, self.d, self.n)

    def verify(self, message, signature):
        message = int(message.encode('hex'), 16)
        verify = pow(signature, self.e, self.n)
        return message == verify

"""
    Keys
"""

n = 26507591511689883990023896389022361811173033984051016489514421457013639621509962613332324662222154683066173937658495362448733162728817642341239457485221865493926211958117034923747221236176204216845182311004742474549095130306550623190917480615151093941494688906907516349433681015204941620716162038586590895058816430264415335805881575305773073358135217732591500750773744464142282514963376379623449776844046465746330691788777566563856886778143019387464133144867446731438967247646981498812182658347753229511846953659235528803754112114516623201792727787856347729085966824435377279429992530935232902223909659507613583396967
e = 65537

암/복호화 하는 부분은 textbook RSA와 동일하다. 역시나 n과 e가 주어져 있는데, RsaCtfTool을 이용해서 인수분해를 시도해 보았으나 성공하지는 못했다.

while True:
    send_message('Enter your command:')
    message = read_message().strip()
    (sgn, cmd_exp) = message.split(' ', 1)
    eprint('Accepting command {0}'.format(cmd_exp))
    eprint('Accepting command signature: {0}'.format(sgn))

    cmd_l = shlex.split(cmd_exp)
    cmd = cmd_l[0]
    if cmd == 'ls' or cmd == 'dir':
        ret_str = run_cmd(cmd_exp)
        send_message(ret_str)

    elif cmd == 'cd':
        try:
            sgn = int(sgn)
            if not signature.verify(cmd_exp, sgn):
                raise SignatureException('Signature verification check failed')
            os.chdir(cmd_l[1])
            send_message('')
        except Exception as ex:
            send_message(str(ex))

    elif cmd == 'cat':
        try:
            sgn = int(sgn)
            if not signature.verify(cmd_exp, sgn):
                raise SignatureException('Signature verification check failed')
            if len(cmd_l) == 1:
                raise Exception('Nothing to cat')
            ret_str = run_cmd(cmd_exp)
            send_message(ret_str)
        except Exception as ex:
            send_message(str(ex))

    elif cmd == 'sign':
        try:
            send_message('Enter your command to sign:')
            message = read_message().strip()
            message = message.decode('base64')
            cmd_l = shlex.split(message)
            sign_cmd = cmd_l[0]
            if sign_cmd not in ['cat', 'cd']:
                sgn = signature.sign(sign_cmd)
                send_message(str(sgn))
            else:
                send_message('Invalid command')
        except Exception as ex:
            send_message(str(ex))

이 부분이 핵심이다. 공백으로 구분된 sign과 command를 던져주면, command에 따라 처리하는 루틴이다.

lsdir은 서명 검증 없이 수행하고, cdcat은 서명 검사 후 실행하며, sign은 서명을 생성해 주는 역할을 하는데 command가 cat이나 cd인 경우에는 서명을 생성해주지 않는다.

일단 서버 테스트를 해보자.

서명 자리에 아무 수나 넣고 ls -l을 실행해 봤더니, server와 동일한 디렉토리에 flag 파일이 있는 것을 확인할 수 있었다. cat flag 명령을 수행하면 flag를 얻을 수 있을 것 같다.

cat flag에 대한 서명을 어떻게 생성할 수 있을까 고민하다가, catcd가 아닌 임의의 데이터에 대해 서명을 생성하는게 가능하다는 사실이 떠올랐다. RSA의 multiplicative property를 이용해보자.

아래와 같이 파라미터를 설정하면,

  • m0 = "cat flag"
  • m1 = 2
  • s1 = sign(m1)
  • s01 = sign(m0 * m1)

m0에 대한 서명 s0는 다음과 같이 계산할 수 있을 것이다.

  • s1_inv = s1-1 mod n
  • s0 = s01 * s1_inv mod n = (m0 * m1)d * s1-1 mod n
    = m0d * m1d * m1d * -1 mod n = m0d * m10 mod n = m0d mod n

이렇게 얻은 s0와 m0를 서버로 전송하면 m0가 정상적으로 실행된 결과를 확인할 수 있을 것이다.

s0를 구하는 코드를 작성하여 실행하면 flag를 얻을 수 있다.

Flag : VolgaCTF{B1ind_y0ur_tru3_int3nti0n5}

RSA에 대한 timing attack 방어에 mulitiplicative property를 이용한 blinding을 사용하기 때문에 문제 제목이 Blind가 된것 같다.

'writeups > Crypto' 카테고리의 다른 글

Shadow Cat  (0) 2019.11.26
LG  (0) 2019.11.26
babyrsa  (0) 2019.11.26
Easy Pisy  (0) 2019.11.26
Count me in  (0) 2019.11.26

+ Recent posts