Challenge / Reversing

Partial Encryption

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

EasyPublished 2025-07-15Sanitized local writeup

Scenario

Partial Encryption attack path

Partial 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 Reversing evidence, validation, and reusable operator lessons.

Partial Encryption sanitized attack graph

Walkthrough flow

01

Extracted the HTB ZIP with the standard archive...

02

Static triage identified a small AES-NI runtime...

03

Reimplemented the narrow AES-NI decryptor locally...

04

Decrypted .data chunks into analysis/decrypted/ and...

05

Found validator stubs that compare individual argv[1]...

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.

  • Reversing/Partial-Encryption/writeup.md
  • htb-challenge/Reversing/Partial-Encryption/notes.md
  • htb-challenge/Reversing/Partial-Encryption/memory-summary.md
  • htb-challenge/Reversing/Partial-Encryption/hypothesis-board.md
  • HTB/_knowledge/exports/ctf-lightrag-latest-203412/documents/challenge__Reversing__Partial-Encryption__memory-summary.md.9392879455.md
  • HTB/_knowledge/exports/ctf-lightrag-latest-203412/documents/challenge__Reversing__Partial-Encryption__notes.md.f5a4260fe1.md

Technical Walkthrough

Writeup

Challenge

  • Name: Partial-Encryption
  • Category: Reversing
  • Difficulty: Easy
  • Mode: file

Summary

The program hides most of its validation logic in encrypted .data chunks. The static body contains a small AES-NI-based decryptor that allocates executable memory, decrypts selected chunks at runtime, and calls them. Reimplementing that decryptor reveals validator stubs that compare each flag character by index.

Artifact Inventory

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

  • partialencryption.exe: PE32+ x86-64 Windows console executable.
  • Imports include memory-permission APIs and anti-debug/runtime helpers, consistent with dynamically decrypted code.

Analysis

The static disassembly identified two important routines:

  • 0x140001000: decrypts one 16-byte block using aeskeygenassist, pxor, and aesdeclast.
  • 0x140001050: loops across encrypted chunks, uses the block decryptor, then calls VirtualProtect before returning an executable buffer.

After reproducing the decryptor, the decrypted payloads in analysis/decrypted/ disassembled as normal x64 stubs. The large stubs load argv[1], compare fixed character positions, and set a failure flag when any comparison fails.

Solve

Run:

bash
python3 solve/solve.py

The script reads the PE file, decrypts the runtime chunks, extracts the (index, character) comparisons, and prints the reconstructed HTB flag.

Flag

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

Lessons

  • When static strings and control flow are sparse but the binary imports memory-permission APIs, inspect runtime unpacking/decryption first.
  • AES-NI instructions can be reimplemented for the narrow operation used by the binary; full Windows execution was not required.

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: Partial-Encryption
  • Category: Reversing
  • Difficulty: Easy
  • Mode: file
  • Remote instance: none
  • Start time: 2026-06-10T08:53:40Z
  • 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/a12c7378-617d-418e-8f57-5b462527b7bc.zip6067<hash redacted>Zip archive data, at least v1.0 to extract, compression method=storezip entries: 2 shown in artifact inventory JSON
files/extracted/rev_partialencryption/partialencryption.exe13312<hash redacted>PE32+ executable (console) x86-64, for MS Windows

Evidence Ledger

TimeActionOutput/FileFindingConfidenceNext
2026-06-10T08:53:40Zharness initchallenge-state.jsonWorkspace initialized with deterministic state fileHighInventory artifacts
2026-06-10T08:54:04Zartifact inventoryanalysis/artifact-inventory.json2 artifact(s) inventoriedHighBuild or update hypotheses
2026-06-10T08:54:21Zhypothesis recordedhypothesis-board.mdWindows PE performs partial/runtime decryption; inspect imports/strings first, then run under Wine or emulate/decrypt transformed data dynamically.MediumRun file/strings/imports, then attempt controlled execution under Wine or equivalent to capture behavior and generated/decrypted data.
2026-06-10T08:54:32Zresearch recordanalysis/research/research-records.mdResearch tagged MATCHEDMediumValidate against current evidence
2026-06-10T08:59:57Zflag captureloot/flag.txtHTB-format flag captured; raw value kept in loot onlyHighWrite solution and run completion gate
2026-06-10T08:59:57Zcompletion gatechallenge-state.jsonCompletion gate passed; state marked COMPLETEHighOptional sanitized memory summary approval
2026-06-10T09:00:09Zevaluatoranalysis/evaluator-20260610T090009280414Z-6c88eb10.mdProceedHighSolved locally with solve/solve.py and captured the recovered flag.

Key Findings

  • The binary is a PE32+ Windows console executable that imports VirtualAlloc, VirtualProtect, VirtualFree, IsDebuggerPresent, and CRT output routines.
  • Static triage showed AES-NI instructions in the unpacking helper: aeskeygenassist and aesdeclast.
  • The runtime decryptor at 0x140001050 decrypts .data chunks block-by-block, allocates executable memory, marks it executable, and calls the decrypted code.
  • Reproduced the AES-NI decryptor locally and wrote decrypted payloads under analysis/decrypted/.
  • The decrypted payloads are validation stubs that compare individual argv[1] character positions and OR mismatches into a failure variable.
  • solve/solve.py reconstructs the expected flag from the decrypted validator comparisons without requiring Wine or a Windows debugger.

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: Reversing
  • Challenge: Partial-Encryption
  • 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 the HTB ZIP with the standard archive password and inventoried a single PE32+ x86-64 Windows console executable.
  2. Static triage identified a small AES-NI runtime decryptor using aeskeygenassist, aesdeclast, VirtualAlloc, and VirtualProtect.
  3. Reimplemented the narrow AES-NI decryptor locally instead of requiring Wine or a Windows debugger.
  4. Decrypted .data chunks into analysis/decrypted/ and disassembled them as raw x64 code.
  5. Found validator stubs that compare individual argv[1] character positions against constants and OR mismatch bits into a failure flag.
  6. Wrote solve/solve.py to decrypt the chunks, extract the (index, character) comparisons, reconstruct the HTB flag, and support harness capture.

Reusable Lessons

  • When a reversing prompt says static analysis is weak and the binary imports memory-permission APIs, look for runtime-decrypted executable chunks before spending time on string hunting.
  • AES-NI instruction usage can often be reproduced narrowly; a full emulator is not always required.
  • For validator stubs, direct comparison extraction from decrypted code can be faster and more reliable than attempting to run the original Windows PE.

Dead Ends

  • Raw static strings did not reveal the flag.
  • Direct local execution was not used because Wine was unavailable; the decryptor path was sufficient.

Tool Quirks

  • capstone, pefile, Wine, Ghidra, radare2/rizin, and gdb were not available locally.
  • x86_64-w64-mingw32-objdump was available and sufficient for PE and raw x64 disassembly.
  • Crypto was installed but the final solver uses a pure-Python AES table implementation for portability.

Evidence Paths

  • analysis/disasm-mingw.txt
  • analysis/decrypted/manifest.txt
  • analysis/decrypted/*.asm
  • 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
1Windows PE performs partial/runtime decryption; inspect imports/strings first, then run under Wine or emulate/decrypt transformed data dynamically.Challenge prompt says static analysis did not reveal much; extracted artifact is a small Windows PE executable.Run file/strings/imports, then attempt controlled execution under Wine or equivalent to capture behavior and generated/decrypted data.MediumActive

Closed Branches

BranchEvidence TestedFailure OutputReason ClosedRevisit Condition

Memory Summary

approval_required: true

Sanitized Memory Summary

Metadata

  • Platform: HackTheBox Challenges
  • Category: Reversing
  • Challenge: Partial-Encryption
  • 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 the HTB ZIP with the standard archive password and inventoried a single PE32+ x86-64 Windows console executable.
  2. Static triage identified a small AES-NI runtime decryptor using aeskeygenassist, aesdeclast, VirtualAlloc, and VirtualProtect.
  3. Reimplemented the narrow AES-NI decryptor locally instead of requiring Wine or a Windows debugger.
  4. Decrypted .data chunks into analysis/decrypted/ and disassembled them as raw x64 code.
  5. Found validator stubs that compare individual argv[1] character positions against constants and OR mismatch bits into a failure flag.
  6. Wrote solve/solve.py to decrypt the chunks, extract the (index, character) comparisons, reconstruct the HTB flag, and support harness capture.

Reusable Lessons

  • When a reversing prompt says static analysis is weak and the binary imports memory-permission APIs, look for runtime-decrypted executable chunks before spending time on string hunting.
  • AES-NI instruction usage can often be reproduced narrowly; a full emulator is not always required.
  • For validator stubs, direct comparison extraction from decrypted code can be faster and more reliable than attempting to run the original Windows PE.

Dead Ends

  • Raw static strings did not reveal the flag.
  • Direct local execution was not used because Wine was unavailable; the decryptor path was sufficient.

Tool Quirks

  • capstone, pefile, Wine, Ghidra, radare2/rizin, and gdb were not available locally.
  • x86_64-w64-mingw32-objdump was available and sufficient for PE and raw x64 disassembly.
  • Crypto was installed but the final solver uses a pure-Python AES table implementation for portability.

Evidence Paths

  • analysis/disasm-mingw.txt
  • analysis/decrypted/manifest.txt
  • analysis/decrypted/*.asm
  • solve/solve.py
  • loot/flag.txt

Ingestion Decision

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

Notes

Notes

Scope

  • Challenge: Partial-Encryption
  • Category: Reversing
  • Difficulty: Easy
  • Mode: file
  • Remote instance: none
  • Start time: 2026-06-10T08:53:40Z
  • 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/a12c7378-617d-418e-8f57-5b462527b7bc.zip6067<hash redacted>Zip archive data, at least v1.0 to extract, compression method=storezip entries: 2 shown in artifact inventory JSON
files/extracted/rev_partialencryption/partialencryption.exe13312<hash redacted>PE32+ executable (console) x86-64, for MS Windows

Evidence Ledger

TimeActionOutput/FileFindingConfidenceNext
2026-06-10T08:53:40Zharness initchallenge-state.jsonWorkspace initialized with deterministic state fileHighInventory artifacts
2026-06-10T08:54:04Zartifact inventoryanalysis/artifact-inventory.json2 artifact(s) inventoriedHighBuild or update hypotheses
2026-06-10T08:54:21Zhypothesis recordedhypothesis-board.mdWindows PE performs partial/runtime decryption; inspect imports/strings first, then run under Wine or emulate/decrypt transformed data dynamically.MediumRun file/strings/imports, then attempt controlled execution under Wine or equivalent to capture behavior and generated/decrypted data.
2026-06-10T08:54:32Zresearch recordanalysis/research/research-records.mdResearch tagged MATCHEDMediumValidate against current evidence
2026-06-10T08: <REDACTED>
2026-06-10T08:59:57Zcompletion gatechallenge-state.jsonCompletion gate passed; state marked COMPLETEHighOptional sanitized memory summary approval
2026-06-10T09: <REDACTED>

Key Findings

  • The binary is a PE32+ Windows console executable that imports VirtualAlloc, VirtualProtect, VirtualFree, IsDebuggerPresent, and CRT output routines.
  • Static triage showed AES-NI instructions in the unpacking helper: aeskeygenassist and aesdeclast.
  • The runtime decryptor at 0x140001050 decrypts .data chunks block-by-block, allocates executable memory, marks it executable, and calls the decrypted code.
  • Reproduced the AES-NI decryptor locally and wrote decrypted payloads under analysis/decrypted/.
  • The decrypted payloads are validation stubs that compare individual argv[1] character positions and OR mismatches into a failure variable.
  • solve/solve.py reconstructs the expected flag from the decrypted validator comparisons without requiring Wine or a Windows debugger.

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 it like taking apart a small appliance on a workbench. You do not need every screw at once; you trace the control path and rebuild just enough logic to make it reveal the answer.

For Partial 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.