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
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.
Walkthrough flow
Audit Setup.sol: solved when the auction key owner...
Audit AuctionHouse.sol: bids are stored as uint64,...
Identify that a 2^63 wei bid makes the next required...
Deploy a payable helper contract to alternate senders...
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.
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 whetherTARGET.keyOwner() == player.files/extracted/blockchain_false_bidding/AuctionHouse.sol: contains the auction logic, narrow integer bid/timeout fields, andclaimPrize().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:
python3 Blockchain/False-Bidding/solve/solve.py \
--base-url http://<TARGET>:31828 \
--workspace Blockchain/False-Bidding \
--readonlyExecution through the harness:
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 \
--executeThe 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.xdoes 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
| File | Size | SHA256 | Type | Notes |
|---|---|---|---|---|
files/a12c7356-1110-42c2-a518-8eead12fdd01.zip | 1684 | <hash redacted> | Zip archive data, at least v1.0 to extract, compression method=store | zip entries: 3 shown in artifact inventory JSON |
files/extracted/blockchain_false_bidding/AuctionHouse.sol | 2135 | <hash redacted> | ASCII text | |
files/extracted/blockchain_false_bidding/Setup.sol | 421 | <hash redacted> | Java source, ASCII text |
Evidence Ledger
| Time | Action | Output/File | Finding | Confidence | Next |
|---|---|---|---|---|---|
| 2026-06-13T00:16:11Z | harness init | challenge-state.json | Workspace initialized with deterministic state file | High | Inventory artifacts |
| 2026-06-13T00:16:11Z | artifact inventory | analysis/artifact-inventory.json | 3 artifact(s) inventoried | High | Build or update hypotheses |
| 2026-06-13T00:20:32Z | hypothesis recorded | hypothesis-board.md | Exploit 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(). | High | Run solve.py --execute once through challenge_exec and inspect solve-run-summary.json before flag capture. |
| 2026-06-13T00:20:32Z | source audit | analysis/source-audit.md | Source audit recorded | High | Gate before exploit |
| 2026-06-13T00:20:32Z | instrumentation plan | analysis/instrumentation-plan.md | Use unchecked uint64 and uint32 arithmetic to reduce future bid requirements to zero and wrap the auction timeout. | High | Stop 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:32Z | checkpoint recorded | analysis/checkpoint-analysis-20260613T002032537130Z-c252706e.md | Checkpoint for ANALYSIS | High | Use checkpoint to drive next decision |
| 2026-06-13T00:20:48Z | RAG query | analysis/rag/rag-query-20260613T002039562819Z-64595e02.txt | RAG helper exited 0; output saved | Medium | Record retrieval tag and validation |
| 2026-06-13T00:21:09Z | RAG record | analysis/rag-records.md | Retrieved memory tagged GENERIC | Medium | Validate or reject with live evidence |
| 2026-06-13T00:21:09Z | local memory record | analysis/local-memory-records.md | Prior local notes reviewed as fallback/advisory context | Medium | Validate against current evidence |
| 2026-06-13T00:21:09Z | evaluator | analysis/evaluator-20260613T002109836478Z-91c27c11.md | Proceed | High | Run solve.py --execute through challenge_exec, then capture flag only after isSolved(player) is true. |
| 2026-06-13T00:24:12Z | flag capture | loot/flag.txt | HTB-format flag captured; raw value kept in loot only | High | Write solution and run completion gate |
| 2026-06-13T00:25:10Z | completion gate | challenge-state.json | Completion gate passed; state marked COMPLETE | High | Optional sanitized memory summary approval |
Key Findings
-
RAG / Advisory Memory
RAG output is advisory only. Record evaluated retrievals with:
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.
- Audit
Setup.sol: solved when the auction key owner equals the player. - Audit
AuctionHouse.sol: bids are stored asuint64, timeout asuint32, and Solidity version is0.7.0. - Identify that a
2^63wei bid makes the next required bid wrap to zero underuint64arithmetic. - Deploy a payable helper contract to alternate senders for zero-value bids.
- Player sends the high bid to become top bidder and set the next required bid to zero.
- Alternate helper/player zero-value bids to keep bids valid while incrementing
timeout. - Continue until
uint32 timeoutwraps below the current timestamp and the player is top bidder. - Player calls
claimPrize(), then the harness captures the flag.
Reusable Lessons
- In Solidity
0.7.x, arithmetic onuint64,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.sendermust 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
uint64wrap to reduce the required bid to zero. - Withdraw/refund mechanics were not needed for the final path.
Tool Quirks
- Python
web3and Foundry were not required; plain JSON-RPC was sufficient. npx solc@0.7.6compiled the helper contract when nativesolcwas unavailable.- The solve script records raw connection info under
loot/and redacted connection info underanalysis/.
Evidence Paths
analysis/source-audit.mdanalysis/live-readonly-probe.jsonanalysis/readonly-auction-state.jsonsolve/FalseBidder.solsolve/solve.pyanalysis/solve-run-summary.jsonloot/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.
| Rank | Path | Evidence | Missing Proof | Cheapest Validation | Confidence | Status |
|---|---|---|---|---|---|---|
| 1 | Exploit 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. | High | active |
Closed Branches
| Branch | Evidence Tested | Failure Output | Reason Closed | Revisit 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.