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 2025: Tales from Eldoria

Eldorion

Personal Rating: Easy

This blockchain challenge was quite fun and illustrated the risks of relying on (inaccurate) block timestamps for verification. This is the contract we are presented with:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

contract Eldorion {
    uint256 public health = 300;
    uint256 public lastAttackTimestamp;
    uint256 private constant MAX_HEALTH = 300;
    
    event EldorionDefeated(address slayer);
    
    modifier eternalResilience() {
        if (block.timestamp > lastAttackTimestamp) {
            health = MAX_HEALTH;
            lastAttackTimestamp = block.timestamp;
        }
        _;
    }
    
    function attack(uint256 damage) external eternalResilience {
        require(damage <= 100, "Mortals cannot strike harder than 100");
        require(health >= damage, "Overkill is wasteful");
        health -= damage;
        
        if (health == 0) {
            emit EldorionDefeated(msg.sender);
        }
    }

    function isDefeated() external view returns (bool) {
        return health == 0;
    }
}

As with most blockchain challenges, we have an rpc port to interact with the contract and a control port where we can fetch our private key, target contract address etc. So I started with fetching these details:

Inspecting the contract, this is how it seems to work:

There is a boss with 300 health that has to be defeated to win the challenge. Each hit can make a maximum of 100 damage, but if the timestamp increased when striking again, the health will be set to 300 again by the EternalResilience modifier. This command worked to make 100 damage:

cast send --rpc-url=http://83.136.251.145:36755 --private-key=0xf7daa5e11be210259f7a57643a2aaf95e75c36f9cf02992e91ba3728e1f2b8b0 0x73E69769AD010a24603cB3B18dc5688c7eFC6576 "attack(uint256)" 100

As expected, consecutive hits do not work to reduce Eldorion's health by 300 due to the modifier.

If there is a time gap (block.timestamp > lastAttackTimestamp), the health is reset at the start of each function call of attack().

By researching I found out that block.timestamp is accurate to about the second, but should not be trusted for millisecond precision. The attack vector seems to be that you have to send 3 attack requests within the smallest amount of time possible, so that the timestamp does not change during the three hits.

I wrote a script to execute three consecutive attacks, followed by the isDefeated function. The script checks for the flag afterwards. After a few attempts, it worked.

./sender.sh && echo 3 | nc 83.136.251.145 30791

HTB{w0w_tr1pl3_hit_c0mbo_ggs_y0u_defe4ted_Eld0r10n}

PreviousEchoes in StoneNextEmbassy

Last updated 1 month ago

Rapid Attack Script