Noncesense Encryption
Noncesense Encryption is a sanitized challenge note from the local HTB archive, organized for quick review by category, difficulty, evidence flow, and reusable operator
Scenario
Noncesense Encryption attack path
Noncesense Encryption 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 Crypto evidence, validation, and reusable operator lessons.
Walkthrough flow
Challenge parameters
Weak assumption
Recovered secret state
Proof captured
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.
- Crypto/Noncesense-Encryption/writeup.md
- htb-challenge/Crypto/Noncesense-Encryption/notes.md
- htb-challenge/Crypto/Noncesense-Encryption/memory-summary.md
- htb-challenge/Crypto/Noncesense-Encryption/hypothesis-board.md
- HTB/_knowledge/exports/ctf-lightrag-latest-203412/documents/challenge__Crypto__Noncesense-Encryption__memory-summary.md.c8132c9fc8.md
- HTB/_knowledge/exports/ctf-lightrag-latest-203412/documents/challenge__Crypto__Noncesense-Encryption__notes.md.698e728700.md
Technical Walkthrough
Writeup
Challenge
- Name: Noncesense-Encryption
- Category: Crypto
- Difficulty: Medium
- Mode: hybrid
Summary
The service exposes chosen-plaintext encryption for a custom stream-cipher-like
scheme. The keystream is not random: each query uses the flag integer reduced
modulo 0x13373 * (nonce + counter), then expands that small residue through an
invertible linear bit transform. Because the attacker controls plaintext, every
ciphertext reveals one expanded keystream value.
The solve inverts the key expansion to recover several modular residues of the
flag, searches the small timestamp nonce window, and uses CRT to reconstruct the
flag integer.
Artifact Inventory
Reference analysis/artifact-inventory.json and summarize the relevant files or remote surface.
files/a12c7366-3ed9-4c61-bdcf-b385e875b951.zip: original HTB ZIP.analysis/extracted/crypto_noncesense_encryption/server.py: provided source
for the encryption service.
analysis/server-numbered.txt: numbered source view used during audit.analysis/local-simulation.txt: local proof that the residue recovery and CRT
reconstruction work against fake flags.
analysis/remote-recovery-summary.json: sanitized remote recovery metadata.analysis/remote-solve-run.txt: gated remote solve transcript without raw
flag output.
Analysis
The source initializes:
generator = bytes_to_long(FLAG.encode())k = 0x13373nonce = int(time())counter = 0
For each encryption, the base key is:
base = FLAG_integer mod ((nonce + counter) * k)Then counter increments. The base key is split into two 25-bit halves and run
through 250 total rounds of the state update:
kh, kl = kl, kh ^ klThe resulting ten 50-bit states are concatenated into the final XOR key. This
update is invertible: given a later (kh, kl), the previous state is
(kh ^ kl, kh). Therefore the low 50 bits of the expanded key can be inverted
250 rounds to recover the original base key.
Since encryption is ciphertext = plaintext xor expanded_key, querying a known
plaintext reveals the expanded key. Repeating this for consecutive counters
gives residues:
FLAG_integer ≡ residue_i mod (0x13373 * (nonce + i))The nonce is a Unix timestamp from service startup. The solver searches a small
window around the observed connection time and applies CRT for each candidate
nonce. With 14 residues, the combined modulus is large enough to recover the
full flag integer directly. The local simulation succeeded in 20/20 fake-flag
runs before remote execution.
Solve
The solver is solve/solve.py. It supports a local simulation and remote mode:
cd <local workspace>
python3 Crypto/Noncesense-Encryption/solve/solve.py --simulate --simulate-runs 20
python3 Crypto/Noncesense-Encryption/solve/solve.py \
--host <TARGET> \
--port 31089 \
--queries 14 \
--window 1800 \
--output Crypto/Noncesense-Encryption/loot/flag-candidate.txtThe candidate flag was captured through the harness:
python3 scripts/challenge_harness.py capture-flag Crypto/Noncesense-Encryption --from loot/flag-candidate.txtFlag
Raw flag is stored in loot/flag.txt and intentionally not reproduced here.
Lessons
Custom stream ciphers fail quickly when their keystream is deterministic and
recoverable under chosen plaintext. Nonces must be unique unpredictable inputs
to secure keystream generation; using int(time()) plus a counter around secret
material gave enough structured modular equations to reconstruct the secret.
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: Noncesense-Encryption
- Category: Crypto
- Difficulty: Medium
- Mode: hybrid
- Remote instance: <TARGET>:31089
- Start time: 2026-06-11T08:22:29Z
- 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/a12c7366-3ed9-4c61-bdcf-b385e875b951.zip | 1167 | <hash redacted> | Zip archive data, at least v1.0 to extract, compression method=store | zip entries: 2 shown in artifact inventory JSON |
Evidence Ledger
| Time | Action | Output/File | Finding | Confidence | Next |
|---|---|---|---|---|---|
| 2026-06-11T08:22:29Z | harness init | challenge-state.json | Workspace initialized with deterministic state file | High | Inventory artifacts |
| 2026-06-11T08:22:29Z | artifact inventory | analysis/artifact-inventory.json | 1 artifact(s) inventoried | High | Build or update hypotheses |
| 2026-06-11T08:22:29Z | session bootstrap | notes.md | Challenge metadata, scenario, and prior context seeded into workspace | High | Record initial hypothesis and research |
| 2026-06-11T08:22:29Z | hypothesis recorded | hypothesis-board.md | initial triage from supplied challenge metadata | Medium | inventory files / inspect app surface / map routes depending on category |
| 2026-06-11T08:22:29Z | research task | analysis/research/task-20260611T082229965093Z-0b68d19e.md | Research task created for advisory investigation | Medium | Record research output |
| 2026-06-11T08:23:45Z | source audit | analysis/source-audit.md | Source audit recorded | High | Gate before exploit |
| 2026-06-11T08:23:45Z | checkpoint recorded | analysis/checkpoint-analysis-20260611T082345625964Z-f9a88184.md | Checkpoint for ANALYSIS | High | Use checkpoint to drive next decision |
| 2026-06-11T08:23:53Z | RAG query | analysis/rag/rag-query-20260611T082345679657Z-94bd202a.txt | RAG helper exited 0; output saved | Medium | Record retrieval tag and validation |
| 2026-06-11T08:24:26Z | RAG record | analysis/rag-records.md | Retrieved memory tagged MISSING | Medium | Validate or reject with live evidence |
| 2026-06-11T08:24:26Z | research record | analysis/research/research-records.md | Research tagged MATCHED | Medium | Validate against current evidence |
| 2026-06-11T08:24:26Z | local memory record | analysis/local-memory-records.md | Prior local notes reviewed as fallback/advisory context | Medium | Validate against current evidence |
| 2026-06-11T08:24:26Z | hypothesis recorded | hypothesis-board.md | chosen-plaintext keystream inversion plus nonce-window CRT | Medium | Simulate fake server transcript, invert expanded keys to residues, brute-force nonce window, and CRT-recover a fake HTB flag. |
| 2026-06-11T08:26:18Z | instrumentation plan | analysis/instrumentation-plan.md | Recover the flag integer from chosen-plaintext keystream leaks by inverting the custom key expansion and solving FLAG mod k*(nonce+counter) residues with CRT. | High | Stop after two remote failures without new parse/timing facts; do not widen brute force beyond timestamp nonce window without a new checkpoint/evaluator. |
| 2026-06-11T08:26:18Z | evaluator | analysis/evaluator-20260611T082618813057Z-4c2ec2cb.md | Proceed | High | Run gated remote solve and capture loot/flag-candidate.txt. |
| 2026-06-11T08:26:48Z | flag capture | loot/flag.txt | HTB-format flag captured; raw value kept in loot only | High | Write solution and run completion gate |
| 2026-06-11T08:26:48Z | checkpoint recorded | analysis/checkpoint-analysis-20260611T082648294709Z-0dba5730.md | Checkpoint for ANALYSIS | High | Use checkpoint to drive next decision |
| 2026-06-11T08:27:50Z | 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.
Scenario
I've mastered Stream Ciphers, and i decided to create one myself!
Operator Question
HTB Crypto Medium Noncesense Encryption custom stream cipher nonce misuse source remote solve path
Memory Summary
Metadata
- Platform: HackTheBox Challenges
- Category: Crypto
- Challenge: Noncesense-Encryption
- 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.
Reusable Lessons
-
Dead Ends
-
Tool Quirks
-
Evidence Paths
-
Ingestion Decision
- Proposed for LightRAG: yes/no
- 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 | initial triage from supplied challenge metadata | challenge name, category, difficulty, scenario, and remote target were provided by operator | inventory files / inspect app surface / map routes depending on category | Medium | Active | |
| 1 | chosen-plaintext keystream inversion plus nonce-window CRT | encrypt(msg) returns msg xor __gen_key(); __gen_key is invertible; base key is FLAG_integer mod ((nonce+counter)*0x13373); nonce is int(time()). | Simulate fake server transcript, invert expanded keys to residues, brute-force nonce window, and CRT-recover a fake HTB flag. | 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: Crypto
- Challenge: Noncesense-Encryption
- 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.
Reusable Lessons
-
Dead Ends
-
Tool Quirks
-
Evidence Paths
-
Ingestion Decision
- Proposed for LightRAG: yes/no
- Requires user approval before ingestion: yes
Notes
Notes
Scope
- Challenge: Noncesense-Encryption
- Category: Crypto
- Difficulty: Medium
- Mode: hybrid
- Remote instance: <TARGET>:31089
- Start time: 2026-06-11T08:22:29Z
- 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/a12c7366-3ed9-4c61-bdcf-b385e875b951.zip | 1167 | <hash redacted> | Zip archive data, at least v1.0 to extract, compression method=store | zip entries: 2 shown in artifact inventory JSON |
Evidence Ledger
| Time | Action | Output/File | Finding | Confidence | Next |
|---|---|---|---|---|---|
| 2026-06-11T08:22:29Z | harness init | challenge-state.json | Workspace initialized with deterministic state file | High | Inventory artifacts |
| 2026-06-11T08:22:29Z | artifact inventory | analysis/artifact-inventory.json | 1 artifact(s) inventoried | High | Build or update hypotheses |
| 2026-06-11T08:22:29Z | session bootstrap | notes.md | Challenge metadata, scenario, and prior context seeded into workspace | High | Record initial hypothesis and research |
| 2026-06-11T08:22:29Z | hypothesis recorded | hypothesis-board.md | initial triage from supplied challenge metadata | Medium | inventory files / inspect app surface / map routes depending on category |
| 2026-06-11T08:22:29Z | research task | analysis/research/task-20260611T082229965093Z-0b68d19e.md | Research task created for advisory investigation | Medium | Record research output |
| 2026-06-11T08:23:45Z | source audit | analysis/source-audit.md | Source audit recorded | High | Gate before exploit |
| 2026-06-11T08:23:45Z | checkpoint recorded | analysis/checkpoint-analysis-20260611T082345625964Z-f9a88184.md | Checkpoint for ANALYSIS | High | Use checkpoint to drive next decision |
| 2026-06-11T08:23:53Z | RAG query | analysis/rag/rag-query-20260611T082345679657Z-94bd202a.txt | RAG helper exited 0; output saved | Medium | Record retrieval tag and validation |
| 2026-06-11T08:24:26Z | RAG record | analysis/rag-records.md | Retrieved memory tagged MISSING | Medium | Validate or reject with live evidence |
| 2026-06-11T08:24:26Z | research record | analysis/research/research-records.md | Research tagged MATCHED | Medium | Validate against current evidence |
| 2026-06-11T08:24:26Z | local memory record | analysis/local-memory-records.md | Prior local notes reviewed as fallback/advisory context | Medium | Validate against current evidence |
| 2026-06-11T08: <REDACTED>, invert expanded keys to residues, brute-force nonce window, and CRT-recover a fake HTB flag. | |||||
| 2026-06-11T08: <REDACTED> | |||||
| 2026-06-11T08: <REDACTED> | |||||
| 2026-06-11T08: <REDACTED> | |||||
| 2026-06-11T08:26:48Z | checkpoint recorded | analysis/checkpoint-analysis-20260611T082648294709Z-0dba5730.md | Checkpoint for ANALYSIS | High | Use checkpoint to drive next decision |
| 2026-06-11T08:27:50Z | 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.
Scenario
I've mastered Stream Ciphers, and i decided to create one myself!
Operator Question
HTB Crypto Medium Noncesense Encryption custom stream cipher nonce misuse source remote solve path
Technical analogy
How to remember this solve
Think of the challenge like a locked box where the lock is mathematical but slightly flawed. The goal is not to smash the box; it is to notice which part of the lock repeats, leaks, or trusts the wrong assumption.
For Noncesense Encryption, 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.