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
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.
Walkthrough flow
Extracted server.py from the provided archive and...
Noted that check_operands() allows ~0, which...
Used the same allowed binary, grep, with one argument...
Multiplying by mode -1 produced -1 and -2.
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.
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:
1
~0
2
grep
3
server.py,.
4
<secret redacted>,a
5It 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
| File | Size | SHA256 | Type | Notes |
|---|---|---|---|---|
files/a12c73a5-9cec-45f2-955b-1aa32860d24e.zip | 1989 | <hash redacted> | Zip archive data, at least v1.0 to extract, compression method=store | zip entries: 2 shown in artifact inventory JSON |
files/extracted/misc_not_posixtive/__pycache__/server.cpython-314.pyc | 9106 | <hash redacted> | data | |
files/extracted/misc_not_posixtive/server.py | 5559 | <hash redacted> | Python script text executable, Unicode text, UTF-8 text |
Evidence Ledger
| Time | Action | Output/File | Finding | Confidence | Next |
|---|---|---|---|---|---|
| 2026-06-07T23:24:37Z | harness init | challenge-state.json | Workspace initialized with deterministic state file | High | Inventory artifacts |
| 2026-06-07T23:24:46Z | artifact inventory | analysis/artifact-inventory.json | 0 artifact(s) inventoried | High | Build or update hypotheses |
| 2026-06-07T23:25:02Z | hypothesis recorded | hypothesis-board.md | Analyze the provided archive first; challenge appears to be a POSIX/shell scripting puzzle with a menu-driven remote service. | Medium | Extract archive, inspect scripts/source, then reproduce menu interaction locally if possible. |
| 2026-06-07T23:25:02Z | checkpoint recorded | analysis/checkpoint-triage-20260607T232502771095Z-d3804306.md | Checkpoint for TRIAGE | High | Use checkpoint to drive next decision |
| 2026-06-07T23:25:17Z | artifact inventory | analysis/artifact-inventory.json | 1 artifact(s) inventoried | High | Build or update hypotheses |
| 2026-06-07T23:26:47Z | source audit | analysis/source-audit.md | Source audit recorded | High | Gate before exploit |
| 2026-06-07T23:27:52Z | artifact inventory | analysis/artifact-inventory.json | 3 artifact(s) inventoried | High | Build or update hypotheses |
| 2026-06-07T23:27:52Z | local memory record | analysis/local-memory-records.md | Prior local notes reviewed as fallback/advisory context | Medium | Validate against current evidence |
| 2026-06-07T23:27:52Z | hypothesis recorded | hypothesis-board.md | Use 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. | Medium | Run solve/solve.py against the remote and capture loot/flag-candidate.txt through harness. |
| 2026-06-07T23:28:04Z | evaluator | analysis/evaluator-20260607T232804020929Z-6bb4be54.md | Proceed | High | Run solve/solve.py, capture flag through harness, then complete. |
| 2026-06-07T23:28:25Z | flag capture | loot/flag.txt | HTB-format flag captured; raw value kept in loot only | High | Write solution and run completion gate |
| 2026-06-07T23:29:12Z | completion gate | challenge-state.json | Completion gate passed; state marked COMPLETE | High | Optional sanitized memory summary approval |
Key Findings
- The provided archive contains a single
server.pyfile. - Remote service is a menu-driven TCP application.
check_operands()allows~0, which evaluates to integer-1.execute()multiplies subprocess return codes bymode.- Python integer hashes satisfy
hash(-1) == hash(-2). - Local validation confirmed
grep <secret redacted> server.pyreturns1andgrep a .returns2. - With mode
~0, those return codes produce-1and-2, satisfying the service's hash-collision win condition. solve/solve.pycaptured the flag candidate, and the harness stored the validated flag inloot/flag.txt.
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: 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.
- Extracted
server.pyfrom the provided archive and identified thatcheck_win()needs two distinct same-type values with equal Python hashes. - Noted that
check_operands()allows~0, which evaluates to integer-1. - Used the same allowed binary,
grep, with one argument pair that exits1and another that exits2. - Multiplying by mode
-1produced-1and-2. - Python hashes both
-1and-2as-2, satisfying the service's collision check. - Automated the menu interaction with
solve/solve.pyand 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 return1for no match.grep <pattern> .returns2because the target is a directory.
Evidence Paths
files/extracted/misc_not_posixtive/server.pyanalysis/source-audit.mdanalysis/remote/initial-nc-probe.txtanalysis/remote/solve-transcript.txtsolve/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.
| Rank | Path | Evidence | Missing Proof | Cheapest Validation | Confidence | Status |
|---|---|---|---|---|---|---|
| 1 | Analyze 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. | Medium | Active | |
| 1 | Use 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. | Medium | Active |
Closed Branches
| Branch | Evidence Tested | Failure Output | Reason Closed | Revisit 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.
- Extracted
server.pyfrom the provided archive and identified thatcheck_win()needs two distinct same-type values with equal Python hashes. - Noted that
check_operands()allows~0, which evaluates to integer-1. - Used the same allowed binary,
grep, with one argument pair that exits1and another that exits2. - Multiplying by mode
-1produced-1and-2. - Python hashes both
-1and-2as-2, satisfying the service's collision check. - Automated the menu interaction with
solve/solve.pyand 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 return1for no match.grep <pattern> .returns2because the target is a directory.
Evidence Paths
files/extracted/misc_not_posixtive/server.pyanalysis/source-audit.mdanalysis/remote/initial-nc-probe.txtanalysis/remote/solve-transcript.txtsolve/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
| File | Size | SHA256 | Type | Notes |
|---|---|---|---|---|
files/a12c73a5-9cec-45f2-955b-1aa32860d24e.zip | 1989 | <hash redacted> | Zip archive data, at least v1.0 to extract, compression method=store | zip entries: 2 shown in artifact inventory JSON |
files/extracted/misc_not_posixtive/__pycache__/server.cpython-314.pyc | 9106 | <hash redacted> | data | |
files/extracted/misc_not_posixtive/server.py | 5559 | <hash redacted> | Python script text executable, Unicode text, UTF-8 text |
Evidence Ledger
| Time | Action | Output/File | Finding | Confidence | Next |
|---|---|---|---|---|---|
| 2026-06-07T23:24:37Z | harness init | challenge-state.json | Workspace initialized with deterministic state file | High | Inventory artifacts |
| 2026-06-07T23:24:46Z | artifact inventory | analysis/artifact-inventory.json | 0 artifact(s) inventoried | High | Build or update hypotheses |
| 2026-06-07T23:25:02Z | hypothesis recorded | hypothesis-board.md | Analyze the provided archive first; challenge appears to be a POSIX/shell scripting puzzle with a menu-driven remote service. | Medium | Extract archive, inspect scripts/source, then reproduce menu interaction locally if possible. |
| 2026-06-07T23:25:02Z | checkpoint recorded | analysis/checkpoint-triage-20260607T232502771095Z-d3804306.md | Checkpoint for TRIAGE | High | Use checkpoint to drive next decision |
| 2026-06-07T23:25:17Z | artifact inventory | analysis/artifact-inventory.json | 1 artifact(s) inventoried | High | Build or update hypotheses |
| 2026-06-07T23:26:47Z | source audit | analysis/source-audit.md | Source audit recorded | High | Gate before exploit |
| 2026-06-07T23:27:52Z | artifact inventory | analysis/artifact-inventory.json | 3 artifact(s) inventoried | High | Build or update hypotheses |
| 2026-06-07T23:27:52Z | local memory record | analysis/local-memory-records.md | Prior local notes reviewed as fallback/advisory context | Medium | Validate against current evidence |
| 2026-06-07T23: <REDACTED>, run grep once with rc= <REDACTED>, then trigger option 5. | Medium | Run 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:12Z | completion gate | challenge-state.json | Completion gate passed; state marked COMPLETE | High | Optional sanitized memory summary approval |
Key Findings
- The provided archive contains a single
server.pyfile. - Remote service is a menu-driven TCP application.
check_operands()allows~0, which evaluates to integer-1.execute()multiplies subprocess return codes bymode.- Python integer hashes satisfy
hash(-1) == hash(-2). - Local validation confirmed
grep <secret redacted> server.pyreturns1andgrep a .returns2. - With mode
~0, those return codes produce-1and-2, satisfying the service's hash-collision win condition. solve/solve.pycaptured the flag candidate, and the harness stored the validated flag inloot/flag.txt.
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.
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.