Challenge / Hardware

Bare Metal

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

MediumPublished 2024-09-07Sanitized local writeup

Scenario

Bare Metal attack path

Bare Metal 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 Hardware evidence, validation, and reusable operator lessons.

Bare Metal sanitized attack graph

Walkthrough flow

01

Parsed the Intel HEX firmware into raw flash bytes.

02

Identified the main behavior as direct AVR SBI/CBI...

03

Reconstructed the GPIO timeline for PD5 and PD6.

04

Treated PD6 as clock and PD5 as data based on the...

05

Sampled PD5 on rising edges of PD6.

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.

  • Hardware/Bare-Metal/writeup.md
  • htb-challenge/Hardware/Bare-Metal/notes.md
  • htb-challenge/Hardware/Bare-Metal/memory-summary.md
  • htb-challenge/Hardware/Bare-Metal/hypothesis-board.md

Technical Walkthrough

Writeup

Challenge

  • Name: Bare-Metal
  • Category: Hardware
  • Difficulty: Medium
  • Mode: file

Summary

The firmware was an ATmega328p Intel HEX image. Its main routine did not use a standard serial peripheral; it bit-banged a two-wire payload by directly toggling PORTD.

The important pattern was repeated SBI/CBI instructions against PORTD bits 5 and 6. PD5 was the data line and PD6 was the clock line. Sampling PD5 on each rising edge of PD6 produced an MSB-first ASCII command beginning with set_flag:. The value after that prefix was the flag.

Artifact Inventory

  • files/a12c73a9-a82a-44c2-80e0-3aef51c08e29.zip: original archive.
  • analysis/extracted/extracted_firmware.hex: extracted ATmega328p Intel HEX firmware.
  • analysis/avr-flash.bin: raw flash bytes parsed from the Intel HEX file.
  • analysis/avr-disasm-lite.txt: lightweight decode of relevant AVR instructions.
  • analysis/avr-portd-states.csv: reconstructed PORTD state changes.

Analysis

The firmware starts with a typical AVR vector table. The reset vector transfers into startup code, which calls a routine at byte address 0x0080; see analysis/avr-disasm-lite.txt.

That routine configures DDRD, then repeatedly uses SBI and CBI instructions:

  • 0x9a5e: set PORTD,6
  • 0x985e: clear PORTD,6
  • 0x9a5d: set PORTD,5
  • 0x985d: clear PORTD,5

This forms a data/clock pattern:

  • PD5: data bit
  • PD6: clock pulse

analysis/avr-portd-states.csv records each state transition. Sampling the current PD5 value whenever PD6 rises yields 352 bits. Grouping those bits as MSB-first bytes yields a 44-byte ASCII command. analysis/clocked-bit-decode.txt records the manual decode with the raw flag redacted.

Solve

The reproducible solver is solve/solve.py. It:

  1. Parses analysis/extracted/extracted_firmware.hex.
  2. Tracks SBI/CBI writes to PORTD.
  3. Samples PD5 on rising edges of PD6.
  4. Groups bits into MSB-first bytes.
  5. Extracts the HTB-format flag from the decoded set_flag: command.

Run:

bash
cd <local workspace>
python3 solve/solve.py

The decoded message is written redacted to analysis/decoded-message.txt; the raw flag candidate is written to loot/flag-candidate.txt and captured by the harness into loot/flag.txt.

Flag

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

Lessons

  • For small AVR firmware, direct opcode decoding can be faster than installing a full decompiler.
  • Repeated SBI/CBI instructions on GPIO pins often indicate a bit-banged bus.
  • Reconstructing pin state transitions can reveal what a device sent to a slave even when the hardware is unavailable.

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: Bare-Metal
  • Category: Hardware
  • Difficulty: Medium
  • Mode: file
  • Remote instance: none
  • Start time: 2026-06-13T13:51:42Z
  • 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/a12c73a9-a82a-44c2-80e0-3aef51c08e29.zip1115<hash redacted>Zip archive data, at least v2.0 to extract, compression method=deflatezip entries: 1 shown in artifact inventory JSON

Evidence Ledger

TimeActionOutput/FileFindingConfidenceNext
2026-06-13T13:51:42Zharness initchallenge-state.jsonWorkspace initialized with deterministic state fileHighInventory artifacts
2026-06-13T13:52:04Zartifact inventoryanalysis/artifact-inventory.json1 artifact(s) inventoriedHighBuild or update hypotheses
2026-06-13T13:52:25Zhypothesis recordedhypothesis-board.mdParse the ATmega328p Intel HEX firmware, reverse the UART/SPI/I2C behavior, and derive what command or data was sent to the tapped slave device; the flag is likely encoded in that device action or payload.MediumConvert Intel HEX to binary, inspect strings and reset vector, then disassemble enough AVR code around main/peripheral routines to identify protocol bytes.
2026-06-13T13:54:31Zresearch taskanalysis/research/task-20260613T135431865632Z-c421b6d8.mdResearch task created for advisory investigationMediumRecord research output
2026-06-13T13:54:31Zresearch recordanalysis/research/research-records.mdResearch tagged MATCHEDMediumValidate against current evidence
2026-06-13T13:54:31Zcheckpoint recordedanalysis/checkpoint-analysis-20260613T135431979107Z-68ae6235.mdCheckpoint for ANALYSISHighUse checkpoint to drive next decision
2026-06-13T13:54:32Zinstrumentation plananalysis/instrumentation-plan.mdReconstruct the slave-device command bitstream from firmware-level PORTD writes.HighStop if no HTB-format value appears after sampling PD5 on PD6 rising edges or if alternative bit ordering contradicts printable ASCII.
2026-06-13T13:54:32Zevaluatoranalysis/evaluator-20260613T135432082468Z-f26ddd95.mdProceedHighRun gate, execute solve.py, capture the flag, then complete documentation.
2026-06-13T13:54:47Zflag captureloot/flag.txtHTB-format flag captured; raw value kept in loot onlyHighWrite solution and run completion gate
2026-06-13T13:55:50Zcompletion gatechallenge-state.jsonCompletion gate passed; state marked COMPLETEHighOptional sanitized memory summary approval

Key Findings

  • The challenge archive contains one Intel HEX firmware image: analysis/extracted/extracted_firmware.hex.
  • The firmware is small, about 2.2 KiB after Intel HEX parsing.
  • Reset/startup code calls the routine beginning near byte address 0x0080.
  • The core routine uses repeated AVR SBI/CBI operations against I/O address 0x0b, which corresponds to PORTD for ATmega328p.
  • The active bit-banged lines are PD5 and PD6; PD5 is data and PD6 is clock.
  • Sampling PD5 on each rising edge of PD6 yields 352 bits, or 44 MSB-first ASCII bytes.
  • The decoded command starts with set_flag: and contains the challenge flag.
  • solve/avr_trace.py records the PORTD state timeline; solve/solve.py reproduces the flag extraction from the original Intel HEX.

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: Hardware
  • Challenge: Bare-Metal
  • 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. Parsed the Intel HEX firmware into raw flash bytes.
  2. Identified the main behavior as direct AVR SBI/CBI writes to ATmega328p PORTD.
  3. Reconstructed the GPIO timeline for PD5 and PD6.
  4. Treated PD6 as clock and PD5 as data based on the repeated set-data then pulse-clock pattern.
  5. Sampled PD5 on rising edges of PD6.
  6. Decoded the resulting MSB-first bitstream as ASCII.
  7. Extracted the flag from a decoded set_flag: command.

Reusable Lessons

  • Small AVR firmware can often be solved by decoding a small subset of opcodes rather than using full AVR tooling.
  • SBI/CBI bursts against one port are strong evidence of GPIO bit-banging.
  • Reconstructing pin transitions is an effective way to infer what a removed embedded device sent to a slave.

Dead Ends

  • Direct string search was not useful; the flag was not stored as text in firmware, it was represented as GPIO operations.

Tool Quirks

  • avr-objdump, binwalk, ghidra, avrdude, and openocd were unavailable locally.
  • A purpose-built Python parser was sufficient because the relevant instruction set was limited to Intel HEX parsing and AVR SBI/CBI decoding.

Evidence Paths

  • analysis/extracted/extracted_firmware.hex
  • analysis/avr-disasm-lite.txt
  • analysis/avr-portd-states.csv
  • analysis/clocked-bit-decode.txt
  • analysis/decoded-message.txt
  • solve/avr_trace.py
  • solve/solve.py
  • 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
1Parse the ATmega328p Intel HEX firmware, reverse the UART/SPI/I2C behavior, and derive what command or data was sent to the tapped slave device; the flag is likely encoded in that device action or payload.Challenge provides only extracted_firmware.hex and states the device was on a serial network, with ATmega328p microcontroller.Need convert HEX to flash bytes, locate strings/constants/peripheral register accesses, and reconstruct the slave-device interaction.Convert Intel HEX to binary, inspect strings and reset vector, then disassemble enough AVR code around main/peripheral routines to identify protocol bytes.MediumActive

Closed Branches

BranchEvidence TestedFailure OutputReason ClosedRevisit Condition

Technical analogy

How to remember this solve

Think of the hardware challenge like following copper tracks on a circuit board. The useful clue is usually where signals enter, where they are transformed, and which debug or storage path exposes hidden state.

For Bare Metal, 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.