본문 바로가기
CTF

(CTF) UMDCTF 2022 writeup

by snwo 2022. 3. 7.

요즘 ctf 에 블록체인, 스마트컨트렉트 관련 문제도 많이 나오고 있다.

바운티도 많이주고 재미있는 분야라서 올해 열심히 연구해보려고 한다.

마침 블록체인 문제가 있길래 하나 풀어봤다.

Blockchain 2 - ChungusCoin

https://hackernoon.com/learn-blockchains-by-building-one-117428612f46

위 글에 있는 내용을 기반으로 축소해서 파이썬+Flask 로 구축한 simple blockchain 이다시마.

/nodes/update 에 chain 을 전송해 조건에 맞으면 flag 를 보내준다리미.

values = request.get_json()
length = values['length']
challenger_chain = values['chain']
name = values['name']

if (length - len(blockchain.chain) == 1) and 
(blockchain.valid_chain(challenger_chain)) and 
(len(challenger_chain) == length) 
and not (name in blockchain.names):

name 이 중복되면 안되고,

기존 chain 에 블록 하나를 추가해서 valid_chain 함수를 통과하면 된다.

기존 chain 은 /chain 에서 json 으로 가져올 수 있다.

valid_chain

        last_block = chain[0]
        if last_block['proof'] != REDACTED or last_block['previous_hash'] != 1:
            print("Invalid genesis block")
            return False

기존 chain 에 마지막 블록만 추가하면 되므로 이 부분은 그냥 통과할 수 있다.

if sha256(f"{last_block['proof']}{block['proof']}".encode()).hexdigest()[:5]!="00000":
                print("invalid proof")
                return False

여기서부터는 반복문 돌며 비교한다.

이전 블록 해시한 것 == previous_hash

if sha256(f"{last_block['proof']}{block['proof']}".encode()).hexdigest()[:5]!="00000":
                print("invalid proof")
                return False

이전 proof 값과 현재 proof 값을 해시한 결과가 00000 으로 시작해야함

chain[-1]proof 값과 반복문돌려서 나오는 조건에 맞는 값 구하면 된다.

if current_index + 1 != block['index']:
                print("invalid index")
                return False

index check

if last_block['timestamp'] > block['timestamp']:
                print("invalid timestamp")
                return False

timestamp is increasing order

if self.pending_transactions != last_block['transactions']:
            print("invalid transactions")
            return False

반복문을 빠져나오고, 마지막 블록의 transactionspending_transactions 와 같아야 하는데

/pending_transactions 에 요청보내면 가져올 수 있다. 그대로 사용하면 됨.


solve.py

import requests
import json
from random import randint
from time import time
from hashlib import sha256
url="http://0.cloud.chals.io:24797"

def Pow(proof):
    c=0
    while 1:
        if sha256(f"{proof}{c}".encode()).hexdigest()[:5]=="00000":
            break
        c+=1
    return c

s=requests.session()
r=s.get(url+"/pending_transactions")
pending=r.json()

r=s.get(url+'/chain')
chain=r.json()['chain']
last_chain=chain[-1]
previous_hash=sha256(json.dumps(last_chain,sort_keys=True).encode()).hexdigest()
length=len(chain)+1

new_block={'previous_hash':previous_hash,
                    'proof':Pow(last_chain['proof']),
                    'index':length,
                    'timestamp':last_chain['timestamp']+0.5,
                    'transactions':pending}

chain.append(json.loads(json.dumps(new_block,sort_keys=True)))
data={"length":length,"chain":chain,"name":"hellllo"}

r=s.post(url+"/nodes/update",json=data)
print(r.text)

timezone 설정하기 귀찮아서 그냥 이전 timestamp 에 0.5 더해줬다.