Challenge / Misc

Not Posixtive

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

EasyPublished 2024-12-15Sanitized local writeup

Scenario

Not Posixtive attack path

Not Posixtive 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 Misc evidence, validation, and reusable operator lessons.

Not Posixtive sanitized attack graph

Walkthrough flow

01

Extracted server.py from the provided archive and...

02

Noted that check_operands() allows ~0, which...

03

Used the same allowed binary, grep, with one argument...

04

Multiplying by mode -1 produced -1 and -2.

05

Python hashes both -1 and -2 as -2, satisfying the...

Source coverage

High source coverage

Status: complete. This article is generated from 6 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.

  • Misc/Not-Posixtive/writeup.md
  • htb-challenge/Misc/Not-Posixtive/notes.md
  • htb-challenge/Misc/Not-Posixtive/memory-summary.md
  • htb-challenge/Misc/Not-Posixtive/hypothesis-board.md
  • HTB/_knowledge/exports/ctf-lightrag-latest-203412/documents/challenge__Misc__Not-Posixtive__memory-summary.md.afcf8d11ba.md
  • HTB/_knowledge/exports/ctf-lightrag-latest-203412/documents/challenge__Misc__Not-Posixtive__notes.md.a3e24fa8a9.md

Technical Walkthrough

Writeup

Challenge

  • Name: Not-Posixtive
  • Category: Misc
  • Difficulty: Easy
  • Mode: hybrid

Summary

The challenge is a menu-driven Python service that asks for a command, arguments, and a numeric mode. The win condition tries to compare two subprocess-derived debug values and requires different same-type values with equal hashes. The reliable path is to use Python's integer hash edge case where hash(-1) == hash(-2).

Artifact Inventory

Reference analysis/artifact-inventory.json and summarize the relevant files or remote surface.

  • files/a12c73a5-9cec-45f2-955b-1aa32860d24e.zip: original HTB archive.
  • files/extracted/misc_not_posixtive/server.py: full challenge server logic.
  • analysis/remote/initial-nc-probe.txt: remote banner and menu capture.
  • solve/solve.py: reproducible remote solver.

Analysis

server.py filters the menu inputs but allows ~ in the mode parser. Because only the first two characters are evaluated, the mode input ~0 becomes integer -1.

The service executes the same binary twice with different filtered arguments and stores returncode * mode for each execution. The win condition requires the two values to be distinct, have distinct string forms, share the same type, and have the same Python hash.

For Python integers, hash(-1) and hash(-2) are both -2. Local validation showed grep <secret redacted> server.py exits with code 1, while grep a . exits with code 2. With mode -1, those become -1 and -2, satisfying the collision check.

Solve

The solver connects to the remote TCP service and sends this menu sequence:

text
1
~0
2
grep
3
server.py,.
4
<secret redacted>,a
5

It saves the remote transcript to analysis/remote/solve-transcript.txt, extracts the flag candidate into loot/flag-candidate.txt, and the harness stores the validated flag in loot/flag.txt.

Flag

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

Lessons

  • Python integer hashing has special behavior for -1; hash(-1) == hash(-2).
  • Input filters that block arithmetic operators can still allow arithmetic effects through unary bitwise operators such as ~.
  • In constrained command challenges, exit codes can be enough to satisfy logic without command injection or shell metacharacters.

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: Not-Posixtive
  • Category: Misc
  • Difficulty: Easy
  • Mode: hybrid
  • Remote instance: <TARGET>:32055
  • Start time: 2026-06-07T23:24:37Z
  • 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/a12c73a5-9cec-45f2-955b-1aa32860d24e.zip1989<hash redacted>Zip archive data, at least v1.0 to extract, compression method=storezip entries: 2 shown in artifact inventory JSON
files/extracted/misc_not_posixtive/__pycache__/server.cpython-314.pyc9106<hash redacted>data
files/extracted/misc_not_posixtive/server.py5559<hash redacted>Python script text executable, Unicode text, UTF-8 text

Evidence Ledger

TimeActionOutput/FileFindingConfidenceNext
2026-06-07T23:24:37Zharness initchallenge-state.jsonWorkspace initialized with deterministic state fileHighInventory artifacts
2026-06-07T23:24:46Zartifact inventoryanalysis/artifact-inventory.json0 artifact(s) inventoriedHighBuild or update hypotheses
2026-06-07T23:25:02Zhypothesis recordedhypothesis-board.mdAnalyze the provided archive first; challenge appears to be a POSIX/shell scripting puzzle with a menu-driven remote service.MediumExtract archive, inspect scripts/source, then reproduce menu interaction locally if possible.
2026-06-07T23:25:02Zcheckpoint recordedanalysis/checkpoint-triage-20260607T232502771095Z-d3804306.mdCheckpoint for TRIAGEHighUse checkpoint to drive next decision
2026-06-07T23:25:17Zartifact inventoryanalysis/artifact-inventory.json1 artifact(s) inventoriedHighBuild or update hypotheses
2026-06-07T23:26:47Zsource auditanalysis/source-audit.mdSource audit recordedHighGate before exploit
2026-06-07T23:27:52Zartifact inventoryanalysis/artifact-inventory.json3 artifact(s) inventoriedHighBuild or update hypotheses
2026-06-07T23:27:52Zlocal memory recordanalysis/local-memory-records.mdPrior local notes reviewed as fallback/advisory contextMediumValidate against current evidence
2026-06-07T23:27:52Zhypothesis recordedhypothesis-board.mdUse Python integer hash edge case hash(-1) == hash(-2): set mode to ~0, run grep once with rc=1 and once with rc=2, then trigger option 5.MediumRun solve/solve.py against the remote and capture loot/flag-candidate.txt through harness.
2026-06-07T23:28:04Zevaluatoranalysis/evaluator-20260607T232804020929Z-6bb4be54.mdProceedHighRun solve/solve.py, capture flag through harness, then complete.
2026-06-07T23:28:25Zflag captureloot/flag.txtHTB-format flag captured; raw value kept in loot onlyHighWrite solution and run completion gate
2026-06-07T23:29:12Zcompletion gatechallenge-state.jsonCompletion gate passed; state marked COMPLETEHighOptional sanitized memory summary approval

Key Findings

  • The provided archive contains a single server.py file.
  • Remote service is a menu-driven TCP application.
  • check_operands() allows ~0, which evaluates to integer -1.
  • execute() multiplies subprocess return codes by mode.
  • Python integer hashes satisfy hash(-1) == hash(-2).
  • Local validation confirmed grep <secret redacted> server.py returns 1 and grep a . returns 2.
  • With mode ~0, those return codes produce -1 and -2, satisfying the service's hash-collision win condition.
  • solve/solve.py captured the flag candidate, and the harness stored the validated flag in loot/flag.txt.

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: Misc
  • Challenge: Not-Posixtive
  • Difficulty: Easy
  • Source workspace: <local workspace>

Validated Solve Chain

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

  1. Extracted server.py from the provided archive and identified that check_win() needs two distinct same-type values with equal Python hashes.
  2. Noted that check_operands() allows ~0, which evaluates to integer -1.
  3. Used the same allowed binary, grep, with one argument pair that exits 1 and another that exits 2.
  4. Multiplying by mode -1 produced -1 and -2.
  5. Python hashes both -1 and -2 as -2, satisfying the service's collision check.
  6. Automated the menu interaction with solve/solve.py and captured the flag through the harness.

Reusable Lessons

  • Check Python edge cases around hash(), especially -1, when a challenge compares hashes rather than values.
  • A filter can block obvious arithmetic operators while still allowing unary operators such as ~.
  • In command-wrapper puzzles, controlled exit codes can be a clean solve primitive.

Dead Ends

  • No brute force was needed.
  • Random fallback branches in check_win() were not used.

Tool Quirks

  • grep <pattern> <regular-file> can reliably return 1 for no match.
  • grep <pattern> . returns 2 because the target is a directory.

Evidence Paths

  • files/extracted/misc_not_posixtive/server.py
  • analysis/source-audit.md
  • analysis/remote/initial-nc-probe.txt
  • analysis/remote/solve-transcript.txt
  • solve/solve.py

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
1Analyze the provided archive first; challenge appears to be a POSIX/shell scripting puzzle with a menu-driven remote service.Remote TCP banner shows steps: create mode, add it to bin, research arguments, let go of beliefs, beat competitor.Extract archive, inspect scripts/source, then reproduce menu interaction locally if possible.MediumActive
1Use Python integer hash edge case hash(-1) == hash(-2): set mode to ~0, run grep once with rc=1 and once with rc=2, then trigger option 5.server.py check_win requires distinct same-type values with equal hash; local validation proves grep <secret redacted> server.py returns 1 and grep a . returns 2.Run solve/solve.py against the remote and capture loot/flag-candidate.txt through harness.MediumActive

Closed Branches

BranchEvidence TestedFailure OutputReason ClosedRevisit Condition

Memory Summary

approval_required: true

Sanitized Memory Summary

Metadata

  • Platform: HackTheBox Challenges
  • Category: Misc
  • Challenge: Not-Posixtive
  • Difficulty: Easy
  • Source workspace: <local workspace>

Validated Solve Chain

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

  1. Extracted server.py from the provided archive and identified that check_win() needs two distinct same-type values with equal Python hashes.
  2. Noted that check_operands() allows ~0, which evaluates to integer -1.
  3. Used the same allowed binary, grep, with one argument pair that exits 1 and another that exits 2.
  4. Multiplying by mode -1 produced -1 and -2.
  5. Python hashes both -1 and -2 as -2, satisfying the service's collision check.
  6. Automated the menu interaction with solve/solve.py and captured the flag through the harness.

Reusable Lessons

  • Check Python edge cases around hash(), especially -1, when a challenge compares hashes rather than values.
  • A filter can block obvious arithmetic operators while still allowing unary operators such as ~.
  • In command-wrapper puzzles, controlled exit codes can be a clean solve primitive.

Dead Ends

  • No brute force was needed.
  • Random fallback branches in check_win() were not used.

Tool Quirks

  • grep <pattern> <regular-file> can reliably return 1 for no match.
  • grep <pattern> . returns 2 because the target is a directory.

Evidence Paths

  • files/extracted/misc_not_posixtive/server.py
  • analysis/source-audit.md
  • analysis/remote/initial-nc-probe.txt
  • analysis/remote/solve-transcript.txt
  • solve/solve.py

Ingestion Decision

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

Notes

Notes

Scope

  • Challenge: Not-Posixtive
  • Category: Misc
  • Difficulty: Easy
  • Mode: hybrid
  • Remote instance: <TARGET>:32055
  • Start time: 2026-06-07T23:24:37Z
  • 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/a12c73a5-9cec-45f2-955b-1aa32860d24e.zip1989<hash redacted>Zip archive data, at least v1.0 to extract, compression method=storezip entries: 2 shown in artifact inventory JSON
files/extracted/misc_not_posixtive/__pycache__/server.cpython-314.pyc9106<hash redacted>data
files/extracted/misc_not_posixtive/server.py5559<hash redacted>Python script text executable, Unicode text, UTF-8 text

Evidence Ledger

TimeActionOutput/FileFindingConfidenceNext
2026-06-07T23:24:37Zharness initchallenge-state.jsonWorkspace initialized with deterministic state fileHighInventory artifacts
2026-06-07T23:24:46Zartifact inventoryanalysis/artifact-inventory.json0 artifact(s) inventoriedHighBuild or update hypotheses
2026-06-07T23:25:02Zhypothesis recordedhypothesis-board.mdAnalyze the provided archive first; challenge appears to be a POSIX/shell scripting puzzle with a menu-driven remote service.MediumExtract archive, inspect scripts/source, then reproduce menu interaction locally if possible.
2026-06-07T23:25:02Zcheckpoint recordedanalysis/checkpoint-triage-20260607T232502771095Z-d3804306.mdCheckpoint for TRIAGEHighUse checkpoint to drive next decision
2026-06-07T23:25:17Zartifact inventoryanalysis/artifact-inventory.json1 artifact(s) inventoriedHighBuild or update hypotheses
2026-06-07T23:26:47Zsource auditanalysis/source-audit.mdSource audit recordedHighGate before exploit
2026-06-07T23:27:52Zartifact inventoryanalysis/artifact-inventory.json3 artifact(s) inventoriedHighBuild or update hypotheses
2026-06-07T23:27:52Zlocal memory recordanalysis/local-memory-records.mdPrior local notes reviewed as fallback/advisory contextMediumValidate against current evidence
2026-06-07T23: <REDACTED>, run grep once with rc= <REDACTED>, then trigger option 5.MediumRun solve/solve.py against the remote and capture loot/flag-candidate.txt through harness.
2026-06-07T23: <REDACTED>, capture flag through harness, then complete.
2026-06-07T23: <REDACTED>
2026-06-07T23:29:12Zcompletion gatechallenge-state.jsonCompletion gate passed; state marked COMPLETEHighOptional sanitized memory summary approval

Key Findings

  • The provided archive contains a single server.py file.
  • Remote service is a menu-driven TCP application.
  • check_operands() allows ~0, which evaluates to integer -1.
  • execute() multiplies subprocess return codes by mode.
  • Python integer hashes satisfy hash(-1) == hash(-2).
  • Local validation confirmed grep <secret redacted> server.py returns 1 and grep a . returns 2.
  • With mode ~0, those return codes produce -1 and -2, satisfying the service's hash-collision win condition.
  • solve/solve.py captured the flag candidate, and the harness stored the validated flag in loot/flag.txt.

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.

Technical analogy

How to remember this solve

Think of the challenge like a timed puzzle booth. If the task is too fast or repetitive for a person, the intended move is usually to write a small helper that performs the simple action perfectly.

For Not Posixtive, 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.