Challenge / Blockchain

False Bidding

False Bidding is a sanitized challenge note from the local HTB archive, organized for quick review by category, difficulty, evidence flow, and reusable operator

MediumPublished 2024-01-19Sanitized local writeup

Scenario

False Bidding attack path

False Bidding is a sanitized challenge note from the local HTB archive, organized for quick review by category, difficulty, evidence flow, and reusable operator

Objective

Challenge walkthrough focused on Blockchain evidence, validation, and reusable operator lessons.

False Bidding sanitized attack graph

Walkthrough flow

01

Audit Setup.sol: solved when the auction key owner...

02

Audit AuctionHouse.sol: bids are stored as uint64,...

03

Identify that a 2^63 wei bid makes the next required...

04

Deploy a payable helper contract to alternate senders...

05

Player sends the high bid to become top bidder and...

Source coverage

High source coverage

Status: complete. This article is generated from 4 sanitized Markdown sources and keeps raw flags, credentials, keys, cookies, and reusable secrets out of the rendered blog.

100% coverage
Evidence verdict

High confidence: the page is reconstructed from a primary walkthrough plus multiple supporting notes or evidence sources. Treat the chain as source-backed, while still checking the listed source files for sensitive values.

  • Blockchain/False-Bidding/writeup.md
  • htb-challenge/Blockchain/False-Bidding/notes.md
  • htb-challenge/Blockchain/False-Bidding/memory-summary.md
  • htb-challenge/Blockchain/False-Bidding/hypothesis-board.md

Technical Walkthrough

Writeup

Challenge

  • Name: False-Bidding
  • Category: Blockchain
  • Difficulty: Medium
  • Mode: hybrid

Summary

False Bidding was solved by abusing unchecked integer arithmetic in Solidity 0.7.0. The auction stores bids as uint64 and the lock timeout as uint32.

A player bid of 2^63 wei makes the next required bid wrap to zero because 2 * 2^63 mod 2^64 == 0. After that, alternating zero-value bids between the player and a helper contract repeatedly increments timeout by one year until the uint32 value wraps below the current timestamp. The player then claims the prize as top bidder.

Artifact Inventory

  • files/extracted/blockchain_false_bidding/Setup.sol: solved condition checks whether TARGET.keyOwner() == player.
  • files/extracted/blockchain_false_bidding/AuctionHouse.sol: contains the auction logic, narrow integer bid/timeout fields, and claimPrize().
  • solve/FalseBidder.sol: helper contract used as the alternate zero-bid sender.
  • solve/solve.py: reproducible JSON-RPC solver.
  • analysis/readonly-auction-state.json: read-only validation of initial top bidder, player balance, and high-bid wrap condition.
  • analysis/solve-run-summary.json: final transaction sequence and solved-state proof.

Analysis

Setup.isSolved(player) returns true only when the auction key owner is the player.

The auction starts with the setup contract as top bidder at 0.5 ether. New bids are accepted in receive() only if uint64(msg.value) >= 2 * topBidder().bid, the sender differs from the current top bidder, and the sender accepts a zero-value payment.

Because the contract uses Solidity 0.7.0, arithmetic on the narrow integer types is unchecked. Bidding 2^63 wei stores 2^63 as the uint64 top bid. The next required bid wraps to zero, so a zero-value call can become a valid bid. Since the sender must differ from the current top bidder, the solver deploys FalseBidder and alternates zero-value bids between the helper and the player.

Each accepted bid runs timeout += YEAR, where timeout is uint32. After enough zero bids, the timeout wraps to zero. The solver ensures the final top bidder is the player, then calls claimPrize().

analysis/solve-run-summary.json confirms the high bid, accepted zero bids, wrapped timeout, player top-bidder state, successful claim transaction, and is_solved_player: true.

Solve

Read-only validation:

bash
python3 Blockchain/False-Bidding/solve/solve.py \
  --base-url http://<TARGET>:31828 \
  --workspace Blockchain/False-Bidding \
  --readonly

Execution through the harness:

bash
python3 scripts/challenge_exec.py Blockchain/False-Bidding \
  --phase <secret redacted> \
  --output analysis/solve-run-summary.json \
  -- python3 Blockchain/False-Bidding/solve/solve.py \
    --base-url http://<TARGET>:31828 \
    --workspace Blockchain/False-Bidding \
    --execute

The execute path deploys FalseBidder, sends the 2^63 wei bid, alternates zero-value bids until the timeout wraps and the player is top bidder, calls claimPrize(), then writes the flag candidate to loot/flag-candidate.txt. The harness captures it into loot/flag.txt.

Flag

Raw flag is stored in loot/flag.txt and intentionally not reproduced here.

Lessons

  • Solidity 0.7.x does not have default checked arithmetic, so narrow integer fields are high-risk.
  • Overflowing a threshold calculation can be more useful than overflowing the stored value itself.
  • Zero-value calls can still trigger receive() and update contract state.
  • If a contract requires alternating senders, a minimal payable helper contract is often enough.

Source-Backed Dossier

The sections below are merged from companion Markdown notes for the same case. They are rendered after sanitization so the article stays precise without publishing raw flags, credentials, or target-specific secrets.

Notes

Scope

  • Challenge: False-Bidding
  • Category: Blockchain
  • Difficulty: Medium
  • Mode: hybrid
  • Remote instance: none
  • Start time: 2026-06-13T00:16:11Z
  • Operator: harness
  • State file: challenge-state.json

Harness Status

  • Current phase: see challenge-state.json
  • Next allowed actions: see next-action.json
  • Raw flags and sensitive material stay in loot/ only. Do not paste them here.

Artifact Inventory

FileSizeSHA256TypeNotes
files/a12c7356-1110-42c2-a518-8eead12fdd01.zip1684<hash redacted>Zip archive data, at least v1.0 to extract, compression method=storezip entries: 3 shown in artifact inventory JSON
files/extracted/blockchain_false_bidding/AuctionHouse.sol2135<hash redacted>ASCII text
files/extracted/blockchain_false_bidding/Setup.sol421<hash redacted>Java source, ASCII text

Evidence Ledger

TimeActionOutput/FileFindingConfidenceNext
2026-06-13T00:16:11Zharness initchallenge-state.jsonWorkspace initialized with deterministic state fileHighInventory artifacts
2026-06-13T00:16:11Zartifact inventoryanalysis/artifact-inventory.json3 artifact(s) inventoriedHighBuild or update hypotheses
2026-06-13T00:20:32Zhypothesis recordedhypothesis-board.mdExploit uint64 bid overflow with a 2^63 wei player bid, then alternate zero-value bids between helper and player until uint32 timeout wraps, ending with player top bidder and claimPrize().HighRun solve.py --execute once through challenge_exec and inspect solve-run-summary.json before flag capture.
2026-06-13T00:20:32Zsource auditanalysis/source-audit.mdSource audit recordedHighGate before exploit
2026-06-13T00:20:32Zinstrumentation plananalysis/instrumentation-plan.mdUse unchecked uint64 and uint32 arithmetic to reduce future bid requirements to zero and wrap the auction timeout.HighStop if high bid fails, zero bid fails, timeout does not wrap within 60 zero-bid steps, player is not top bidder when timeout expires, or claimPrize fails.
2026-06-13T00:20:32Zcheckpoint recordedanalysis/checkpoint-analysis-20260613T002032537130Z-c252706e.mdCheckpoint for ANALYSISHighUse checkpoint to drive next decision
2026-06-13T00:20:48ZRAG queryanalysis/rag/rag-query-20260613T002039562819Z-64595e02.txtRAG helper exited 0; output savedMediumRecord retrieval tag and validation
2026-06-13T00:21:09ZRAG recordanalysis/rag-records.mdRetrieved memory tagged GENERICMediumValidate or reject with live evidence
2026-06-13T00:21:09Zlocal memory recordanalysis/local-memory-records.mdPrior local notes reviewed as fallback/advisory contextMediumValidate against current evidence
2026-06-13T00:21:09Zevaluatoranalysis/evaluator-20260613T002109836478Z-91c27c11.mdProceedHighRun solve.py --execute through challenge_exec, then capture flag only after isSolved(player) is true.
2026-06-13T00:24:12Zflag captureloot/flag.txtHTB-format flag captured; raw value kept in loot onlyHighWrite solution and run completion gate
2026-06-13T00:25:10Zcompletion gatechallenge-state.jsonCompletion gate passed; state marked COMPLETEHighOptional sanitized memory summary approval

Key Findings

-

RAG / Advisory Memory

RAG output is advisory only. Record evaluated retrievals with:

bash
scripts/challenge_harness.py rag-record <workspace> --query "..." --tag MATCHED|PARTIAL|MISSING|<secret redacted>|GENERIC --validation "..."

Secrets/Flags

Raw flags and sensitive material stay in loot/ only. Use scripts/challenge_harness.py capture-flag to validate and record flag capture without printing the value.

Memory Summary

Metadata

  • Platform: HackTheBox Challenges
  • Category: Blockchain
  • Challenge: False-Bidding
  • Difficulty: Medium
  • Source workspace: <local workspace>

Validated Solve Chain

Concepts only. Do not include raw flags, reusable credentials, tokens, cookies, private keys, or live secrets.

  1. Audit Setup.sol: solved when the auction key owner equals the player.
  2. Audit AuctionHouse.sol: bids are stored as uint64, timeout as uint32, and Solidity version is 0.7.0.
  3. Identify that a 2^63 wei bid makes the next required bid wrap to zero under uint64 arithmetic.
  4. Deploy a payable helper contract to alternate senders for zero-value bids.
  5. Player sends the high bid to become top bidder and set the next required bid to zero.
  6. Alternate helper/player zero-value bids to keep bids valid while incrementing timeout.
  7. Continue until uint32 timeout wraps below the current timestamp and the player is top bidder.
  8. Player calls claimPrize(), then the harness captures the flag.

Reusable Lessons

  • In Solidity 0.7.x, arithmetic on uint64, uint32, and other narrow types can wrap silently.
  • Bid/auction challenges may be solved by manipulating the next threshold rather than outbidding honestly.
  • Zero-value transactions and calls still trigger payable receive() logic.
  • When msg.sender must differ from the previous actor, a minimal helper contract can alternate state-changing calls with the player.
  • Dynamic execution should check state after each transaction and stop when the required condition is met, rather than assuming a fixed loop count.

Dead Ends

  • Waiting for time naturally is not viable; the intended route is timeout overflow.
  • Honest doubling bids are not viable with the player balance; use uint64 wrap to reduce the required bid to zero.
  • Withdraw/refund mechanics were not needed for the final path.

Tool Quirks

  • Python web3 and Foundry were not required; plain JSON-RPC was sufficient.
  • npx solc@0.7.6 compiled the helper contract when native solc was unavailable.
  • The solve script records raw connection info under loot/ and redacted connection info under analysis/.

Evidence Paths

  • analysis/source-audit.md
  • analysis/live-readonly-probe.json
  • analysis/readonly-auction-state.json
  • solve/FalseBidder.sol
  • solve/solve.py
  • analysis/solve-run-summary.json
  • loot/flag.txt

Ingestion Decision

  • Proposed for LightRAG: yes
  • Requires user approval before ingestion: yes

Hypothesis Board

Keep no more than 3 active hypotheses on Easy/Medium and 5 on Hard unless the user explicitly asks for breadth.

RankPathEvidenceMissing ProofCheapest ValidationConfidenceStatus
1Exploit uint64 bid overflow with a 2^63 wei player bid, then alternate zero-value bids between helper and player until uint32 timeout wraps, ending with player top bidder and claimPrize().Source audit shows Solidity 0.7 unchecked uint64 and uint32 arithmetic; readonly probe confirms player can afford 2^63 wei, initial top bid is 0.5 ether, and 2 * 2^63 mod uint64 is zero.Need live execution proof that zero bids are accepted, timeout wraps below current timestamp, player remains top bidder, claimPrize succeeds, and isSolved(player) becomes true.Run solve.py --execute once through challenge_exec and inspect solve-run-summary.json before flag capture.Highactive

Closed Branches

BranchEvidence TestedFailure OutputReason ClosedRevisit Condition

Technical analogy

How to remember this solve

Think of the smart contract like a transparent bank ledger with strict but imperfect rules. The trick is to make the rules execute in an order the author did not protect against.

For False Bidding, keep the mental model simple: identify the trusted assumption, prove it with the smallest safe test, then automate or repeat only the part that directly leads to the flag.