요즘 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
반복문을 빠져나오고, 마지막 블록의 transactions
가 pending_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 더해줬다.