Skip to content

SigStash Payload Embedding

Kriyos Arcane edited this page Jul 4, 2026 · 4 revisions

SigStash Payload Embedding

A signed PE stores its signature in a PKCS#7 blob near the end of the file. SigStash hides extra data inside that blob, not after it. Windows still sees a valid signature because the hidden data sits in an unsigned attribute field.

Diagram

SigFlip technique

SigStash Direct Mode

SigStash Camouflage Mode

Technical detail

  • PKCS#7 SignerInfo holds both authenticated and unauthenticated attributes.
  • RFC 5652 section 5.3 leaves unsignedAttrs outside the signature check.
  • SigStash writes payload bytes there, so Authenticode stays valid.

Direct mode

  • OID: 1.3.6.1.4.1.311.99.1
  • Shape: SET { OCTET STRING <payload> }
  • Result: the payload sits under a custom unsigned attribute.

Camouflage mode

  • OID: 1.3.6.1.4.1.311.2.4.1
  • Wrapper: fake SPC_NESTED_SIGNATURE
  • Reason: this matches the OID that signtool uses on dual-signed PEs, so the blob blends into a normal Authenticode pattern.

Why this differs from SigFlip

  • SigFlip, CVE-2013-3900, writes data into certificate table padding after the DER blob.
  • EnableCertPaddingCheck rejects that padding.
  • SigStash writes data inside the DER structure itself.
  • Result: EnableCertPaddingCheck does not break SigStash.

Capacity and overhead

DER length encoding supports payloads up to 4 GB in theory. Lab tests round-tripped the following sizes without breaking the signature.

Payload size Roundtrip Signature status
24 bytes success valid
64 KB success valid
1 MB success valid
8 MB success valid
16 MB success valid

ASN.1 overhead

  • Direct mode adds about 15 bytes for the OID, SET, and OCTET STRING headers.
  • Camouflage mode adds about 58 bytes for the ContentInfo and SignedData wrapper.

The wrapper cost is negligible next to the tested payload sizes.

Nested-signature parser behavior

signtool verify /pa ignores nested signatures. signtool verify /all walks them and reports each one separately. In kernel mode, ci.dll iterates nested signatures by hash strength. The camouflage wrapper uses empty signerInfos, which lines up with the cases the kernel skips.

Dual-signed PE notes

Dual-signed PEs carry two WIN_CERTIFICATE entries. The embed tool preserves both entries. --signer-index selects which entry receives the payload. Default -1 targets the last entry, which is usually the SHA-256 signature.

Clone this wiki locally