Challenge / Crypto

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

MediumPublished 2024-04-11Sanitized local writeup

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.

Infosekurus Query sanitized attack graph

Walkthrough flow

01

Query all RSA public-key choices in one session to...

02

Use the non-coprime exponent row where phi is...

03

Enumerate modular 8192nd roots modulo the two primes,...

04

Use option 2 to obtain a deterministic middle hash...

05

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.

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.

  • 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:

text
passcode || zero-fill-to-27-bytes

For 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:

text
zero-fill || glue-padding-for-64+27-byte-prefix

This 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:

bash
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-passcode

Full solve:

bash
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.txt

Non-sensitive solve metadata:

  • analysis/rsa-collection.json
  • analysis/hash-sample-stats.json
  • analysis/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

FileSizeSHA256TypeNotes
files/a12c7385-87c1-4dbe-88c1-ad83c30e223c.zip2787<hash redacted>Zip archive data, at least v1.0 to extract, compression method=storezip entries: 2 shown in artifact inventory JSON
files/extracted/crypto_infosekurus_query/server.py10436<hash redacted>Python script text executable, Unicode text, UTF-8 text, with CRLF line terminators

Evidence Ledger

TimeActionOutput/FileFindingConfidenceNext
2026-06-12T08:32:04Zharness initchallenge-state.jsonWorkspace initialized with deterministic state fileHighInventory artifacts
2026-06-12T08:32:17Zartifact inventoryanalysis/artifact-inventory.json2 artifact(s) inventoriedHighBuild or update hypotheses
2026-06-12T08:33:42Zhypothesis recordedhypothesis-board.mdUse 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.MediumQuery 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:17Zsource auditanalysis/source-audit.mdSource audit recordedHighGate before exploit
2026-06-12T08:34:17Zcheckpoint recordedanalysis/checkpoint-triage-20260612T083417664455Z-abde3540.mdCheckpoint for TRIAGEHighUse checkpoint to drive next decision
2026-06-12T08:34:17Zinstrumentation plananalysis/instrumentation-plan.mdRecover the fixed session passcode from the RSA menu, derive a source-backed 2FA bypass, and capture the flag with a bounded authenticated interaction.HighStop 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:38ZRAG queryanalysis/rag/rag-query-20260612T083426300763Z-088172f4.txtRAG helper exited 0; output savedMediumRecord retrieval tag and validation
2026-06-12T08:35:05ZRAG recordanalysis/rag-records.mdRetrieved memory tagged MISSINGMediumValidate or reject with live evidence
2026-06-12T08:35:05Zlocal memory recordanalysis/local-memory-records.mdPrior local notes reviewed as fallback/advisory contextMediumValidate against current evidence
2026-06-12T08:35:16Zevaluatoranalysis/evaluator-20260612T083516170618Z-0fc62dee.mdProceedHighRun gated remote collection and write solver outputs to analysis/ and loot/.
2026-06-12T08:50:40Zflag captureloot/flag.txtHTB-format flag captured; raw value kept in loot onlyHighWrite solution and run completion gate
2026-06-12T08:52:11Zcompletion gatechallenge-state.jsonCompletion gate passed; state marked COMPLETEHighOptional sanitized memory summary approval

Key Findings

  • Option 1 exposes the same session passcode encrypted under 13 public-key choices.
  • Choice 6 uses exponent 8192 and returns phi; 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-fill message 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:

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: 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.

  1. Query all RSA public-key choices in one session to collect ciphertexts for the fixed session passcode.
  2. Use the non-coprime exponent row where phi is returned to factor N.
  3. Enumerate modular 8192nd roots modulo the two primes, combine by CRT, and filter candidates against every RSA ciphertext from the same session.
  4. Use option 2 to obtain a deterministic middle hash state for passcode || zero-fill-to-27.
  5. Put the corresponding glue padding inside the 2FA answer so option 3 becomes a length extension of the option-2 message.
  6. 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 = 8192 row 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.md
  • analysis/instrumentation-plan.md
  • analysis/rsa-collection.json
  • analysis/hash-sample-stats.json
  • analysis/solution-summary.json
  • solve/solve.py
  • loot/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.

RankPathEvidenceMissing ProofCheapest ValidationConfidenceStatus
1Use 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.MediumActive

Closed Branches

BranchEvidence TestedFailure OutputReason ClosedRevisit 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.