Challenge / ICS

Ether Tag

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

Very EasyPublished 2024-11-14Sanitized local writeup

Scenario

Ether Tag attack path

Ether Tag 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 ICS evidence, validation, and reusable operator lessons.

Ether Tag sanitized attack graph

Walkthrough flow

01

Artifact review

02

Hypothesis

03

Validated solve path

04

Proof captured

Source coverage

Moderate source coverage

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

68% coverage
Evidence verdict

Moderate confidence: the page is useful for review, but it should be treated as partial because the available source material is thinner or less narrative-complete.

  • ICS/EtherTag/writeup.md
  • htb-challenge/ICS/EtherTag/notes.md
  • htb-challenge/ICS/EtherTag/memory-summary.md
  • htb-challenge/ICS/EtherTag/hypothesis-board.md

Technical Walkthrough

Ether Tag - Writeup

Challenge Info

  • Name: Ether Tag
  • Category: ICS
  • Difficulty: Very Easy
  • Flag: <flag stored in loot/flag.txt>

Approach

Triage

Target exposes EtherNet/IP (CIP protocol) on a non-standard port. Not HTTP โ€” raw industrial protocol.

Analysis

  • pycomm3 LogixDriver connects but fails tag enumeration (simplified CIP implementation)
  • cpppo client successfully reads tags via the EtherNet/IP pipeline
  • Single element read returns [72] (ASCII 'H') โ€” flag stored as SINT array

Solve

python
from cpppo.server.enip import client

with client.connector(host='TARGET', port=PORT, timeout=10) as conn:
    operations = client.parse_operations(['FLAG[0-99]'])
    for idx, dsc, op, rpy, sts, val in conn.pipeline(operations=operations, timeout=10):
        if val is not None:
            flag = ''.join(chr(v) for v in val if v != 0)
            print(flag)

Key Insight

The flag is stored as an array of SINT (8-bit integer) values in a CIP tag named "FLAG". Reading FLAG alone returns only the first byte. Reading FLAG[0-99] returns the full array which decodes to the flag string.

Time: ~3 minutes

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: Ether Tag
  • Category: ICS
  • Difficulty: Very Easy
  • Target: <TARGET>:32430 (EtherNet/IP)
  • Started: 2026-05-07

Evidence Ledger

TimestampActionFindingNext
00:00nc -z port checkPort 32430 open, not HTTPEtherNet/IP protocol
00:01pycomm3 LogixDriverConnected but tag list enum fails, read returns NoneTry cpppo
00:02cpppo parse_operations FLAGReturns [72] (ASCII 'H') โ€” single elementRead array
00:03cpppo FLAG[0-99]Full flag: <flag stored in loot/flag.txt>Done

Solution

  • EtherNet/IP controller with a CIP tag named "FLAG"
  • Tag stores flag as SINT array (one ASCII byte per element)
  • Read with cpppo library: client.parse_operations(['FLAG[0-99]']) over pipeline
  • Convert integer array to ASCII string

Memory Summary

Metadata

  • Platform: HackTheBox Challenges
  • Category:
  • Challenge:
  • Difficulty:
  • Source workspace:

Validated Solve Chain

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

1.

Reusable Lessons

-

Dead Ends

-

Tool Quirks

-

Evidence Paths

-

Ingestion Decision

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

Hypothesis Board

RankPathEvidenceMissing ProofCheapest ValidationConfidenceStatus

Closed Branches

BranchEvidence TestedFailure OutputReason ClosedRevisit Condition

Technical analogy

How to remember this solve

Think of the industrial system like a control-room checklist. You map the inputs, outputs, and assumptions, then find the one control path that accepts a state it should have rejected.

For Ether Tag, 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.