Infosekurus Query
Infosekurus Query is a sanitized challenge note from the local HTB archive, organized for quick review by category, difficulty, evidence flow, and reusable operator
Scenario
Infosekurus Query attack path
Infosekurus Query 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
Query all RSA public-key choices in one session to...
Use the non-coprime exponent row where phi is...
Enumerate modular 8192nd roots modulo the two primes,...
Use option 2 to obtain a deterministic middle hash...
Put the corresponding glue padding inside the 2FA...
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.
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/Infosekurus-Query/writeup.md
- htb-challenge/Crypto/Infosekurus-Query/notes.md
- htb-challenge/Crypto/Infosekurus-Query/memory-summary.md
- htb-challenge/Crypto/Infosekurus-Query/hypothesis-board.md
Technical Walkthrough
Writeup
Challenge
- Name: Infosekurus-Query
- Category: Crypto
- Difficulty: Medium
- Mode: hybrid
Summary
Infosekurus Query combines an RSA passcode oracle with a custom keyed hash used for a second authentication step. The passcode is fixed per connection and can be recovered from the RSA menu by using the non-coprime e = 8192 key: the service returns phi for that key, so the modulus can be factored and the 8192nd roots can be enumerated. The correct root is the one that matches every other RSA ciphertext in the same session.
After recovering the passcode, the second step is bypassed with a length-extension style attack against the custom hash. A deterministic option-2 hash sample gives the finalized middle state for passcode || zero-fill. The answer sent to option 3 includes the exact glue padding for that prefix, so the displayed hash can be checked offline for each possible five-byte authorization value.
Artifact Inventory
files/a12c7385-87c1-4dbe-88c1-ad83c30e223c.zip: original HTB archive.files/extracted/crypto_infosekurus_query/server.py: source for the remote service.analysis/artifact-inventory.json: full inventory and hashes.analysis/source-audit.md: source-backed audit of the RSA and custom hash paths.
Analysis
The source audit is in analysis/source-audit.md.
The RSA portion exposes one ciphertext per public-key choice for the same session passcode. Most choices hide phi because gcd(e, phi) == 1, but the e = 8192 choice returns phi because the exponent is not coprime with the totient. From N and phi, the solver recovers p and q.
Because e = 8192 is not invertible modulo phi, ordinary RSA decryption does not apply. The solver instead computes modular 8192nd roots modulo both primes, combines them with CRT, and filters the roots by checking which candidate satisfies all 13 public ciphertext equations. That leaves one passcode candidate, stored under loot/.
For the second step, Hasher.hash_digest pads key || md5(hash_word) || message, then processes 16-byte blocks with a custom AES-based compression. The unknown prefix length is 64 bytes, which is block-aligned. The solver queries option 2 with:
passcode || zero-fill-to-27-bytesFor this input shape, the rxor mutation produced a deterministic middle hash state in the observed run. The solver then sends option 3 an answer equal to:
zero-fill || glue-padding-for-64+27-byte-prefixThis makes the option-3 hash message equivalent to a length extension of the option-2 message. The five-byte authorization value is drawn from the known alphabet created by randomize, so the solver brute forces that local 12^5 space against the displayed hash and submits the recovered value once.
RAG did not contain useful challenge-specific prior knowledge and was recorded as missing in analysis/rag-records.md; the solve is based on the provided source and bounded remote transcript.
Solve
The reproducible solver is solve/solve.py.
Collection and passcode recovery only:
cd <local workspace>
python3 scripts/challenge_exec.py Crypto/Infosekurus-Query -- sh -lc 'cd Crypto/Infosekurus-Query && /opt/homebrew/bin/python3 solve/solve.py collect-rsa --host <TARGET> --port 30463'
/opt/homebrew/bin/python3 Crypto/Infosekurus-Query/solve/solve.py recover-passcodeFull solve:
cd <local workspace>
python3 scripts/challenge_exec.py Crypto/Infosekurus-Query -- sh -lc 'cd Crypto/Infosekurus-Query && /opt/homebrew/bin/python3 solve/solve.py solve-remote --host <TARGET> --port 30463 --samples 160 --top-digests 5'
python3 scripts/challenge_harness.py capture-flag Crypto/Infosekurus-Query --from loot/flag-candidate.txtNon-sensitive solve metadata:
analysis/rsa-collection.jsonanalysis/hash-sample-stats.jsonanalysis/solution-summary.json
Sensitive recovered passcode, authorization value, final service response, and raw flag are stored only under loot/.
Flag
Raw flag is stored in loot/flag.txt and intentionally not reproduced here.
Lessons
- Non-coprime RSA exponents require root extraction rather than modular inversion.
- Multiple ciphertexts of the same plaintext under different public keys make root filtering straightforward.
- Secret-prefix hash constructions are vulnerable when the prefix length is known and the attacker can insert glue padding into a later message.
- A five-byte local brute force is acceptable only after the cryptographic state has been reduced to a fully offline check; it should not be attempted blindly against the service.
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: Infosekurus-Query
- Category: Crypto
- Difficulty: Medium
- Mode: hybrid
- Remote instance: none
- Start time: 2026-06-12T08:32:04Z
- 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/a12c7385-87c1-4dbe-88c1-ad83c30e223c.zip | 2787 | <hash redacted> | Zip archive data, at least v1.0 to extract, compression method=store | zip entries: 2 shown in artifact inventory JSON |
files/extracted/crypto_infosekurus_query/server.py | 10436 | <hash redacted> | Python script text executable, Unicode text, UTF-8 text, with CRLF line terminators |
Evidence Ledger
| Time | Action | Output/File | Finding | Confidence | Next |
|---|---|---|---|---|---|
| 2026-06-12T08:32:04Z | harness init | challenge-state.json | Workspace initialized with deterministic state file | High | Inventory artifacts |
| 2026-06-12T08:32:17Z | artifact inventory | analysis/artifact-inventory.json | 2 artifact(s) inventoried | High | Build or update hypotheses |
| 2026-06-12T08:33:42Z | hypothesis recorded | hypothesis-board.md | Use the encrypted-passcode oracle across all RSA public-key choices to recover the session passcode, then analyze the custom hash/2FA path to recover or forge the 5-byte random token value. | Medium | Query option 1 for all key choices in one session, factor any weak/shared moduli or use provided phi, and check whether any invertible RSA instance decrypts the same passcode. |
| 2026-06-12T08:34:17Z | source audit | analysis/source-audit.md | Source audit recorded | High | Gate before exploit |
| 2026-06-12T08:34:17Z | checkpoint recorded | analysis/checkpoint-triage-20260612T083417664455Z-abde3540.md | Checkpoint for TRIAGE | High | Use checkpoint to drive next decision |
| 2026-06-12T08:34:17Z | instrumentation plan | analysis/instrumentation-plan.md | Recover the fixed session passcode from the RSA menu, derive a source-backed 2FA bypass, and capture the flag with a bounded authenticated interaction. | High | Stop after two failed authenticate attempts or if RSA collection does not yield a passcode; do not brute-force the remote 2FA blindly. |
| 2026-06-12T08:34:38Z | RAG query | analysis/rag/rag-query-20260612T083426300763Z-088172f4.txt | RAG helper exited 0; output saved | Medium | Record retrieval tag and validation |
| 2026-06-12T08:35:05Z | RAG record | analysis/rag-records.md | Retrieved memory tagged MISSING | Medium | Validate or reject with live evidence |
| 2026-06-12T08:35:05Z | local memory record | analysis/local-memory-records.md | Prior local notes reviewed as fallback/advisory context | Medium | Validate against current evidence |
| 2026-06-12T08:35:16Z | evaluator | analysis/evaluator-20260612T083516170618Z-0fc62dee.md | Proceed | High | Run gated remote collection and write solver outputs to analysis/ and loot/. |
| 2026-06-12T08:50:40Z | flag capture | loot/flag.txt | HTB-format flag captured; raw value kept in loot only | High | Write solution and run completion gate |
| 2026-06-12T08:52:11Z | completion gate | challenge-state.json | Completion gate passed; state marked COMPLETE | High | Optional sanitized memory summary approval |
Key Findings
- Option 1 exposes the same session passcode encrypted under 13 public-key choices.
- Choice 6 uses exponent
8192and returnsphi; this enables factorization but requires modular root extraction rather than ordinary RSA inversion. - Filtering the CRT-combined 8192nd roots against all 13 ciphertexts leaves one passcode candidate.
- Option 2 can provide a deterministic middle hash state for the chosen
passcode || zero-fillmessage shape. - Option 3 can be converted into a length-extension continuation by placing the matching glue padding inside the answer field.
- The final five-byte authorization value was recovered offline and submitted once; raw recovered values are under
loot/.
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: Crypto
- Challenge: Infosekurus-Query
- 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.
- Query all RSA public-key choices in one session to collect ciphertexts for the fixed session passcode.
- Use the non-coprime exponent row where
phiis returned to factorN. - Enumerate modular 8192nd roots modulo the two primes, combine by CRT, and filter candidates against every RSA ciphertext from the same session.
- Use option 2 to obtain a deterministic middle hash state for
passcode || zero-fill-to-27. - Put the corresponding glue padding inside the 2FA answer so option 3 becomes a length extension of the option-2 message.
- Brute force the local 12^5 authorization space against the displayed digest and submit the recovered value once.
Reusable Lessons
- For RSA with
gcd(e, phi) != 1, recover roots instead of trying to compute a private exponent. - Multiple public-key encryptions of the same plaintext can identify the correct root without knowing the plaintext format.
- Secret-prefix hash designs remain length-extension vulnerable if the attacker can include glue padding in a later accepted message.
- Keep online interaction bounded; move brute force offline once a verifiable digest equation is available.
Dead Ends
- RAG had no useful prior match for this challenge.
- Direct RSA inversion does not work for the vulnerable
e = 8192row because the exponent is non-coprime with the totient.
Tool Quirks
- Heavy crypto tools were unavailable, but Python plus PyCryptodome was sufficient.
- The initial root recovery is fast; the slower step is the local authorization-value brute force.
- Raw recovered passcode, authorization value, final response, and flag are intentionally kept under
loot/.
Evidence Paths
analysis/source-audit.mdanalysis/instrumentation-plan.mdanalysis/rsa-collection.jsonanalysis/hash-sample-stats.jsonanalysis/solution-summary.jsonsolve/solve.pyloot/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.
| Rank | Path | Evidence | Missing Proof | Cheapest Validation | Confidence | Status |
|---|---|---|---|---|---|---|
| 1 | Use the encrypted-passcode oracle across all RSA public-key choices to recover the session passcode, then analyze the custom hash/2FA path to recover or forge the 5-byte random token value. | server.py exposes N, phi conditionally, encrypted_passcode for a fixed random passcode, non-coprime exponent 8192, and a custom AES-based keyed hash used in two_factor_generate. | Query option 1 for all key choices in one session, factor any weak/shared moduli or use provided phi, and check whether any invertible RSA instance decrypts the same passcode. | Medium | Active |
Closed Branches
| Branch | Evidence Tested | Failure Output | Reason Closed | Revisit Condition |
|---|
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 Infosekurus Query, 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.